2019-12-04 20:12:06 LLeetion 阅读数 20
  • Excel公式入门实战视频课程【你学得会】

    所谓的公式是人们在研究自然界物与物之间时发现的一些联系,并通过一定的方式表达出来的一种表达方法。而这里我们所说的Excel公式一般是指计算公式,包括常用的四则运算和函数的使用。通过这些运算,我们能从普通数据中得到计算结果以满足分析需求。从而进一步推敲具体的实施方案。杨老师通过《Excel公式实战视频课程【你学得会】》的课程教你如何使用Excel公式来处理数据。

    8691 人正在学习 去看看 杨仕航

目录

图像反色

图像线性点运算

图像对数点运算

图像幂数点运算

图像灰度均衡化

以上函数测试脚本

1.线性,反色,对数,幂数

2.灰度均衡化

结果


图像反色

图像反色利用的公式为% MathType!MTEF!2!1!+- % feaahqart1ev3aaatCvAUfeBSjuyZL2yd9gzLbvyNv2CaerbuLwBLn % hiov2DGi1BTfMBaeXatLxBI9gBaerbd9wDYLwzYfdmGievaebbnrfi % fHhDYfgatCvAUfeBSn0BKvguHDwzZbqegSSZmxoasaacH8srps0lbb % f9q8WrFfeuY-Hhbbf9v8qqaqFr0xc9pk0xbba9q8WqFfea0-yr0RYx % ir-Jbba9q8aq0-yq-He9q8qqQ8frFve9Fve9Ff0dmeaabaqaciGaca % GaaeqabaWaaeaaeaqbaOqaaiaad+eadaqadaqaaiaad2gacaGGSaGa % amOBaaGaayjkaiaawMcaaiabg2da9iaaikdacaaI1aGaaGynaiabgk % HiTiaadMeadaqadaqaaiaad2gacaGGSaGaamOBaaGaayjkaiaawMca % aaaa!4CF6! \[O\left( {m,n} \right) = 255 - I\left( {m,n} \right)\]\[O\left( {m,n} \right) = 255 - I\left( {m,n} \right)\]。Matlab本擅长矩阵运算可以直接运算,由于实验要求不能使用矩阵运算,使用循环完成,以下其他点运算也是一样的处理,不再解释。

function OutImage = InverseImageCompute(InputImage)
%================================================================
% 功能:图像灰度发转
% 参数:InputImage为输入单通道图像
% 返回值:OutImage为InputImage同维数组
% 主要思路:直接计算反转后的灰度255-f(m,n)
% 备注:如果图像为多通道则需要重复调用
% 调用方法:OutImage= InverseImageCompute(InputImage)
% 日期:2019.11.27
% 作者:Leetion
[iLimit,jLimit] = size(InputImage);
OutImage = zeros(iLimit,jLimit);
for yIndex = 1:iLimit
    for xIndex = 1:jLimit
        OutImage(yIndex,xIndex) = 255-InputImage(yIndex,xIndex);
    end
end
end

图像线性点运算

 

function OutImage= LinearImageCompute(InputImage,LineBegin,LineEnd,Minout,MaxOut)
%================================================================
% 功能:图像灰度的线性运算
% 参数:InputImage为输入单通道图像。
% 返回值:OutImage为InputImage同维数组,LineBegin,LineEnd,Minout,MaxOut分别对应a,b,c,d
% 主要思路:构造分段函数
% 备注:如果图像为多通道则需要重复调用
%       使用逻辑函数会更简洁
% 调用方法:LinearImageCompute(InputImage,LineBegin,LineEnd,Minout,MaxOut)
% 日期:2019.11.27
% 作者:Leetion
[iLimit,jLimit] = size(InputImage);
OutImage = zeros(iLimit,jLimit);
for yIndex = 1:iLimit
    for xIndex = 1:jLimit
        if (InputImage(yIndex,xIndex)<LineBegin) & (InputImage(yIndex,xIndex)>=0)
            OutImage(yIndex,xIndex) = Minout;
        elseif (InputImage(yIndex,xIndex)<LineEnd) & (InputImage(yIndex,xIndex)>=LineBegin) 
            OutImage(yIndex,xIndex) = Minout+(MaxOut-Minout)*(InputImage(yIndex,xIndex)-LineBegin)/(LineEnd-LineBegin);
        else
            OutImage(yIndex,xIndex) = MaxOut;
        end
    end
end
OutImage = uint8(OutImage);
end

图像对数点运算

对数运算利用的公式为\[O\left( {m,n} \right) = k \cdot \log \left( {1 + I\left( {m,n} \right)} \right)\]

其中k为调节常数,用它来调节变换后的灰度值,对数变换的作用是扩展图像的低灰度范围,使其符合实际要求。同时压缩高灰度范围,使得图像灰度分布均匀,与人的视觉特性相匹配。

function OutImage = LogImageCompute(InputImage,AdjConstant)
%================================================================
% 功能:图像灰度的对数运算
% 参数:InputImage为输入单通道图像,AdjConstant为调节常数
% 返回值:OutImage为InputImage同维数组
% 主要思路:每一点进行灰度变换
% 备注:如果图像为多通道则需要重复调用
%       利用矩阵的运算会更简洁
% 调用方法:OutImage= LogImageCompute(InputImage,AdjConstant)
% 日期:2019.11.27
% 作者:Leetion
[iLimit,jLimit] = size(InputImage);
OutImage = zeros(iLimit,jLimit);
for yIndex = 1:iLimit
    for xIndex = 1:jLimit
        OutImage(yIndex,xIndex) = AdjConstant*log10(double(InputImage(yIndex,xIndex)+1));
    end
end
OutImage = uint8(OutImage);
end

图像幂数点运算

图像的幂数运算公式为\[O\left( {m,n} \right) = k \cdot I{\left( {m,n} \right)^r}{\rm{ + }}a\]

其中k,a,r为正常数。

function OutImage = PowerImageCompute(InputImage,MulConstant,PowerConstant,PlusConstant)
%================================================================
% 功能:图像灰度的幂数运算
% 参数:InputImage为输入单通道图像,MulConstant,PowerConstant,PlusConstant分别为a,k,r
% 返回值:OutImage为InputImage同维数组
% 主要思路:每一点进行灰度变换
% 备注:如果图像为多通道则需要重复调用
%       利用矩阵的运算会更简洁
% 调用方法:OutImage = PowerImageCompute(InputImage,MulConstant,PowerConstant,PlusConstant)
% 日期:2019.11.27
% 作者:Leetion
[iLimit,jLimit] = size(InputImage);
OutImage = zeros(iLimit,jLimit);
for yIndex = 1:iLimit
    for xIndex = 1:jLimit
        OutImage(yIndex,xIndex) =PlusConstant + MulConstant*(InputImage(yIndex,xIndex)^PowerConstant);
    end
end
OutImage = uint8(OutImage);
end

图像灰度均衡化

图像的灰度均衡原理比较复杂,感兴趣的可以参考下面的文章。

先留个空,有时间码一篇文章。

function OutImage = BalanceImageCompute(InputImage)
%================================================================
% 功能:直方图均衡化
% 参数:InputImage为输入单通道图像
% 返回值:OutImage为InputImage同维灰度计数数组
% 主要思路:用分布函数做点计算
% 备注:相当于库函数histeq
% 调用方法:[Gray,GrayCount] = GrayCountFun(InputImage)
% 日期:2019.11.26
% 作者:Leetion
[iLimit,jLimit] = size(InputImage);
[Gray,GrayCount] = GrayCountFun(InputImage);%进行像素灰度统计;
PDF = GrayCount./(iLimit*jLimit);
CDF = zeros(1,256);
CDF(1) = PDF(1);
for ii = 2:256
    CDF(ii) = CDF(ii-1)+PDF(ii);
end
CDF = 255*CDF;
for iImageIndex = 1:iLimit
    for jImageIndex = 1:jLimit
       OutImage(iImageIndex,jImageIndex) = CDF((InputImage(iImageIndex,jImageIndex)+1));
    end
