OpenCV教程 之 基础操作:图像的读入、输出、访问、Mat类、色彩缩减与线性融合
2017-10-06 23:18
351 查看
这里总结了一点关于OpenCV3版本的简单操作、供初学者快速入门。过程中会对代码分块逐个讲解,并给出测试结果图
![](https://oscdn.geek-share.com/Uploads/Images/Content/201710/06/5f90f065abf2ee50f26a6602c214987f)
OpenCV图标
测试结果
![](https://oscdn.geek-share.com/Uploads/Images/Content/201710/06/b9046e9706355a18a7f7469c6b0b9713)
![](https://oscdn.geek-share.com/Uploads/Images/Content/201710/06/83f9a8f738da2104706c68f86a25bba8)
![](https://oscdn.geek-share.com/Uploads/Images/Content/201710/06/30bcd37e80c2389f835918b021765716)
![](https://oscdn.geek-share.com/Uploads/Images/Content/201710/06/140be7c64cc5ade6cd525e12f0942382)
在解决问题中,传递图像是常有的事,但图像的复制会造成很大的计算开销与空间损失,因此,OpenCV使用了引用计数机制,其思路是让每个Mat对像有自己的信息头,但共享一个矩阵,接下来简单介绍一下Mat类型的创建,和元素访问
显示结果
其实仅用这些颜色中最具有代表性的很小的部分,就足以达到相同的效果,颜色空间缩减的做法是:将现有的颜色空间值除以某个输入值,以获得较少的颜色数。比如,颜色0~9可以取值为0,10~19可以取值为10,依次类推,依据这种思想,我们可以实现如下代码
效果图
![](https://oscdn.geek-share.com/Uploads/Images/Content/201710/06/3455aa5949b426cb03d31b2ca6ebe756)
接下来在要做的演示中,我们用到的两张图如下
![](https://oscdn.geek-share.com/Uploads/Images/Content/201710/06/3c3e6641b7de5f2262c9cfb6059f2328)
![](https://oscdn.geek-share.com/Uploads/Images/Content/201710/06/65590efa3b96fd6451fb8d3a2bcf9f93)
演示代码为
效果图:
一、OpenCV简介
OpenCV,是一个基于开源发行的跨平台计算机视觉库,它实现了图像处理和计算机视觉方面的很多通用的算法,已经成为了计算机视觉领域最有力的研究工具之一。其全称是Open Source Computer Vision Library,直译就是开源计算机视觉库,OpenCV由一系列C函数和C++类构成,轻量且高效,强大的OpenCV除了用C/C++语言进行开发和使用之外,还支持使用C#、Ch、Ruby等编程语言,同时提供了对Python、Ruby、MATLAB等语言的接口,通用性强。本文所用的语言为C++,在eclipse-Mac环境下开发,代码基本兼容Windows系统OpenCV图标
二、图像的读入与输出
作为最基本的图像操作,读入和输出这里需要介绍两个非常实用的基本函数imread还有imshow2.1 imread
//imread的函数原型 Mat imread(const string& filename, int flags = 1); (1)第一个参数,const string&类型的filepath,填我们需要载入的图片路径名 imread函数支持读取的常用文件类型有: > Windows位图: *.bmp,*.dib >JPEG文件: *.jpeg,*jpg,*jpe >JPEG 2000文件:*.jp2 >PNG图片: *.png >... (2)第二个参数,int类型的flags,为载入标识,它指定一个加载图像的颜色类型,自带默认值为1 其备选参数和意义为: >0 : 将原图准换为灰度图像读取 >1 : 返回一个3通道的彩色图像 >2 : 如果读入的图像深度为16位活着32位,则返回对应深度的图像,否则转换为8位图像再返回 >4 : 读取任意色彩模式的图像,根据原图 ps :flags可以不取以上枚举值,当 flags > 0时,等价于1 flags < 0时,返回包含Alpha通道的加载图像
2.2 imshow
//imshow的函数原型 void imshow(const string& winname,InputArray mat); (1)第一个参数:const string&类型的winname,需要填写显示的窗口标识名称 (2)第二个参数:InputArray 类型的mat,填写需要显示的图像
2.3 应用举例
#include <opencv2/opencv.hpp> using namespace cv; int main(){ Mat g_srcImage1 = imread("/Users/zhuxiaoxiansheng/Desktop/lalaland_1.jpeg",0); resize(g_srcImage1,g_srcImage1,Size(1000,640)); //设定图像大小 imshow("flags = 0",g_srcImage1); //显示图像 waitKey(); //等待任意键输入 Mat g_srcImage2 = imread("/Users/zhuxiaoxiansheng/Desktop/lalaland_1.jpeg",1); resize(g_srcImage2,g_srcImage2,Size(1000,640)); imshow("flags = 1",g_srcImage2); waitKey(); Mat g_srcImage3 = imread("/Users/zhuxiaoxiansheng/Desktop/lalaland_1.jpeg",2); resize(g_srcImage3,g_srcImage3,Size(1000,640)); imshow("flags = 2",g_srcImage3); waitKey(); Mat g_srcImage4 = imread("/Users/zhuxiaoxiansheng/Desktop/lalaland_1.jpeg",4); resize(g_srcImage4,g_srcImage4,Size(1000,640)); imshow("flags = 4",g_srcImage4); waitKey(); return 0; }
测试结果
三、图像的基本管理:Mat类
自从OpenCV跨入了2.0时代,Mat类数据结构便成为了图像处理的主打类型,Mat类由两部分组成:矩阵头(包含矩阵尺寸、存储方法、存储地址等信息)和一个指向存储所有像素值的矩阵(根据所选存储方法的不同,矩阵可以是不同的维数)的指针。矩阵头的尺寸是一个常数值,但矩阵本事身的尺寸会依图像的不同而不同,通常比矩阵头的尺寸数大数个数量级。在解决问题中,传递图像是常有的事,但图像的复制会造成很大的计算开销与空间损失,因此,OpenCV使用了引用计数机制,其思路是让每个Mat对像有自己的信息头,但共享一个矩阵,接下来简单介绍一下Mat类型的创建,和元素访问
3.1 Mat类的创建
这里介绍几种常用的Mat创建方法(1)使用Mat的构造函数 Mat M(2,2,CV_8UC3,Scalar:all(0)); cout << M << endl; 上式中CV_8UC3是指使用8位的unsigned char型,每个像素由三个元素组成三通道 Scalar是一个short型向量,能用指定的定制化值来初始化矩阵,上式的输出为 [ 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0] (2)采用Matlab的初始化方式 Mat E = Mat::eye(4,4,CV_64F); cout << "E = " << endl << E << endl << endl; Mat O = Mat::ones(2,2,CV_32F); cout << "O = " << endl << O << endl << endl; Mat Z = Mat::zeros(3,3,CV_8UC1); cout << "Z = " << endl << Z << endl << endl; 上式的输出为: E = [1, 0, 0, 0; 0, 1, 0, 0; 0, 0, 1, 0; 0, 0, 0, 1] O = [1, 1; 1, 1] Z = [0, 0, 0; 0, 0, 0; 0, 0, 0]
3.2 Mat类的元素值访问
这一部分可以简单的用一个swich代表来表述,示例如下:switch(img.channels()) //根据图像的通道数作出不同的选择 { case 1: {for(int i=0;i<img.rows;i++) { for(int j=0;j<img.cols;j++) { img.at<uchar>(i,j)=0; //访问单通道元素 } } break; } case 3: { for(int i=0;i<img.rows;i++) { for(int j=0;j<img.cols;j++) { img.at<Vec3b>(i,j)[0]=0; //访问三通道元素 img.at<Vec3b&g e729 t;(i,j)[1]=0; img.at<Vec3b>(i,j)[2]=0; } } break; } }
3.3 应用举例
#include <opencv2/opencv.hpp> #include <iostream> using namespace cv; using namespace std; int main(){ Mat A(2,2,CV_8UC3),B,C; //定义A矩阵,设定其结构为2X2,3通道颜色,并声明B,C randu(A,0,255); //给A随机赋值 B = A; //引用 A.copyTo(C); //复制 cout << "A = " << endl << A << endl; cout << "B = " << endl << B << endl; cout << "C = " << endl << C << endl <<endl; A.at<Vec3b>(1,1)[0] = 0; //改变A的(1,1)元素三个通道的值 A.at<Vec3b>(1,1)[1] = 0; A.at<Vec3b>(1,1)[2] = 0; cout << "A = " << endl << A << endl; cout << "B = " << endl << B << endl; cout << "C = " << endl << C << endl; return 0; }
显示结果
A = [ 91, 2, 79, 179, 52, 205; 236, 8, 181, 239, 26, 248] B = [ 91, 2, 79, 179, 52, 205; 236, 8, 181, 239, 26, 248] C = [ 91, 2, 79, 179, 52, 205; 236, 8, 181, 239, 26, 248] A = [ 91, 2, 79, 179, 52, 205; 236, 8, 181, 0, 0, 0] B = [ 91, 2, 79, 179, 52, 205; 236, 8, 181, 0, 0, 0] C = [ 91, 2, 79, 179, 52, 205; 236, 8, 181, 239, 26, 248]
四、图像的色彩缩减
我们知道,若矩阵元素存储的是单通道像素,使用C或C++的无符号字符类型,那么像素可能有256个不同的值。但若是三通道图像,这种存储格式的颜色会达到一千六百多万种,用如此之多的颜色来进行处理,可能会对算法性能造成严重影响。其实仅用这些颜色中最具有代表性的很小的部分,就足以达到相同的效果,颜色空间缩减的做法是:将现有的颜色空间值除以某个输入值,以获得较少的颜色数。比如,颜色0~9可以取值为0,10~19可以取值为10,依次类推,依据这种思想,我们可以实现如下代码
#include <iostream> #include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp> #include <opencv2/opencv.hpp> using namespace cv; using namespace std; void colorReduce(Mat& inputImage,Mat& outputImage,int div); int main(){ Mat srcImage = imread("/Users/zhuxiaoxiansheng/Desktop/lalaland_1.jpeg"); resize(srcImage,srcImage,Size(1000*1.5,640*1.5)); Mat dstImage; dstImage.create(srcImage.rows,srcImage.cols,srcImage.type()); colorReduce(srcImage,dstImage,32); imshow("效果图",dstImage); waitKey(0); return 0; } void colorReduce(Mat& inputImage,Mat&outputImage,int div){ outputImage = inputImage.clone(); Mat_<Vec3b>::iterator it = outputImage.begin<Vec3b>(); Mat_<Vec3b>::iterator itend = outputImage.end<Vec3b>(); for(;it != itend;++it){ (*it)[0] = (*it)[0]/div*div + div/2; (*it)[1] = (*it)[1]/div*div + div/2; (*it)[2] = (*it)[2]/div*div + div/2; } }
效果图
五、两张图片的线形融合
两张图片的线形融合,在OpenCV里有一个非常实用的函数,接下来,先简单介绍一下这个函数//addWeighted的函数原型 void addWeighted(InputArray src1,double alpha,InputArray Src2,double beta,double gamma,OutputArray dst,int dtype = -1); >第一个参数,表示第一个需要加权的图像M >第二个参数,表示第一个数组的权重 >第三个参数,表示第二个需要加权的图像,两个图像的大小与通道数必须相等 >第四个参数,表示第二个图像的权重 >第五个参数,一个加到总和上的标量值,影响合成图片的亮度 >第六个参数,输出图像 >第七个参数,输出图像的深度,默认-1,即和第一个输入图像相同
接下来在要做的演示中,我们用到的两张图如下
演示代码为
#include <opencv2/imgproc/imgproc.hpp> #include <opencv2/opencv.hpp> using namespace cv; #define WINDOW_NAME "【线性混合示例】" const int g_nMaxAlphaValue = 100; int g_nAlphaValueSlider; double g_dAlphaValue; double g_dBetaValue; Mat g_srcImage1; Mat g_srcImage2; Mat g_dstImage; void on_Trackbar(int ,void*){ g_dAlphaValue = (double) g_nAlphaValueSlider/g_nMaxAlphaValue; g_dBetaValue = 1 - g_dAlphaValue; addWeighted(g_srcImage1,g_dAlphaValue,g_srcImage2,g_dBetaValue,0.0,g_dstImage); imshow(WINDOW_NAME, g_dstImage); } int main(int argc,char *argv[]){ g_srcImage1 = imread("/Users/zhuxiaoxiansheng/Desktop/lalaland_1.jpeg"); g_srcImage2 = imread("/Users/zhuxiaoxiansheng/Desktop/lalaland_2.jpg"); resize(g_srcImage1,g_srcImage1,Size(1000*1.5,640*1.5)); resize(g_srcImage2,g_srcImage2,Size(1000*1.5,640*1.5)); if(!g_srcImage1.data){ printf("读取第一幅图片错误,请确定目录下是否有imread函数指定图片存在!\n"); return -1; } if(!g_srcImage2.data){ printf("读取第二幅图片错误,请确定目录下是否有imread函数指定图片存在!\n"); return -1; } g_nAlphaValueSlider = 70; namedWindow(WINDOW_NAME,1); char TrackbarName[50]; sprintf(TrackbarName,"透明值 %d",g_nMaxAlphaValue); createTrackbar(TrackbarName,WINDOW_NAME,&g_nAlphaValueSlider,g_nMaxAlphaValue,on_Trackbar); on_Trackbar(g_nAlphaValueSlider,0); waitKey(0); return 0; }
效果图:
相关文章推荐
- OpenCV-Python——图像的基础操作
- OpenCV 基础知识------图像创建、访问、转换
- opencv 线性图像融合
- opencv图像基础操作
- 凡哥OpenCV基础入门教程(跳一跳专题)-CH2.3-几何图像绘制与文字绘制
- 【OpenCV入门教程之三】 图像的载入,显示和输出 一站式完全解析
- 【OpenCV入门教程之三】 图像的载入,显示和输出 一站式完全解析
- 【OpenCV入门教程之三】 图像的载入,显示和输出 一站式完全解析
- 【OpenCV入门教程之三】 图像的载入,显示和输出 一站式完全解析
- opencv图像线性混合操作
- OpenCV-Python图像处理教程:图像基本操作
- OpenCV入门教程(3)-Mat类之选取图像局部区域
- 【学习OpenCV】教程三:图像的载入,显示和输出
- OpenCV Python教程之图像元素的访问、通道分离与合并
- 凡哥OpenCV基础入门教程(跳一跳专题)-CH1.1-读入图片并显示图片的相关属性
- opencv 学习第二天 图片图像的基础操作
- opencv图像的基础操作
- opencv学习(5)图像像素的访问、颜色通道的分离和融合
- 【opencv 官方教程】翻译8 进阶图像操作--HDR
- python基础教程之popen函数操作其它程序的输入和输出示例