形态学操作

形态学操作  主要针对 二值图像 进行处理


图像形态学操作是  基于形状的一系列图像处理操作的合集,主要是基于集合论基础上的形态学数学。
形态学有四个基本操作:膨胀、腐蚀、开、闭。
膨胀与 腐蚀是图像处理中最常用的形态学操作手段,常常被组合起来一起使用实现一些复杂的图像形态学操作。

膨胀与腐蚀能实现各种各样的功能,主要如下:
1、消除噪声。
2、分割出独立的图像元素,在图像中连接相邻的元素。
3、寻找图像中的明显的极大值区域或极小值区域。
求出图像的梯度。

膨胀与腐蚀都是对于白色部分即高亮部分(不是黑色部分)进行操作。膨胀是图像中的高亮部分进行膨胀,类似于“领域扩大”,而腐蚀是原图像中的高亮部分被腐蚀,类似于“领域被吞噬”。



膨胀(dilation)
跟卷积操作类似,假设有图像A和结构元素B,结构元素B在A上面移动,其中B定义其中心为锚点,计算B覆盖下A的最大像素值来替换锚点的像素,其中B作为结构体可以是任意形状。
OpenCV提供的API:
void dilate(InputArray src,
 OutputArray dst,     
InputArray kernel,//第三个参数表示膨胀操作的核,当为NULL时,表示使用参考点位于中心3*3的核。
 Point anchor=Point(- 1 ,- 1 ), 
int iterations= 1 ,
int borderType=BORDER_CONSTANT,
const Scalar& borderValue=morphologyDefaultBorderValue())

一般在调用erode以及dilate函数之前,先定义一个Mat类型的变量来获得函数getStructuringElemen返回的指定形状和尺寸的结构元素(内核矩阵)。
Mat getStructuringElement(int shape, 
Size ksize, //内核的尺寸
Point anchor=Point(-1,-1))//锚点的位置
第一个参数表示内核的形状,有如下三种形状可以选择.
  • 矩形:MORPH_RECT;
  • 交叉形:MORPH_CROSS;
  • 椭圆形:MORPH_ELLIPSE;


处理结果:





腐蚀 (erode)
腐蚀操作和膨胀操作的过程类似,唯一不同的是一最小值替换锚点重叠下图像的像素值。
OpenCV提供的API:
void erode(InputArray src,
OutputArray dst,
InputArray kernel, 
Point anchor=Point(-1,-1), 
int iterations=1,
int borderType=BORDER_CONSTANT, 
const Scalar& borderValue=morphologyDefaultBorderValue())  


处理结果:

很好的消除了小白点的干扰,但是主体还是有损失。



创建滑动条:
滑动条 依附于窗口(window) 而存在。
它往往会和一个 回调函数配合 起来用。

函数原型:
int createTrackbar(
conststring& trackbarname,//轨迹条的名字
conststring& winname,//依附在哪一个窗口
int* value,//表示滑块的初始位置,当操作滑动条的时候,值小于初始值的话,程序中断。
int count,//表示滑块可以达到的最大值
TrackbarCallback onChange=0,//指定回调函数,在轨迹改变的时候会自动调用这个回调函数
void* userdata=0);

步骤:
1、声明相关变量。(这里我定义的是全局变量)
int dilateval = 1;
int dilatecst = 20;
2、定义一个回调函数,这个回调函数 在轨迹改变的时候会自动调用  。
void CallBack_Demo_Dilate(int, void*)  //回调函数的格式
{
       //获取自定义核
       Size ksize(dilateval, dilateval);
       Mat element = getStructuringElement(MORPH_RECT, ksize);//获取内核的形状
       //膨胀  
       dilate(src, DilatePic, element);
       imshow("膨胀后", DilatePic);
}
3、创建滚动条,并依附于相应窗口,代码写在一起好看一点。
namedWindow( "膨胀后",WINDOW_AUTOSIZE);
createTrackbar("dilate-size:", "膨胀后",&dilateval, dilatecst,CallBack_Demo_Dilate);
CallBack_Demo_Dilate(0, 0); //先执行一次代码让图像在程序Run时就显示。



