OpenCv形态学操作和漫水填充
2016-09-08 19:48
399 查看
OpenCv形态学操作
函数介绍
在常用的腐蚀和膨胀基础上,常使用**morphology()**函数.
该方法支持常用的灰度图或是彩色图像(会分单通道处理)。
" morphologyEx函数的参数声明 " void morphologyEx( InputArray src, //输入图像 OutputArray dst, //输出图像 int op, //表示形态学操作的标识 InputArray kernel, //自定义核 Point anchor=Point(-1,-1), //核锚点 int iterations=1, //操作迭代次数 int borderType=BORDER_CONSTANT, //图像边界像素填充类型(默认为常数,配合borderValue参数) const Scalar& borderValue=morphologyDefaultBorderValue() );
op参数:
MORPH_ERODE -->"腐蚀操作" MORPH_DILATE -->"膨胀操作" MORPH_OPEN(MORPH_OPEN) -->"开运算" CV_MOP_CLOSE(MORPH_CLOSE) -->"闭运算" CV_MOP_GRADIENT(MORPH_GRADIENT) -->"形态梯度" CV_MOP_TOPHAT(MORPH_TOPHAT) -->"礼帽" CV_MOP_BLACKHAT(MORPH_BLACKHAT) -->"黑帽"
kernel参数:
默认参数为NULL,表示使用系统提供的3×3内核,锚点为中心位置。
常常使用自定义内核,使用函数getStructuringElement()生成我们想要的核矩阵。
Mat getStructuringElement( int shape, //核矩阵形状 Size ksize, //尺寸 Point anchor=Point(-1,-1) //锚点位置 ); **shape**参数: MORPH_RECT -->"矩形" MORPH_CROSS -->"十字形" MORPH_ELLIPSE -->"椭圆形" **anchor**参数: 默认为Point(-1,-1)即为核中心。 对于"十字形"核中心决定核矩阵形状(十字形为单线宽)。 可以自定义一个核矩阵: int kernel_size; //根据实际情况赋值 Mat kernel = getStructuringElement(MORPH_RECT, Size(kernel_size*2+1,kerner_size*2+1), Point(kernel_size,kernel_size));
其他参数可使用默认值
所有操作支持in-place(原地输出)
形态运算
开运算再膨胀" title="">
开运算常用与分割图片(除去小的明亮区域,剩余明亮区域被隔绝)
灰度图中会消除高于其邻点的孤立点。
闭运算
再腐蚀" title="">
闭运算常用消除噪声(亮的区域连接在一起,大小基本不变)
灰度图中会消除低于其邻点的孤立点。
对于开闭运算的迭代的情况下(例如2次开运算)
是执行 腐蚀–>腐蚀–>膨胀–>膨胀
形态梯度运算
梯度运算应用于灰度图,凸显出灰度变化边界值
灰度图中边缘高亮突出。
礼帽运算
开运算是放大裂缝或局部低亮度区域,进行TOPHAT操作后,可以突出局部最大值周围的区域
突出轮廓周围更亮的区域
常用于分割大背景配合小图片(分割出背景)
黑帽运算
原图" title="">
突出轮廓周围更暗的区域
- 可以分割出图像的轮廓
代码
#include <opencv2/core/core.hpp> #include <opencv2/imgproc/imgproc.hpp> #include <opencv2/highgui/highgui.hpp> #include <opencv2/core/types_c.h> #include <iostream> #include <opencv.hpp> using namespace cv; using namespace std; void onBarChangeListener(int,void*); //trackbar回调 Mat src; int kernel_size = 7; //核心矩阵大小 int Shape_Type=0; //核矩阵形态类型 int iterations = 1; //迭代次数 int main() { namedWindow("src",0); namedWindow("dst_open",0); namedWindow("dst_close",0); namedWindow("dst_gradient",0); namedWindow("dst_tophat",0); namedWindow("dst_blackhat",0); src = imread("H:\\road.png"); createTrackbar("Shape","src",&Shape_Type,2,onBarChangeListener); createTrackbar("KernelSise","src",&kernel_size,10,onBarChangeListener); createTrackbar("Iterations","src",&iterations,14,onBarChangeListener); waitKey(0); return 0; } void onBarChangeListener(int,void*) { Mat dst_open,dst_close,dst_gradient,dst_tophat,dst_blackhat; Mat kernel; int s_type; //保证kernel矩阵最小为3x3 kernel_size = (kernel_size==0)?1:kernel_size; //保证iterations迭代次数最小为1 iterations = (iterations==0)?1:iterations; switch (Shape_Type) { case 0: s_type = MORPH_RECT; break; case 1: s_type = MORPH_CROSS; break; case 2: s_type = MORPH_ELLIPSE; break; default: s_type = MORPH_RECT; break; } //锚点默认为中心 kernel=getStructuringElement(s_type,Size(kernel_size*2+1,kernel_size*2+1)); morphologyEx(src,dst_open,MORPH_OPEN, kernel,Point(-1,-1),iterations); morphologyEx(src,dst_close,MORPH_CLOSE, kernel,Point(-1,-1),iterations); morphologyEx(src,dst_gradient,MORPH_GRADIENT, kernel,Point(-1,-1),iterations); morphologyEx(src,dst_tophat,MORPH_TOPHAT, kernel,Point(-1,-1),iterations); morphologyEx(src,dst_blackhat,MORPH_BLACKHAT, kernel,Point(-1,-1),iterations); imshow("src",src); imshow("dst_open",dst_open); imshow("dst_close",dst_close); imshow("dst_gradient",dst_gradient); imshow("dst_tophat",dst_tophat); imshow("dst_blackhat",dst_blackhat); }
漫水填充算法
函数声明
用来标记或分离图像的一部分,类似于PS内的魔术棒功能。 在确定一个中心点情况下,利用一个下限间隔值和一个上限间隔值确定连通区域,对该区域做漫填充操作。
使用low(R1,G1,B1)和high(R2,G2,B2)来确定像素点可接受域
该函数可以彩色图片或者灰度图操作,对于彩色图如果在区域内,可以三个通道同时设置不同的间隔值,如果在接收范围内则会留下该点。
函数的操作区域一定为连续区域。
不带掩码的填充函数说明 int floodFill( InputOutputArray image, //输入图像 Point seedPoint, //中心点 CV_OUT Rect* rect=0, //设置边界区域最小矩阵 Scalar loDiff=Scalar(), //低像素间隔值 Scalar upDiff=Scalar(), //高像素间隔值 int flags=4 //控制填充区域的连通性,相关性 );
带掩码 int floodFill( InputOutputArray image, //输入图像 InputOutputArray mask, //掩码 Point seedPoint, //中心点 Scalar newVal, //填充像素值 CV_OUT Rect* rect=0, //边界最小矩阵 Scalar loDiff=Scalar(), //低 Scalar upDiff=Scalar(), //高 int flags=4 //标志 ); ----------
参数说明 mask: 注意该Mat对象应该满足: 1. 单通道 CV_8UC1 2. 长宽比原图大2倍(2个像素点即可) (src.rows+2,src.cols+2) 3. floodFill函数"只操作mask内像素点为0的值" 4. mask图像的(x+1,y+1)与原图的(x,y)点对应 - 在使用过程中可以先划定并清空mask中ROI区域,再做floodFill操作。 - 也可以在mask中标定原图的边界区域,防止floodFill填充到边界。 ---------- seedPoint: floodFill操作的中心点(可以利用鼠标点击事件来获取到用户输入) ---------- newVal: 标定区域后填充的颜色值。( 彩色:Scalar(r,g,b)或灰度:Scalar(d) ) ---------- rect: 默认值为0,设置floodFill函数将要填充的最小边界区域 ---------- loDiff: 低下限间隔值( 彩色:Scalar(r,g,b) 灰度:Scalar(d) ) upDiff: 高上限间隔值( 彩色:Scalar(r,g,b) 灰度:Scalar(d) ) ---------- flags: int型定义前24位。参数包含三个部分。 1.对于低8位(0~7位)。控制填充算法的连通性。可以设置4或8。 a.为4 -->填充算法只考虑当前像素点的左右和垂直方向的相邻点 b.为8 -->填充算法还会考虑对角线方向的相邻点 2.对于8~15位。 指定填充掩码图像的值。如果设置为0,则mask即会用1填充。 3.对于16~23位。 a. FLOODFILL_FIXED_RANGE 只有当某个相邻点与中心点(seekPoint)像素差在范围内才填充 b. FLOODFILL_MASK_ONLY 函数不填充原始图像,只填充mask图像 flags可以通过OR操作连接起来。 例如:想用8领域填充,并填充固定像素值范围,填充mask图像,填充值为47. 则输入参数为: flags = FLOODFILL_FIXED_RANGE | FLOODFILL_MASK_ONLY | (47<<8); ----------
程序实例
#include <opencv2/core/core.hpp> #include <opencv2/imgproc/imgproc.hpp> #include <opencv2/highgui/highgui.hpp> #include <opencv2/core/types_c.h> #include <iostream> #include <opencv.hpp> using namespace cv; using namespace std; void onMouseChangeListener(int event,int x,int y,int,void*);//鼠标回调 void onBarChangeLisener(int,void*); //bar回调 Mat src,src_gray,temp,dst; int lowDiff=5,highDiff=5,maxGap=30; bool isSrc_Gray=false; //源图是否为灰度图 bool isMask=false; //floodFill是否需要掩码阵 int main() { src = imread("H:\\cat.jpg"); temp.create(src.rows+2,src.cols+2,CV_8UC1); //初始化掩码矩阵 temp = Scalar::all(0); namedWindow("src"); setMouseCallback("src",onMouseChangeListener); createTrackbar("low","src",&lowDiff,maxGap,onBarChangeLisener); createTrackbar("high","src",&highDiff,maxGap,onBarChangeLisener); imshow("src",src); int key=0; while (1) { key=waitKey(0); char c=(char)key; if (key=='e') //按下E -->退出 { break; } switch (c) { case 'g': isSrc_Gray = true; break; //按下g --> 灰度图 case 'r': isSrc_Gray = false;break; //按下r --> 彩色图 case 'm': isMask=true; break; //按下m --> 带掩码 case 'n': isMask=false; break; //按下n --> 不带掩码 default: break; } } waitKey(0); return 0; } void onMouseChangeListener(int event,int x,int y,int,void*) { if (event!=CV_EVENT_LBUTTONDOWN) { return; // 只响应左击事件 } Rect ccmp; Point seedPoint = Point(x,y); //漫水填充原始点=鼠标点击点 isSrc_Gray?(cvtColor(src,dst,CV_RGB2GRAY)):(src.copyTo(dst)); //确定目标图是否为灰度图 if (isMask) //需要掩码 { threshold(temp,temp,1,128,CV_THRESH_BINARY); //确定mask阵 if (isSrc_Gray) { floodFill(dst,temp,seedPoint,Scalar(1),&ccmp, Scalar(lowDiff),Scalar(highDiff),4); } else //彩色通道 { floodFill(dst,temp,seedPoint,Scalar(255,0,0),&ccmp, Scalar(lowDiff,lowDiff,lowDiff),Scalar(highDiff,highDiff,highDiff),4); } } else //不带mask的floodFill函数 { if (isSrc_Gray) { floodFill(dst,seedPoint,Scalar(1),&ccmp,Scalar(lowDiff),Scalar(highDiff),4); } else { floodFill(dst,seedPoint,Scalar(255,0,0),&ccmp, Scalar(lowDiff,lowDiff,lowDiff),Scalar(highDiff,highDiff,highDiff),4); } } imshow("dst",dst); } void onBarChangeLisener(int,void*) { lowDiff = lowDiff==0?1:lowDiff; highDiff = highDiff==0?1:highDiff; }
相关文章推荐
- php学习网站
- linux查看日志常用命令
- linux系统性能监控常用命令
- Linux下配置 Keepalived(心跳检测部署)
- Linux下配置 Keepalived(心跳检测部署)
- Linux下查看文件和文件夹大小
- Linux权限管理
- CentOS 卸载OpenJdk
- centos 6.5 部署tomcat 实现自动化部署
- 教你如何使用IDEA新建WEB工程
- (二)OpenGL中的Shader
- titan-1.0.0-hadoop1 + Hbase 问题
- JZOJ4753【GDOI2017模拟9.4】种树 LCT维护子树信息+换根时维护Dfs序(CC MONOPLOY加强版)
- centos安装zeromq, jzmq
- MyEclipse+Tomcat+MAVEN+SVN项目完整环境搭建
- BASH中2>1 与2>&1的区别
- docker镜像加速之CentOS7
- 【操作系统】CentOS 7 syntax error near unexpected token 问题解决
- linux的find命令详解
- Linux killall命令详解