图像处理找两张图片不同

2017-02-22 23:33:46 MysticalRzc 阅读数 3254

使用openCV这个工具进行图片处理还是很简单的,这里总结一下两张大小不同的图片的和成。

openCV合唱两张类型,大小相同的图片是很简单的只需使用addWeighted函数就行了。

函数的参数是addWeighted ( 第一张鱼片,第一张图片所占的比例,第二张图片,第二张图片所占的比例, 0., 输出图片) ;

	Mat imageROI;
	imageROI = girl(Rect(0, 0, leave.cols, leave.rows));
	addWeighted(imageROI,0.5,leave,0.5,0,imageROI);
	imshow("girl",girl);

个人理解,请多多指教。

首先要创建一个矩阵这个矩阵要按照最小的那个图片来,将这个图片放置于大图片当中,有电箱ps中的选择框框,以后的图形合成会在这个框框内进行。下面进行图形合成的时候合成的两张图片是那张较小的图片和全出框框的那个图片,合成之后改变的是大图,二不是带框框的那个图片。

2016-04-06 19:04:00 huapenguag 阅读数 15267
下面这张图片估计很多人都非常熟悉,是的,图像处理领域的标准图Lena,记得之前看到过这张图的原图,突然有兴致,看看这张图片背后的故事。

lena

 

原图如下:

p32605371-2

最开始看到这张原图也是有点吃惊,原来司空见惯的Lenna头像图竟然是这张图的一小部分,那么这样经典的图片是怎么来的呢?

Lenna/Lena是谁?


从comp.compression FAQ中, 我们知道Lenna/Lena是一张数字化了的1972年12月份的《花花公子》折页。Lenna这个单词是在《花花公子》里的拼法,Lena是她名字的瑞典语拼法。(在英语中,为了正确发音,Lena有时被拼做Lenna。)最后的关于Lena Soderberg (ne Sjooblom)的报道说她现在居住在她的本国瑞典,有着幸福的婚姻并是三个孩子的妈妈,在liquor monopoly州有一份工作。1988年,她被某个瑞典计算机相关杂志采访,因为她的照片而发生的一切令她很高兴。这是她第一次得知她的照片在计算机领域被使用。

为何要使用Lenna图像?

David C. Munson. 在“A Note on Lena” 中给出了两条理由:首先,Lenna图像包含了各种细节、平滑区域、阴影和纹理,这些对测试各种图像处理算法很有用。它是一副很好的测试图像!第二,Lena图像里是一个很迷人的女子。所以不必奇怪图像处理领域里的人(大部分为男性)被一副迷人的图像吸引。

谁制作了Lenna图像?

在1999年10月29日,我收到一封来自Chuck McNanis的email,里面告诉我们这个曾经扫描了Lenna图像的“不知名的科研人员”是William K. Pratt博士。下面是email:

我在图像处理研究所的图像处理实验室作为一个系统程序员工作了5年('78-'83),这个实验室发布了Lenna图像和其他一些被人们经常引用做“The baboon image”的图像(包括Manril)。这个“不知名的科研人员”是William K. Pratt博士,现在在Sun Microsystems。他当时正在写一本关于图像处理的书,他需要几张标准图像。For a long time the folded up centerfold that had been the basis for that image was in the file cabinet at the lab. I went back in 1997 to visit and the lab has undergone many changes and the original image files were nowhere to be found. The original distribution format was 1600BPI 9-track tape with each color plane stored separately.