开操作  先腐蚀后膨胀
      在上面的腐蚀操作中,使用腐蚀虽然使白(亮)点消失,但是也使主体损失,这时我们可以再使用膨胀进行弥补。这一过程就是开操作。开操作是一般使对象的轮廓变得光滑,断开狭窄的间断和消除细的突出物。
OpenCV提供的API:
void morphologyEx(
InputArray src,
OutputArray dst,
int op,
InputArray kernel,
Point anchor=Point(-1,-1),
int iterations=1,
int borderType=BORDER_CONSTANT,
const Scalar& borderValue=morphologyDefaultBorderValue())
/*
部分参数介绍:
op:选择使用什么形态学操作
MORPH_OPEN - 开操作
MORPH_CLOSE - 闭操作
MORPH_GRADIENT - 形态学梯度
MORPH_TOPHAT - 顶帽
MORPH_BLACKHAT - 黑帽
MORPH_HITMISS - 击中与击不中
*/


处理结果:

很好的消除了噪点,也使主体损失减小。


闭操作  先膨胀后腐蚀
闭操作可使轮廓线更光滑,但与开操作相反的是,闭操作通常消弥狭窄的间断和长细的鸿沟,消除小的空洞,并填补轮廓线中的断裂。

代码几乎相同,只是改动一个参数(op)罢了。

处理结果:




形态学梯度 


1、基本梯度
基本梯度是用膨胀后的图像减去腐蚀后的图像得到差值图像,称为梯度图像也是OpenCV中支持的计算形态学梯度的方法,而此方法得到梯度有被称为基本梯度。

2、内部梯度
是用原图像减去腐蚀之后的图像得到差值图像,称为图像的内部梯度

3、外部梯度
图像膨胀之后再减去原来的图像得到的差值图像,称为图像的外部梯度。

4、方向梯度
方向梯度是使用X方向与Y方向的直线作为结构元素之后得到图像梯度,X的结构元素分布膨胀与腐蚀得到图像之后求差值得到称为X方向梯度,用Y方向直线做结构分别膨胀与腐蚀之后得到图像求差值之后称为Y方向梯度。



顶帽   顶帽是原图像与开操作之间的差值图像。


处理结果:




黑帽   黑帽是闭操作减去原图像


处理结果:





提取水平与垂直线(形态学操作应用)

图像形态学操作的时候,可以通过自定义的结构元素实现结构元素对输入图像一些对象敏感,另外一些对象不敏感,这样就会让敏感的对象改变而不敏感的对象保留输出。通过使用两个最基本的形态学操作–膨胀与腐蚀,使用不同的结构元素实现对输入图像的操作,得到想要的结果。


操作过程:
  •       1、读取原图;
  •       2、转为灰度图像;
  •       3、转为二值图像;(像逻辑电路一样,要么0要么1的图像)

  • 采用自适应二值化adaptiveThreshold(属于阈值操作部分)
      _src      要二值化的灰度图
  _dst      二值化后的图
  maxValue  二值化后要设置的那个值
  method   块计算的方法(ADAPTIVE_THRESH_MEAN_C 平均值,ADAPTIVE_THRESH_GAUSSIAN_C 高斯分布加权和)
  type      二值化类型(CV_THRESH_BINARY 大于为最大值,CV_THRESH_BINARY_INV 小于为最大值)
  blockSize  块大小(奇数,大于1)
  delta     差值(负值也可以)

  •       4、定义结构元素;
  •       5、开操作。