end
OutImage = uint8(OutImage);
end

以上函数测试脚本

1.线性,反色,对数,幂数

%================================================================
% 功能:点计算
% 主要思路:
% 备注:
% 日期:2019.11.27
% 作者:Leetion
clc,clear
close all
InputImage = imread('cameraman.tif'); 
[LineBegin,LineEnd,Minout,MaxOut] = deal(7,50,7.5,80);
AdjConstant = 100;
[MulConstant,PowerConstant,PlusConstant] = deal(5,1,1.5);
LinearCompute = LinearImageCompute(InputImage,LineBegin,LineEnd,Minout,MaxOut);
LogCompute = LogImageCompute(InputImage,AdjConstant);
PowerCompute= PowerImageCompute(InputImage,MulConstant,PowerConstant,PlusConstant);
InvertCompute = InverseImageCompute(InputImage);
subplot(2,3,1);
imshow(uint8(InputImage));
title("原图");
subplot(2,3,2);
imshow(uint8(LinearCompute));
title("线性运算");
subplot(2,3,3);
imshow(uint8(LogCompute));
title("对数运算");
subplot(2,3,4);
imshow(uint8(PowerCompute));
title("幂数运算");
subplot(2,3,5);
imshow(uint8(InvertCompute));
title("反转运算");

2.灰度均衡化

%================================================================
% 功能:直方图均衡化
% 主要思路:
% 备注:
% 日期:2019.11.27
% 作者:Leetion
clc,clear
close all
InputImage = imread('cameraman.tif'); 
subplot(3,2,1);
imshow(uint8(InputImage));
title("InputImage");
subplot(3,2,2);
[iLimit,jLimit] = size(InputImage);
[counts,x] = imhist(InputImage);
bar(x,counts/(iLimit*jLimit));
subplot(3,2,3);
BalanceCompute = BalanceImageCompute(InputImage);
imshow(BalanceCompute);
title("BalanceCompute");
subplot(3,2,4);
[iLimit,jLimit] = size(BalanceCompute);
[counts,x] = imhist(BalanceCompute);
bar(x,counts/(iLimit*jLimit));
subplot(3,2,5);
imshow(histeq(InputImage,256));
title("histeq");
subplot(3,2,6);
[counts,x] = imhist(histeq(InputImage,256));
bar(x,counts/(iLimit*jLimit));





结果

点运算
点运算

 

直方图均衡化
直方图均衡化

 

2018-06-09 16:15:31 liangjiubujiu 阅读数 257
  • Excel公式入门实战视频课程【你学得会】

    所谓的公式是人们在研究自然界物与物之间时发现的一些联系,并通过一定的方式表达出来的一种表达方法。而这里我们所说的Excel公式一般是指计算公式,包括常用的四则运算和函数的使用。通过这些运算,我们能从普通数据中得到计算结果以满足分析需求。从而进一步推敲具体的实施方案。杨老师通过《Excel公式实战视频课程【你学得会】》的课程教你如何使用Excel公式来处理数据。

    8691 人正在学习 去看看 杨仕航

上篇文章中,我们重点了解了腐蚀和膨胀这两种最基本的形态学操作,而运用这两个基本操作,我们可以实现更高级的形态学变换。

所以,本文的主角是OpenCV中的morphologyEx函数,它利用基本的膨胀和腐蚀技术,来执行更加高级的形态学变换,如开闭运算、形态学梯度、“顶帽”、“黑帽”等等。

 先上几张示例程序的截图吧:


有没有很熟悉这张图?没错,这就是最近热映的电影Captain America~

下面这张图的效果就有些凶残了:

OK,截图先看到这里。在正文之前先来唠唠和主题相关的事情。


第一件事,OpenCV最新版本更新到了2.4.9。


在写这篇博文的两天之前(4月25日上午),OpenCV官网页面显示最新版本还是2.4.8,但是通过浅墨细心地发现,文档页面的标题已经悄悄而低调地改成了2.4.9.所以我们当时应该可以去断定,OpenCV2.4.9应该马上就要和我们见面了。

 

果然,OpenCV2.4.9就在两天后(4月27日),正式在OpenCV官方网站上上线了。现在转到OpenCV的官方主页,赫然发现最新版本已然显示为2.4.9:

这是OpenCV的官方主页传送门:http://opencv.org/

大家可以自己前去看看以及下载最新版本的OpenCV。如果不出意外的话呢,下次文章我们就将紧跟时代,用上最新版本的OpenCV2.4.9进行讲解和程序的书写,所以,大家在看这篇文章之后呢,可以去下载当前最新的2.4.9版本并装上配置好。




第二件事,是浅墨想跟大家做一个关于OpenCV系列文章的书写内容和风格的思想汇报。


是这样的,浅墨发现最近几期写出来的文章有些偏离自己开始开这个专栏的最初的愿望——原理和概念部分占的比重有些大,有些弱化OpenCV实际的使用。

写这些博文的初心是教大家如何使用OpenCV来写代码,原理部分我想很多朋友应该多少都懂,就算某些同学对某些概念有些模糊,大家也完全可以带着关键词句去google或者百度。

浅墨的想法是,以后的专栏文章原理部分尽量从简,“深入”的源码剖析部分也是从简,重点突出“浅出”部分,让大家快速上手OpenCV函数的使用,这样浅墨的工作量也会小很多,更新也会更勤。

PS:浅墨其实每次在写图像处理原理部分的时候都特纠结,因为浅墨其实感兴趣的和大家一样,也是如何写代码,而不是那些多多少少让人提不起兴趣来的图像处理公式和概念。这往往就照成了博文更新的拖延症。

所以呢,在浅墨以后写的OpenCV文章中,原理和深入部分我们就点到为止,文章的拳头内容是“浅出”部分,重点教大家如何快速上手OpenCV API。我想这也是大家一直期待和想要看到的浅墨出品的文章的样子吧。:)

OK,大概就是这些。我们开始今天的正题。






一、理论与概念讲解——从现象到本质



首先呢,要知道形态学的高级形态,往往都是建立在腐蚀和膨胀这两个基本操作之上的。而关于腐蚀和膨胀,概念和细节以及相关代码可以看浅墨之前写的这篇文章:


【OpenCV入门教程之十】 形态学图像处理(一):膨胀与腐蚀


对膨胀和腐蚀心中有数了,接下来的高级形态学操作,应该就不难理解。

另外,为了下面对比和演示以及理解的方便,浅墨自己制作了一张毛笔字图,这里先上原图:

 

 OK,我们开始讲解。





1.1 开运算(Opening Operation)

 



开运算(Opening Operation),其实就是先腐蚀后膨胀的过程。其数学表达式如下:




开运算可以用来消除小物体、在纤细点处分离物体、平滑较大物体的边界的同时并不明显改变其面积。效果图是这样的:

实际效果图:

 




1.2 闭运算(Closing Operation)


先膨胀后腐蚀的过程称为闭运算(Closing Operation),其数学表达式如下:

 

闭运算能够排除小型黑洞(黑色区域)。效果图如下所示:

 

实际效果图:





1.3 形态学梯度(MorphologicalGradient)


形态学梯度(Morphological Gradient)为膨胀图与腐蚀图之差,数学表达式如下:

 

对二值图像进行这一操作可以将团块(blob)的边缘突出出来。我们可以用形态学梯度来保留物体的边缘轮廓,如下所示:

 

实际素材效果图:





1.4 顶帽(Top Hat)


顶帽运算(Top Hat)又常常被译为”礼帽“运算。为原图像与上文刚刚介绍的“开运算“的结果图之差,数学表达式如下:

因为开运算带来的结果是放大了裂缝或者局部低亮度的区域,因此,从原图中减去开运算后的图,得到的效果图突出了比原图轮廓周围的区域更明亮的区域,且这一操作和选择的核的大小相关。

顶帽运算往往用来分离比邻近点亮一些的斑块。当一幅图像具有大幅的背景的时候,而微小物品比较有规律的情况下,可以使用顶帽运算进行背景提取。