--Chuck McManis (USC Class of '83)

你想看原始的Lenna图像么?

标准的数字Lena图像只是原始图像的脸和露肩特写。最近Chuck Rosenberg获得了原始的《花花公子》杂志的图像,并把它放在网上。下面是相关的一组图片。

200804261209199804109200804261209199824046

据说1997年第五十届IS&T,邀請她参加,她的反应是“那么多年了,大家一定看的很腻吧”有人甚至把 Lena 称为 “The First Lady of Internet”。200804261209199915015200804261209199942015


2017-06-08 15:39:54 chen232450061 阅读数 9435

利用OpenCV处理图片后,希望将处理后的图片和处理前的图片显示在一起,以方便看出两者之间的差别。

       刚开始的想法是利用SetImageRoi和CvCopy函数,可是CvCopy函数必须要求源图片和目的图片的尺寸一致,即使设置了Roi,由于图片的尺寸不一致,运行的时候还是会导致尺寸不匹配的错误。

       然后想到的是SetImageRoi和CvCloneImage函数,但是CvCloneImage函数运行后,会将目的图片的尺寸修改成和源图片的尺寸一致,即使设置了Roi也没有效果。

        后来看到了CvRepeat这个函数,可以完成想要的功能。

[cpp] view plain copy
  1. #include <cv.h>  
  2.   
  3. #include <cxcore.h>  
  4.   
  5. #include <cassert>  
  6.   
  7. using namespace std;  
  8.   
  9. void ImageMerge(IplImage* pImageA,IplImage* pImageB,IplImage*& pImageRes)  
  10. {  
  11. assert(pImageA != NULL && pImageB != NULL);  
  12. assert(pImageA->depth == pImageB->depth && pImageA->nChannels == pImageB->nChannels);  
  13.   
  14. if (pImageRes != NULL)  
  15. {  
  16.    cvReleaseImage(&pImageRes);  
  17.    pImageRes = NULL;  
  18. }  
  19.   
  20. CvSize size;  
  21. size.width = pImageA->width + pImageB->width + 10;  
  22. size.height = (pImageA->height > pImageB->height) ? pImageA->height : pImageB->height;  
  23. pImageRes = cvCreateImage(size,pImageA->depth,pImageA->nChannels);  
  24.   
  25. CvRect rect = cvRect(0,0,pImageA->width,pImageA->height);  
  26. cvSetImageROI(pImageRes,rect);  
  27. cvRepeat(pImageA,pImageRes);  
  28. cvResetImageROI(pImageRes);  
  29. rect = cvRect(pImageA->width + 10,0,pImageB->width,pImageB->height);  
  30. cvSetImageROI(pImageRes,rect);  
  31. cvRepeat(pImageB,pImageRes);  
  32. cvResetImageROI(pImageRes);  
  33. }  



http://blog.sina.com.cn/s/blog_643831a40102vize.html


在Opencv里面很多理论大家说起来都知道,也都能想到怎么做,但是真正实践起来不是那样的,可能你会经历很多次试验的失败,再到睡觉都思索时候你也还是失败,然后洗把脸继续钻研,一行一行钻研,做笔记,画图,后来发现OK了。这也就是研究的乐趣。哈哈哈。不说这么多废话。开始记录技术点。


图片合成:


注意:


1:如果你是两张合并的图片大小尺寸和深度都一样,那随便用那个方法都行。

     cvAdd(pCutPic,pBgImage, pBgImage, NULL);   (参数IplImage*方式贴)

     这个是两个图片像素的叠加,会有两个像素区域加起来颜色太亮,或者太暗。但是如果两幅图其中有一个是

     透明的也无所谓。

      cutROIMat.copyTo(bgROIMat);  (参数Mat直接拷贝)

      cutROIMat.copyTo(bgROIMat,cutROIGrayMask); (参数Mat直接拷贝)

      addWeighted(bgROIMat, 0.5, cutROIMat, 0.5, 0, bgROIMat); 这个能调节两幅图的alpha合成比例。  (参数 Mat直接拷贝)

2:两幅大小不同图片合成,且在另一幅上扣除一块区域合成。

      A:这里需要注意的就是先从一副图上取出那块区域生成一个小的mat图,

            Mat cutROIMat = srcCutPic(Rect

                                           (mBoardRect.x,mBoardRect.y,mBoardRect.width,mBoardRect.height));

             //把要扣出来的内容取出来作为小图。

      B:然后目标图片指定贴上去的区域。

          Mat bgROIMat = mBGImage(Rect

           (mBoardRect.x,mBoardRect.y,mBoardRect.width,mBoardRect.height));

           //注意必须在要贴的大图上指定感兴趣区域。

      C:把这个cutROIMat 作为源小图贴在bgROIMat 上。

             cutROIMat.copyTo(bgROIMat); //也是可以的,只是有黑色矩形框。

             cutROIMat.copyTo(bgROIMat,cutROIGrayMask);  这个是去掉黑色边缘。

             addWeighted(bgROIMat, 0.5, cutROIMat, 0.5, 0, bgROIMat); 这个是调节两个图的alpha合成。避免

             合成区域变色。

注意: srcCutPic= imread("D:\\test.jpg");
           mBGImage = imread("D:\\view.jpg");   这个是自己写的,不是全部代码。只是将理论。自己做笔记备注。


3:如果是两幅图片大小尺寸不一样的。必须在要贴上去的图片上指定ROI,细节:目标图片的ROI的Rect必须 

      是准备贴上去图的区域或者大小。      如下就行:

C++: void Mat::copyTo(OutputArraym)const

C++: void Mat::copyTo(OutputArraym, InputArraymask)const
这个函数可以复制图像到另一个图像或矩阵上,可选参数是掩码
由于叠加的图像大小不一定相等,比如我们这里把一张小照片加到一张大照片上
我们可以在大照片上设置一个和小照片一样大的感兴趣区域
不使用掩码的时候,我们载入一张png,和一张jpg


#include <</SPAN>opencv2/highgui/highgui.hpp>
 #include <</SPAN>opencv2/core/core.hpp>
 
int main(){
cv::Mat image = cv::imread("E:/Image/Fruits.jpg");
cv::Mat logo = cv::imread("E:/logo.png");
cv::Mat imageROI;
imageROI = image(cv::Rect(10,10,logo.cols,logo.rows));
logo.copyTo(imageROI);
cv::namedWindow("result");
cv::imshow("result",image);
cv::waitKey();
 return 0;
} 



原先在png里面是透明的地方,现在成了黑色,可见原来是透明的地方被认为是值0。
我们使用掩码来看看效果,掩码就使用png图片,掩码只能是一个通道的,我们载入灰度图像作为掩码


#include <</SPAN>opencv2/highgui/highgui.hpp>
 #include <</SPAN>opencv2/core/core.hpp>
 
int main(){
cv::Mat image = cv::imread("E:/Image/Fruits.jpg");
cv::Mat logo = cv::imread("E:/logo.png");
cv::Mat mask = cv::imread("E:/logo.png",0);
cv::Mat imageROI;
imageROI = image(cv::Rect(10,10,logo.cols,logo.rows));
logo.copyTo(imageROI,mask);
cv::namedWindow("result");
cv::imshow("result",image);
cv::waitKey();
 return 0;
} 



这样能看出差别了吧。
再来看看另一个函数
C++: void addWeighted(InputArraysrc1, doublealpha, InputArray src2, doublebeta, doublegamma, OutputArray dst, intdtype=-1)
转换成数学表达式就是


#include <</SPAN>opencv2/highgui/highgui.hpp>
 #include <</SPAN>opencv2/core/core.hpp>
 
int main(){
cv::Mat image = cv::imread("E:/Image/Fruits.jpg");
cv::Mat logo = cv::imread("E:/logo.png");
cv::Mat imageROI;
imageROI = image(cv::Rect(10,10,logo.cols,logo.rows));
cv::addWeighted(imageROI, 1.0, logo, 0.3, 0, imageROI);
cv::namedWindow("result");
cv::imshow("result",image);
cv::waitKey();
 return 0;
} 



http://blog.csdn.net/poem_qianmo/article/details/20911629


 

本系列文章由@浅墨_毛星云 出品,转载请注明出处。  

文章链接: http://blog.csdn.net/poem_qianmo/article/details/20911629

作者:毛星云(浅墨)    邮箱: happylifemxy@163.com 

写作当前博文时配套使用的OpenCV版本: 2.4.8


 

在这篇文章里,我们一起学习了在OpenCV中如何定义感兴趣区域ROI,如何使用addWeighted函数进行图像混合操作,以及将ROI和addWeighted函数结合起来使用,对指定区域进行图像混合操作。

PS:文章末尾提供了博文配套程序源代码的下载。


文章开头,依旧是先放一张截图:


 

 





一、设定感兴趣区域——ROI(region of interest)




在图像处理领域,我们常常需要设置感兴趣区域(ROI,region of interest),来专注或者简化我们的工作过程 。也就是从图像中选择的一个图像区域,这个区域是我们图像分析所关注的重点。我们圈定这个区域,以便进行进一步处理。而且,使用ROI指定我们想读入的目标,可以减少处理时间,增加精度,给图像处理来带不小的便利。

 

 


ROI区域定义的两种方法

 


定义ROI区域有两种方法,第一种是使用cv:Rect.顾名思义,cv::Rect表示一个矩形区域。指定矩形的左上角坐标(构造函数的前两个参数)和矩形的长宽(构造函数的后两个参数)就可以定义一个矩形区域。

 

  1. //定义一个Mat类型并给其设定ROI区域  
  2. Mat imageROI;  
  3. //方法一  
  4. imageROI=image(Rect(500,250,logo.cols,logo.rows));  


另一种定义ROI的方式是指定感兴趣行或列的范围(Range)。Range是指从起始索引到终止索引(不包括终止索引)的一连段连续序列。cv::Range可以用来定义Range。如果使用cv::Range来定义ROI,那么前例中定义ROI的代码可以重写为:

  1. //方法二  
  2. imageROI=srcImage3(Range(250,250+logoImage.rows),Range(200,200+logoImage.cols));  


好了,下面我们来看一个实例,显示如何利用ROI将一幅图加到另一幅图的指定位置。大家如果需要拷贝如下的函数中的代码直接运行的话,自己建一个基于console的程序,然后把函数体中的内容拷贝到main函数中,然后找两幅大小合适的图片,加入到工程目录下,并和代码中读取的文件名一致即可。

在下面的代码中,我们通过一个图像掩膜(mask),直接将插入处的像素设置为logo图像的像素值,这样效果会很赞很逼真:

 

  1. //----------------------------------【ROI_AddImage( )函数】----------------------------------  
  2. // 函数名:ROI_AddImage()  
  3. //     描述:利用感兴趣区域ROI实现图像叠加  
  4. //----------------------------------------------------------------------------------------------  
  5. bool ROI_AddImage()  
  6. {  
  7.    
  8.        //【1】读入图像  
  9.        Mat srcImage1= imread("dota_pa.jpg");  
  10.        Mat logoImage= imread("dota_logo.jpg");  
  11.        if(!srcImage1.data ) { printf("你妹,读取srcImage1错误~! \n"); return false; }  
  12.        if(!logoImage.data ) { printf("你妹,读取logoImage错误~! \n"); return false; }  
  13.    
  14.        //【2】定义一个Mat类型并给其设定ROI区域  
  15.        Mat imageROI= srcImage1(Rect(200,250,logoImage.cols,logoImage.rows));  
  16.    
  17.        //【3】加载掩模(必须是灰度图)  
  18.        Mat mask= imread("dota_logo.jpg",0);  
  19.    
  20.        //【4】将掩膜拷贝到ROI  
  21.        logoImage.copyTo(imageROI,mask);  
  22.    
  23.        //【5】显示结果  
  24.        namedWindow("<1>利用ROI实现图像叠加示例窗口");  
  25.        imshow("<1>利用ROI实现图像叠加示例窗口",srcImage1);  
  26.    
  27.        return true;  
  28. }  


这个函数首先是载入了两张jpg图片到srcImage1和logoImage中,然后定义了一个Mat类型的imageROI,并使用cv::Rect设置其感兴趣区域为srcImage1中的一块区域,将imageROI和srcImage1关联起来。接着定义了一个Mat类型的的mask并读入dota_logo.jpg,顺势使用Mat:: copyTo把mask中的内容拷贝到imageROI中,于是就得到了最终的效果图,namedWindow和imshow配合使用,显示出最终的结果。


运行结果如下:


 

这里白色的dota2 logo,就是通过操作之后加上去的图像。

 

 

 



 

二、初级图像混合——线性混合操作

 



 

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

  

                                                              

 

如果看过我之前写的游戏编程Alpha混合那篇文章的朋友们应该有些熟悉,其实他们是差不多的:

 

【Visual C++】游戏开发五十五浅墨 DirectX教程二十二水乳交融的美学:alpha混合技术


 

我们通过在范围0到1之间改变alpha值,来对两幅图像(f0(x)和f1(x))或两段视频(同样为(f0(x)和f1(x))产生时间上的画面叠化(cross-dissolve)效果,就像幻灯片放映和电影制作中的那样。即在幻灯片翻页时设置的前后页缓慢过渡叠加效果,以及电影情节过渡时经常出现的画面叠加效果。

实现方面,我们主要运用了OpenCV中addWeighted函数,我们来全面的了解一下它:

 


addWeighted函数


这个函数的作用是,计算两个数组(图像阵列)的加权和。原型如下:

 

  1. void addWeighted(InputArray src1, double alpha, InputArray src2, double beta, double gamma, OutputArray dst, int dtype=-1);  

  • 第一个参数,InputArray类型的src1,表示需要加权的第一个数组,常常填一个Mat。
  • 第二个参数,alpha,表示第一个数组的权重
  • 第三个参数,src2,表示第二个数组,它需要和第一个数组拥有相同的尺寸和通道数。
  • 第四个参数,beta,表示第二个数组的权重值。
  • 第五个参数,dst,输出的数组,它和输入的两个数组拥有相同的尺寸和通道数。
  • 第六个参数,gamma,一个加到权重总和上的标量值。看下面的式子自然会理解。
  • 第七个参数,dtype,输出阵列的可选深度,有默认值-1。;当两个输入数组具有相同的深度时,这个参数设置为-1(默认值),即等同于src1.depth()。

 

如果用数学公式来表达,addWeighted函数计算如下两个数组(src1和src2)的加权和,得到结果输出给第四个参数。即addWeighted函数的作用可以被表示为为如下的矩阵表达式为:

 

                                                      dst = src1[I]*alpha+ src2[I]*beta + gamma;

 

其中的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错误~! \n"); return false; }  
  17.        if(!srcImage3.data ) { printf("你妹,读取srcImage3错误~! \n"); return false; }  
  18.    
  19.        //【2】做图像混合加权操作  
  20.        betaValue= ( 1.0 - alphaValue );  
  21.        addWeighted(srcImage2, alphaValue, srcImage3, betaValue, 0.0, dstImage);  
  22.    
  23.        //【3】创建并显示原图窗口  
  24.        namedWindow("<2>线性混合示例窗口【原图】 by浅墨", 1);  
  25.        imshow("<2>线性混合示例窗口【原图】 by浅墨", srcImage2 );  
  26.    
  27.        namedWindow("<3>线性混合示例窗口【效果图】 by浅墨", 1);  
  28.        imshow("<3>线性混合示例窗口【效果图】 by浅墨", dstImage );  
  29.    
  30.        return true;  
  31.         
  32. }  



代码解析:


<0>首先当然是定义一些局部变量,alpha值beta值,三个Mat类型的变量。

 

  1. //【0】定义一些局部变量  
  2.        double alphaValue = 0.5;  
  3.        double betaValue;  
  4.        Mat srcImage2, srcImage3, dstImage;  

       

在这里我们设置alpha值为0.5。

 

<1>读取两幅图像并作错误处理

这步很简单,直接上代码:

       

  1. //读取图像 ( 两幅图片需为同样的类型和尺寸 )  
  2.        srcImage2= imread("mogu.jpg");  
  3.        srcImage3= imread("rain.jpg");  
  4. if(!srcImage2.data ) { printf("你妹,读取srcImage2错误~! \n"); return false; }  
  5.        if(!srcImage3.data ) { printf("你妹,读取srcImage3错误~! \n"); return false; }  


在这里需要注意的是,因为我们是对 srcImage1和srcImage2求和,所以它们必须要有相同的尺寸(宽度和高度)和类型,不然多余的部分没有对应的“伴”,肯定会出问题。


<2> 进行图像混合加权操作

载入图像后,我们就可以来生成混合图像,也就是之前公式中的g(x)。为此目的,使用函数 addWeighted 可以很方便地实现,也就是因为 addWeighted 进行了如下计算:

 

这里的对应于addWeighted的第2个参数alpha

这里的对应于addWeighted的第4个参数beta

这里的对应于addWeighted的第5个参数,在上面代码中被我们设为0.0。

代码其实很简单,就是这样: 

  1. //【2】进行图像混合加权操作  
  2.   betaValue = ( 1.0 - alphaValue );  
  3.   addWeighted( srcImage2, alphaValue, srcImage3,betaValue, 0.0, dstImage);  
  4. 其中beta值为1-alpha,gamma值为0。  


<3>创建显示窗口,显示图像。

  1. // 【3】创建并显示原图窗口  
  2.        namedWindow("<2>线性混合示例窗口【原图】 by浅墨", 1);  
  3.        imshow("<2>线性混合示例窗口【原图】 by浅墨", srcImage2 );  
  4.    
  5.        namedWindow("<3>线性混合示例窗口【效果图】 by浅墨", 1);  
  6.        imshow("<3>线性混合示例窗口【效果图】 by浅墨", dstImage );  


接着来看一下运行效果图,首先是原图:



然后是效果图:

 

 





三、综合示例

 



在前面分别介绍的设定感兴趣区域ROI和使用addWeighted函数进行图像线性混合的基础上,我们还将他们两者中和起来使用,也就是先指定ROI,并用addWeighted函数对我们指定的ROI区域的图像进行混合操作,我们将其封装在了一个名为ROI_LinearBlending的函数中,方便大家分块学习。

 


  1. //---------------------------------【ROI_LinearBlending()】-------------------------------------  
  2. // 函数名:ROI_LinearBlending()  
  3. // 描述:线性混合实现函数,指定区域线性图像混合.利用cv::addWeighted()函数结合定义  
  4. //                     感兴趣区域ROI,实现自定义区域的线性混合  
  5. //--------------------------------------------------------------------------------------------  
  6. bool ROI_LinearBlending()  
  7. {  
  8.    
  9.        //【1】读取图像  
  10.        Mat srcImage4= imread("dota_pa.jpg",1);  
  11.        Mat logoImage= imread("dota_logo.jpg");  
  12.    
  13.        if(!srcImage4.data ) { printf("你妹,读取srcImage4错误~! \n"); return false; }  
  14.        if(!logoImage.data ) { printf("你妹,读取logoImage错误~! \n"); return false; }  
  15.    
  16.        //【2】定义一个Mat类型并给其设定ROI区域  
  17.        Mat imageROI;  
  18.               //方法一  
  19.        imageROI=srcImage4(Rect(200,250,logoImage.cols,logoImage.rows));  
  20.        //方法二  
  21.        //imageROI=srcImage4(Range(250,250+logoImage.rows),Range(200,200+logoImage.cols));  
  22.    
  23.        //【3】将logo加到原图上  
  24.        addWeighted(imageROI,0.5,logoImage,0.3,0.,imageROI);  
  25.    
  26.        //【4】显示结果  
  27.        namedWindow("<4>区域线性图像混合示例窗口 by浅墨");  
  28.        imshow("<4>区域线性图像混合示例窗口 by浅墨",srcImage4);  
  29.         
  30.        return true;  
  31. }  



从这篇文章开始,如果不出意外的话,为了方便大家分块各个击破学习,每讲一个部分,示例代码都将封装在一个函数中,免得大家像学习各种不是特别地道的OpenCV教程时一样,看到代码全放在main函数中,心都碎了。

 

好了,下面放出详细注释的本篇文章的全部示例源代码:

 

  1. //-----------------------------------【程序说明】----------------------------------------------  
  2. //  程序名称::【OpenCV入门教程之四】 ROI区域图像叠加&初级图像混合 全剖析   配套源码  
  3. // VS2010版   OpenCV版本:2.4.8  
  4. //     2014年3月10日 Create by 浅墨  
  5. //    图片素材出处:dota2原画 dota2logo   
  6. //     浅墨的微博:@浅墨_毛星云  
  7. //------------------------------------------------------------------------------------------------  
  8.    
  9. //-----------------------------------【头文件包含部分】---------------------------------------  
  10. //     描述:包含程序所依赖的头文件  
  11. //----------------------------------------------------------------------------------------------                                                                                      
  12. #include <cv.h>  
  13. #include <highgui.h>  
  14. #include <iostream>  
  15.    
  16. //-----------------------------------【命名空间声明部分】---------------------------------------  
  17. //     描述:包含程序所使用的命名空间  
  18. //-----------------------------------------------------------------------------------------------    
  19. using namespace cv;  
  20. using namespace std;  
  21.    
  22.    
  23. //-----------------------------------【全局函数声明部分】--------------------------------------  
  24. //     描述:全局函数声明  
  25. //-----------------------------------------------------------------------------------------------  
  26. bool ROI_AddImage();  
  27. bool LinearBlending();  
  28. bool ROI_LinearBlending();  
  29.    
  30. //-----------------------------------【main( )函数】--------------------------------------------  
  31. //     描述:控制台应用程序的入口函数,我们的程序从这里开始  
  32. //-----------------------------------------------------------------------------------------------  
  33. int main(  )  
  34. {  
  35.        system("color 5E");  
  36.    
  37.        if(ROI_AddImage()&& LinearBlending( )&&ROI_LinearBlending( ))  
  38.        {  
  39.               cout<<endl<<"嗯。好了,得出了你需要的图像~! : )";  
  40.        }  
  41.    
  42.        waitKey(0);  
  43.        return 0;  
  44. }  
  45.    
  46. //----------------------------------【ROI_AddImage( )函数】----------------------------------  
  47. // 函数名:ROI_AddImage()  
  48. //     描述:利用感兴趣区域ROI实现图像叠加  
  49. //----------------------------------------------------------------------------------------------  
  50. bool ROI_AddImage()  
  51. {  
  52.    
  53.        //【1】读入图像  
  54.        Mat srcImage1= imread("dota_pa.jpg");  
  55.        Mat logoImage= imread("dota_logo.jpg");  
  56.        if(!srcImage1.data ) { printf("你妹,读取srcImage1错误~! \n"); return false; }  
  57.        if(!logoImage.data ) { printf("你妹,读取logoImage错误~! \n"); return false; }  
  58.    
  59.        //【2】定义一个Mat类型并给其设定ROI区域  
  60.        Mat imageROI= srcImage1(Rect(200,250,logoImage.cols,logoImage.rows));  
  61.    
  62.        //【3】加载掩模(必须是灰度图)  
  63.        Mat mask= imread("dota_logo.jpg",0);  
  64.    
  65.        //【4】将掩膜拷贝到ROI  
  66.        logoImage.copyTo(imageROI,mask);  
  67.    
  68.        //【5】显示结果  
  69.        namedWindow("<1>利用ROI实现图像叠加示例窗口");  
  70.        imshow("<1>利用ROI实现图像叠加示例窗口",srcImage1);  
  71.    
  72.        return true;  
  73. }  
  74.    
  75.    
  76. //---------------------------------【LinearBlending()函数】-------------------------------------  
  77. // 函数名:LinearBlending()  
  78. // 描述:利用cv::addWeighted()函数实现图像线性混合  
  79. //--------------------------------------------------------------------------------------------  
  80. bool LinearBlending()  
  81. {  
  82.        //【0】定义一些局部变量  
  83.        double alphaValue = 0.5;  
  84.        double betaValue;  
  85.        Mat srcImage2, srcImage3, dstImage;  
  86.    
  87.        //【1】读取图像 ( 两幅图片需为同样的类型和尺寸 )  
  88.        srcImage2= imread("mogu.jpg");  
  89.        srcImage3= imread("rain.jpg");  
  90.    
  91.        if(!srcImage2.data ) { printf("你妹,读取srcImage2错误~! \n"); return false; }  
  92.        if(!srcImage3.data ) { printf("你妹,读取srcImage3错误~! \n"); return false; }  
  93.    
  94.        //【2】进行图像混合加权操作  
  95.        betaValue= ( 1.0 - alphaValue );  
  96.        addWeighted(srcImage2, alphaValue, srcImage3, betaValue, 0.0, dstImage);  
  97.    
  98.        //【3】创建并显示原图窗口  
  99.        namedWindow("<2>线性混合示例窗口【原图】 by浅墨", 1);  
  100.        imshow("<2>线性混合示例窗口【原图】 by浅墨", srcImage2 );  
  101.    
  102.        namedWindow("<3>线性混合示例窗口【效果图】 by浅墨", 1);  
  103.        imshow("<3>线性混合示例窗口【效果图】 by浅墨", dstImage );  
  104.    
  105.        return true;  
  106.         
  107. }  
  108.    
  109. //---------------------------------【ROI_LinearBlending()】-------------------------------------  
  110. // 函数名:ROI_LinearBlending()  
  111. // 描述:线性混合实现函数,指定区域线性图像混合.利用cv::addWeighted()函数结合定义  
  112. //                     感兴趣区域ROI,实现自定义区域的线性混合  
  113. //--------------------------------------------------------------------------------------------  
  114. bool ROI_LinearBlending()  
  115. {  
  116.    
  117.        //【1】读取图像  
  118.        Mat srcImage4= imread("dota_pa.jpg",1);  
  119.        Mat logoImage= imread("dota_logo.jpg");  
  120.    
  121.        if(!srcImage4.data ) { printf("你妹,读取srcImage4错误~! \n"); return false; }  
  122.        if(!logoImage.data ) { printf("你妹,读取logoImage错误~! \n"); return false; }  
  123.    
  124.        //【2】定义一个Mat类型并给其设定ROI区域  
  125.        Mat imageROI;  
  126.               //方法一  
  127.        imageROI=srcImage4(Rect(200,250,logoImage.cols,logoImage.rows));  
  128.        //方法二  
  129.        //imageROI=srcImage4(Range(250,250+logoImage.rows),Range(200,200+logoImage.cols));  
  130.    
  131.        //【3】将logo加到原图上  
  132.        addWeighted(imageROI,0.5,logoImage,0.3,0.,imageROI);  
  133.    
  134.        //【4】显示结果  
  135.        namedWindow("<4>区域线性图像混合示例窗口 by浅墨");  
  136.        imshow("<4>区域线性图像混合示例窗口 by浅墨",srcImage4);  
  137.         
  138.        return true;  
  139. }  


最后看一下整体的运行效果图。

首先是经过背景颜色修改的console窗口:



然后依次是四张效果图:









 嗯,本篇文章到这里就基本结束了,最后放出本篇文章配套示例程序的下载地址。


2019-04-14 12:28:28 matt45m 阅读数 8677

前言

1.有一个小游戏,就给出两张内容几乎差不多全部相同的图像,让大家在最快的时间内找出两个图像中有几处不同地方,我这里试着用OpenCV实现这个功能。
2.我的编程环境是Windows 7 64位,IDE是VS2015,配置了OpenCV3.3与OpenCV_Contrib,实现语言是C++。是于如果配置以上的环境,可以看我之前写的博文。

一、资源准备

可以在网上搜《图片大找茬》,然后下载两张相似的图像,但图像的大小必须一样。下面是我指用的两张图像。如果不一样,就用resize()这个函数去调整两张图像的尺寸。

在这里插入图片描述
在这里插入图片描述

二、代码演示

1.这里用到的是OpenCV图像基本运算,两图相减。使用的API是subtract()。
代码是传入两张图像

void imageSubtract(Mat &image1, Mat &image2)
{
	if ((image1.rows != image2.rows) || (image1.cols != image2.cols))
	{
		if (image1.rows > image2.rows)
		{
			resize(image1, image1, image2.size(), 0, 0, INTER_LINEAR);
		}
		else if (image1.rows < image2.rows)
		{
			resize(image2, image2, image1.size(), 0, 0, INTER_LINEAR);
		}
	}

	Mat image1_gary, image2_gary;
	if (image1.channels() != 1)
	{
		cvtColor(image1, image1_gary, COLOR_BGR2GRAY);
	}
	if (image2.channels() != 1)
	{
		cvtColor(image2, image2_gary, COLOR_BGR2GRAY);
	}

	Mat frameDifference, absFrameDifferece;
	Mat previousGrayFrame = image2_gary.clone();
	//图1减图2
	subtract(image1_gary, image2_gary, frameDifference, Mat(), CV_16SC1);

	//取绝对值
	absFrameDifferece = abs(frameDifference);

	//位深的改变
	absFrameDifferece.convertTo(absFrameDifferece, CV_8UC1, 1, 0);
	imshow("absFrameDifferece", absFrameDifferece);
	Mat segmentation;
	
	//阈值处理(这一步很关键,要调好二值化的值)
	threshold(absFrameDifferece, segmentation,100, 255, THRESH_BINARY);

	//中值滤波
	medianBlur(segmentation, segmentation, 3);

	//形态学处理(开闭运算)
	//形态学处理用到的算子
	Mat morphologyKernel = getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1));
	morphologyEx(segmentation, segmentation, MORPH_CLOSE, morphologyKernel, Point(-1, -1), 2, BORDER_REPLICATE);

	//显示二值化图片
	imshow("segmentation", segmentation);

	//找边界
	vector< vector<Point> > contours;
	vector<Vec4i> hierarchy;
	findContours(segmentation, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));//CV_RETR_TREE
	vector< vector<Point> > contours_poly(contours.size());

	vector<Rect> boundRect;
	boundRect.clear();

	for (int index = 0; index < contours.size(); index++)
	{
		approxPolyDP(Mat(contours[index]), contours_poly[index], 3, true);
		Rect rect = boundingRect(Mat(contours_poly[index]));
		rectangle(image2, rect, Scalar(0, 255, 0), 2);
	}
	imshow("效果图", image2);
}