实例代码:
void GetLine(){
    Mat src,grayImg,binImg,dest;
    //①、读取图片
    src = imread( "line.png" );
    if ( ! src .data ){
        cout << "图片打开失败!" << endl;
        return ;
    }
    namedWindow( "原图像" ,CV_WINDOW_AUTOSIZE);
    imshow( "原图像" ,src);
    //②、转为灰度图
    cvtColor(src,grayImg,CV_RGB2GRAY);
    namedWindow( "灰度图" ,CV_WINDOW_AUTOSIZE);
    imshow( "灰度图" ,grayImg);
    //③、转为二值图像
    adaptiveThreshold(~grayImg,binImg, 255 ,ADAPTIVE_THRESH_MEAN_C,THRESH_BINARY , 15 , - 2 );
    namedWindow( "二值图像" ,CV_WINDOW_AUTOSIZE);
    imshow( "二值图像" ,binImg);
    //④、定义结构元素
    Mat kernel = getStructuringElement(MORPH_RECT,Size( 1 , 20 ));
     //⑤、开操作
    morphologyEx(binImg,dest,MORPH_OPEN,kernel);
    namedWindow( "最终结果" ,CV_WINDOW_AUTOSIZE);
    imshow( "最终结果" ,~dest);//图像的取反操作
    cvWaitKey();
}


提取结果:






去除横线,提取字母:



实例代码:

void GetChar(){
    Mat src,grayImg,binImg,dest;
    //①、读取图片
    src = imread( "char.png" );
    if ( ! src .data ){
        cout << "图片打开失败!" << endl;
        return ;
    }
    namedWindow( "原图像" ,CV_WINDOW_AUTOSIZE);
    imshow( "原图像" ,src);
    //②、转为灰度图
    cvtColor(src,grayImg,CV_RGB2GRAY);
    namedWindow( "灰度图" ,CV_WINDOW_AUTOSIZE);
    imshow( "灰度图" ,grayImg);
    //③、转为二值图像
    /*
    void adaptiveThreshold(InputArray src, OutputArray dst, double maxValue, int adaptiveMethod, int thresholdType, int blockSize, double C)
    */
    adaptiveThreshold(~grayImg,binImg, 255 ,ADAPTIVE_THRESH_MEAN_C,THRESH_BINARY , 15 , - 2 );
    namedWindow( "二值图像" ,CV_WINDOW_AUTOSIZE);
    imshow( "二值图像" ,binImg);
    //④、定义结构元素
    Mat kernel = getStructuringElement(MORPH_RECT,Size( 3 , 3 ));
     //⑤、开操作
    morphologyEx(binImg,dest,MORPH_OPEN,kernel);
    namedWindow( "最终结果" ,CV_WINDOW_AUTOSIZE);
    imshow( "最终结果" ,~dest);
    cvWaitKey();
}




处理结果:





代码示例如下:

 

#include <opencv2/opencv.hpp>

using namespace std; using namespace cv; void CallBack_Demo_Erode(int, void*); void CallBack_Demo_Dilate(int, void*); //全局变量 Mat src = imread("helloworld.png"); Mat DilatePic = Mat(src.size(), src.type()); int dilateval = 1; int dilatecst = 20; Mat ErodePic = Mat(src.size(), src.type()); int erodeval = 1; int erodecst = 20; int main(int argc, char** argv) { if (!src.data) { printf("could not find picture .../n"); return -1; } namedWindow("原图像",WINDOW_AUTOSIZE); namedWindow("膨胀后",WINDOW_AUTOSIZE); createTrackbar("dilate-size:", "膨胀后",&dilateval, dilatecst,CallBack_Demo_Dilate); namedWindow("腐蚀后",WINDOW_AUTOSIZE); createTrackbar("erode-size:", "腐蚀后",&erodeval,erodecst,CallBack_Demo_Erode); //这个只是让回调函数执行一次把图像显示出来而已,可以不要。 CallBack_Demo_Dilate(0, 0); CallBack_Demo_Erode(0, 0); imshow("原图像", src); waitKey(0); return 0; } void CallBack_Demo_Dilate(int, void*) { //获取自定义核 Size ksize(dilateval, dilateval); Mat element = getStructuringElement(MORPH_RECT, ksize); //膨胀 dilate(src, DilatePic, element); imshow("膨胀后", DilatePic); } void CallBack_Demo_Erode(int, void*) { //获取自定义核 Size ksize(erodeval, erodeval); Mat element = getStructuringElement(MORPH_RECT, ksize); //腐蚀 erode(src, ErodePic, element); imshow("腐蚀后", ErodePic); }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

玖零猴

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值