如下所示:

素材效果图:

 

 



1.5 黑帽(Black Hat)



黑帽(Black Hat)运算为”闭运算“的结果图与原图像之差。数学表达式为:


黑帽运算后的效果图突出了比原图轮廓周围的区域更暗的区域,且这一操作和选择的核的大小相关。

所以,黑帽运算用来分离比邻近点暗一些的斑块。非常完美的轮廓效果图:

 

实际素材效果图:





 

二、深入——OpenCV源码分析溯源




本文的主角是OpenCV中的morphologyEx函数,它利用基本的膨胀和腐蚀技术,来执行更加高级的形态学变换,如开闭运算,形态学梯度,“顶帽”、“黑帽”等等。这一节我们来一起看一下morphologyEx函数的源代码。

  1. //-----------------------------------【erode()函数中文注释版源代码】----------------------------    
  2. //   说明:以下代码为来自于计算机开源视觉库OpenCV的官方源代码    
  3. //   OpenCV源代码版本:2.4.8    
  4. //   源码路径:…\opencv\sources\modules\imgproc\src\morph.cpp    
  5. //   源文件中如下代码的起始行数:1369行    
  6. //   中文注释by浅墨    
  7. //--------------------------------------------------------------------------------------------------------     
  8. void cv::morphologyEx( InputArray _src,OutputArray _dst, int op,  
  9.                        InputArray kernel, Pointanchor, int iterations,  
  10.                        int borderType, constScalar& borderValue )  
  11. {  
  12. //拷贝Mat数据到临时变量  
  13.    Mat src = _src.getMat(), temp;  
  14.    _dst.create(src.size(), src.type());  
  15.    Mat dst = _dst.getMat();  
  16.    
  17. //一个大switch,根据不同的标识符取不同的操作  
  18.    switch( op )  
  19.     {  
  20.    case MORPH_ERODE:  
  21.        erode( src, dst, kernel, anchor, iterations, borderType, borderValue );  
  22.        break;  
  23.    case MORPH_DILATE:  
  24.        dilate( src, dst, kernel, anchor, iterations, borderType, borderValue );  
  25.        break;  
  26.    case MORPH_OPEN:  
  27.        erode( src, dst, kernel, anchor, iterations, borderType, borderValue );  
  28.        dilate( dst, dst, kernel, anchor, iterations, borderType, borderValue );  
  29.        break;  
  30.    case CV_MOP_CLOSE:  
  31.        dilate( src, dst, kernel, anchor, iterations, borderType, borderValue );  
  32.        erode( dst, dst, kernel, anchor, iterations, borderType, borderValue );  
  33.        break;  
  34.    case CV_MOP_GRADIENT:  
  35.        erode( src, temp, kernel, anchor, iterations, borderType, borderValue );  
  36.        dilate( src, dst, kernel, anchor, iterations, borderType, borderValue );  
  37.        dst -= temp;  
  38.        break;  
  39.    case CV_MOP_TOPHAT:  
  40.        if( src.data != dst.data )  
  41.            temp = dst;  
  42.        erode( src, temp, kernel, anchor, iterations, borderType, borderValue );  
  43.         dilate( temp, temp, kernel, anchor,iterations, borderType, borderValue );  
  44.        dst = src - temp;  
  45.        break;  
  46.    case CV_MOP_BLACKHAT:  
  47.        if( src.data != dst.data )  
  48.            temp = dst;  
  49.        dilate( src, temp, kernel, anchor, iterations, borderType, borderValue);  
  50.        erode( temp, temp, kernel, anchor, iterations, borderType, borderValue);  
  51.        dst = temp - src;  
  52.        break;  
  53.    default:  
  54.        CV_Error( CV_StsBadArg, "unknown morphological operation" );  
  55.     }  
  56. }  

看上面的源码可以发现,其实morphologyEx函数其实就是内部一个大switch而已。根据不同的标识符取不同的操作。比如开运算MORPH_OPEN,按我们上文中讲解的数学表达式,就是先腐蚀后膨胀,即依次调用erode和dilate函数,为非常简明干净的代码。

 




 


三、浅出——API函数快速上手

 



3.1 morphologyEx函数详解



上面我们已经讲到,morphologyEx函数利用基本的膨胀和腐蚀技术,来执行更加高级形态学变换,如开闭运算,形态学梯度,“顶帽”、“黑帽”等等。这一节我们来了解它的参数意义和使用方法。

  1. C++: void morphologyEx(  
  2. InputArray src,  
  3. OutputArray dst,  
  4. int op,  
  5. InputArraykernel,  
  6. Pointanchor=Point(-1,-1),  
  7. intiterations=1,  
  8. intborderType=BORDER_CONSTANT,  
  9. constScalar& borderValue=morphologyDefaultBorderValue() );  

  • 第一个参数,InputArray类型的src,输入图像,即源图像,填Mat类的对象即可。图像位深应该为以下五种之一:CV_8U, CV_16U,CV_16S, CV_32F 或CV_64F。
  • 第二个参数,OutputArray类型的dst,即目标图像,函数的输出参数,需要和源图片有一样的尺寸和类型。
  • 第三个参数,int类型的op,表示形态学运算的类型,可以是如下之一的标识符:
    • MORPH_OPEN – 开运算(Opening operation)
    • MORPH_CLOSE – 闭运算(Closing operation)
    • MORPH_GRADIENT -形态学梯度(Morphological gradient)
    • MORPH_TOPHAT - “顶帽”(“Top hat”)
    • MORPH_BLACKHAT - “黑帽”(“Black hat“)

另有CV版本的标识符也可选择,如CV_MOP_CLOSE,CV_MOP_GRADIENT,CV_MOP_TOPHAT,CV_MOP_BLACKHAT,这应该是OpenCV1.0系列版本遗留下来的标识符,和上面的“MORPH_OPEN”一样的效果。

 

  • 第四个参数,InputArray类型的kernel,形态学运算的内核。若为NULL时,表示的是使用参考点位于中心3x3的核。我们一般使用函数 getStructuringElement配合这个参数的使用。getStructuringElement函数会返回指定形状和尺寸的结构元素(内核矩阵)。关于getStructuringElement我们上篇文章中讲过了,这里为了大家参阅方便,再写一遍:

其中,getStructuringElement函数的第一个参数表示内核的形状,我们可以选择如下三种形状之一:

    • 矩形: MORPH_RECT
    • 交叉形: MORPH_CROSS
    • 椭圆形: MORPH_ELLIPSE

而getStructuringElement函数的第二和第三个参数分别是内核的尺寸以及锚点的位置。

我们一般在调用erode以及dilate函数之前,先定义一个Mat类型的变量来获得getStructuringElement函数的返回值。对于锚点的位置,有默认值Point(-1,-1),表示锚点位于中心。且需要注意,十字形的element形状唯一依赖于锚点的位置。而在其他情况下,锚点只是影响了形态学运算结果的偏移。

getStructuringElement函数相关的调用示例代码如下:

  1. int g_nStructElementSize = 3; //结构元素(内核矩阵)的尺寸  
  2.    
  3. //获取自定义核  
  4. Mat element =getStructuringElement(MORPH_RECT,  
  5.        Size(2*g_nStructElementSize+1,2*g_nStructElementSize+1),  
  6.        Point(g_nStructElementSize, g_nStructElementSize ));  


调用这样之后,我们便可以在接下来调用erode、dilate或morphologyEx函数时,kernel参数填保存getStructuringElement返回值的Mat类型变量。对应于我们上面的示例,就是填element变量。

  • 第五个参数,Point类型的anchor,锚的位置,其有默认值(-1,-1),表示锚位于中心。
  • 第六个参数,int类型的iterations,迭代使用函数的次数,默认值为1。
  • 第七个参数,int类型的borderType,用于推断图像外部像素的某种边界模式。注意它有默认值BORDER_ CONSTANT。
  • 第八个参数,const Scalar&类型的borderValue,当边界为常数时的边界值,有默认值morphologyDefaultBorderValue(),一般我们不用去管他。需要用到它时,可以看官方文档中的createMorphologyFilter()函数得到更详细的解释。

