数字形态学(OpenCV)

Posted jianle23

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数字形态学(OpenCV)相关的知识,希望对你有一定的参考价值。

形态学 

 形态学(morphology)是生物学的一个分支,其关注的是动植物的形态和结构等。这里用同一词语表示图像处理的数学形态学的内容。数学形态学的语言是集合论,其中的集合表示图像的对象,如:二值化图像中,所有白色像素的集合是该图像的一个完整形态学描述。集合中每两个分量提供一个像素的坐标,第三个分量则对应于其离散灰度值。更高维度空间的集合可以包含其他的图像属性,譬如颜色和随时间变化的分量。除了基本的集合定义之外,集合的反射和平移的概念在形态学中用得也很广泛。一个集合B的反射表示B‘,定义如下:B‘={w|w=-b,b∈B}。如果B是描述图像中物体的像素的集合(二维点),则B‘是B中(x,y)坐标被(-x,-y)替代的点的集合。集合B按照点z=(z1,z2)表示(B)z的平移定义:(B)z={c|c=b+z,b∈B}。图像表示如下:

技术图片

  集合反射操作类似于空间卷积中执行的翻转(旋转)操作。在形态学中集合的反射和平移用来表达基于结构元(SE)的操作:研究一幅图像中感兴趣特性所用的小集合或子图像。对于结构元的操作可以使用下图做一些简单的介绍:

技术图片

  当我们使用“结构元包含在几何中”这样的术语时,我们明确地指出A和B的元素完全重叠。

 

 

 

 

形态学梯度运算:

#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
using namespace cv;

int main()
{ 
    Mat image = imread("1.jpg");    
    imshow("【原始图】形态学梯度", image);

    Mat element = getStructuringElement(MORPH_RECT, Size(15, 15));
    morphologyEx(image, image, MORPH_GRADIENT, element);
    imshow("【效果图】形态学梯度", image);

    waitKey(0);
    return 0;
}

形态学综合示例:

技术图片
#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
using namespace std;
using namespace cv;

Mat g_srcImage, g_dstImage;//原始图和效果图
int g_nElementShape = MORPH_RECT;//元素结构的形状

//变量接收的TrackBar位置参数
int g_nMaxIterationNum = 10;
int g_nOpenCloseNum = 0;
int g_nErodeDilateNum = 0;
int g_nTopBlackHatNum = 0;

static void on_OpenClose(int, void*);//回调函数
static void on_ErodeDilate(int, void*);//回调函数
static void on_TopBlackHat(int, void*);//回调函数