2.运行效果
在这里插入图片描述

结语

1.例子很简单,但是这个方法用到移动目标追踪的上去,就是两帧差。
2.关于工程的源码,运行程序时的bug,都可以加这个群(487350510)互相讨论学习。

2019-09-20 11:36:08 Leytton 阅读数 52168

在数字图像处理中,Lena(Lenna)是一张被广泛使用的标准图片,特别在图像压缩的算法研究中。


(为什么用这幅图,是因为这图的各个频段的能量都很丰富:即有低频(光滑的皮肤),也有高频(帽子上的羽毛),很适合来验证各种算法)
       然而,这张图片背后的故事是颇有意思的,很多人都抱有学究都是呆子的看法,然而Lena对此就是一个有力的驳斥。lena(lenna)是一张于1972年11月出版的Playboy的中间插页,在这期杂志中使用了“Lenna”的拼写,而实际莉娜在瑞典语中的拼写是“lena”。如今的Lena生活在自己的祖国瑞典,从事于酿造业,婚后并生下3个孩子。


从1973年以来,Lena就开始出现在图像处理的科学论文中,直到1988年,她才得知自己原来已经被从事图像处理行业的工作者认识。 1997年,lena 被邀请参加了在波士顿举办的第50届图像科技技术年会。
       1973年6,7月间,南加州大学信号图像处理研究所的副教授Alexander和学生一起,为了一个同事的学会论文正忙于寻找一副好的图片。他们想要一副具有良好动态范围的人的面部图片用于扫描。不知是谁拿着一本Playboy走进研究室。由于当时实验室里使用的扫描仪(Muirhead wirephoto scanner)分辨率是100行/英寸,试验也仅仅需要一副512X512的图片,所以他们只将图片顶端开始的5.12英寸扫描下来,切掉肩膀一下的部分。多年以来,由于图像Lena源于Playboy,将其引用于科技文章中饱受争议。Playboy杂志也将未授权的引用告上法庭。随着时间流失,人们渐渐淡忘Lena的来源,Playboy也放松了对此的关注。值得一提的是,Lena也是playboy发行的最畅销的海报,已经出售7,161,561份。

      这个是原版的Lena照片,图像处理的初学者一定会大跌眼镜吧