其中的这些操作都可以进行就地(in-place)操作。且对于多通道图像,每一个通道都是单独进行操作。

 OK,讲解完毕,下面就是使用的范例。



高能预警!高能预警!高能预警!

一大波示例代码正在逼近。

为了方便大家需要的时候随时取用。下面我们依次列举出开运算,闭运算,形态学梯度,顶帽,黑帽,腐蚀,膨胀的效果实现简化版完整代码。

其实说白了,这些代码基本上内容一致,其实就是改一下morphologyEx里面的第三个标识符参数而已。核都是选的MORPH_RECT,矩形元素结构。

另外,通过看源码我们发现,最基本的腐蚀和膨胀操作也可以用morphologyEx函数来实现,他们由morphologyEx函数源码中switch的前两个case来实现(虽然在case体内就是简单地各自调用了一下erode和dilation函数,但还是有写出来的必要)。所以在这里,我们也用morphologyEx再重新来实现一遍他们。

按着顺序来列出吧,就直接列详细注释好的代码和运行结果了。

 




3.2 开运算示例程序


OpenCV中调用morphologyEx函数进行开运算操作的示例程序如下:

  1. //-----------------------------------【头文件包含部分】---------------------------------------  
  2. //            描述:包含程序所依赖的头文件  
  3. //----------------------------------------------------------------------------------------------  
  4. #include <opencv2/opencv.hpp>  
  5. #include<opencv2/highgui/highgui.hpp>  
  6. #include<opencv2/imgproc/imgproc.hpp>  
  7.    
  8. //-----------------------------------【命名空间声明部分】---------------------------------------  
  9. //            描述:包含程序所使用的命名空间  
  10. //-----------------------------------------------------------------------------------------------  
  11. using namespace cv;  
  12. //-----------------------------------【main( )函数】--------------------------------------------  
  13. //            描述:控制台应用程序的入口函数,我们的程序从这里开始  
  14. //-----------------------------------------------------------------------------------------------  
  15. int main( )  
  16. {  
  17.        //载入原始图    
  18.        Mat image = imread("1.jpg");  //工程目录下应该有一张名为1.jpg的素材图  
  19.        //创建窗口    
  20.        namedWindow("【原始图】开运算");   
  21.        namedWindow("【效果图】开运算");   
  22.        //显示原始图   
  23.        imshow("【原始图】开运算", image);   
  24.        //定义核  
  25.        Mat element = getStructuringElement(MORPH_RECT, Size(15, 15));   
  26.        //进行形态学操作  
  27.        morphologyEx(image,image, MORPH_OPEN, element);  
  28.        //显示效果图   
  29.        imshow("【效果图】开运算", image);   
  30.    
  31.        waitKey(0);   
  32.    
  33.        return 0;   
  34. }  

运行效果图:







3.3 闭运算示例程序



OpenCV中调用morphologyEx函数进行闭运算操作的示例程序如下:


  1. //-----------------------------------【头文件包含部分】---------------------------------------  
  2. //            描述:包含程序所依赖的头文件  
  3. //----------------------------------------------------------------------------------------------  
  4. #include <opencv2/opencv.hpp>  
  5. #include <opencv2/highgui/highgui.hpp>  
  6. #include<opencv2/imgproc/imgproc.hpp>  
  7.    
  8. //-----------------------------------【命名空间声明部分】---------------------------------------  
  9. //            描述:包含程序所使用的命名空间  
  10. //-----------------------------------------------------------------------------------------------  
  11. using namespace cv;  
  12. //-----------------------------------【main( )函数】--------------------------------------------  
  13. //            描述:控制台应用程序的入口函数,我们的程序从这里开始  
  14. //-----------------------------------------------------------------------------------------------  
  15. int main( )  
  16. {  
  17.        //载入原始图    
  18.        Mat image = imread("1.jpg");  //工程目录下应该有一张名为1.jpg的素材图  
  19.        //创建窗口    
  20.        namedWindow("【原始图】闭运算");   
  21.        namedWindow("【效果图】闭运算");   
  22.        //显示原始图   
  23.        imshow("【原始图】闭运算", image);   
  24.        //定义核  
  25.        Mat element = getStructuringElement(MORPH_RECT, Size(15, 15));   
  26.        //进行形态学操作  
  27.        morphologyEx(image,image, MORPH_CLOSE, element);  
  28.        //显示效果图   
  29.        imshow("【效果图】闭运算", image);   
  30.    
  31.        waitKey(0);   
  32.    
  33.        return 0;   
  34. }  

运行效果图:





3.4 形态学梯度示例程序



OpenCV中调用morphologyEx函数进行形态学梯度操作的示例程序如下:

  1. //-----------------------------------【头文件包含部分】---------------------------------------  
  2. //            描述:包含程序所依赖的头文件  
  3. //----------------------------------------------------------------------------------------------  
  4. #include <opencv2/opencv.hpp>  
  5. #include<opencv2/highgui/highgui.hpp>  
  6. #include<opencv2/imgproc/imgproc.hpp>  
  7.    
  8. //-----------------------------------【命名空间声明部分】---------------------------------------  
  9. //            描述:包含程序所使用的命名空间  
  10. //-----------------------------------------------------------------------------------------------  
  11. using namespace cv;  
  12. //-----------------------------------【main( )函数】--------------------------------------------  
  13. //            描述:控制台应用程序的入口函数,我们的程序从这里开始  
  14. //-----------------------------------------------------------------------------------------------  
  15. int main( )  
  16. {  
  17.        //载入原始图    
  18.        Mat image = imread("1.jpg");  //工程目录下应该有一张名为1.jpg的素材图  
  19.        //创建窗口    
  20.        namedWindow("【原始图】形态学梯度");   
  21.        namedWindow("【效果图】形态学梯度");   
  22.        //显示原始图   
  23.        imshow("【原始图】形态学梯度", image);   
  24.        //定义核  
  25.        Mat element = getStructuringElement(MORPH_RECT, Size(15, 15));   
  26.        //进行形态学操作  
  27.        morphologyEx(image,image, MORPH_GRADIENT, element);  
  28.        //显示效果图   
  29.        imshow("【效果图】形态学梯度", image);   
  30.    
  31.        waitKey(0);   
  32.    
  33.        return 0;   
  34. }  

运行效果图:






3.5 顶帽运算(Top Hat)示例程序



OpenCV中调用morphologyEx函数进行顶帽运算操作的示例程序如下:

  1. //-----------------------------------【头文件包含部分】---------------------------------------  
  2. //            描述:包含程序所依赖的头文件  
  3. //----------------------------------------------------------------------------------------------  
  4. #include <opencv2/opencv.hpp>  
  5. #include<opencv2/highgui/highgui.hpp>  
  6. #include<opencv2/imgproc/imgproc.hpp>  
  7.    
  8. //-----------------------------------【命名空间声明部分】---------------------------------------  
  9. //            描述:包含程序所使用的命名空间  
  10. //-----------------------------------------------------------------------------------------------  
  11. using namespace cv;  
  12. //-----------------------------------【main( )函数】--------------------------------------------  
  13. //            描述:控制台应用程序的入口函数,我们的程序从这里开始  
  14. //-----------------------------------------------------------------------------------------------  
  15. int main( )  
  16. {  
  17.        //载入原始图    
  18.        Mat image = imread("1.jpg");  //工程目录下应该有一张名为1.jpg的素材图  
  19.        //创建窗口    
  20.        namedWindow("【原始图】顶帽运算");   
  21.        namedWindow("【效果图】顶帽运算");   
  22.        //显示原始图   
  23.        imshow("【原始图】顶帽运算", image);   
  24.        //定义核  
  25.        Mat element = getStructuringElement(MORPH_RECT, Size(15, 15));   
  26.        //进行形态学操作  
  27.        morphologyEx(image,image, MORPH_TOPHAT, element);  
  28.        //显示效果图   
  29.        imshow("【效果图】顶帽运算", image);   
  30.    
  31.        waitKey(0);   
  32.    
  33.        return 0;   
  34. }  