int main()
{
    g_srcImage = imread("1.jpg");
    if (!g_srcImage.data) { printf("Oh,no,读取srcImage错误~! 
"); return false; }
    imshow("【原始图】", g_srcImage);

    namedWindow("【开运算/闭运算】", 1);
    namedWindow("【腐蚀/膨胀】", 1);
    namedWindow("【顶帽/黑帽】", 1);

    //参数赋值
    g_nOpenCloseNum = 9;
    g_nErodeDilateNum = 9;
    g_nTopBlackHatNum = 2;

    //分别为三个窗口创建滚动条
    createTrackbar("迭代值", "【开运算/闭运算】", &g_nOpenCloseNum, g_nMaxIterationNum * 2 + 1, on_OpenClose);
    createTrackbar("迭代值", "【腐蚀/膨胀】", &g_nErodeDilateNum, g_nMaxIterationNum * 2 + 1, on_ErodeDilate);
    createTrackbar("迭代值", "【顶帽/黑帽】", &g_nTopBlackHatNum, g_nMaxIterationNum * 2 + 1, on_TopBlackHat);

    //轮询获取按键信息
    while (1)
    {
        int c;

        //执行回调函数
        on_OpenClose(g_nOpenCloseNum, 0);
        on_ErodeDilate(g_nErodeDilateNum, 0);
        on_TopBlackHat(g_nTopBlackHatNum, 0);

        //获取按键
        c = waitKey(0);

        //按下键盘按键Q或者ESC,程序退出
        if ((char)c == q || (char)c == 27)
            break;
        //按下键盘按键1,使用椭圆(Elliptic)结构元素结构元素MORPH_ELLIPSE
        if ((char)c == 49)//键盘按键1的ASII码为49
            g_nElementShape = MORPH_ELLIPSE;
        //按下键盘按键2,使用矩形(Rectangle)结构元素MORPH_RECT
        else if ((char)c == 50)//键盘按键2的ASII码为50
            g_nElementShape = MORPH_RECT;
        //按下键盘按键3,使用十字形(Cross-shaped)结构元素MORPH_CROSS
        else if ((char)c == 51)//键盘按键3的ASII码为51
            g_nElementShape = MORPH_CROSS;
        //按下键盘按键space,在矩形、椭圆、十字形结构元素中循环
        else if ((char)c ==  )
            g_nElementShape = (g_nElementShape + 1) % 3;
    }

    return 0;
}

static void on_OpenClose(int, void*)
{
    //偏移量的定义
    int offset = g_nOpenCloseNum - g_nMaxIterationNum;//偏移量
    int Absolute_offset = offset > 0 ? offset : -offset;//偏移量绝对值
    //自定义核
    Mat element = getStructuringElement(g_nElementShape, Size(Absolute_offset * 2 + 1, Absolute_offset * 2 + 1), Point(Absolute_offset, Absolute_offset));
    //进行操作
    if (offset < 0)
        //此句代码的OpenCV2版为:
        //morphologyEx(g_srcImage, g_dstImage, CV_MOP_OPEN, element);
        //此句代码的OpenCV3版为:
        morphologyEx(g_srcImage, g_dstImage, MORPH_OPEN, element);
    else
        //此句代码的OpenCV2版为:
        //morphologyEx(g_srcImage, g_dstImage, CV_MOP_CLOSE, element);
        //此句代码的OpenCV3版为:
        morphologyEx(g_srcImage, g_dstImage, MORPH_CLOSE, element);



    //显示图像
    imshow("【开运算/闭运算】", g_dstImage);
}

static void on_ErodeDilate(int, void*)
{
    //偏移量的定义
    int offset = g_nErodeDilateNum - g_nMaxIterationNum;    //偏移量
    int Absolute_offset = offset > 0 ? offset : -offset;//偏移量绝对值
    //自定义核
    Mat element = getStructuringElement(g_nElementShape, Size(Absolute_offset * 2 + 1, Absolute_offset * 2 + 1), Point(Absolute_offset, Absolute_offset));
    //进行操作
    if (offset < 0)
        erode(g_srcImage, g_dstImage, element);
    else
        dilate(g_srcImage, g_dstImage, element);
    //显示图像
    imshow("【腐蚀/膨胀】", g_dstImage);
}

static void on_TopBlackHat(int, void*)
{
    //偏移量的定义
    int offset = g_nTopBlackHatNum - g_nMaxIterationNum;//偏移量
    int Absolute_offset = offset > 0 ? offset : -offset;//偏移量绝对值
    //自定义核
    Mat element = getStructuringElement(g_nElementShape, Size(Absolute_offset * 2 + 1, Absolute_offset * 2 + 1), Point(Absolute_offset, Absolute_offset));
    //进行操作
    if (offset < 0)
        morphologyEx(g_srcImage, g_dstImage, MORPH_TOPHAT, element);
    else
        morphologyEx(g_srcImage, g_dstImage, MORPH_BLACKHAT, element);
    //显示图像
    imshow("【顶帽/黑帽】", g_dstImage);
}
morphologyEx

 填充:

技术图片
#include <opencv2/opencv.hpp>  
#include <opencv2/imgproc/imgproc.hpp>  
using namespace cv;

int main()
{
    Mat src = imread("1.jpg");
    imshow("【原始图】", src);
    Rect ccomp;
    floodFill(src, Point(50, 300), Scalar(155, 255, 55), &ccomp, Scalar(20, 20, 20), Scalar(20, 20, 20));
    imshow("【效果图】", src);
    waitKey(0);
    return 0;
}
floodfill

--------------------------continue----------------------------------------

以上是关于数字形态学(OpenCV)的主要内容,如果未能解决你的问题,请参考以下文章

opencv实现二值图像孔洞填充

OpenCV实战(11)——形态学变换详解

python+opencv图像形态学处理详细解释(膨胀腐蚀开闭运算礼帽和黑猫)

opencv学习之路(14)形态学之膨胀腐蚀

OpenCV学习笔记——形态学梯度操作

opencv学习-形态学操作应用-提取水平与垂直线