PlayBoy杂志封面上的Lena.jpg;

https://img-blog.csdn.net/20140702104120484

另外一件有趣的事情是,Lenna的那一期杂志是当时Playboy销量最好的一期,共卖出去了7161561份。

现在Lena.jpg

标准Lena.jpg

该图原本是刊于1972年11月号花花公子杂志上的一张裸体插图照片的一部分,这期花花公子也是历年来最畅销的一期,销量达7,161,561本。1973 年6月,美国南加州大学的信号图像处理研究所的一个助理教授和他的一个研究生打算为了一个学术会议找一张数字照片,而他们对于手头现有成堆"无聊"照片感到厌烦。事实上他们需要的是一个人脸照片,同时又能让人眼前一亮。这时正好有人走进实验室,手上带着一本当时的花花公子杂志,结果故事发生了……而限于当时实验室设备和测试图片的需要,lenna的图片只抠到了原图的肩膀部分。

       图中人为瑞典模特儿 Lena Soderberg (Lena Söderberg)。现在被广泛使用的英文化名字"Lenna"最初是由花花公子杂志发表此照片时命名的,以方便英语读者近似正确地读出瑞典语中"Lena"的发音。Lena Soderberg女士现在仍住在她的家乡瑞典,拥有一个有三个孩子的家庭,并且在国家酒类专卖局工作。在1988年的时候,她接受了瑞典一些计算机相关出版社的访问,她对于她的照片有这样的奇遇感到非常的惊奇与兴奋。这是她首次得知她的照片被应用在计算机行业。Lena Soderberg于1997年被邀请为嘉宾,参加了数字图像科学技术50周年学术会议。在该会议上,Lenna成了最受欢迎的人之一,她做了关于自己介绍的简要发言,并被无数的fans索取签名。 

       莱娜图在图像压缩算法是最广泛应用的标准测试图——她的脸部与裸露的肩部已经变成了事实上的工业准。然而,这张图像的使用也引起了一些争议。一些人担心它的色情内容;《花花公子》杂志曾经威胁要起诉对莱娜图未经授权的使用。不过这家杂志已经放弃了这种威胁,取而代之的是鼓励因为公众利益使用莱娜图。

        戴维·C·蒙森(David C.Munson),IEEE图像处理汇刊(IEEE Transactions on Image Processing)的主编, 在1996年1月引用了两个原因来说明莱娜图在科研领域流行的原因:1.该图适度的混合了细节、平滑区域、阴影和纹理,从而能很好的测试各种图像处理算法。2.Lenna是个美女,对于图象处理界的研究者来说,美女图可以有效的吸引他们来做研究。

 

转载,原文地址:http://blog.sina.com.cn/s/blog_53220cef0100lbzk.html

图像处理入门教程

阅读数 32635