运行效果图:




3.6 黑帽运算(BlackHat)示例程序


OpenCV中调用morphologyEx函数进行黑帽运算操作的示例程序如下:

  1. //-----------------------------------【头文件包含部分】---------------------------------------  
  2. //            描述:包含程序所依赖的头文件  
  3. //----------------------------------------------------------------------------------------------  
  4. #include <opencv2/opencv.hpp>  
  5. #include <opencv2/highgui/highgui.hpp>  
  6. #include<opencv2/imgproc/imgproc.hpp>  
  7.    
  8. //-----------------------------------【命名空间声明部分】---------------------------------------  
  9. //            描述:包含程序所使用的命名空间  
  10. //-----------------------------------------------------------------------------------------------  
  11. using namespace cv;  
  12. //-----------------------------------【main( )函数】--------------------------------------------  
  13. //            描述:控制台应用程序的入口函数,我们的程序从这里开始  
  14. //-----------------------------------------------------------------------------------------------  
  15. int main( )  
  16. {  
  17.        //载入原始图    
  18.        Mat image = imread("1.jpg");  //工程目录下应该有一张名为1.jpg的素材图  
  19.        //创建窗口    
  20.        namedWindow("【原始图】黑帽运算");   
  21.        namedWindow("【效果图】黑帽运算");   
  22.        //显示原始图   
  23.        imshow("【原始图】黑帽运算", image);   
  24.        //定义核  
  25.        Mat element = getStructuringElement(MORPH_RECT, Size(15, 15));   
  26.        //进行形态学操作  
  27.        morphologyEx(image,image, MORPH_BLACKHAT, element);  
  28.        //显示效果图   
  29.        imshow("【效果图】黑帽运算", image);   
  30.    
  31.        waitKey(0);   
  32.    
  33.        return 0;   
  34. }  

运行效果图:



 



3.7 腐蚀(morphologyEx调用版)示例程序



OpenCV中调用morphologyEx函数进行腐蚀操作的示例程序如下:

  1. //-----------------------------------【头文件包含部分】---------------------------------------  
  2. //            描述:包含程序所依赖的头文件  
  3. //----------------------------------------------------------------------------------------------  
  4. #include <opencv2/opencv.hpp>  
  5. #include <opencv2/highgui/highgui.hpp>  
  6. #include<opencv2/imgproc/imgproc.hpp>  
  7.    
  8. //-----------------------------------【命名空间声明部分】---------------------------------------  
  9. //            描述:包含程序所使用的命名空间  
  10. //-----------------------------------------------------------------------------------------------  
  11. using namespace cv;  
  12. //-----------------------------------【main( )函数】--------------------------------------------  
  13. //            描述:控制台应用程序的入口函数,我们的程序从这里开始  
  14. //-----------------------------------------------------------------------------------------------  
  15. int main( )  
  16. {  
  17.        //载入原始图    
  18.        Mat image = imread("1.jpg");  //工程目录下应该有一张名为1.jpg的素材图  
  19.        //创建窗口    
  20.        namedWindow("【原始图】腐蚀");   
  21.        namedWindow("【效果图】腐蚀");   
  22.        //显示原始图   
  23.        imshow("【原始图】腐蚀", image);   
  24.        //定义核  
  25.        Mat element = getStructuringElement(MORPH_RECT, Size(15, 15));   
  26.        //进行形态学操作  
  27.        morphologyEx(image,image, MORPH_ERODE, element);  
  28.        //显示效果图   
  29.        imshow("【效果图】腐蚀", image);   
  30.    
  31.        waitKey(0);   
  32.    
  33.        return 0;   
  34. }  

运行效果图:



 



3.8 膨胀(morphologyEx调用版)示例程序



OpenCV中调用morphologyEx函数进行膨胀操作的示例程序如下:

  1. //-----------------------------------【头文件包含部分】---------------------------------------  
  2. //            描述:包含程序所依赖的头文件  
  3. //----------------------------------------------------------------------------------------------  
  4. #include <opencv2/opencv.hpp>  
  5. #include<opencv2/highgui/highgui.hpp>  
  6. #include<opencv2/imgproc/imgproc.hpp>  
  7.    
  8. //-----------------------------------【命名空间声明部分】---------------------------------------  
  9. //            描述:包含程序所使用的命名空间  
  10. //-----------------------------------------------------------------------------------------------  
  11. using namespace cv;  
  12. //-----------------------------------【main( )函数】--------------------------------------------  
  13. //            描述:控制台应用程序的入口函数,我们的程序从这里开始  
  14. //-----------------------------------------------------------------------------------------------  
  15. int main( )  
  16. {  
  17.        //载入原始图    
  18.        Mat image = imread("1.jpg");  //工程目录下应该有一张名为1.jpg的素材图  
  19.        //创建窗口    
  20.        namedWindow("【原始图】膨胀");   
  21.        namedWindow("【效果图】膨胀");   
  22.        //显示原始图   
  23.        imshow("【原始图】膨胀", image);   
  24.        //定义核  
  25.        Mat element = getStructuringElement(MORPH_RECT, Size(15, 15));   
  26.        //进行形态学操作  
  27.        morphologyEx(image,image, MORPH_DILATE, element);  
  28.        //显示效果图   
  29.        imshow("【效果图】膨胀", image);   
  30.    
  31.        waitKey(0);   
  32.    
  33.        return 0;   
  34. }  

运行效果图:



 








四、综合示例——在实战中熟稔

 



依然是每篇文章都会配给大家的一个详细注释的博文配套示例程序,把这篇文章中介绍的知识点以代码为载体,展现给大家。

这个示例程序中,一共有四个显示图像的窗口。

原始图一个,开/闭运算为一个,腐蚀/膨胀为一个,顶帽/黑帽运算为一个。

分别使用滚动条,来控制得到的形态学效果。且迭代值为10的时候,为中间。

另外,还可以通过键盘按键1,2,3以及空格,来调节成不同的元素结构(矩形、椭圆、十字形)。说明页面如下:





废话不多说,上代码吧:


  1. //-----------------------------------【程序说明】----------------------------------------------  
  2. //      程序名称::《【OpenCV入门教程之十一】形态学图像处理(一):膨胀与腐蚀  》 博文配套源码   
  3. //      开发所用IDE版本:Visual Studio 2010  
  4. //      <span style="white-space:pre;"> </span>开发所用OpenCV版本:    2.4.8  
  5. //      2014年4月25日 Create by 浅墨  
  6. //----------------------------------------------------------------------------------------------  
  7.   
  8. //-----------------------------------【头文件包含部分】---------------------------------------  
  9. //      描述:包含程序所依赖的头文件  
  10. //----------------------------------------------------------------------------------------------   
  11. #include <opencv2/opencv.hpp>  
  12. #include <opencv2/highgui/highgui.hpp>  
  13. #include <opencv2/imgproc/imgproc.hpp>  
  14.   
  15. //-----------------------------------【命名空间声明部分】--------------------------------------  
  16. //      描述:包含程序所使用的命名空间  
  17. //-----------------------------------------------------------------------------------------------   
  18. using namespace std;  
  19. using namespace cv;  
  20.   
  21.   
  22. //-----------------------------------【全局变量声明部分】--------------------------------------  
  23. //      描述:全局变量声明  
  24. //-----------------------------------------------------------------------------------------------  
  25. Mat g_srcImage, g_dstImage;//原始图和效果图  
  26. int g_nElementShape = MORPH_RECT;//元素结构的形状  
  27.   
  28. //变量接收的TrackBar位置参数  
  29. int g_nMaxIterationNum = 10;  
  30. int g_nOpenCloseNum = 0;  
  31. int g_nErodeDilateNum = 0;  
  32. int g_nTopBlackHatNum = 0;  
  33.   
  34.   
  35.   
  36. //-----------------------------------【全局函数声明部分】--------------------------------------  
  37. //      描述:全局函数声明  
  38. //-----------------------------------------------------------------------------------------------  
  39. static void on_OpenClose(intvoid*);//回调函数  
  40. static void on_ErodeDilate(intvoid*);//回调函数  
  41. static void on_TopBlackHat(intvoid*);//回调函数  
  42. static void ShowHelpText();//帮助文字显示  
  43.   
  44.   
  45. //-----------------------------------【main( )函数】--------------------------------------------  
  46. //      描述:控制台应用程序的入口函数,我们的程序从这里开始  
  47. //-----------------------------------------------------------------------------------------------  
  48. int main( )  
  49. {  
  50.     //改变console字体颜色  
  51.     system("color 2F");    
  52.   
  53.     ShowHelpText();  
  54.   
  55.     //载入原图  
  56.     g_srcImage = imread("1.jpg");//工程目录下需要有一张名为1.jpg的素材图  
  57.     if( !g_srcImage.data ) { printf("Oh,no,读取srcImage错误~! \n"); return false; }  
  58.   
  59.     //显示原始图  
  60.     namedWindow("【原始图】");  
  61.     imshow("【原始图】", g_srcImage);  
  62.   
  63.     //创建三个窗口  
  64.     namedWindow("【开运算/闭运算】",1);  
  65.     namedWindow("【腐蚀/膨胀】",1);  
  66.     namedWindow("【顶帽/黑帽】",1);  
  67.   
  68.     //参数赋值  
  69.     g_nOpenCloseNum=9;  
  70.     g_nErodeDilateNum=9;  
  71.     g_nTopBlackHatNum=2;  
  72.   
  73.     //分别为三个窗口创建滚动条  
  74.     createTrackbar("迭代值""【开运算/闭运算】",&g_nOpenCloseNum,g_nMaxIterationNum*2+1,on_OpenClose);  
  75.     createTrackbar("迭代值""【腐蚀/膨胀】",&g_nErodeDilateNum,g_nMaxIterationNum*2+1,on_ErodeDilate);  
  76.     createTrackbar("迭代值""【顶帽/黑帽】",&g_nTopBlackHatNum,g_nMaxIterationNum*2+1,on_TopBlackHat);  
  77.   
  78.     //轮询获取按键信息  
  79.     while(1)  
  80.     {  
  81.         int c;  
  82.   
  83.         //执行回调函数  
  84.         on_OpenClose(g_nOpenCloseNum, 0);  
  85.         on_ErodeDilate(g_nErodeDilateNum, 0);  
  86.         on_TopBlackHat(g_nTopBlackHatNum,0);  
  87.   
  88.         //获取按键  
  89.         c = waitKey(0);  
  90.   
  91.         //按下键盘按键Q或者ESC,程序退出  
  92.         if( (char)c == 'q'||(char)c == 27 )  
  93.             break;  
  94.         //按下键盘按键1,使用椭圆(Elliptic)结构元素结构元素MORPH_ELLIPSE  
  95.         if( (char)c == 49 )//键盘按键1的ASII码为49  
  96.             g_nElementShape = MORPH_ELLIPSE;  
  97.         //按下键盘按键2,使用矩形(Rectangle)结构元素MORPH_RECT  
  98.         else if( (char)c == 50 )//键盘按键2的ASII码为50  
  99.             g_nElementShape = MORPH_RECT;  
  100.         //按下键盘按键3,使用十字形(Cross-shaped)结构元素MORPH_CROSS  
  101.         else if( (char)c == 51 )//键盘按键3的ASII码为51  
  102.             g_nElementShape = MORPH_CROSS;  
  103.         //按下键盘按键space,在矩形、椭圆、十字形结构元素中循环  
  104.         else if( (char)c == ' ' )  
  105.             g_nElementShape = (g_nElementShape + 1) % 3;  
  106.     }  
  107.   
  108.     return 0;  
  109. }  
  110.   
  111.   
  112. //-----------------------------------【on_OpenClose( )函数】----------------------------------  
  113. //      描述:【开运算/闭运算】窗口的回调函数  
  114. //-----------------------------------------------------------------------------------------------  
  115. static void on_OpenClose(intvoid*)  
  116. {  
  117.     //偏移量的定义  
  118.     int offset = g_nOpenCloseNum - g_nMaxIterationNum;//偏移量  
  119.     int Absolute_offset = offset > 0 ? offset : -offset;//偏移量绝对值  
  120.     //自定义核  
  121.     Mat element = getStructuringElement(g_nElementShape, Size(Absolute_offset*2+1, Absolute_offset*2+1), Point(Absolute_offset, Absolute_offset) );  
  122.     //进行操作  
  123.     if( offset < 0 )  
  124.         morphologyEx(g_srcImage, g_dstImage, CV_MOP_OPEN, element);  
  125.     else  
  126.         morphologyEx(g_srcImage, g_dstImage, CV_MOP_CLOSE, element);  
  127.     //显示图像  
  128.     imshow("【开运算/闭运算】",g_dstImage);  
  129. }  
  130.   
  131.   
  132. //-----------------------------------【on_ErodeDilate( )函数】----------------------------------  
  133. //      描述:【腐蚀/膨胀】窗口的回调函数  
  134. //-----------------------------------------------------------------------------------------------  
  135. static void on_ErodeDilate(intvoid*)  
  136. {  
  137.     //偏移量的定义  
  138.     int offset = g_nErodeDilateNum - g_nMaxIterationNum;    //偏移量  
  139.     int Absolute_offset = offset > 0 ? offset : -offset;//偏移量绝对值  
  140.     //自定义核  
  141.     Mat element = getStructuringElement(g_nElementShape, Size(Absolute_offset*2+1, Absolute_offset*2+1), Point(Absolute_offset, Absolute_offset) );  
  142.     //进行操作  
  143.     if( offset < 0 )  
  144.         erode(g_srcImage, g_dstImage, element);  
  145.     else  
  146.         dilate(g_srcImage, g_dstImage, element);  
  147.     //显示图像  
  148.     imshow("【腐蚀/膨胀】",g_dstImage);  
  149. }  
  150.   
  151.   
  152. //-----------------------------------【on_TopBlackHat( )函数】--------------------------------  
  153. //      描述:【顶帽运算/黑帽运算】窗口的回调函数  
  154. //----------------------------------------------------------------------------------------------  
  155. static void on_TopBlackHat(intvoid*)  
  156. {  
  157.     //偏移量的定义  
  158.     int offset = g_nTopBlackHatNum - g_nMaxIterationNum;//偏移量  
  159.     int Absolute_offset = offset > 0 ? offset : -offset;//偏移量绝对值  
  160.     //自定义核  
  161.     Mat element = getStructuringElement(g_nElementShape, Size(Absolute_offset*2+1, Absolute_offset*2+1), Point(Absolute_offset, Absolute_offset) );  
  162.     //进行操作  
  163.     if( offset < 0 )  
  164.         morphologyEx(g_srcImage, g_dstImage, MORPH_TOPHAT , element);  
  165.     else  
  166.         morphologyEx(g_srcImage, g_dstImage, MORPH_BLACKHAT, element);  
  167.     //显示图像  
  168.     imshow("【顶帽/黑帽】",g_dstImage);  
  169. }  
  170.   
  171. //-----------------------------------【ShowHelpText( )函数】----------------------------------  
  172. //      描述:输出一些帮助信息  
  173. //----------------------------------------------------------------------------------------------  
  174. static void ShowHelpText()  
  175. {  
  176. //输出一些帮助信息  
  177.     printf("\n\n\n\t请调整滚动条观察图像效果~\n\n");  
  178.     printf( "\n\n\t按键操作说明: \n\n"  
  179.         "\t\t键盘按键【ESC】或者【Q】- 退出程序\n"  
  180.         "\t\t键盘按键【1】- 使用椭圆(Elliptic)结构元素\n"  
  181.         "\t\t键盘按键【2】- 使用矩形(Rectangle )结构元素\n"  
  182.         "\t\t键盘按键【3】- 使用十字型(Cross-shaped)结构元素\n"  
  183.         "\t\t键盘按键【空格SPACE】- 在矩形、椭圆、十字形结构元素中循环\n"  
  184.         "\n\n\t\t\t\t\t\t\t\t by浅墨"  
  185.         );  
  186. }  

