core组件进阶

访问图像像素

存储方式

BGR连续存储有助于提升图像扫描速度。

isContinuous()判断是否是连续存储。

颜色空间缩减

仅用这些颜色中具有代表性的很小的部分,就足以达到同样的效果。

将现有颜色空间值除以某个输入值,获得较少的颜色数。

LUT函数:look up table操作

用于批量进行图像元素查找、扫描和操作图像。

 使用方法如下:

1 Mat lookUpTable(1,256,CV_8U);
2 uchar* p = lookUpTable.data;
3 for(int i=0;i<256;i++)
4     p[i] = table[i];
5 //然后调用函数(I是输入,J是输出)
6 for(int i=0;i<times;++i)
7     LUT(I,lookUpTable,J);

计时函数

两个函数组合起来使用:

double time0 = static_cast<double>(getTickCount());//记录起始时间
//进行图像处理。。。。。。
time0 = ((double)getTickCount() - time0 ) / getTickFrequency();
cout << "此方法运行时间" << time0 << "" << endl;//输出运行时间

访问图像中像素的三类方法

要求:减少图像中颜色的数量,比如原来的图像是256种颜色,希望它变成64种颜色,只需将原来颜色除以4(整除)以后再乘以4就可以

  • 方法一,指针访问:C操作符[];
  • 方法二,迭代器iterator
  • 方法三,动态地址计算

方法一

 1 //---------------------------------【头文件、命名空间包含部分】--------------------------
 2 //        描述:包含程序所使用的头文件和命名空间
 3 //-----------------------------------------------------------------------------------------------
 4 #include <opencv2/core/core.hpp>  
 5 #include <opencv2/highgui/highgui.hpp>  
 6 #include <iostream>  
 7 using namespace std;  
 8 using namespace cv;  
 9 
