zoukankan      html  css  js  c++  java
  • 数字形态学(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

    图像金字塔

    #include <opencv2/opencv.hpp>
    #include <opencv2/highgui/highgui.hpp>
    #include <opencv2/imgproc/imgproc.hpp>
    using namespace std;
    using namespace cv;
    
    #define WINDOW_NAME "【程序窗口】"        //为窗口标题定义的宏
    
    static void ShowHelpText();
    Mat g_srcImage, g_dstImage, g_tmpImage;
    
    int main()
    {
        g_srcImage = imread("1.jpg");//工程目录下需要有一张名为1.jpg的测试图像,且其尺寸需被2的N次方整除,N为可以缩放的次数
        if (!g_srcImage.data) { printf("Oh,no,读取srcImage错误~! 
    "); return false; }
    
        namedWindow(WINDOW_NAME, WINDOW_AUTOSIZE);
        imshow(WINDOW_NAME, g_srcImage);
    
        g_tmpImage = g_srcImage;
        g_dstImage = g_tmpImage;
    
        int key = 0;
    
        ShowHelpText();
    
        while (1)
        {
            key = waitKey();//读取键值到key变量中
    
            //根据key变量的值,进行不同的操作
            switch (key)
            {
                //======================【程序退出相关键值处理】=======================  
            case 27://按键ESC
                return 0;
                break;
    
            case 'q'://按键Q
                return 0;
                break;
    
                //======================【图片放大相关键值处理】=======================  
            case 'a'://按键A按下,调用pyrUp函数
                pyrUp(g_tmpImage, g_dstImage, Size(g_tmpImage.cols * 2, g_tmpImage.rows * 2));
                printf(">检测到按键【A】被按下,开始进行基于【pyrUp】函数的图片放大:图片尺寸×2 
    ");
                break;
    
            case 'w'://按键W按下,调用resize函数
                resize(g_tmpImage, g_dstImage, Size(g_tmpImage.cols * 2, g_tmpImage.rows * 2));
                printf(">检测到按键【W】被按下,开始进行基于【resize】函数的图片放大:图片尺寸×2 
    ");
                break;
    
            case '1'://按键1按下,调用resize函数
                resize(g_tmpImage, g_dstImage, Size(g_tmpImage.cols * 2, g_tmpImage.rows * 2));
                printf(">检测到按键【1】被按下,开始进行基于【resize】函数的图片放大:图片尺寸×2 
    ");
                break;
    
            case '3': //按键3按下,调用pyrUp函数
                pyrUp(g_tmpImage, g_dstImage, Size(g_tmpImage.cols * 2, g_tmpImage.rows * 2));
                printf(">检测到按键【3】被按下,开始进行基于【pyrUp】函数的图片放大:图片尺寸×2 
    ");
                break;
                //======================【图片缩小相关键值处理】=======================  
            case 'd': //按键D按下,调用pyrDown函数
                pyrDown(g_tmpImage, g_dstImage, Size(g_tmpImage.cols / 2, g_tmpImage.rows / 2));
                printf(">检测到按键【D】被按下,开始进行基于【pyrDown】函数的图片缩小:图片尺寸/2
    ");
                break;
    
            case  's': //按键S按下,调用resize函数
                resize(g_tmpImage, g_dstImage, Size(g_tmpImage.cols / 2, g_tmpImage.rows / 2));
                printf(">检测到按键【S】被按下,开始进行基于【resize】函数的图片缩小:图片尺寸/2
    ");
                break;
    
            case '2'://按键2按下,调用resize函数
                resize(g_tmpImage, g_dstImage, Size(g_tmpImage.cols / 2, g_tmpImage.rows / 2));
                printf(">检测到按键【2】被按下,开始进行基于【resize】函数的图片缩小:图片尺寸/2
    ");
                break;
    
            case '4': //按键4按下,调用pyrDown函数
                pyrDown(g_tmpImage, g_dstImage, Size(g_tmpImage.cols / 2, g_tmpImage.rows / 2));
                printf(">检测到按键【4】被按下,开始进行基于【pyrDown】函数的图片缩小:图片尺寸/2
    ");
                break;
            }
    
            imshow(WINDOW_NAME, g_dstImage);
            g_tmpImage = g_dstImage;
        }
    
        return 0;
    }
    
    static void ShowHelpText()
    {
        //输出一些帮助信息
        printf("
    
    
    	欢迎来到OpenCV图像金字塔和resize示例程序~
    
    ");
        printf("
    
    	按键操作说明: 
    
    "
            "		键盘按键【ESC】或者【Q】- 退出程序
    "
            "		键盘按键【1】或者【W】- 进行基于【resize】函数的图片放大
    "
            "		键盘按键【2】或者【S】- 进行基于【resize】函数的图片缩小
    "
            "		键盘按键【3】或者【A】- 进行基于【pyrUp】函数的图片放大
    "
            "		键盘按键【4】或者【D】- 进行基于【pyrDown】函数的图片缩小
    "
        );
    }
    resize

     基本阈值操作

    #include "opencv2/imgproc/imgproc.hpp"
    #include "opencv2/highgui/highgui.hpp"
    #include <iostream>
    using namespace cv;
    using namespace std;
    
    #define WINDOW_NAME "【程序窗口】"        //为窗口标题定义的宏 
    
    int g_nThresholdValue = 100;
    int g_nThresholdType = 3;
    Mat g_srcImage, g_grayImage, g_dstImage;
    
    static void ShowHelpText();//输出帮助文字
    void on_Threshold(int, void*);//回调函数
    
    int main()
    {
        ShowHelpText();
    
        g_srcImage = imread("1.jpg");
        if (!g_srcImage.data) { printf("读取图片错误,请确定目录下是否有imread函数指定的图片存在~! 
    "); return false; }
        imshow("原始图", g_srcImage);
    
        cvtColor(g_srcImage, g_grayImage, COLOR_RGB2GRAY);
    
        namedWindow(WINDOW_NAME, WINDOW_AUTOSIZE);
    
        createTrackbar("模式",
            WINDOW_NAME, &g_nThresholdType,
            4, on_Threshold);
    
        createTrackbar("参数值",
            WINDOW_NAME, &g_nThresholdValue,
            255, on_Threshold);
    
        on_Threshold(0, 0);
    
        while (1)
        {
            int key;
            key = waitKey(20);
            if ((char)key == 27) { break; }
        }
    
    }
    
    void on_Threshold(int, void*)
    {
        //调用阈值函数
        threshold(g_grayImage, g_dstImage, g_nThresholdValue, 255, g_nThresholdType);
    
        //更新效果图
        imshow(WINDOW_NAME, g_dstImage);
    }
    
    static void ShowHelpText()
    {
        //输出欢迎信息和OpenCV版本
        printf("
    
    			   当前使用的OpenCV版本为:" CV_VERSION);
        printf("
    
      ----------------------------------------------------------------------------
    ");
    
        //输出一些帮助信息  
        printf("
    	欢迎来到【基本阈值操作】示例程序~
    
    ");
        printf("
    	按键操作说明: 
    
    "
            "		键盘按键【ESC】- 退出程序
    "
            "		滚动条模式0- 二进制阈值
    "
            "		滚动条模式1- 反二进制阈值
    "
            "		滚动条模式2- 截断阈值
    "
            "		滚动条模式3- 反阈值化为0
    "
            "		滚动条模式4- 阈值化为0
    ");
    }
    threshold

     轮廓

    #include "opencv2/highgui/highgui.hpp"
    #include "opencv2/imgproc/imgproc.hpp"
    #include <iostream>
    using namespace cv;
    using namespace std;
    
    #define WINDOW_NAME1 "【原始图窗口】"                    //为窗口标题定义的宏 
    #define WINDOW_NAME2 "【效果图窗口】"                    //为窗口标题定义的宏 
    
    Mat g_srcImage; Mat g_grayImage;
    int g_nThresh = 50;
    int g_maxThresh = 255;
    RNG g_rng(12345);
    Mat srcImage_copy = g_srcImage.clone();
    Mat g_thresholdImage_output;
    vector<vector<Point> > g_vContours;
    vector<Vec4i> g_vHierarchy;
    
    static void ShowHelpText();
    void on_ThreshChange(int, void*);
    void ShowHelpText();
    
    int main()
    {
        ShowHelpText();
    
        g_srcImage = imread("1.jpg", 1);
    
        cvtColor(g_srcImage, g_grayImage, COLOR_BGR2GRAY);
        blur(g_grayImage, g_grayImage, Size(3, 3));
    
        namedWindow(WINDOW_NAME1, WINDOW_AUTOSIZE);
        imshow(WINDOW_NAME1, g_srcImage);
    
        createTrackbar(" 阈值:", WINDOW_NAME1, &g_nThresh, g_maxThresh, on_ThreshChange);
        on_ThreshChange(0, 0);//调用一次进行初始化
    
        waitKey(0);
        return(0);
    }
    
    void on_ThreshChange(int, void*)
    {
        // 对图像进行二值化,控制阈值
        threshold(g_grayImage, g_thresholdImage_output, g_nThresh, 255, THRESH_BINARY);
    
        // 寻找轮廓
        findContours(g_thresholdImage_output, g_vContours, g_vHierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0));
    
        // 遍历每个轮廓,寻找其凸包
        vector<vector<Point> >hull(g_vContours.size());
        for (unsigned int i = 0; i < g_vContours.size(); i++)
        {
            convexHull(Mat(g_vContours[i]), hull[i], false);
        }
    
        // 绘出轮廓及其凸包
        Mat drawing = Mat::zeros(g_thresholdImage_output.size(), CV_8UC3);
        for (unsigned int i = 0; i < g_vContours.size(); i++)
        {
            Scalar color = Scalar(g_rng.uniform(0, 255), g_rng.uniform(0, 255), g_rng.uniform(0, 255));
            drawContours(drawing, g_vContours, i, color, 1, 8, vector<Vec4i>(), 0, Point());
            drawContours(drawing, hull, i, color, 1, 8, vector<Vec4i>(), 0, Point());
        }
    
        imshow(WINDOW_NAME2, drawing);
    }
    
    void ShowHelpText()
    {
        printf("当前使用的OpenCV版本为:" CV_VERSION);
    }
    convexhull

     绘制包围轮廓的矩形和圆

    #include "opencv2/highgui/highgui.hpp"
    #include "opencv2/imgproc/imgproc.hpp"
    using namespace cv;
    using namespace std;
    
    #define WINDOW_NAME1 "【原始图窗口】"        //为窗口标题定义的宏 
    #define WINDOW_NAME2 "【效果图窗口】"        //为窗口标题定义的宏 
    
    Mat g_srcImage;
    Mat g_grayImage;
    int g_nThresh = 50;//阈值
    int g_nMaxThresh = 255;//阈值最大值
    RNG g_rng(12345);//随机数生成器
    
    void on_ContoursChange(int, void*);
    static void ShowHelpText();
    
    int main()
    {
        ShowHelpText();
    
        //【1】载入3通道的原图像
        g_srcImage = imread("1.jpg", 1);
        if (!g_srcImage.data) { printf("读取图片错误,请确定目录下是否有imread函数指定的图片存在~! 
    "); return false; }
    
        //【2】得到原图的灰度图像并进行平滑
        cvtColor(g_srcImage, g_grayImage, COLOR_BGR2GRAY);
        blur(g_grayImage, g_grayImage, Size(3, 3));
    
        //【3】创建原始图窗口并显示
        namedWindow(WINDOW_NAME1, WINDOW_AUTOSIZE);
        imshow(WINDOW_NAME1, g_srcImage);
    
        //【4】设置滚动条并调用一次回调函数
        createTrackbar(" 阈值:", WINDOW_NAME1, &g_nThresh, g_nMaxThresh, on_ContoursChange);
        on_ContoursChange(0, 0);
    
        waitKey(0);
    
        return(0);
    }
    
    void on_ContoursChange(int, void*)
    {
        //定义一些参数
        Mat threshold_output;
        vector<vector<Point>> contours;
        vector<Vec4i> hierarchy;
    
        // 使用Threshold检测边缘
        threshold(g_grayImage, threshold_output, g_nThresh, 255, THRESH_BINARY);
    
        // 找出轮廓
        findContours(threshold_output, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0));
    
        // 多边形逼近轮廓 + 获取矩形和圆形边界框
        vector<vector<Point> > contours_poly(contours.size());
        vector<Rect> boundRect(contours.size());
        vector<Point2f>center(contours.size());
        vector<float>radius(contours.size());
    
        //一个循环,遍历所有部分,进行本程序最核心的操作
        for (unsigned int i = 0; i < contours.size(); i++)
        {
            approxPolyDP(Mat(contours[i]), contours_poly[i], 3, true);//用指定精度逼近多边形曲线 
            boundRect[i] = boundingRect(Mat(contours_poly[i]));//计算点集的最外面(up-right)矩形边界
            minEnclosingCircle(contours_poly[i], center[i], radius[i]);//对给定的 2D点集,寻找最小面积的包围圆形 
        }
    
        // 绘制多边形轮廓 + 包围的矩形框 + 圆形框
        Mat drawing = Mat::zeros(threshold_output.size(), CV_8UC3);
        for (int unsigned i = 0; i < contours.size(); i++)
        {
            Scalar color = Scalar(g_rng.uniform(0, 255), g_rng.uniform(0, 255), g_rng.uniform(0, 255));//随机设置颜色
            drawContours(drawing, contours_poly, i, color, 1, 8, vector<Vec4i>(), 0, Point());//绘制轮廓
            rectangle(drawing, boundRect[i].tl(), boundRect[i].br(), color, 2, 8, 0);//绘制矩形
            circle(drawing, center[i], (int)radius[i], color, 2, 8, 0);//绘制圆
        }
    
        // 显示效果图窗口
        namedWindow(WINDOW_NAME2, WINDOW_AUTOSIZE);
        imshow(WINDOW_NAME2, drawing);
    }
    
    static void ShowHelpText()
    {
        printf("当前使用的OpenCV版本为:" CV_VERSION);
        printf("欢迎来到【创建包围轮廓的矩形和圆形边界框】示例程序
    ");
        printf("按键操作说明: 
    "
            "键盘按键【ESC】- 退出程序
    "
            "滑动滚动条 - 改变阈值
    ");
    }

     轮廓面积与中心距

    #include "opencv2/highgui/highgui.hpp"
    #include "opencv2/imgproc/imgproc.hpp"
    #include <iostream>
    using namespace cv;
    using namespace std;
    
    #define WINDOW_NAME1 "【原始图】"                    //为窗口标题定义的宏 
    #define WINDOW_NAME2 "【图像轮廓】"        //为窗口标题定义的宏 
    
    Mat g_srcImage; Mat g_grayImage;
    int g_nThresh = 100;
    int g_nMaxThresh = 255;
    RNG g_rng(12345);
    Mat g_cannyMat_output;
    vector<vector<Point> > g_vContours;
    vector<Vec4i> g_vHierarchy;
    
    void on_ThreshChange(int, void*);
    static void ShowHelpText();
    
    int main(int argc, char** argv)
    {
        
        ShowHelpText();
        // 读入原图像, 返回3通道图像数据
        g_srcImage = imread("1.jpg", 1);
    
        // 把原图像转化成灰度图像并进行平滑
        cvtColor(g_srcImage, g_grayImage, COLOR_BGR2GRAY);
        blur(g_grayImage, g_grayImage, Size(3, 3));
    
        // 创建新窗口
        namedWindow(WINDOW_NAME1, WINDOW_AUTOSIZE);
        imshow(WINDOW_NAME1, g_srcImage);
    
        //创建滚动条并进行初始化
        createTrackbar(" 阈值", WINDOW_NAME1, &g_nThresh, g_nMaxThresh, on_ThreshChange);
        on_ThreshChange(0, 0);
    
        waitKey(0);
        return(0);
    }
    
    void on_ThreshChange(int, void*)
    {
        // 使用Canndy检测边缘
        Canny(g_grayImage, g_cannyMat_output, g_nThresh, g_nThresh * 2, 3);
    
        // 找到轮廓
        findContours(g_cannyMat_output, g_vContours, g_vHierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0));
    
        // 计算矩
        vector<Moments> mu(g_vContours.size());
        for (unsigned int i = 0; i < g_vContours.size(); i++)
        {
            mu[i] = moments(g_vContours[i], false);
        }
    
        //  计算中心矩
        vector<Point2f> mc(g_vContours.size());
        for (unsigned int i = 0; i < g_vContours.size(); i++)
        {
            mc[i] = Point2f(static_cast<float>(mu[i].m10 / mu[i].m00), static_cast<float>(mu[i].m01 / mu[i].m00));
        }
    
        // 绘制轮廓
        Mat drawing = Mat::zeros(g_cannyMat_output.size(), CV_8UC3);
        for (unsigned int i = 0; i < g_vContours.size(); i++)
        {
            Scalar color = Scalar(g_rng.uniform(0, 255), g_rng.uniform(0, 255), g_rng.uniform(0, 255));//随机生成颜色值
            drawContours(drawing, g_vContours, i, color, 2, 8, g_vHierarchy, 0, Point());//绘制外层和内层轮廓
            circle(drawing, mc[i], 4, color, -1, 8, 0);;//绘制圆
        }
    
        // 显示到窗口中
        namedWindow(WINDOW_NAME2, WINDOW_AUTOSIZE);
        imshow(WINDOW_NAME2, drawing);
    
        // 通过m00计算轮廓面积并且和OpenCV函数比较
        printf("	 输出内容: 面积和轮廓长度
    ");
        for (unsigned int i = 0; i < g_vContours.size(); i++)
        {
            printf(" >通过m00计算出轮廓[%d]的面积: (M_00) = %.2f 
     OpenCV函数计算出的面积=%.2f , 长度: %.2f 
    
    ", i, mu[i].m00, contourArea(g_vContours[i]), arcLength(g_vContours[i], true));
            Scalar color = Scalar(g_rng.uniform(0, 255), g_rng.uniform(0, 255), g_rng.uniform(0, 255));
            drawContours(drawing, g_vContours, i, color, 2, 8, g_vHierarchy, 0, Point());
            circle(drawing, mc[i], 4, color, -1, 8, 0);
        }
    }
    
    void ShowHelpText()
    {
        printf("当前使用的OpenCV版本为:" CV_VERSION);
    }
    contourmoment

     分水岭算法

    #include <opencv2/core/utility.hpp>
    #include "opencv2/imgproc.hpp"
    #include "opencv2/imgcodecs.hpp"
    #include "opencv2/highgui.hpp"
    #include <cstdio>
    #include <iostream>
    using namespace cv;
    using namespace std;
    static void help(char** argv)
    {
        cout << "
    This program demonstrates the famous watershed segmentation algorithm in OpenCV: watershed()
    "
            "Usage:
    " << argv[0] << " [image_name -- default is 1.jpg]
    " << endl;
        cout << "Hot keys: 
    "
            "	ESC - quit the program
    "
            "	r - restore the original image
    "
            "	w or SPACE - run watershed segmentation algorithm
    "
            "		(before running it, *roughly* mark the areas to segment on the image)
    "
            "	  (before that, roughly outline several markers on the image)
    ";
    }
    Mat markerMask, img;
    Point prevPt(-1, -1);
    static void onMouse(int event, int x, int y, int flags, void*)
    {
        if (x < 0 || x >= img.cols || y < 0 || y >= img.rows)
            return;
        if (event == EVENT_LBUTTONUP || !(flags & EVENT_FLAG_LBUTTON))
            prevPt = Point(-1, -1);
        else if (event == EVENT_LBUTTONDOWN)
            prevPt = Point(x, y);
        else if (event == EVENT_MOUSEMOVE && (flags & EVENT_FLAG_LBUTTON))
        {
            Point pt(x, y);
            if (prevPt.x < 0)
                prevPt = pt;
            line(markerMask, prevPt, pt, Scalar::all(255), 5, 8, 0);
            line(img, prevPt, pt, Scalar::all(255), 5, 8, 0);
            prevPt = pt;
            imshow("image", img);
        }
    }
    int main(int argc, char** argv)
    {
        cv::CommandLineParser parser(argc, argv, "{help h | | }{ @input | 1.jpg | }");
        if (parser.has("help"))
        {
            help(argv);
            return 0;
        }
        string filename = samples::findFile(parser.get<string>("@input"));
        Mat img0 = imread(filename, 1), imgGray;
        if (img0.empty())
        {
            cout << "Couldn't open image ";
            help(argv);
            return 0;
        }
        help(argv);
        namedWindow("image", 1);
        img0.copyTo(img);
        cvtColor(img, markerMask, COLOR_BGR2GRAY);
        cvtColor(markerMask, imgGray, COLOR_GRAY2BGR);
        markerMask = Scalar::all(0);
        imshow("image", img);
        setMouseCallback("image", onMouse, 0);
        for (;;)
        {
            char c = 'w';
            c = (char)waitKey(0);
            if (c == 27)
                break;
            if (c == 'r')
            {
                markerMask = Scalar::all(0);
                img0.copyTo(img);
                imshow("image", img);
            }
            if (c == 'w' || c == ' ')
            {
                int i, j, compCount = 0;
                vector<vector<Point> > contours;
                vector<Vec4i> hierarchy;
                findContours(markerMask, contours, hierarchy, RETR_CCOMP, CHAIN_APPROX_SIMPLE);
                if (contours.empty())
                    continue;
                Mat markers(markerMask.size(), CV_32S);
                markers = Scalar::all(0);
                int idx = 0;
                for (; idx >= 0; idx = hierarchy[idx][0], compCount++)
                    drawContours(markers, contours, idx, Scalar::all(compCount + 1), -1, 8, hierarchy, INT_MAX);
                if (compCount == 0)
                    continue;
                vector<Vec3b> colorTab;
                for (i = 0; i < compCount; i++)
                {
                    int b = theRNG().uniform(0, 255);
                    int g = theRNG().uniform(0, 255);
                    int r = theRNG().uniform(0, 255);
                    colorTab.push_back(Vec3b((uchar)b, (uchar)g, (uchar)r));
                }
                double t = (double)getTickCount();
                watershed(img0, markers);
                t = (double)getTickCount() - t;
                printf("execution time = %gms
    ", t * 1000. / getTickFrequency());
                Mat wshed(markers.size(), CV_8UC3);
                // paint the watershed image
                for (i = 0; i < markers.rows; i++)
                    for (j = 0; j < markers.cols; j++)
                    {
                        int index = markers.at<int>(i, j);
                        if (index == -1)
                            wshed.at<Vec3b>(i, j) = Vec3b(255, 255, 255);
                        else if (index <= 0 || index > compCount)
                            wshed.at<Vec3b>(i, j) = Vec3b(0, 0, 0);
                        else
                            wshed.at<Vec3b>(i, j) = colorTab[index - 1];
                    }
                wshed = wshed * 0.5 + imgGray * 0.5;
                imshow("watershed transform", wshed);
            }
        }
        return 0;
    }
    watershed

     修补图像

    #include "opencv2/highgui/highgui.hpp"
    #include "opencv2/imgproc/imgproc.hpp"
    #include "opencv2/photo/photo.hpp"
    #include <iostream>
    using namespace cv;
    using namespace std;
    
    #define WINDOW_NAME0 "【原始图参考】"        //为窗口标题定义的宏 
    #define WINDOW_NAME1 "【原始图】"        //为窗口标题定义的宏 
    #define WINDOW_NAME2 "【修补后的效果图】"        //为窗口标题定义的宏 
    
    Mat srcImage0, srcImage1, inpaintMask;
    Point previousPoint(-1, -1);//原来的点坐标
    
    static void ShowHelpText()
    {
    
        printf("当前使用的OpenCV版本为:" CV_VERSION);
        printf("
    欢迎来到【图像修复】示例程序
    ");
        printf("请在进行图像修复操作之前,在【原始图】窗口中进行适量的绘制"
            "
    按键操作说明: 
    "
            "【鼠标左键】-在图像上绘制白色线条
    "
            "键盘按键【ESC】- 退出程序
    "
            "键盘按键【1】或【SPACE】-进行图像修复操作 
    ");
    }
    
    static void On_Mouse(int event, int x, int y, int flags, void*)
    {
        //鼠标左键弹起消息
        if (event == EVENT_LBUTTONUP || !(flags & EVENT_FLAG_LBUTTON))
            previousPoint = Point(-1, -1);
        //鼠标左键按下消息
        else if (event == EVENT_LBUTTONDOWN)
            previousPoint = Point(x, y);
        //鼠标按下并移动,进行绘制
        else if (event == EVENT_MOUSEMOVE && (flags & EVENT_FLAG_LBUTTON))
        {
            Point pt(x, y);
            if (previousPoint.x < 0)
                previousPoint = pt;
            //绘制白色线条
            line(inpaintMask, previousPoint, pt, Scalar::all(255), 5, 8, 0);
            line(srcImage1, previousPoint, pt, Scalar::all(255), 5, 8, 0);
            previousPoint = pt;
            imshow(WINDOW_NAME1, srcImage1);
        }
    }
    
    int main(int argc, char** argv)
    {
        //显示帮助文字
        ShowHelpText();
    
        //载入原始图并进行掩膜的初始化
        Mat srcImage = imread("1.jpg", -1);
        if (!srcImage.data) { printf("读取图片错误,请确定目录下是否有imread函数指定图片存在~! 
    "); return false; }
        srcImage0 = srcImage.clone();
        srcImage1 = srcImage.clone();
        inpaintMask = Mat::zeros(srcImage1.size(), CV_8U);
    
        //显示原始图参考
        imshow(WINDOW_NAME0, srcImage0);
        //显示原始图
        imshow(WINDOW_NAME1, srcImage1);
        //设置鼠标回调消息
        setMouseCallback(WINDOW_NAME1, On_Mouse, 0);
    
        //轮询按键,根据不同的按键进行处理
        while (1)
        {
            //获取按键键值
            char c = (char)waitKey();
    
            //键值为ESC,程序退出
            if (c == 27)
                break;
    
            //键值为2,恢复成原始图像
            if (c == '2')
            {
                inpaintMask = Scalar::all(0);
                srcImage.copyTo(srcImage1);
                imshow(WINDOW_NAME1, srcImage1);
            }
    
            //键值为1或者空格,进行图像修补操作
            if (c == '1' || c == ' ')
            {
                Mat inpaintedImage;
                inpaint(srcImage1, inpaintMask, inpaintedImage, 3, INPAINT_TELEA);
                imshow(WINDOW_NAME2, inpaintedImage);
            }
        }
    
        return 0;
    }
    inpant

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

  • 相关阅读:
    装java开发环境 报client/jvm.dll找不到
    json expected name at 1 1
    svn右键菜单不显
    win10 随记
    eclipse配置打开选中文件存储的目录快捷配置
    mybatis 常见面试题
    java 求取昨天日期
    字符串反转记录总结
    @RequestMapping 无法加载
    expected at least 1 bean which qualifies as autowire candidate for this depe (spring无法注入)
  • 原文地址:https://www.cnblogs.com/jianle23/p/13892760.html
Copyright © 2011-2022 走看看