放出一些效果图:

首先是原图:


非常帅气的Captain America有木有!

腐蚀效果图:


膨胀效果图:



开运算效果图:



闭运算效果图:



顶帽运算效果图:


黑帽运算效果图:



好的,就放出这些效果图吧,具体更多的运行效果大家就自己下载示例程序回去玩~

 

本篇文章的配套源代码请点击这里下载:


【浅墨OpenCV入门教程之十一】配套源代码下载

 


OK,今天的内容大概就是这些,我们下篇文章见:)


2015-04-08 09:43:28 Trent1985 阅读数 875
  • Excel公式入门实战视频课程【你学得会】

    所谓的公式是人们在研究自然界物与物之间时发现的一些联系,并通过一定的方式表达出来的一种表达方法。而这里我们所说的Excel公式一般是指计算公式,包括常用的四则运算和函数的使用。通过这些运算,我们能从普通数据中得到计算结果以满足分析需求。从而进一步推敲具体的实施方案。杨老师通过《Excel公式实战视频课程【你学得会】》的课程教你如何使用Excel公式来处理数据。

    8691 人正在学习 去看看 杨仕航


[函数名称]

二值图像开运算函数OpenOperateProcess(WriteableBitmap src)

[算法说明]

 开运算就是先进性一次腐蚀后进行一次膨胀。算法过程如公式2-(27)

[函数代码]

       ///<summary>

       /// Open operate process.

       ///</summary>

       ///<param name="src">The source image(It should be the binary image).</param>

       ///<returns></returns>

       publicstaticWriteableBitmap OpenOperateProcess(WriteableBitmap src)////23图像开运算

       {

           if (src !=null)

           {

               WriteableBitmap temp = DilationProcess(CorrosionProcess(src));

               return temp;

           }

           else

           {

               returnnull;

           }

       }

[图像效果]

2019-09-25 22:41:52 shinian1987 阅读数 491
  • Excel公式入门实战视频课程【你学得会】

    所谓的公式是人们在研究自然界物与物之间时发现的一些联系,并通过一定的方式表达出来的一种表达方法。而这里我们所说的Excel公式一般是指计算公式,包括常用的四则运算和函数的使用。通过这些运算,我们能从普通数据中得到计算结果以满足分析需求。从而进一步推敲具体的实施方案。杨老师通过《Excel公式实战视频课程【你学得会】》的课程教你如何使用Excel公式来处理数据。

    8691 人正在学习 去看看 杨仕航

在图像处理中,对图像的滤波是非常常见的一种运算,我们耳熟能详的高斯滤波,双边滤波,导向滤波,而所有的这些滤波其实都是基于局部的一种线性运算。

我们知道,几乎所有的滤波或者局部运算都可以表示成如下的这种形式:

yi=1zjΩiwjyj y_{i} = \frac{1}{z} \sum_{j \in \Omega_{i}} w_{j} y_{j}

其中,z=wjz = \sum w_{j},是一个归一化系数,上面这个表达式,也就意味着图像中,像素 ii 的值 yiy_i 等于其邻域 yjy_j 的一个线性组合,wjw_{j} 表示的就是邻域像素 yjy_{j} 的权重,这个表达式是一系列滤波器的基础。

对于高斯滤波来说,其 wjw_{j} 就是相对位置的一个关系:

wj=12πσe(xixj)22σ2w_{j} = -\frac{1}{\sqrt{2 \pi} \sigma} e^{-\frac{(x_{i} - x_{j})^2}{2\sigma^{2}}}

为了简化,一般可以假设 σ=1\sigma = 1, xi,xjx_{i}, x_{j} 可以看成是像素 i,ji, j 在图像中的坐标,因为高速滤波其实考虑的是像素的相对位置,所以告诉滤波器的权重一般都是固定的,设置好滤波器的尺度,以及 σ\sigma,滤波器可以很快的得到,利用卷积运算,就可以得到一个高斯模糊的运算。除了高斯滤波,还有一个平均滤波,

wj=1N w_{j} = \frac{1}{N}

这种滤波器,表示邻域像素的权重是一样的。

除了高斯滤波,还有一个双边滤波器,双边滤波器,在高斯滤波器的基础上,引入了像素值的考量,

wj=exp((xixj)22σd2)exp((yiyj)22σr2)w_{j} = exp \left({-\frac{(x_{i} - x_{j})^2}{2\sigma_{d}^{2}}} \right) exp \left({-\frac{(y_{i} - y_{j})^2}{2\sigma_{r}^{2}}} \right)

双边滤波,既考虑了像素的位置关系,也考虑像素值的关系,所以在每个邻域上,其权重值 wjw_{j} 是不一样的。

除了高斯滤波,双边滤波之外,还有一种 non-local mean 的滤波,与前面两种滤波方式相比,non-local mean 的滤波器的权重计算,考虑的不是像素与像素之间的相似度,而是像素 ii 的邻域 ViV_{i} 和像素 jj 的邻域 VjV_{j} 之间的相似度,利用像素的邻域来计算权重:

wj=exp((ViVj)22σ2) w_{j} = exp \left({-\frac{(V_{i} - V_{j})^2}{2\sigma^{2}}} \right)

(ViVj)2=1d2l[d,d](yi+lyj+l)2 (V_{i} - V_{j})^2 = \frac{1}{d^{2}} \sum_{l \in [-d, d]} (y_{i+l} - y_{j+l})^2

dd 表示邻域 VV 的半径,d2d^2 也就是邻域的像素个数,邻域 ViV_{i}VjV_{j} 的相似度,也就是邻域里对应像素的欧式距离,这里我们看到,理论上来说,jj 可以是全图范围内的任何一个像素点,不过在实际计算的时候,一般会设置一个搜索范围,也就是在像素 ii 的附近,搜索半径为 DD , 所以一般来说,这个 non-local mean 的计算量是比较大的。

最后介绍一下表面模糊,这个在磨皮算法中经常会遇到,表面模糊也是要利用邻域的像素值,根据如下的表达式,计算每个邻域像素的权重:

wj=1yiyj2.5Tw_{j} = 1 - \frac{|y_{i} - y_j{}|}{2.5T}

上面的 TT 表示一个经验阈值。TT 越大,模糊的程度越高。

从上面的表达式可以看出,除了高斯模糊的权重与像素值无关之外,其他几种模糊形式的权重都和像素值有关,所以高斯模糊可以利用卷积快速地运算得到,而其他几种模糊形式都相对来说要慢很多,比较耗时。

2019-08-16 22:06:08 weixin_39445525 阅读数 51
  • Excel公式入门实战视频课程【你学得会】

    所谓的公式是人们在研究自然界物与物之间时发现的一些联系,并通过一定的方式表达出来的一种表达方法。而这里我们所说的Excel公式一般是指计算公式,包括常用的四则运算和函数的使用。通过这些运算,我们能从普通数据中得到计算结果以满足分析需求。从而进一步推敲具体的实施方案。杨老师通过《Excel公式实战视频课程【你学得会】》的课程教你如何使用Excel公式来处理数据。

    8691 人正在学习 去看看 杨仕航

一、图像的缩放

1.1 图像缩放概念

图像缩放是通过增减像素来改变图像的尺寸的。

1.2 功效

图像缩小,图像变清晰;图像放大,图像变模糊,所以需要插值进一步处理。

1.3 图像缩放变换的矩阵公式

\alpha = \beta:等比缩放;\alpha,\beta大于1,放大,\alpha,\beta小于1,缩小。

1.4 图像的缩小