10 //-----------------------------------【全局函数声明部分】-----------------------------------
11 //          描述:全局函数声明
12 //-----------------------------------------------------------------------------------------------
13 void colorReduce(Mat& inputImage, Mat& outputImage, int div);  
14 
15 //--------------------------------------【main( )函数】---------------------------------------
16 //          描述:控制台应用程序的入口函数,我们的程序从这里开始执行
17 //-----------------------------------------------------------------------------------------------
18 int main( )  
19 {  
20     //【1】创建原始图并显示
21     Mat srcImage = imread("1.jpg");  
22     imshow("原始图像",srcImage);  
23 
24     //【2】按原始图的参数规格来创建创建效果图
25     Mat dstImage;
26     dstImage.create(srcImage.rows,srcImage.cols,srcImage.type());//效果图的大小、类型与原图片相同 
27 
28     //【3】记录起始时间
29     double time0 = static_cast<double>(getTickCount());  
30     printf("

			   当前使用的OpenCV版本为:" CV_VERSION );
31 
32     //【4】调用颜色空间缩减函数
33     colorReduce(srcImage,dstImage,32);  
34 
35     //【5】计算运行时间并输出
36     time0 = ((double)getTickCount() - time0)/getTickFrequency();
37     cout<<"	此方法运行时间为: "<<time0<<""<<endl;  //输出运行时间
38 
39     //【6】显示效果图
40     imshow("效果图",dstImage);  
41     waitKey(0);  
42 }  
43 
44 
45 //---------------------------------【colorReduce( )函数】---------------------------------
46 //          描述:使用【指针访问:C操作符[ ]】方法版的颜色空间缩减函数
47 //----------------------------------------------------------------------------------------------
48 void colorReduce(Mat& inputImage, Mat& outputImage, int div)  //div是要转成多少种颜色的数量
49 {  
50     //参数准备
51     outputImage = inputImage.clone();  //拷贝实参到临时变量
52     int rowNumber = outputImage.rows;  //行数
53     int colNumber = outputImage.cols * outputImage.channels();  //列数 x 通道数=每一行元素的个数
54 
55     //双重循环,遍历所有的像素值
56     for(int i = 0;i < rowNumber;i++)  //行循环
57     {  
58         uchar* data = outputImage.ptr<uchar>(i);  //获取第i行的首地址
59         for(int j = 0;j < colNumber;j++)   //列循环
60         {      
61             // ---------【开始处理每个像素】-------------     
62             data[j] = data[j]/div*div + div/2; 
63             //可以等效使用指针运算从一列移动到下一列,所以还可以这样写:
64             // *data++ = *data/div*div + div/2;
65             // ----------【处理结束】---------------------
66         }  //行处理结束
67     }  
68 }  

Mat类有若干成员函数可以获取图像的属性。公有成员变量cols和rows给出了图像的宽和高,成员函数channels()用于返回图像的通道数。

ptr函数可以得到图像任意行的首地址,ptr是模板函数,返回第i行的首地址。

方法二:

获得图像矩阵的begin和end,然后增加迭代从begin到end,将*操作符添加在迭代指针前,即可访问当前指向的内容。

相比用指针直接访问可能出现越界问题,迭代器很安全。

 1 //-------------------------------------【colorReduce( )函数】-----------------------------
 2 //        描述:使用【迭代器】方法版的颜色空间缩减函数
 3 //----------------------------------------------------------------------------------------------
 4 void colorReduce(Mat& inputImage, Mat& outputImage, int div)  
 5 {  
 6     //参数准备
 7     outputImage = inputImage.clone();  //拷贝实参到临时变量
 8     //获取迭代器
 9     Mat_<Vec3b>::iterator it = outputImage.begin<Vec3b>();  //初始位置的迭代器
10     Mat_<Vec3b>::iterator itend = outputImage.end<Vec3b>();  //终止位置的迭代器
11 
12     //存取彩色图像像素
13     for(;it != itend;++it)  
14     {  
15         // ------------------------【开始处理每个像素】--------------------
16         (*it)[0] = (*it)[0]/div*div + div/2;  
17         (*it)[1] = (*it)[1]/div*div + div/2;  
18         (*it)[2] = (*it)[2]/div*div + div/2;  //三个通道
19         // ------------------------【处理结束】----------------------------
20     }  
21 }  

方法三:

 1 //----------------------------------【colorReduce( )函数】-------------------------------
 2 //          描述:使用【动态地址运算配合at】方法版本的颜色空间缩减函数
 3 //----------------------------------------------------------------------------------------------
 4 void colorReduce(Mat& inputImage, Mat& outputImage, int div)  
 5 {  
 6     //参数准备
 7     outputImage = inputImage.clone();  //拷贝实参到临时变量
 8     int rowNumber = outputImage.rows;  //行数
 9     int colNumber = outputImage.cols;  //列数
10 
11     //存取彩色图像像素
12     for(int i = 0;i < rowNumber;i++)  
13     {  
14         for(int j = 0;j < colNumber;j++)  
15         {      
16             // ------------------------【开始处理每个像素】--------------------
17             outputImage.at<Vec3b>(i,j)[0] =  outputImage.at<Vec3b>(i,j)[0]/div*div + div/2;  //蓝色通道
18             outputImage.at<Vec3b>(i,j)[1] =  outputImage.at<Vec3b>(i,j)[1]/div*div + div/2;  //绿色通道
19             outputImage.at<Vec3b>(i,j)[2] =  outputImage.at<Vec3b>(i,j)[2]/div*div + div/2;  //红是通道
20             // -------------------------【处理结束】----------------------------
21         }  // 行处理结束     
22     }  
23 }  

Mat类的成员函数at(int x,int y)可以用来存取图像元素。要确保指定的数据类型要和矩阵中的数据类型相符合,因为at方法本身不会对任何数据类型进行转换。

对于一个包含彩色图像的Mat,会返回一个有三个8位数组成的向量。opencv将此类型的向量定义为Vec3b,即有三个unsigned char组成的向量,这也解释了为什么存取彩色图像像素的代码的形式:

1 image.at<Vec3b>(j,i)[channel]=value;

感兴趣区域:ROI

这个区域是图像分析所关注的重点,圈住这个区域,方便进行进一步的处理。使用ROI指定想读入的目标,可以减少处理时间,提升精度,带来很大便利。

定义ROI区域的方法有两种:

第一种是使用表示矩形区域的Rect。指定矩形的左上角坐标和矩形的weidth和heigth

1 Mat imageROI;
2 imageROI = image(Rect(500,250,logo.cols,logo.rows))

第二种指定ROI的行或列的范围Range。Range是指起始索引到终止索引(不包括终止索引)的一段连续序列:

1 imageROI = image(Range(250,250+logoImage.rows),Range(200,200+logoImage.cols));

下面代码中,通过一个图像掩模,直接将插入处的像素设置为logo图像的像素值,这样效果会很逼真。

 1 //-----ROI_AddImage()函数
 2 //利用感兴趣区域ROI实现图像叠加
 3 bool ROI_AddImage()
 4 {
 5     //1、读入图像
 6     Mat srcImagel = imread("doata");
 7     Mat logoImage = imread("dota_logo.jpg");
 8     if(!srcImagel.data)
 9     {
10         printf("读取错误!
");
11         return false;
12     }
13     if(!logoImage.data)
14     {
15         printf("读取错误!
");
16         return false;
17     }
18     
19     //2、定义一个Mat类型并给其设定ROI区域
20     Mat imageROI = srcImagel(Rect(200,250,logoImage.cols,logoImage.rows));
21     //3、加载掩模(必须是灰度图)
22     Mat mask = imread("dota_logo.jpg",0);
23     //4、将掩模复制到ROI
24     logoImage.copyTo(imageROI,mask);
25     //5、显示结果
26     namedWindow("test");
27     imshow("test",srcImagel);
28     return true;
29 }

图像掩模一般用来对处理的图像(全部或者局部)进行遮挡,来控制图像处理的区域或处理过程。

掩模一般是小于等于源图像的单通道矩阵,掩模中的值分为两种0和非0。以Mat::copyTo为例,当mask的值不为0,则将源图像拷贝到目标图像,当mask为0,则不进行拷贝,目标图像保持不变。

线性混合操作

线性混合操作是一种典型的二元(两个输入)的像素操作,它的理论公式如下:

通过范围0~1之间改变alpha值,来对两幅图像f(x)或两段视频产生时间上的画面叠化效果,就想幻灯片放映和电影制作中的那样,也就是在幻灯片翻页时设置的前后叶缓慢过度叠加效果。

主要用到了addWeighted函数。

计算数组加权和:addWeighted函数

这个函数的作用是计算两个数组(图像阵列)的加权和:

void addWeighted(inputarray src1, double alpha, inputarray arc2, double beta, double gamma, outputarray dst, int dtyoe=-1);

(1)需要加权的第一个数组,常常填一个Mat

(2)alpht,第一个数组的权重

(3)src2,第二个数组,和第一个数组拥有相同的尺寸和通道数

(4)beta,第二个数组的权重值

(5)gamma,一个加到权重总和上的标量值

(6)dst,输出的数组,和输入的两个数组有相同的尺寸和通道数

(7)dtype,输出阵列的可选深度,默认-1,。当两个输入数组具有相同的深度时,这个参数设置为-1。

最终的计算结果:

其中I是多维数组的索引值。每个通道都要独立的进行处理。当输出数组的深度为CV_32S时,这个函数就不适用了。

 1 /---------------------------------【LinearBlending()函数】-------------------------------------
 2 // 函数名:LinearBlending()
 3 // 描述:利用cv::addWeighted()函数实现图像线性混合
 4 //--------------------------------------------------------------------------------------------
 5 bool  LinearBlending()
 6 {
 7     //【0】定义一些局部变量
 8     double alphaValue = 0.5; 
 9     double betaValue;
10     Mat srcImage2, srcImage3, dstImage;
11 
12     // 【1】读取图像 ( 两幅图片需为同样的类型和尺寸 )
13     srcImage2 = imread("mogu.jpg");
14     srcImage3 = imread("rain.jpg");
15 
16     if( !srcImage2.data ) { printf("读取srcImage2错误! 
"); return false; }
17     if( !srcImage3.data ) { printf("读取srcImage3错误! 
"); return false; }
18 
19     // 【2】进行图像混合加权操作
20     betaValue = ( 1.0 - alphaValue );
21     addWeighted( srcImage2, alphaValue, srcImage3, betaValue, 0.0, dstImage);
22 
23     // 【3】显示原图窗口
24     imshow( "<2>线性混合示例窗口【原图】", srcImage2 );
25     imshow( "<3>线性混合示例窗口【效果图】", dstImage );
26 
27     return true;
28 
29 }

初级图像混合

  1 //---------------------------------【头文件、命名空间包含部分】-------------------------------
  2 //        描述:包含程序所使用的头文件和命名空间
  3 //------------------------------------------------------------------------------------------------                                                                                 
  4 #include <opencv2/core/core.hpp>
  5 #include <opencv2/highgui/highgui.hpp>
  6 #include <iostream>
  7 
  8 using namespace cv;
  9 using namespace std;
 10 
 11 
 12 //-----------------------------------【全局函数声明部分】--------------------------------------
 13 //    描述:全局函数声明
 14 //-----------------------------------------------------------------------------------------------
 15 bool  ROI_AddImage();
 16 bool  LinearBlending();
 17 bool  ROI_LinearBlending();
 18 void   ShowHelpText();
 19 
 20 //-----------------------------------【main( )函数】--------------------------------------------
 21 //    描述:控制台应用程序的入口函数,我们的程序从这里开始
 22 //-----------------------------------------------------------------------------------------------
 23 int main(   )
 24 {
 25     //system调用dos命令
 26     //color 6f是用来设置dos窗口颜色的;1设置窗口背景颜色,f设置窗口字体颜色。
 27     system("color 6F");
 28  
 29     ShowHelpText();
 30 
 31     if(ROI_AddImage( ) && LinearBlending( ) && ROI_LinearBlending( ))
 32     {
 33         cout<<endl<<"
运行成功,得出了需要的图像";
 34     }
 35 
 36     waitKey(0);//等待键位操作,按下-> 返回键盘的操作值,否则返回-1
 37     return 0;
 38 }
 39 
 40 
 41 //-----------------------------------【ShowHelpText( )函数】----------------------------------
 42 //         描述:输出一些帮助信息
 43 //----------------------------------------------------------------------------------------------
 44 void ShowHelpText()
 45 {
 46     //输出欢迎信息和OpenCV版本
 47     printf("

			非常感谢购买《OpenCV3编程入门》一书!
");
 48     printf("

			此为本书OpenCV3版的第25个配套示例程序
");
 49     printf("

			   当前使用的OpenCV版本为:" CV_VERSION );
 50     printf("

  ----------------------------------------------------------------------------
");
 51 }
 52 
 53 
 54 
 55 
 56 //----------------------------------【ROI_AddImage( )函数】----------------------------------
 57 // 函数名:ROI_AddImage()
 58 //    描述:利用感兴趣区域ROI实现图像叠加
 59 //----------------------------------------------------------------------------------------------
 60 bool  ROI_AddImage()
 61 {
 62 
 63     // 【1】读入图像
 64     Mat srcImage1= imread("dota_pa.jpg");
 65     Mat logoImage= imread("dota_logo.jpg");
 66     if( !srcImage1.data ) { printf("读取srcImage1错误~! 
"); return false; }
 67     if( !logoImage.data ) { printf("读取logoImage错误~! 
"); return false; }
 68 
 69     // 【2】定义一个Mat类型并给其设定ROI区域
 70     Mat imageROI= srcImage1(Rect(200,250,logoImage.cols,logoImage.rows));
 71 
 72     // 【3】加载掩模(必须是灰度图)
 73     Mat mask= imread("dota_logo.jpg",0);
 74 
 75     //【4】将掩膜拷贝到ROI
 76     logoImage.copyTo(imageROI,mask);
 77 
 78     // 【5】显示结果
 79     namedWindow("<1>利用ROI实现图像叠加示例窗口");
 80     imshow("<1>利用ROI实现图像叠加示例窗口",srcImage1);
 81 
 82     return true;
 83 }
 84 
 85 
 86 //---------------------------------【LinearBlending()函数】-------------------------------------
 87 // 函数名:LinearBlending()
 88 // 描述:利用cv::addWeighted()函数实现图像线性混合
 89 //--------------------------------------------------------------------------------------------
 90 bool  LinearBlending()
 91 {
 92     //【0】定义一些局部变量
 93     double alphaValue = 0.5; 
 94     double betaValue;
 95     Mat srcImage2, srcImage3, dstImage;
 96 
 97     // 【1】读取图像 ( 两幅图片需为同样的类型和尺寸 )
 98     srcImage2 = imread("mogu.jpg");
 99     srcImage3 = imread("rain.jpg");
100 
101     if( !srcImage2.data ) { printf("读取srcImage2错误! 
"); return false; }
102     if( !srcImage3.data ) { printf("读取srcImage3错误! 
"); return false; }
103 
104     // 【2】进行图像混合加权操作
105     betaValue = ( 1.0 - alphaValue );
106     addWeighted( srcImage2, alphaValue, srcImage3, betaValue, 0.0, dstImage);
107 
108     // 【3】显示原图窗口
109     imshow( "<2>线性混合示例窗口【原图】", srcImage2 );
110     imshow( "<3>线性混合示例窗口【效果图】", dstImage );
111 
112     return true;
113 
114 }
115 
116 //---------------------------------【ROI_LinearBlending()】-------------------------------------
117 // 函数名:ROI_LinearBlending()
118 // 描述:线性混合实现函数,指定区域线性图像混合.利用cv::addWeighted()函数结合定义
119 //              感兴趣区域ROI,实现自定义区域的线性混合
120 //--------------------------------------------------------------------------------------------
121 bool  ROI_LinearBlending()
122 {
123 
124     //【1】读取图像
125     Mat srcImage4= imread("dota_pa.jpg",1);
126     Mat logoImage= imread("dota_logo.jpg");
127 
128     if( !srcImage4.data ) { printf("读取srcImage4错误~! 
"); return false; }
129     if( !logoImage.data ) { printf("读取logoImage错误~! 
"); return false; }
130 
131     //【2】定义一个Mat类型并给其设定ROI区域
132     Mat imageROI;
133     //方法一
134     imageROI= srcImage4(Rect(200,250,logoImage.cols,logoImage.rows));
135     //方法二
136     //imageROI= srcImage4(Range(250,250+logoImage.rows),Range(200,200+logoImage.cols));
137 
138     //【3】将logo加到原图上
139     addWeighted(imageROI,0.5,logoImage,0.3,0.,imageROI);
140 
141     //【4】显示结果
142     imshow("<4>区域线性图像混合示例窗口",srcImage4);
143 
144     return true;
145 }

分离颜色通道、多通道图像混合

通道分离:split函数

split函数用于将一个多通道数组分离成几个单通道数组,这里的array用语境翻译为数组或者阵列。

两个原型:

1 void split(const Mat& src, Mat*mvbegin);
2 void split(inputarray m, outputarrayofarrays mv);

(1)src、m是需要进行分离的多通道数组

(2)mv是函数的输出数组或者输出的vector容器

 1 Mat imageBlueChannel;
 2 Mat imageGreenChannel;
 3 Mat imageRedChannel;
 4 vector<Mat> channels;
 5 
 6 srcImge4 = imread("dota.jpg");
 7 split(srcImage4,channels);//分离色彩通道
 8 
 9 //把载入的三通道图像转换到三个单通道图像,放到vector<Mat>类型的channel中
10 imageBlueChannel = channels.at(0);
11 imageGreenChannel = channels.at(1);
12 imageRedChannel = channels.at(2);

通道合并:merge函数

两个原型:

1 void merge(const Mat* mv, size_tcount, OutputArray dst);
2 void merge(inputarrayofarrays mv, outputarray dst);

(1)mv,需要被合并的输入矩阵或vector容器的阵列,这个mv参数中所有矩阵必须有一样的尺寸和深度。

(2)count,当mv为空白的C数组时,代表输入矩阵的个数,这个参数显然必须大于1

(3)dst,输出矩阵,和mv[0]有一样的尺寸,并且通道的数量是矩阵阵列中的通道的总数

merge函数将一些数组合并成一个多通道数组。第i个输入数组的元素被视为mv[i]。C一般用一中的Mat::at()函数对某个通道进行存取,channels.at(0)。

Mat::at()方法返回一个引用到指定的数组元素。注意是引用,相当于两者等价

  1 //-----------------------------------【头文件包含部分】---------------------------------------
  2 //    描述:包含程序所依赖的头文件
  3 //------------------------------------------------------------------------------------------------                                                                                     
  4 #include <opencv2/core/core.hpp>
  5 #include <opencv2/highgui/highgui.hpp>
  6 #include <iostream>
  7 
  8 //-----------------------------------【命名空间声明部分】---------------------------------------
  9 //    描述:包含程序所使用的命名空间
 10 //-------------------------------------------------------------------------------------------------   
 11 using namespace cv;
 12 using namespace std;
 13 
 14 
 15 //-----------------------------------【全局函数声明部分】--------------------------------------
 16 //    描述:全局函数声明
 17 //-----------------------------------------------------------------------------------------------
 18 bool  MultiChannelBlending();
 19 void ShowHelpText();
 20 
 21 
 22 //-----------------------------------【main( )函数】------------------------------------------
 23 //    描述:控制台应用程序的入口函数,我们的程序从这里开始
 24 //-----------------------------------------------------------------------------------------------
 25 int main(   )
 26 {
 27     system("color 9F");
 28 
 29     ShowHelpText( );
 30 
 31     if(MultiChannelBlending( ))
 32     {
 33         cout<<endl<<"
运行成功,得出了需要的图像~! ";
 34     }
 35 
 36     waitKey(0);
 37     return 0;
 38 }
 39 
 40 
 41 
 42 //-----------------------------------【ShowHelpText( )函数】----------------------------------
 43 //         描述:输出一些帮助信息
 44 //----------------------------------------------------------------------------------------------
 45 void ShowHelpText()
 46 {
 47     //输出欢迎信息和OpenCV版本
 48     printf("

			非常感谢购买《OpenCV3编程入门》一书!
");
 49     printf("

			此为本书OpenCV3版的第26个配套示例程序
");
 50     printf("

			   当前使用的OpenCV版本为:" CV_VERSION );
 51     printf("

  ----------------------------------------------------------------------------
");
 52 }
 53 
 54 
 55 
 56 
 57 
 58 
 59 //-----------------------------【MultiChannelBlending( )函数】--------------------------------
 60 //    描述:多通道混合的实现函数
 61 //-----------------------------------------------------------------------------------------------
 62 bool  MultiChannelBlending()
 63 {
 64     //【0】定义相关变量
 65     Mat srcImage;
 66     Mat logoImage;
 67     vector<Mat> channels;
 68     Mat  imageBlueChannel;
 69 
 70     //=================【蓝色通道部分】=================
 71     //    描述:多通道混合-蓝色分量部分
 72     //============================================
 73 
 74     // 【1】读入图片
 75     logoImage= imread("dota_logo.jpg",0);//灰度图是因为,我们是对一个通道进行线性加权的,所以也要将logoimage变成一个通道
 76     srcImage= imread("dota_jugg.jpg");
 77 
 78     if( !logoImage.data ) { printf("Oh,no,读取logoImage错误~! 
"); return false; }
 79     if( !srcImage.data ) { printf("Oh,no,读取srcImage错误~! 
"); return false; }
 80 
 81     //【2】把一个3通道图像转换成3个单通道图像
 82     split(srcImage,channels);//分离色彩通道
 83 
 84     //【3】将原图的蓝色通道引用返回给imageBlueChannel,注意是引用,相当于两者等价,修改其中一个另一个跟着变
 85     imageBlueChannel= channels.at(0);
 86     //【4】将原图的蓝色通道的(500,250)坐标处右下方的一块区域和logo图进行加权操作,将得到的混合结果存到imageBlueChannel中
 87     addWeighted(
 88                 imageBlueChannel(Rect(500,250,logoImage.cols,logoImage.rows)),//需要加权的第一个数组
 89                 1.0,//第一个数组的权重
 90                 logoImage,//第二个数组,和第一个数组有相同的尺寸和通道数
 91                 0.5//第二个数组的权重
 92                 0,//gamma,加到权重总和上的标量值
 93                 imageBlueChannel(Rect(500,250,logoImage.cols,logoImage.rows))
 94                 );
 95 
 96     //【5】将三个单通道重新合并成一个三通道
 97     merge(channels,srcImage);
 98 
 99     //【6】显示效果图
100     namedWindow(" <1>游戏原画+logo蓝色通道");
101     imshow(" <1>游戏原画+logo蓝色通道",srcImage);
102 
103 
104     //=================【绿色通道部分】=================
105     //    描述:多通道混合-绿色分量部分
106     //============================================
107 
108     //【0】定义相关变量
109     Mat  imageGreenChannel;
110 
111     //【1】重新读入图片
112     logoImage= imread("dota_logo.jpg",0);
113     srcImage= imread("dota_jugg.jpg");
114 
115     if( !logoImage.data ) { printf("读取logoImage错误~! 
"); return false; }
116     if( !srcImage.data ) { printf("读取srcImage错误~! 
"); return false; }
117 
118     //【2】将一个三通道图像转换成三个单通道图像
119     split(srcImage,channels);//分离色彩通道
120 
121     //【3】将原图的绿色通道的引用返回给imageBlueChannel,注意是引用,相当于两者等价,修改其中一个另一个跟着变
122     imageGreenChannel= channels.at(1);
123     //【4】将原图的绿色通道的(500,250)坐标处右下方的一块区域和logo图进行加权操作,将得到的混合结果存到imageGreenChannel中
124     addWeighted(imageGreenChannel(Rect(500,250,logoImage.cols,logoImage.rows)),1.0,
125         logoImage,0.5,0.,imageGreenChannel(Rect(500,250,logoImage.cols,logoImage.rows)));
126 
127     //【5】将三个独立的单通道重新合并成一个三通道
128     merge(channels,srcImage);
129 
130     //【6】显示效果图
131     namedWindow("<2>游戏原画+logo绿色通道");
132     imshow("<2>游戏原画+logo绿色通道",srcImage);
133 
134 
135 
136     //=================【红色通道部分】=================
137     //    描述:多通道混合-红色分量部分
138     //============================================
139 
140     //【0】定义相关变量
141     Mat  imageRedChannel;
142 
143     //【1】重新读入图片
144     logoImage= imread("dota_logo.jpg",0);
145     srcImage= imread("dota_jugg.jpg");
146 
147     if( !logoImage.data ) { printf("Oh,no,读取logoImage错误~! 
"); return false; }
148     if( !srcImage.data ) { printf("Oh,no,读取srcImage错误~! 
"); return false; }
149 
150     //【2】将一个三通道图像转换成三个单通道图像
151     split(srcImage,channels);//分离色彩通道
152 
153     //【3】将原图的红色通道引用返回给imageBlueChannel,注意是引用,相当于两者等价,修改其中一个另一个跟着变
154     imageRedChannel= channels.at(2);
155     //【4】将原图的红色通道的(500,250)坐标处右下方的一块区域和logo图进行加权操作,将得到的混合结果存到imageRedChannel中
156     addWeighted(imageRedChannel(Rect(500,250,logoImage.cols,logoImage.rows)),1.0,
157         logoImage,0.5,0.,imageRedChannel(Rect(500,250,logoImage.cols,logoImage.rows)));
158 
159     //【5】将三个独立的单通道重新合并成一个三通道
160     merge(channels,srcImage);
161 
162     //【6】显示效果图
163     namedWindow("<3>游戏原画+logo红色通道 ");
164     imshow("<3>游戏原画+logo红色通道 ",srcImage);
165 
166     return true;
167 }

图像对比度、亮度调整

一般图像处理算子都是一个函数,接受一个或多个输入图像,并产生输出图像,下面是算子的一般形式:

图像对比度和亮度的操作,属于比较简单的一种--点操作。点操作的特点:仅仅根据输入像素值,来计算相应的输出像素值。这列算子包括亮度(brightness)、对比度(constrast)、颜色校正(colorcorrection)、变换(transformations)。

两种最常用的点操作(点算子)是乘上一个常数(对比度的调节)再加上一个常数(对应亮度的调节),公式如下:

(1)f(x)表示源图像像素;

(2)g(x)表示输出图像像素

(3)a>0,增益,控制对比度

(4)b,偏置,控制亮度

 进一步可以改写成:

访问图片中的像素

 1 //三个for循环执行运算: new_image(i,j) = a*image(i,j) + b
 2 for(int y = 0; y < image.rows; y++)
 3 {
 4     for(int x = 0; x < image.cols; x++)
 5     {
 6         for(int c = 0; c < 3,; c++)
 7         {
 8             new_image.at<vector>(y,x)[c] = saturate_cast<uchar>( 
 9             (g_nContrastValue*0.01) * (image.at<vector>(y,x)[c]) + g_nBrightValue
10             )
11         }
12     }
13 }

访问图像的每一个像素,使用的语法为:image.at<vector>(y,x)[c]

因为计算结果可能会超出像素取值范围(溢出),还可能是非整数,所以用saturate_cast对结果进行转换,确保是有效值。saturate_cast模板函数,用于溢出保护,大致原理如下:

1 if(data<0)
2     data = 0;
3 else if(data > 255)
4     data=255;

示例程序:图像对比度、亮度调节

  1 //--------------------------------------【程序说明】-------------------------------------------
  2 //        程序说明:《OpenCV3编程入门》OpenCV3版书本配套示例程序27
  3 //        程序描述:图像对比度、亮度值调整
  4 //        开发测试所用IDE版本:Visual Studio 2010
  5 //        开发测试所用OpenCV版本:    3.0 beta
  6 //        2014年11月 Created by @浅墨_毛星云
  7 //        2014年12月 Revised by @浅墨_毛星云
  8 //------------------------------------------------------------------------------------------------
  9 
 10 
 11 
 12 //-----------------------------------【头文件包含部分】---------------------------------------
 13 //    描述:包含程序所依赖的头文件
 14 //---------------------------------------------------------------------------------------------- 
 15 #include <opencv2/core/core.hpp>
 16 #include <opencv2/highgui/highgui.hpp>
 17 #include "opencv2/imgproc/imgproc.hpp"
 18 #include <iostream>
 19 
 20 //-----------------------------------【命名空间声明部分】---------------------------------------
 21 //    描述:包含程序所使用的命名空间
 22 //-----------------------------------------------------------------------------------------------   
 23 using namespace std;
 24 using namespace cv;
 25 
 26 
 27 //-----------------------------------【全局函数声明部分】--------------------------------------
 28 //    描述:全局函数声明
 29 //-----------------------------------------------------------------------------------------------
 30 static void ContrastAndBright(int, void *);
 31 void   ShowHelpText();
 32 
 33 //-----------------------------------【全局变量声明部分】--------------------------------------
 34 //    描述:全局变量声明
 35 //-----------------------------------------------------------------------------------------------
 36 int g_nContrastValue; //对比度值
 37 int g_nBrightValue;  //亮度值
 38 Mat g_srcImage,g_dstImage;
 39 //-----------------------------------【main( )函数】--------------------------------------------
 40 //    描述:控制台应用程序的入口函数,我们的程序从这里开始
 41 //-----------------------------------------------------------------------------------------------
 42 int main(   )
 43 {
 44     //改变控制台前景色和背景色
 45     system("color 2F");  
 46 
 47     ShowHelpText();
 48     // 读入用户提供的图像
 49     g_srcImage = imread( "1.jpg");
 50     if( !g_srcImage.data ) { printf("读取g_srcImage图片错误~! 
"); return false; }
 51     //创建和输入图像一样size和type的全零矩阵
 52     g_dstImage = Mat::zeros( g_srcImage.size(), g_srcImage.type() );
 53 
 54     //设定对比度和亮度的初值
 55     g_nContrastValue=80;
 56     g_nBrightValue=80;
 57 
 58     //创建窗口
 59     namedWindow("【效果图窗口】", 1);
 60 
 61     //创建轨迹条
 62     createTrackbar("对比度:",//轨迹条名字
 63                     "【效果图窗口】",//窗口名字
 64                     &g_nContrastValue, //对比度当前值
 65                     300,//对比度最大值
 66                     ContrastAndBright//回调函数
 67                     );
 68     createTrackbar("亮   度:", "【效果图窗口】",&g_nBrightValue, 200,ContrastAndBright );
 69 
 70     //调用回调函数,viod* 默认用0
 71     ContrastAndBright(g_nContrastValue,0);//为什么是0???
 72     ContrastAndBright(g_nBrightValue,0);
 73 
 74     //输出一些帮助信息
 75     cout<<endl<<"	运行成功,请调整滚动条观察图像效果

"
 76         <<"	按下“q”键时,程序退出
";
 77 
 78     //按下“q”键时,程序退出
 79     while(char(waitKey(1)) != 'q') {}
 80     return 0;
 81 }
 82 
 83 
 84 
 85 
 86 //-----------------------------------【ShowHelpText( )函数】----------------------------------
 87 //         描述:输出一些帮助信息
 88 //----------------------------------------------------------------------------------------------
 89 void ShowHelpText()
 90 {
 91     //输出欢迎信息和OpenCV版本
 92     printf("

			非常感谢购买《OpenCV3编程入门》一书!
");
 93     printf("

			此为本书OpenCV3版的第27个配套示例程序
");
 94     printf("

			   当前使用的OpenCV版本为:" CV_VERSION );
 95     printf("

  ----------------------------------------------------------------------------
");
 96 }
 97 
 98 
 99 //-----------------------------【ContrastAndBright( )函数】------------------------------------
100 //    描述:改变图像对比度和亮度值的回调函数
101 //-----------------------------------------------------------------------------------------------
102 static void ContrastAndBright(int, void *)
103 {
104 
105     // 创建窗口
106     namedWindow("【原始图窗口】", 1);
107 
108     // 三个for循环,执行运算 g_dstImage(i,j) = a*g_srcImage(i,j) + b
109     for( int y = 0; y < g_srcImage.rows; y++ )
110     {
111         for( int x = 0; x < g_srcImage.cols; x++ )
112         {
113             for( int c = 0; c < 3; c++ )
114             {
115                 g_dstImage.at<Vec3b>(y,x)[c] = saturate_cast<uchar>( (g_nContrastValue*0.01)*( g_srcImage.at<Vec3b>(y,x)[c] ) + g_nBrightValue );
116             }
117         }
118     }
119 
120     // 显示图像
121     imshow("【原始图窗口】", g_srcImage);
122     imshow("【效果图窗口】", g_dstImage);
123 }

离散傅里叶变换DFT

指傅里叶变换在时域和频域上都呈现离散的形式,将时域信号的采样变换为在离散时间傅里叶变换(DTFT)频域的采样。

对有限长的离散信号做DFT,也应当对其经过周期延拓成周期信号再进行变换。

实际应用中,通常采用快速傅里叶变换来高效计算DFT。

原理

对一张图像使用傅里叶变换就是将它分解成正弦和余弦的和的形式。傅里叶变换的作用实际上就是函数分解的工具。

二维图像傅里叶变换公式:

转换之后的频域值是复数,因此结果使用实数图像+虚数图像,或者幅度图像+相位图像。

实际图像处理过程中,仅仅使用幅度图像,幅度图像包含了原图像几乎所有我们需要的几何信息。如果想通过修改幅度图像或者相位图像来间接修改原空间图像,需要使用逆傅里叶变换得到修改后的空间图像。

频域里面,对于一幅图像,高频部分代表了图像的细节、纹理信息;低频部分代表了图像的轮廓信息。

如果图像受到的噪声位于某个特定的频率范围之内,则可以通过滤波器来恢复原来的图像。

傅里叶变换在图像处理中可以做到图像增强和图像去燥,图像分割之边缘检测、图像特征提取,图像压缩等。

 dft函数

dft函数是对一维或二维浮点数数组进行正向或反向离散傅里叶变换。

1 void dft(inputarray src, outputarray dst, int flags=0, int nonzeroRows=0);

(1)src,输入矩阵,实数或虚数

(2)dst,运算结果,尺寸和类型取决于标识符,也就是flags

(3)flags,转换标识符,默认0

(4)nonzeroRows,默认值0。

原文地址:https://www.cnblogs.com/pacino12134/p/10980325.html