openCV学习笔记
2016-08-18 08:11
411 查看
[b]*********************2016.8.22***********************[/b]
@2016.8.9~2016.8.12 OpenCV学习细节总结
1.直接读取图像灰度图的方法:Mat LogoMask = imread(“Logo.jpg”, 0);
2.掩模必须为灰度图
3.获取图像ROI的方法:Mat GirlROI = Girl(Rect(200, 200, Logo.cols, Logo.rows));
4.分离颜色通道时候 须要定义 vector channels ——–> 须要搞懂!先保留问题
5.OpenCV的色彩空间为 BGR
6.亮度对比度调节理论依据:g(i,j)=a*f(i,j)+b(其中a为对比度,b为亮度)
7.OpenCV 源代码中的定义:
Vec2b—表示每个Vec2b对象中,可以存储2个char(字符型)数据
Vec3b—表示每一个Vec3b对象中,可以存储3个char(字符型)数据,比如可以用这样的对象,去存储RGB图像中的
Vec4b—表示每一个Vec4b对象中,可以存储4个字符型数据,可以用这样的类对象去存储—4通道RGB+Alpha的图
8.二维图像的遍历像素方法如下(详情查看Mat::at)
9.三通道图像的遍历像素方法如下
10.滤波函数内核的大小不能为0,否则会报错
11.滤波函数内核的大小最好都为奇数。
@2016.8.9~2016.8.12 OpenCV学习函数总结
1.两图像加权融合:addWeighted()
2.分离图像通道:vector channels;
split(Girl, channels);
3.读取BGR中的其中一通道(B为0,G为1,R为2):B=channels.at(0);G=channels.at(1);R=channels.at(2)
4.三通道合成:Merge(channels,OutputDst);
5.运算结果可能超出像素取值范围(溢出),还可能是非整数(如果是浮点数的话),用来确保有效值:saturate_cast<…>()
saturate in the name means that when the input value v is out of the range of the target type
the result is not formed just by taking low bits of the input, but instead the value is clipped.For example :
uchar a = saturate_cast(-100); // a = 0 (UCHAR_MIN)
short b = saturate_cast(33333.33333); // b = 32767 (SHRT_MAX)
6.用于初始化输出图像,使输出图像与输入图像有相同的尺寸类型:
boxFilterDstImg = Mat::zeros(SrcImg.size(), SrcImg.type());
或者
boxFilterDstImg = SrcImg.clone();
7.创建拉动条:createTrackbar()
8.三种线性滤波函数:boxFilter();blur();GaussianBlur();
9.二种非线性滤波函数:medianBlur();bilateralFilter();
10.Returns a structuring element of the specified size and shape for morphological operations(形态学变换用的核):getStructuringElement()
11.
形态学变换初级 dilate(),erode()
形态学变换高级 morphologyEx(MORPH_OPEN /MORPH_CLOSE/ MORPH_GRADIENT/ MORPH_TOPHAT/ MORPH_BLACKHAT)
12.三种边缘检测与一个服务于Sobel 的滤波器
Canny,Sobel,Laplacian/ Scharr滤波器
[b]*********************2016.8.21***********************[/b]
@边缘检测的一般步骤
原图->滤波->转化为灰度图->Canny()/Sobel()【其中Scharr滤波器专为Sobel()函数设计】/Laplacian()。
@两个比较重要的函数
转化为灰度图用的函数:cvtColor()
其他类型格式转化为CV_8U用的函数:convertScaleAbs()
@两个等价的函数
Scharr(src, dst, ddepth, dx, dy, scale,delta, borderType);
<<=====>>Sobel(src, dst, ddepth, dx, dy, CV_SCHARR,scale, delta, borderType);
@Canny,Sobel,Laplacian,Scharr用法源代码
@在学习浅墨的OpenCV入门教程(Soble算子)遇到的问题思考
在学习Sobel算子时,浅墨的代码如下:
然后我问了自己一个问题:
为什么目标图像的深度要转化为CV_16S(16位有符号)类型呢?
接下去发现,浅墨的代码在后续又将其转化成为8位无符号,代码如下:
通过了查询帮助文档了解convertScaleAbs这个函数:
On each element of the input array, the function convertScaleAbs performs three operations sequentially: scaling, taking an absolute value, conversion to an unsigned 8-bit type。
那么我直接在Sobel函数中填入CV_8U的参数呢????!!!!
于是,有了下面这两张图片的对比:其中第一张为直接在Sobel函数里面填入CV_8U,第二张为Sobel输出CV_16S后通过convertScaleAbs()转化为CV_8U.仔细看还是有那么一点差别的(ps:原图为RGB,没有转化为灰度图像,不知道会不会这个因素有影响。。。)
![](https://img-blog.csdn.net/20160821162403206)
通过cvtColor(Src,Dst,CV_RGB2GRAY)将原图转为灰度图后再看效果:
![](https://img-blog.csdn.net/20160821163145295)
嗯,还是有差别的!!!!
@膨胀/腐蚀,开运算/闭运算,顶帽/黑帽综合代码
[b]*********************2016.8.20***********************[/b]
@数学形态学
数学形态学(Mathematical morphology) 是一门建立在格论和拓扑学基础之上的图像分析学科,是数学形态学图像处理的基本理论。其基本的运算包括:二值腐蚀和膨胀、二值开闭运算、骨架抽取、极限腐蚀、击中击不中变换、形态学梯度、Top-hat变换、颗粒分析、流域变换、灰值腐蚀和膨胀、灰值开闭运算、灰值形态学梯度等。
开运算:Dst=Open(Src,element)=dilate(erode(Src,element));
闭运算:Dst=Close(Src,element)=erode(dilate(Src,element));
简单来讲,形态学操作就是基于形状的一系列图像处理操作。OpenCV为进行图像的形态学变换提供了快捷、方便的函数。最基本的形态学操作有二种,他们是:膨胀与腐蚀(Dilation与Erosion)。
在进行腐蚀和膨胀的讲解之前,首先需要注意,腐蚀和膨胀是对白色部分(高亮部分)而言的,不是黑色部分。膨胀就是图像中的高亮部分进行膨胀,“领域扩张”,效果图拥有比原图更大的高亮区域。腐蚀就是原图中的高亮部分被腐蚀,“领域被蚕食”,效果图拥有比原图更小的高亮区域。
@openCV练习中图像读取不出来的问题
有时候图像读取失败可以试卷改 DEBUG 或者 RELEASE 模式
[b]*********************2016.8.19***********************[/b]
@感觉双边滤波更接近于磨皮的效果。
@中值滤波与均值滤波器比较
中值滤波器与均值滤波器比较的优势:在均值滤波器中,由于噪声成分被放入平均计算中,所以输出受到了噪声的影响,但是在中值滤波器中,由于噪声成分很难选上,所以几乎不会影响到输出。因此同样用3x3区域进行处理,中值滤波消除的噪声能力更胜一筹。中值滤波无论是在消除噪声还是保存边缘方面都是一个不错的方法。
中值滤波器与均值滤波器比较的劣势:中值滤波花费的时间是均值滤波的5倍以上。
中值滤波在一定条件下,可以克服线性滤波器(如均值滤波等)所带来的图像细节模糊,如下图:
![](https://img-blog.csdn.net/20160819150517650)
@方框滤波&均值滤波&高斯滤波&中值滤波&双边滤波 源代码
[b]*********************2016.8.18***********************[/b]
@滤波:线性滤波与非线性滤波
线性滤波:
方框滤波——boxblur函数
均值滤波(邻域平均滤波)——blur函数
高斯滤波——GaussianBlur函数
非线性滤波:
中值滤波——medianBlur函数
双边滤波——bilateralFilter函数
@常见的滤波器
允许低频率通过的低通滤波器。
允许高频率通过的高通滤波器。
允许一定范围频率通过的带通滤波器。
阻止一定范围频率通过并且允许其它频率通过的带阻滤波器。
允许所有频率通过、仅仅改变相位关系的全通滤波器。
@值得注意的
滤波≠模糊!!!!!
滤波可分低通滤波和高通滤波两种。而高斯滤波是指用高斯函数作为滤波函数的滤波操作,至于是不是模糊,要看是高斯低通还是高斯高通,低通就是模糊,高通就是锐化。
其实说白了是很简单的,对吧:
高斯滤波是指用高斯函数作为滤波函数的滤波操作。
高斯模糊就是高斯低通滤波。
@图像高低频概念
图像的高低频是对图像各个位置之间强度变化的一种度量方法.
低频分量:主要对整副图像的强度的综合度量.
高频分量:主要是对图像边缘和轮廓的度量.
变化越尖锐的地方高频频谱越多,图像细节就是变化尖锐的地方
高反差也一样,它变化很快,过渡区很小,相当于变化尖锐。
深灰到白的颜色变化比浅灰到白要大,颜色过渡更尖锐,高频分量也更多。
@图像深度
我们把计算机存储单个像素点所用到的bit为称之为图像的深度.一般图片是8bit(位)的,则深度是8.
@基本单位不要混
8bit=1Byte=1B
bit->Byte(B)->KB->MB->GB.
[b]*********************2016.8.17***********************[/b]
@关于openCV中用createTrackbar调亮度对比度源代码
@关于Vec3b,Vec2b,Vec2s等的概念及用法
概念:
【1】Vec2b—表示每个Vec2b对象中,可以存储2个char(字符型)数据
【2】Vec3b—表示每一个Vec3b对象中,可以存储3个char(字符型)数据,比如可以用这样的对象,去存储RGB图像中的
【3】Vec4b—表示每一个Vec4b对象中,可以存储4个字符型数据,可以用这样的类对象去存储—4通道RGB+Alpha的图
用法:例如遍历一图像:
`
[b]*********************2016.8.16***********************[/b]
@assertion failed错误
在debug模式下报assertion failed错误,请教是什么原因,在return true出现断言,release可以运行?
解决方法:这种情况下一般都是项目属性debug和release的都配置在一块了,debug模式下只要debug的库,release模式下只要release的库,应该就可以
[b]*********************2016.8.12***********************[/b]
Mat::Mat(……..)的众多构造函数有很多,很多都涉及到类型 type。type可以是 CV_8UC1,CV_16SC1,…,
CV_64FC4 等。里面的 8U 表示 8 位无符号整数, 16S 表示 16 位有符号整数, 64F
表示 64 位浮点数(即 double 类型); C 后面的数表示通道数,例如 C1 表示一个
通道的图像, C4 表示 4 个通道的图像,以此类推
[b]*********************2016.8.10***********************[/b]
@最简单的OpenCV程序,读取与显示图片
[b]*********************2016.8.9***********************[/b]
@opencv环境配置问题:一直有未经处理的中断异常
其实,在显示了文件的扩展名后才发现问题:本来是1.jpg的图片结果成了1.jpg.jpg了,因此,在出现上述异常时,不仅仅要考虑到是配置问题,还有可能仅仅就是扩展名没有填写正确。当然,保险的做法是不要隐藏电脑的文件扩展名!!!
@2016.8.9~2016.8.12 OpenCV学习细节总结
1.直接读取图像灰度图的方法:Mat LogoMask = imread(“Logo.jpg”, 0);
2.掩模必须为灰度图
3.获取图像ROI的方法:Mat GirlROI = Girl(Rect(200, 200, Logo.cols, Logo.rows));
4.分离颜色通道时候 须要定义 vector channels ——–> 须要搞懂!先保留问题
5.OpenCV的色彩空间为 BGR
6.亮度对比度调节理论依据:g(i,j)=a*f(i,j)+b(其中a为对比度,b为亮度)
7.OpenCV 源代码中的定义:
typedef Vec <uchar, 2> Vec2b;
Vec2b—表示每个Vec2b对象中,可以存储2个char(字符型)数据
Vec3b—表示每一个Vec3b对象中,可以存储3个char(字符型)数据,比如可以用这样的对象,去存储RGB图像中的
Vec4b—表示每一个Vec4b对象中,可以存储4个字符型数据,可以用这样的类对象去存储—4通道RGB+Alpha的图
8.二维图像的遍历像素方法如下(详情查看Mat::at)
Mat H(100, 100, CV_64F); for (int i = 0; i < H.rows; i++) { for (int j = 0; j < H.cols; j++) { H.at<double>(i, j) = 1. / (i + j + 1); } }
9.三通道图像的遍历像素方法如下
for (int y = 0; y < SrcImg.rows; ++y) { for (int x = 0; x < SrcImg.cols; ++x) { for (int c = 0; c < 3; ++c) { DstImg.at<Vec3b>(y, x)[c]= saturate_cast<uchar>((ContrastValue*0.01)*SrcImg.at<Vec3b>(y,x)[c]+BrightValue); } } }
10.滤波函数内核的大小不能为0,否则会报错
11.滤波函数内核的大小最好都为奇数。
@2016.8.9~2016.8.12 OpenCV学习函数总结
1.两图像加权融合:addWeighted()
2.分离图像通道:vector channels;
split(Girl, channels);
3.读取BGR中的其中一通道(B为0,G为1,R为2):B=channels.at(0);G=channels.at(1);R=channels.at(2)
4.三通道合成:Merge(channels,OutputDst);
5.运算结果可能超出像素取值范围(溢出),还可能是非整数(如果是浮点数的话),用来确保有效值:saturate_cast<…>()
saturate in the name means that when the input value v is out of the range of the target type
the result is not formed just by taking low bits of the input, but instead the value is clipped.For example :
uchar a = saturate_cast(-100); // a = 0 (UCHAR_MIN)
short b = saturate_cast(33333.33333); // b = 32767 (SHRT_MAX)
6.用于初始化输出图像,使输出图像与输入图像有相同的尺寸类型:
boxFilterDstImg = Mat::zeros(SrcImg.size(), SrcImg.type());
或者
boxFilterDstImg = SrcImg.clone();
7.创建拉动条:createTrackbar()
8.三种线性滤波函数:boxFilter();blur();GaussianBlur();
9.二种非线性滤波函数:medianBlur();bilateralFilter();
10.Returns a structuring element of the specified size and shape for morphological operations(形态学变换用的核):getStructuringElement()
11.
形态学变换初级 dilate(),erode()
形态学变换高级 morphologyEx(MORPH_OPEN /MORPH_CLOSE/ MORPH_GRADIENT/ MORPH_TOPHAT/ MORPH_BLACKHAT)
12.三种边缘检测与一个服务于Sobel 的滤波器
Canny,Sobel,Laplacian/ Scharr滤波器
[b]*********************2016.8.21***********************[/b]
@边缘检测的一般步骤
原图->滤波->转化为灰度图->Canny()/Sobel()【其中Scharr滤波器专为Sobel()函数设计】/Laplacian()。
@两个比较重要的函数
转化为灰度图用的函数:cvtColor()
其他类型格式转化为CV_8U用的函数:convertScaleAbs()
@两个等价的函数
Scharr(src, dst, ddepth, dx, dy, scale,delta, borderType);
<<=====>>Sobel(src, dst, ddepth, dx, dy, CV_SCHARR,scale, delta, borderType);
@Canny,Sobel,Laplacian,Scharr用法源代码
bool Canny() { Mat SrcImg = imread("benz.jpg"); if (!SrcImg.data) return false; Mat EdgeImg; Mat BWImg; Mat DstImg; cvtColor(SrcImg, BWImg, CV_RGB2GRAY); blur(BWImg, BWImg, Size(3, 3)); //第三个参数,double类型的threshold1,第一个滞后性阈值。 //第四个参数,double类型的threshold2,第二个滞后性阈值。 //这个函数阈值1和阈值2两者的小者用于边缘连接,而大者用来控制强边缘的初始段 //推荐的高低阈值比在2:1到3:1之间。 Canny(BWImg, EdgeImg, 3, 9); //void copyTo(OutputArray m, InputArray mask) const; //! copies those matrix elements to "m" that are marked with non-zero mask elements. SrcImg.copyTo(DstImg, EdgeImg); namedWindow("BWGirl"); imshow("BWGirl", DstImg); } bool Sobel() { Mat SrcImgRGB = imread("benz.jpg"); if (!SrcImgRGB.data) return false; Mat DstImgx, DstImgy, DstImg, absDstImgx, absDstImgy; Mat SrcImgBW; cvtColor(SrcImgRGB, SrcImgBW, CV_RGB2GRAY); //Sobel与Scharr滤波器是等价的 //Scharr(..........) <==> Sobel(Src,Dst,CV_16S,1,0,Scharr) //ksize – Size of the extended Sobel kernel. It must be 1, 3, 5, or 7. //以下默认为Ksize=1 Sobel(SrcImgBW, DstImgx, CV_8U, 1, 0); Sobel(SrcImgBW, DstImgy, CV_8U, 0, 1); addWeighted(DstImgx, 0.5, DstImgy, 0.5, 0, DstImg); namedWindow("Sobel x方向"); namedWindow("Sobel y方向"); namedWindow("Sobel x,y方向通过加权叠加"); namedWindow("原图"); imshow("Sobel x方向", DstImgx); imshow("Sobel y方向", DstImgy); imshow("Sobel x,y方向通过加权叠加", DstImg); imshow("原图", SrcImgRGB); } //Scharr滤波器,不是算子。 bool Scharr() { Mat SrcImg, GraySrcImg; Mat DstImgX, DstImgY; Mat AbsDstImgX, AbsDstImgY; Mat DstImg; SrcImg = imread("benz.jpg"); if (!SrcImg.data) return false; //中值滤波 medianBlur(SrcImg, SrcImg, 3); //转化为灰度图 cvtColor(SrcImg, GraySrcImg, CV_RGB2GRAY); //计算x,y方向的导数 Scharr(GraySrcImg, DstImgX, CV_16S, 1, 0); Scharr(GraySrcImg, DstImgY, CV_16S, 0, 1); //转化为CV_8U convertScaleAbs(DstImgX, AbsDstImgX); convertScaleAbs(DstImgY, AbsDstImgY); //加权融合 addWeighted(AbsDstImgX, 0.5, AbsDstImgY, 0.5, 0, DstImg); namedWindow("滤波后的图"); imshow("滤波后的图", DstImg); } bool Laplacian() { Mat SrcImg, GraySrcImg, DstImg; SrcImg = imread("benz.jpg"); //先对RGB图像滤波,滤波完后再转化为灰度图。 GaussianBlur(SrcImg, SrcImg, Size(3, 3), 0); cvtColor(SrcImg, GraySrcImg, CV_RGB2GRAY); //通过拉普拉斯变换边缘检测函数的核有默认值1,核越大,边缘越明显 //tips:也可以试试改变输出图像不同深度,再转化为8U,效果是不同的。 //第三个参数,int类型的ddepth,输出图像的深度,支持如下src.depth()和ddepth的组合: //若src.depth() = CV_8U, 取ddepth = -1 / CV_16S / CV_32F / CV_64F //若src.depth() = CV_16U / CV_16S, 取ddepth = -1 / CV_32F / CV_64F //若src.depth() = CV_32F, 取ddepth = -1 / CV_32F / CV_64F //若src.depth() = CV_64F, 取ddepth = -1 / CV_64F Laplacian(GraySrcImg, DstImg, CV_16U, 3); //进行CV_16U---->CV_8U的函数 //convertScaleAbs:On each element of the input array, the function convertScaleAbs performs three operations sequentially: //scaling, taking an absolute value, conversion to an unsigned 8-bit type: convertScaleAbs(DstImg, DstImg); namedWindow("灰度图"); namedWindow("拉普拉斯变换图"); imshow("灰度图", GraySrcImg); imshow("拉普拉斯变换图", DstImg); }
@在学习浅墨的OpenCV入门教程(Soble算子)遇到的问题思考
在学习Sobel算子时,浅墨的代码如下:
int main( ) { //【0】创建 grad_x 和 grad_y 矩阵 Mat grad_x, grad_y; Mat abs_grad_x, abs_grad_y,dst; //【1】载入原始图 Mat src = imread("1.jpg"); //工程目录下应该有一张名为1.jpg的素材图 //【2】显示原始图 imshow("【原始图】sobel边缘检测", src); //【3】求 X方向梯度 Sobel( src, grad_x, CV_16S, 1, 0, 3, 1, 1, BORDER_DEFAULT ); convertScaleAbs( grad_x, abs_grad_x ); imshow("【效果图】 X方向Sobel", abs_grad_x); //【4】求Y方向梯度 Sobel( src, grad_y, CV_16S, 0, 1, 3, 1, 1, BORDER_DEFAULT ); convertScaleAbs( grad_y, abs_grad_y ); imshow("【效果图】Y方向Sobel", abs_grad_y); //【5】合并梯度(近似) addWeighted( abs_grad_x, 0.5, abs_grad_y, 0.5, 0, dst ); imshow("【效果图】整体方向Sobel", dst); waitKey(0); return 0; }
然后我问了自己一个问题:
//【3】求 X方向梯度 Sobel( src, grad_x, CV_16S, 1, 0, 3, 1, 1, BORDER_DEFAULT ); //【4】求Y方向梯度 Sobel( src, grad_y, CV_16S, 0, 1, 3, 1, 1, BORDER_DEFAULT );
为什么目标图像的深度要转化为CV_16S(16位有符号)类型呢?
接下去发现,浅墨的代码在后续又将其转化成为8位无符号,代码如下:
convertScaleAbs( grad_x, abs_grad_x ); convertScaleAbs( grad_y, abs_grad_y );
通过了查询帮助文档了解convertScaleAbs这个函数:
On each element of the input array, the function convertScaleAbs performs three operations sequentially: scaling, taking an absolute value, conversion to an unsigned 8-bit type。
那么我直接在Sobel函数中填入CV_8U的参数呢????!!!!
于是,有了下面这两张图片的对比:其中第一张为直接在Sobel函数里面填入CV_8U,第二张为Sobel输出CV_16S后通过convertScaleAbs()转化为CV_8U.仔细看还是有那么一点差别的(ps:原图为RGB,没有转化为灰度图像,不知道会不会这个因素有影响。。。)
通过cvtColor(Src,Dst,CV_RGB2GRAY)将原图转为灰度图后再看效果:
嗯,还是有差别的!!!!
@膨胀/腐蚀,开运算/闭运算,顶帽/黑帽综合代码
#include<opencv2\core\core.hpp> #include<opencv2\highgui\highgui.hpp> #include<opencv2\imgproc\imgproc.hpp> using namespace std; using namespace cv; //全局变量 Mat SrcImg; Mat DstImg; /*源代码:enum { MORPH_RECT=0, MORPH_CROSS=1, MORPH_ELLIPSE=2 };*/ int ElementShape = MORPH_RECT; //10为分界点,超过10与小于10各对应两种状态 int DilateErodeValue = 11; int OpenCloseValue = 11; int TopBlackHatValue = 11; //回调函数声明 void CallbackDilateErode(int, void*); void CallbackOpenClose(int, void*); void CallbackTopBlackHat(int, void*); //打印在DOS界面的帮助信息 void PrintHelpText(); //主函数 int main() { SrcImg = imread("Logo.jpg"); if (!SrcImg.data) return false; PrintHelpText(); DstImg = SrcImg.clone(); //命名窗口一定要先创建 //之前在回调函数里面才创建命名窗口,导致Trackbar显示不出来 namedWindow("膨胀腐蚀效果图"); namedWindow("开闭运算效果图"); namedWindow("顶黑帽运算效果图"); createTrackbar("腐蚀与膨胀", "膨胀腐蚀效果图", &DilateErodeValue, 20, CallbackDilateErode); createTrackbar("开闭运算", "开闭运算效果图", &OpenCloseValue, 20, CallbackOpenClose); createTrackbar("顶黑帽运算", "顶黑帽运算效果图", &TopBlackHatValue, 20, CallbackTopBlackHat); namedWindow("原图"); imshow("原图", SrcImg); //轮询获取按键信息 while (1) { int getKeyInput = waitKey(0);//获取按键的ASCII码 //Trackbar改变的时候调用回调函数 CallbackDilateErode(DilateErodeValue, 0); CallbackOpenClose(OpenCloseValue, 0); CallbackTopBlackHat(TopBlackHatValue, 0); //根据按键的输入,改变核的形状 if (27 == (char)getKeyInput)//ESC { break; } else if ('A'==(char)getKeyInput) { ElementShape = MORPH_RECT; } else if ('S' == (char)getKeyInput) { ElementShape = MORPH_ELLIPSE; } else if ('D' == (char)getKeyInput) { ElementShape = MORPH_CROSS; } else if(' '== (char)getKeyInput)//空格 { ElementShape = (ElementShape + 1) % 3;//三种状态顺序切换 } } waitKey(); return true; } /*回调函数中的Offset表示偏移的中心点*/ void CallbackDilateErode(int ,void*) { int Offset = 10; int AbsOffset = (DilateErodeValue - Offset) > 0 ? (DilateErodeValue - Offset) : -(DilateErodeValue - Offset); Mat element=getStructuringElement(ElementShape, Size(AbsOffset * 2 + 1, AbsOffset * 2 + 1)); if (DilateErodeValue > 10)//腐蚀 { morphologyEx(SrcImg, DstImg, MORPH_ERODE, element); } else//膨胀 { morphologyEx(SrcImg, DstImg, MORPH_DILATE, element); } imshow("膨胀腐蚀效果图", DstImg); } void CallbackOpenClose(int, void*) { int Offset = 10; int AbsOffset = (OpenCloseValue - Offset) > 0 ? (OpenCloseValue - Offset) : -(OpenCloseValue - Offset); Mat element = getStructuringElement(ElementShape, Size(AbsOffset * 2 + 1, AbsOffset * 2 + 1)); if (OpenCloseValue > 10)//闭运算 { morphologyEx(SrcImg, DstImg, MORPH_CLOSE, element); } else//开运算 { morphologyEx(SrcImg, DstImg, MORPH_OPEN, element); } imshow("开闭运算效果图", DstImg); } void CallbackTopBlackHat(int, void*) { int Offset = 10; int AbsOffset = (TopBlackHatValue - Offset) > 0 ? (TopBlackHatValue - Offset) : -(TopBlackHatValue - Offset); Mat element = getStructuringElemen 110c6 t(ElementShape, Size(AbsOffset * 2 + 1, AbsOffset * 2 + 1)); if (TopBlackHatValue > 10)//黑帽运算 { morphologyEx(SrcImg, DstImg, MORPH_BLACKHAT, element); } else//闭帽运算 { morphologyEx(SrcImg, DstImg, MORPH_TOPHAT, element); } imshow("顶黑帽运算效果图", DstImg); } //DOS界面下显示帮助信息 void PrintHelpText() { printf( "\t\t\t\t\ 帮助信息" "\n\t 按下按键ESC退出" "\n\t 按下A------->掩膜形状为MORPH_RECT" "\n\t 按下S------->掩膜形状为MORPH_ELLOPSE" "\n\t 按下D------->掩膜形状为MORPH_CROSS" "\n\t 按下SPACE------->掩膜形状为三种顺序切换"); }
[b]*********************2016.8.20***********************[/b]
@数学形态学
数学形态学(Mathematical morphology) 是一门建立在格论和拓扑学基础之上的图像分析学科,是数学形态学图像处理的基本理论。其基本的运算包括:二值腐蚀和膨胀、二值开闭运算、骨架抽取、极限腐蚀、击中击不中变换、形态学梯度、Top-hat变换、颗粒分析、流域变换、灰值腐蚀和膨胀、灰值开闭运算、灰值形态学梯度等。
开运算:Dst=Open(Src,element)=dilate(erode(Src,element));
闭运算:Dst=Close(Src,element)=erode(dilate(Src,element));
简单来讲,形态学操作就是基于形状的一系列图像处理操作。OpenCV为进行图像的形态学变换提供了快捷、方便的函数。最基本的形态学操作有二种,他们是:膨胀与腐蚀(Dilation与Erosion)。
在进行腐蚀和膨胀的讲解之前,首先需要注意,腐蚀和膨胀是对白色部分(高亮部分)而言的,不是黑色部分。膨胀就是图像中的高亮部分进行膨胀,“领域扩张”,效果图拥有比原图更大的高亮区域。腐蚀就是原图中的高亮部分被腐蚀,“领域被蚕食”,效果图拥有比原图更小的高亮区域。
@openCV练习中图像读取不出来的问题
有时候图像读取失败可以试卷改 DEBUG 或者 RELEASE 模式
[b]*********************2016.8.19***********************[/b]
@感觉双边滤波更接近于磨皮的效果。
@中值滤波与均值滤波器比较
中值滤波器与均值滤波器比较的优势:在均值滤波器中,由于噪声成分被放入平均计算中,所以输出受到了噪声的影响,但是在中值滤波器中,由于噪声成分很难选上,所以几乎不会影响到输出。因此同样用3x3区域进行处理,中值滤波消除的噪声能力更胜一筹。中值滤波无论是在消除噪声还是保存边缘方面都是一个不错的方法。
中值滤波器与均值滤波器比较的劣势:中值滤波花费的时间是均值滤波的5倍以上。
中值滤波在一定条件下,可以克服线性滤波器(如均值滤波等)所带来的图像细节模糊,如下图:
@方框滤波&均值滤波&高斯滤波&中值滤波&双边滤波 源代码
#include<iostream> #include<opencv2\core\core.hpp> #include<opencv2\highgui\highgui.hpp> #include<opencv2\imgproc\imgproc.hpp> using namespace cv; using namespace std; //main函数与回调函数都要使用到-->所以定义成全局变量 Mat SrcImg;//输入图像 Mat boxFilterDstImg;//方框滤波输出图像 Mat blurDstImg;//均值滤波输出图像 Mat GaussianBlurDstImg;//高斯滤波输出图像 Mat meddianBlurDstImg;//中值滤波输出图像 Mat bilateralBlurDstImg;//双边滤波输出图像 //设定滤波函数的内核大小的初值 int boxFilterValue = 2; int blurValue = 2; int GaussianBlurValue = 2; int meddianBlurValue = 7; int bilateralBulrValue = 25; //回调函数的声明 void CallbackBoxFilter(int, void*); void CallbackBlur(int, void*); void CallbackGaussianBlur(int, void*); void CallbackMeddianBlur(int, void*); void CallbackBilateralBlur(int, void*); //主函数 int main() { //DOS界面颜色 system("color 1C"); SrcImg = imread("Dragon.jpg"); if (!SrcImg.data) { printf("读取图片失败"); return false; } //用于初始化输出图像,使输出图像与输入图像有相同的尺寸类型 //但是好像不用初始化也可以 //boxFilterDstImg = Mat::zeros(SrcImg.size(), SrcImg.type()); //blurDstImg= Mat::zeros(SrcImg.size(), SrcImg.type()); //GaussianBlurDstImg = Mat::zeros(SrcImg.size(), SrcImg.type()); //也可以用clone函数来实现输出图像与输入图像有相同的尺寸类型 boxFilterDstImg = SrcImg.clone(); blurDstImg= SrcImg.clone(); GaussianBlurDstImg= SrcImg.clone(); meddianBlurDstImg= SrcImg.clone(); bilateralBlurDstImg= SrcImg.clone(); //创建调用回调函数的Trackbar函数 createTrackbar("方框滤波", "方框滤波效果图", &boxFilterValue, 20, CallbackBoxFilter); createTrackbar("均值滤波", "均值滤波效果图", &blurValue, 20, CallbackBlur); createTrackbar("高斯滤波", "高斯滤波效果图", &GaussianBlurValue, 20, CallbackGaussianBlur); createTrackbar("中值滤波", "中值滤波效果图", &meddianBlurValue, 35, CallbackMeddianBlur); createTrackbar("双边滤波", "双边滤波效果图", &bilateralBulrValue, 100, CallbackBilateralBlur); //Trackbar发生变化时调用的回调函数 CallbackBoxFilter(boxFilterValue, 0); CallbackBlur(blurValue, 0); CallbackGaussianBlur(GaussianBlurValue, 0); CallbackMeddianBlur(meddianBlurValue, 0); CallbackBilateralBlur(bilateralBulrValue, 0); //显示原图 namedWindow("原图"); imshow("原图", SrcImg); //输出一些帮助信息 cout <<endl<< "\t\t\tby我不是斗哥"; waitKey(); return true; } //======================================================================== //滤波函数内核的大小不能为0,否则会报错 //所以Size(m,n)里面的数值都+1; //高斯函数的内核m,n只能为奇数 //======================================================================== //方框滤波回调函数 void CallbackBoxFilter(int, void*) { boxFilter(SrcImg, boxFilterDstImg, -1, Size(boxFilterValue+1, boxFilterValue+1));//方框滤波函数 namedWindow("方框滤波效果图"); imshow("方框滤波效果图", boxFilterDstImg); } //均值滤波回调函数 void CallbackBlur(int, void*) { blur(SrcImg, blurDstImg, Size(blurValue + 1, blurValue + 1));//均值滤波函数 namedWindow("均值滤波效果图"); imshow("均值滤波效果图", blurDstImg); } //高斯滤波回调函数 void CallbackGaussianBlur(int, void*) { GaussianBlur(SrcImg, GaussianBlurDstImg, Size(GaussianBlurValue *2+ 1, GaussianBlurValue*2 + 1), 0, 0);//高斯滤波函数 namedWindow("高斯滤波效果图"); imshow("高斯滤波效果图",GaussianBlurDstImg); } //中值滤波回调函数 void CallbackMeddianBlur(int, void*) { medianBlur(SrcImg, meddianBlurDstImg, meddianBlurValue*2+1); namedWindow("中值滤波效果图"); imshow("中值滤波效果图", meddianBlurDstImg); } //双边滤波回调函数 void CallbackBilateralBlur(int, void*) { //参数三:int d 表示在过滤过程中每个像素邻域的直径 //参数四:double sigmaColor 颜色空间滤波器的sigma值。 //参数四:这个参数的值越大,就表明该像素邻域内有更宽广的颜色会被混合到一起,产生较大的半相等颜色区域。 //参数五:double类型的sigmaSpace 坐标空间中滤波器的sigma值,坐标空间的标注方差。 //参数五:他的数值越大,意味着越远的像素会相互影响,从而使更大的区域足够相似的颜色获取相同的颜色。 //参数五:当d>0,d指定了邻域大小且与sigmaSpace无关。否则,d正比于sigmaSpace。 bilateralFilter(SrcImg, bilateralBlurDstImg, bilateralBulrValue, bilateralBulrValue * 2, bilateralBulrValue / 2); namedWindow("双边滤波效果图"); imshow("双边滤波效果图", bilateralBlurDstImg); }
[b]*********************2016.8.18***********************[/b]
@滤波:线性滤波与非线性滤波
线性滤波:
方框滤波——boxblur函数
均值滤波(邻域平均滤波)——blur函数
高斯滤波——GaussianBlur函数
非线性滤波:
中值滤波——medianBlur函数
双边滤波——bilateralFilter函数
@常见的滤波器
允许低频率通过的低通滤波器。
允许高频率通过的高通滤波器。
允许一定范围频率通过的带通滤波器。
阻止一定范围频率通过并且允许其它频率通过的带阻滤波器。
允许所有频率通过、仅仅改变相位关系的全通滤波器。
@值得注意的
滤波≠模糊!!!!!
滤波可分低通滤波和高通滤波两种。而高斯滤波是指用高斯函数作为滤波函数的滤波操作,至于是不是模糊,要看是高斯低通还是高斯高通,低通就是模糊,高通就是锐化。
其实说白了是很简单的,对吧:
高斯滤波是指用高斯函数作为滤波函数的滤波操作。
高斯模糊就是高斯低通滤波。
@图像高低频概念
图像的高低频是对图像各个位置之间强度变化的一种度量方法.
低频分量:主要对整副图像的强度的综合度量.
高频分量:主要是对图像边缘和轮廓的度量.
变化越尖锐的地方高频频谱越多,图像细节就是变化尖锐的地方
高反差也一样,它变化很快,过渡区很小,相当于变化尖锐。
深灰到白的颜色变化比浅灰到白要大,颜色过渡更尖锐,高频分量也更多。
@图像深度
我们把计算机存储单个像素点所用到的bit为称之为图像的深度.一般图片是8bit(位)的,则深度是8.
@基本单位不要混
8bit=1Byte=1B
bit->Byte(B)->KB->MB->GB.
[b]*********************2016.8.17***********************[/b]
@关于openCV中用createTrackbar调亮度对比度源代码
#include<opencv2\core\core.hpp> #include<opencv2\highgui\highgui.hpp> //#include<opencv2\imgproc\imgproc.hpp> #include<iostream> using namespace std; using namespace cv; //全局变量,因为回调函数和主函数都要用到。 Mat SrcImg; Mat DstImg; int ContrastValue = 50;//对比度初值 int BrightValue = 50;//亮度初值 //声明回调函数 void CallbackContrastBright(int, void*); //主函数 int main(int *argc, char *argv[]) { SrcImg = imread("FIFA.png"); if (!SrcImg.data) { printf("读取图片失败!请尝试检查!\n"); return false; } //初始化目标图像 DstImg = Mat::zeros(SrcImg.size(), SrcImg.type()); //调用回调函数 //第一个参数为目标数值,第二个参数因为目标数值为全局变量,所以为0. CallbackContrastBright(ContrastValue, 0); CallbackContrastBright(BrightValue, 0); //createTrackbar(Trackbar名称,Trackbar附着的窗口名称,目标数值的初值,目标数值的最大值,回调函数) //createTrackbar 的最后一个参数默认为0,因为目标数值(ContrastValue&BrightValue)为全局变量。 //定义的回调函数CallbackContrastBright必须为void Foo(int,void*)格式 createTrackbar("对比度", "效果图", &ContrastValue, 200, CallbackContrastBright); createTrackbar("亮度", "效果图", &BrightValue, 100, CallbackContrastBright); namedWindow("原图", WINDOW_AUTOSIZE); imshow("原图", SrcImg); waitKey(); return true; } //定义的回调函数CallbackContrastBright必须为void Foo(int,void*)格式 //typedef Vec<uchar, 2> Vec2b; //Vec2b---表示每个Vec2b对象中,可以存储2个char(字符型)数据 //Vec3b---表示每一个Vec3b对象中,可以存储3个char(字符型)数据,比如可以用这样的对象,去存储RGB图像中的 //Vec4b---表示每一个Vec4b对象中,可以存储4个字符型数据,可以用这样的类对象去存储---4通道RGB+Alpha的图 //二维图像的遍历像素方法如下(详情查看Mat::at) //Mat H(100, 100, CV_64F); // for (int i = 0; i < H.rows; i++) // for (int j = 0; j < H.cols; j++) // H.at<double>(i, j) = 1. / (i + j + 1); void CallbackContrastBright(int,void*) { //利用3个循环遍历图像中的所有像素 for (int y = 0; y < SrcImg.rows; ++y) { for (int x = 0; x < SrcImg.cols; ++x) { for (int c = 0; c < 3; ++c) { //亮度对比度调节理论依据:g(i,j)=a*f(i,j)+b(其中a为对比度,b为亮度) //我们的轨迹条一般取值都会整数 //所以在这里我们可以,将其代表对比度值的ContrastValue参数设为0到200之间的整型,在最后的式子中乘以一个0.01 //因为我们的运算结果可能超出像素取值范围(溢出),还可能是非整数(如果是浮点数的话) //所以我们要用saturate_cast对结果进行转换,以确保它为有效值。 //saturate in the name means that when the input value v is out of the range of the target type //the result is not formed just by taking low bits of the input, but instead the value is clipped.For example : //uchar a = saturate_cast<uchar>(-100); // a = 0 (UCHAR_MIN) //short b = saturate_cast<short>(33333.33333); // b = 32767 (SHRT_MAX) DstImg.at<Vec3b>(y, x)[c]= saturate_cast<uchar>((ContrastValue*0.01)*SrcImg.at<Vec3b>(y,x)[c]+BrightValue); } } } namedWindow("效果图", WINDOW_AUTOSIZE); imshow("效果图", DstImg); }
@关于Vec3b,Vec2b,Vec2s等的概念及用法
概念:
typedef Vec<unchar,2> Vec2b;
【1】Vec2b—表示每个Vec2b对象中,可以存储2个char(字符型)数据
【2】Vec3b—表示每一个Vec3b对象中,可以存储3个char(字符型)数据,比如可以用这样的对象,去存储RGB图像中的
【3】Vec4b—表示每一个Vec4b对象中,可以存储4个字符型数据,可以用这样的类对象去存储—4通道RGB+Alpha的图
用法:例如遍历一图像:
DstImg.at<Vec3b>(y, x)[c]= saturate_cast<uchar>((ContrastValue*0.01)*SrcImg.at<Vec3b>(y,x)[c]+BrightValue);
`
[b]*********************2016.8.16***********************[/b]
@assertion failed错误
在debug模式下报assertion failed错误,请教是什么原因,在return true出现断言,release可以运行?
解决方法:这种情况下一般都是项目属性debug和release的都配置在一块了,debug模式下只要debug的库,release模式下只要release的库,应该就可以
[b]*********************2016.8.12***********************[/b]
Mat::Mat(……..)的众多构造函数有很多,很多都涉及到类型 type。type可以是 CV_8UC1,CV_16SC1,…,
CV_64FC4 等。里面的 8U 表示 8 位无符号整数, 16S 表示 16 位有符号整数, 64F
表示 64 位浮点数(即 double 类型); C 后面的数表示通道数,例如 C1 表示一个
通道的图像, C4 表示 4 个通道的图像,以此类推
[b]*********************2016.8.10***********************[/b]
@最简单的OpenCV程序,读取与显示图片
using namespace cv; int main() { Mat pic = imread("fengjing.jpg"); namedWindow("风景", WINDOW_NORMAL); imshow("风景",pic); waitKey(10000); return 0; }
[b]*********************2016.8.9***********************[/b]
@opencv环境配置问题:一直有未经处理的中断异常
其实,在显示了文件的扩展名后才发现问题:本来是1.jpg的图片结果成了1.jpg.jpg了,因此,在出现上述异常时,不仅仅要考虑到是配置问题,还有可能仅仅就是扩展名没有填写正确。当然,保险的做法是不要隐藏电脑的文件扩展名!!!
相关文章推荐
- python中使用OpenCV进行人脸检测的例子
- opencv 做人脸识别 opencv 人脸匹配分析
- 使用opencv拉伸图像扩大分辨率示例
- Android Studio中配置OpenCV库开发环境的教程
- 基于C++实现kinect+opencv 获取深度及彩色数据
- visual studio 2012安装配置方法图文教程 附opencv配置教程
- OpenCV 2.4.3 C++ 平滑处理分析
- Python中使用OpenCV库来进行简单的气象学遥感影像计算
- 利用Python和OpenCV库将URL转换为OpenCV格式的方法
- python结合opencv实现人脸检测与跟踪
- Python环境搭建之OpenCV的步骤方法
- Python+Opencv识别两张相似图片
- Python实现OpenCV的安装与使用示例
- 在树莓派2或树莓派B+上安装Python和OpenCV的教程
- opencv-python学习一--人脸检测
- 在Ubuntu上安装OpenCV3.0和Python-openCV的经历
- 使用 Java 开发 OpenCV 应用
- OpenCV配置,从来没有这么简单!
- ubuntu下opencv和qt的安装配置
- visual studio 2012安装配置方法图文教程 附opencv配置教程