图像的缩小分为等比缩小和非等比缩小,处理原理是采样偶数或奇数行/列进而得到新的图像。

1.5 图像的放大

图像的放大分为等比放大和等比缩小,处理原理是采用适当的插值添加像素的灰度或颜色值。注:引出图像处理的超分辨问题的研究。

1.6 图像的插值运算

1.6.1 后向插值和前向插值

需求:对于图像缩放、旋转等几何变换一般需要经过变换和插值两个步骤。当数字图像变换后的坐标不一定是整数,需要将非整数坐标点变换到整数坐标处,通常采用插值运算。插值运算的方式分为后向映射和前向映射。

后向映射:通过目标图像中的像素去计算元图像中的像素位置,遇到非整数,利用最近邻插值和双向性插值等插值方法进行得到目标图像的灰度值或颜色值。

前向映射:通过当前元图像的像素去计算得到目标图像中的映射位置,遇到非整数,将该像素的灰度值或颜色值映射到响应的像素。

注:在实际应用中,由于前向映射会使目标图像出现空白像素,后向映射不会出现空白像素,所以常采用带有最近邻插值、双线性插值的后向映射。

1.6.1 灰度重采样

灰度重采样是指通过几何变换的图像,需要重新插值像素灰度的过程,即对输入图像的像素点进行重采样并将结果赋予相应的输出像素。根据目标像素的最近相关像素通过最近邻插值或双线性插值来求目标像素。

1.6.2 图像处理常用的插值方法

图像处理常用的插值方法有:(1)最近邻插值;(2)双线性插值;(3)双三次插值。

1.7 图像处理常用插值算法代码实现--Opencv处理像素方法

1.7.1 主程序

#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>

using namespace std;
using namespace cv;

// 函数声明
void NearInter(Mat& inputImag_1, Mat& outputImg, double dx, double dy);

int main()
{
	double dx = 1.5, dy = 1.5; // 缩放系数

    // 载入图像并显示
    Mat originImage_boy = imread("baby.png", 1);
    imshow("original_boy", originImage_boy);

    // 创建效果图
    Mat resultImage;
    resultImage.create(round(originImage_boy.rows * dx), round(originImage_boy.cols * dy), originImage_boy.type());

    // 记录时间
    double timeClock = static_cast<double>(getTickCount());

    // 函数调用
    // 可定义和调用不同的函数
    NearInter(originImage_boy, resultImage, dx, dy);

    // 输出时间
    timeClock = ((double)getTickCount() - timeClock) / getTickCount();
    cout << "run time:" << timeClock << "seconds" << endl;

    imshow("result",resultImage);
    waitKey(0);
    return 0;
}

1.7.1 最近邻插值-OpenCV遍历像素

// 函数定义
// 使用动态地址计算图像
void NearInter(Mat& inputImag_1, Mat& outputImg, double dx, double dy)
{
	int rowsNum = inputImag_1.rows;
	int colsNum = inputImag_1.cols;

	for (int i = 0; i < rowsNum; i++) {
		for (int j = 0; j < colsNum; j++) {
			for (int o_i = round(dx * i); o_i < round(dx * (i + 1)); o_i++) {
				for (int o_j = round(dx * j); o_j < round(dy * (j + 1));o_j++) {
					outputImg.at<Vec3b>(o_i, o_j)[0] = inputImag_1.at<Vec3b>(i, j)[0];
					outputImg.at<Vec3b>(o_i, o_j)[1] = inputImag_1.at<Vec3b>(i, j)[1];
					outputImg.at<Vec3b>(o_i, o_j)[2] = inputImag_1.at<Vec3b>(i, j)[2];
				}
			}
		}

	}

}

结果图:

 

1.7.2 双线性邻插值-OpenCV遍历像素

// 函数定义
// 使用动态地址计算图像
void LinearInter(Mat& inputImag_1, Mat& outputImg, double dx, double dy)
{
	int rowsNum = inputImag_1.rows;
	int colsNum = inputImag_1.cols;

	int new_rowsNum = outputImg.rows;
	int new_colsNum = outputImg.cols;
	
	int mi, nj;
	double ci, cj;
	int mci, mcj;

	for (int i = 0; i < new_rowsNum; i++) {
		ci = i / dx;
		mi = (int)ci;
		mci = mi + 1;
		double u = ci - mi;

		for (int j = 0; j < new_colsNum; j++) {
			cj = j /dy;
			nj = (int)cj;
			mcj = nj + 1;
			double v = cj - nj;

			if (mci > (rowsNum - 1)) {mci = mi - 1;}
			if (mcj > (colsNum - 1)) {mcj = nj - 1;}

			//计算新点在原图像像上的位置
			 outputImg.at<Vec3b>(i, j)[0] = (int)inputImag_1.at<Vec3b>(mi, nj)[0] * (1 - u) * (1 - v)
			 		+ inputImag_1.at<Vec3b>(mci, nj)[0] * u * (1 - v) 
			 		+ inputImag_1.at<Vec3b>(mi, mcj)[0] * (1 - u) * v 
			 		+ inputImag_1.at<Vec3b>(mci, mcj)[0] * u * v;
			outputImg.at<Vec3b>(i, j)[1] = (int)inputImag_1.at<Vec3b>(mi, nj)[1] * (1 - u) * (1 - v)
			 		+ inputImag_1.at<Vec3b>(mci, nj)[1] * u * (1 - v) 
			 		+ inputImag_1.at<Vec3b>(mi, mcj)[1] * (1 - u) * v
			 		+ inputImag_1.at<Vec3b>(mci, mcj)[1] * u * v;
			outputImg.at<Vec3b>(i, j)[2] = (int)inputImag_1.at<Vec3b>(mi, nj)[2] * (1 - u) * (1 - v)
			 		+ inputImag_1.at<Vec3b>(mci, nj)[2] * u * (1 - v) 
			 		+ inputImag_1.at<Vec3b>(mi, mcj)[2] * (1 - u) * v
			 		+ inputImag_1.at<Vec3b>(mci, mcj)[2] * u * v;
		}
	}


}

 结果图:

1.7.2 双三次邻插值-OpenCV函数resize()调用

resize()函数原型:其中,可以根据响应的参数,调用最近邻插值、双线性i插值、双三次插值(立方插值)

/************************************************************************/
/* 
OpenCV图像缩放使用的函数是:resize
void resize(InputArray src, OutputArray dst, Size dsize, double fx=0, double fy=0, int interpolation=INTER_LINEAR )
参数含义:
InputArray src     -原图像
OutputArray dst    -输出图像
Size dsize         -目标图像的大小
double fx=0        -在x轴上的缩放比例
double fy=0        -在y轴上的缩放比例
int interpolation  -插值方式,有以下四种方式
INTER_NN      -最近邻插值
INTER_LINEAR  -双线性插值 (缺省使用)
INTER_AREA    -使用象素关系重采样,当图像缩小时候,该方法可以避免波纹出现。当图像放大时,类似于 INTER_NN 方法。
INTER_CUBIC   -立方插值。
说明:dsize与fx和fy必须不能同时为零
*/
/************************************************************************/

 1.7.3 调用OpenCV-reszie()实现-双三次插值

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>

using namespace std;
using namespace cv;

// 函数声明

int main()
{
    // 载入图像并显示
    Mat originImage_boy = imread("baby.png", 1);
    imshow("original_boy", originImage_boy);

    // 创建效果图
    Mat resultImage;
    // resultImage.create(round(originImage_boy.rows), round(originImage_boy.cols), originImage_boy.type());

    // 记录时间
    double timeClock = static_cast<double>(getTickCount());

    // 函数调用
    resize(originImage_boy, resultImage, Size(), 1.5, 1.5, INTER_CUBIC);

    // 输出时间
    timeClock = ((double)getTickCount() - timeClock) / getTickCount();
    cout << "run time:" << timeClock << "seconds" << endl;

    imshow("result",resultImage);
    waitKey(0);
    return 0;
}

 

双三次插值结果图:

 

 

没有更多推荐了,返回首页