zoukankan      html  css  js  c++  java
  • opencv---(腐蚀、膨胀、边缘检测、轮廓检索、凸包、多边形拟合)

    一、腐蚀(Erode)

      取符合模板的点, 用区域最小值代替中心位置值(锚点)

      作用: 平滑对象边缘、弱化对象之间的连接。

    opencv 中相关函数:(erode)

     1 //      C++
     2 /**
     3 shape:  形状 
     4                   MORPH_RECT  矩形
     5                   MORPH_CROSS   交叉形  十字型
     6                   MORPH_ELLIPSE   椭圆形
     7 esize : 大小
     8 anchor: 锚点,默认为中心
     9 **/
    10 Mat getStructuringElement(int shape, Size esize, Point anchor = Point(-1, -1));
    11 
    12 /**
    13 src:  input Mat
    14 dst:  output Mat 
    15 element : kernel element
    16 完整参数:https://docs.opencv.org/4.1.0/d4/d86/group__imgproc__filter.html#gaeb1e0c1033e3f6b891a25d0511362aeb
    17 **/
    18 erode(const Mat& src, Mat&dst , const Mat& element)  // 基本参数
     1 # python
     2 #    dst    =    cv.erode(    src, kernel[, dst[, anchor[, iterations[, borderType[, borderValue]]]]]    )
     3 
     4 import cv2 as cv
     5 import numpy as np
     6 
     7 im = cv.imread("test.jpg")
     8 gray = cv.cvtColor(im,cv.COLOR_BGR2GRAY)
     9 ret,binary = cv.threshold(gray,0,255,cv.THRESH_BINARY_INV|cv.THRESH_OTSU)
    10 
    11 # 获取 kerenl element
    12 kernel = cv.getStructuringElement(cv.MORPH_RECT,(5,5))
    13 # 腐蚀
    14 dst = cv.erode(binary,kernel)
    View Code

    二、 膨胀(Dilate)

      实现: 使用kernel 划过图像,将区域的最大值赋给锚点位置。

      作用: 致使图像的亮区扩展,能起到平滑边缘的作用。

    // C++
    /**
    src:  input Mat
    dst:  output Mat 
    kernel : kernel element
    完整参数:https://docs.opencv.org/master/d4/d86/group__imgproc__filter.html#ga4ff0f3318642c4f469d0e11f242f3b6c
     **/
    #include<opencv2imgprocimgproc.hpp>
    void dilate(InputArray src, OutputArray dst , InputArray kernel) // 基本参数

    三、边缘检测

    边缘检测一般步骤:

      平滑去噪

              对比度增强

              计算梯度

              过滤判断边缘

    1、Canny 边缘检测

     1 // C++
     2 #include<opencv2imgprocimgproc.hpp>
     3 
     4 /**
     5 image  : 输入图像
     6 edges  :  输出图像
     7 threshold1: 阈值1,高于该值 被认为时边缘
     8 threshold2: 阈值2, 低于该值可认为不是边缘
     9                                 若在两值之间,该像素仅连接一个高阈值的像素时被保留。
    10 apertureSize : kernel 大小,默认3  sobel kernel ,;取值 1 3 5 7 (奇数,<31)
    11 L2gradient : L2 norm 求梯度
    12 
    13 详细参数: https://docs.opencv.org/3.4/dd/d1a/group__imgproc__feature.html#ga04723e007ed888ddf11d9ba04e2232de
    14 **/
    15 void  Canny (InputArray  image,  OutputArray   edges,  double threshold1,  double threshold2,  int apertureSize = 3,  bool  L2gradient = false  )
    1 import numpy as np
    2 import cv2 as cv
    3 
    4 # edges    =    cv.Canny(    image, threshold1, threshold2[, edges[, apertureSize[, L2gradient]]]    )
    5 
    6 img = cv2.imread('3.jpg',0)
    7 edges = cv2.Canny(img,100,200)
    View Code

     2、 sobel

    sobel kernel:

    X 方向3X3:                                                                                                       Y方向3x3:

                                                 

    X 方向5x5:

    在opencv sobel 函数中当ksize =-1 时:kernel 为:SCHARR

    opencv 中函数:
     1 // C++
     2 #include <opencv2/imgproc.hpp>
     3 
     4 /** https://docs.opencv.org/master/d4/d86/group__imgproc__filter.html#gacea54f142e81b6758cb6f375ce782c8d
     5     src:   输入图像
     6     dst:   输出图像
     7     ddepth: output image depth
     8                           src.depth() = CV_8U     ---------------    ddepth =-1/CV_16S/CV_32F/CV_64F
     9                           src.depth() = CV_16U/CV_16S -----    ddepth =-1/CV_32F/CV_64F
    10                           src.depth() = CV_64F    ---------------    ddepth = -1/CV_64F
    11      dx  / dy  :  差分阶数 0  or 1
    12      ksize:   取奇数  -1 : SCHARR (3x3)   1: 1x3  or 3x1
    13 **/
    14 void cv::Sobel( InputArray src, OutputArray  dst, int ddepth, int dx, int dy,int ksize=3, double scale=1, double delta=0, int borderType = BORDER_DEFAULT )
    
    1 import cv2 as cv
    2 import numpy as np
    3 
    4 # dst = cv.Sobel(  src, ddepth, dx, dy[, dst[, ksize[, scale[, delta[, borderType]]]]]  )
    5 
    6 img = cv.imread('flower.jpg',0)
    7 #默认ksize=3
    8 sobelx = cv.Sobel(img,cv2.CV_64F,1,0,ksize=3)

    四、二值图像的轮廓分析

    opencv  中可以使用 findContours()工具,分析二值图像的拓扑结构

    void findContours//提取轮廓,用于提取图像的轮廓
    (
        InputOutputArray image,//输入图像,必须是8位单通道图像,并且应该转化成二值的
        OutputArrayOfArrays contours,//检测到的轮廓,每个轮廓被表示成一个point向量
        OutputArray hierarchy,//可选的输出向量,包含轮廓的拓扑信息。其中元素的个数和检测到的轮廓的数量相等
        int mode,     //说明需要的轮廓类型和希望的返回值方式
        int method,//轮廓近似方法
        Point offset = Point()
    )

    参数说明:

          hierarchy:  每一个轮廓,都包含4个整型数据,分别表示:后一个轮廓的序号前一个轮廓的序号子轮廓的序号父轮廓的序号

          mode: 轮廓检索模式    

              method :

          1)、CV_CHAIN_APPROX_NONE  边界上所有连续点

                                  2)、CV_CHAIN_APPROX_SIMPLE   拐点

          3)and 4) 、 CV_CHAIN_APPROX_TC89_L1  、  CV_CHAIN_APPROX_TC89_KCOS  使用teh-Chinl chain 近似法

    # python
    import cv2 as cv
    import numpy as np
    
    #     contours, hierarchy    =    cv.findContours(    image, mode, method[, contours[, hierarchy[, offset]]]    )
    
    
     
    img = cv.imread('12.jpeg')
    gray = cv.cvtColor ( img , cv2.COLOR_BGR2GRAY )
    ret , binary = cv.threshold ( gray , 220 , 255 , cv2.THRESH_BINARY )
    
    # 检测轮廓
    contours , hierarchy = cv.findContours ( binary , cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE )
    
    # 画出轮廓
    cv.drawContours(img,contours,-1,(0,0,255),3) 
    
    '''
    void cv::drawContours   (   InputOutputArray    image,
                                InputArrayOfArrays  contours,
                                int     contourIdx,
                                const Scalar &  color,
                                int     thickness = 1,
                                int     lineType = LINE_8,
                                InputArray  hierarchy = noArray(),
                                int     maxLevel = INT_MAX,
                                Point   offset = Point() 
                            )
    #image:输入输出图像,Mat类型即可 
    #contours:使用findContours检测到的轮廓数据,每个轮廓以点向量的形式存储,point类型的vector 
    #contourIdx:绘制轮廓的只是变量,如果为负值则绘制所有输入轮廓 
    #color:轮廓颜色 
    #thickness:绘制轮廓所用线条粗细度,如果值为负值,则在轮廓内部绘制 
    #lineTpye:线条类型,有默认值LINE_8
    '''

    五、 凸包 和 多边形拟合

    凸包:

    opencv 中使用 convexHull() 函数来查找对象的凸包。

    void cv::convexHull (   InputArray  points,
                            OutputArray     hull,
                            bool    clockwise = false,
                            bool    returnPoints = true
    )

    参数: points: input 2D point set, stored in std::vector or Mat.

           hull : 输出参数,用于输出函数调用后找到的凸包

           clockwise : 操作方向,true顺时针,fasle逆时针

    详细参考: https://docs.opencv.org/master/d3/dc0/group__imgproc__shape.html#ga014b28e56cb8854c0de4a211cb2be656

    多边形拟合:

    opencv 中使用 approxPolyDP() 函数对图像的轮廓点进行多边形拟合。

    void approxPolyDP(InputArray curve, OutputArray approxCurve, double epsilon, bool closed)

    参数:

        curve : Input vector of a 2D point stored in std::vector or Mat

            approxCurve : 表示输出的多边形点集

        epsilon:    精度,两个轮廓点之间的最大距离数

            closed:  表示输出的多边形是否封闭

    #include<opencv2opencv.hpp>
    #include<opencv2imgprocimgproc.hpp>
    #include<iostream>
    
    using namespace std;
    using namespace cv;
    
    
    int  main()
    {
        //  三通道二值图像 
        Mat img = imread("E:\pcblabels\labels2019-11-01-094405.jpg");
        cout << "read image end..." << endl;
    
        // 膨胀
        Mat kernel = getStructuringElement(MORPH_RECT, Size(6, 6));
        Mat dilateImg;
        dilate(img, dilateImg, kernel);
        cout << "dilate end....." << endl;
    
        // 腐蚀
        Mat erodeImg;
        erode(dilateImg, erodeImg, kernel);
        cout << "erode end....." << endl;
    
        // canny
        Mat cannyImg;
        Canny(dilateImg, cannyImg, 5, 2, 5); // ksize: 奇数
        cout << "Canny end....." << endl;
    
        // find contours
        vector<vector<Point>> contours;
        vector<Vec4i> hierarchy;
        // 只检测最外层轮廓,并且保存轮廓上所有点
        findContours(cannyImg, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE, Point());
        drawContours(contours, hierarchy, img.size());
    
        // 找一个点数最多的轮廓
       int index = 0;
        for (int i = 0; i< contours.size(); i++)
        {
            if (contours[i].size() > contours[index].size())
            {
            index = i;
        }
        }
        cout << "findContours end....." << endl;
    
        
         //凸包
        Mat hullImg = img.clone();
        vector<Point> hull;
        convexHull(Mat(contours[index]), hull, true);
        drawContours(hullImg, vector<vector<Point>>{hull}, 0, Scalar(0,0,255), 1, 8, vector<Vec4i>(), 0, Point());
        cout << "draw hull end....." << endl;   
    
        // 多边形拟合
        Mat approxImg = img.clone();
        Mat approxImgRes = Mat::zeros(img.size(), CV_8UC1);
        vector<Point> approxPloy;
        approxPolyDP(contours[index], approxPloy, 1, true);
        drawContours(approxImg, contours, index, Scalar(255, 0, 0), 1, 8, hierarchy);
        drawContours(approxImgRes, vector<vector<Point>>{approxPloy}, 0, Scalar(255), 2, 8, vector<Vec4i>(), 0, Point());
        cout << "draw approxPolyDP end....." << endl;
    
        return 0;
    }
            

      

        

      

  • 相关阅读:
    php多进程和多线程的比较
    设计模式学习系列——建造者模式
    设计模式学习系列——单例模式
    设计模式学习系列——前言
    设计模式学习系列——工厂模式
    记一次给nginx的web服务器目录加软链接
    某公司后端开发工程师面试题学习
    2010年腾讯前端面试题学习(jquery,html,css部分)
    2010年腾讯前端面试题学习(js部分)
    winfrom 隐藏任务栏(win7)
  • 原文地址:https://www.cnblogs.com/feihu-h/p/11814150.html
Copyright © 2011-2022 走看看