opencv---(腐蝕、膨脹、邊緣檢測、輪廓檢索、凸包、多邊形擬合)

1、腐蝕(Erode)

  取符合模板的點, 用區域最小值代替中心位置值(錨點)html

  做用: 平滑對象邊緣、弱化對象之間的鏈接。python

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

2、 膨脹(Dilate)

  實現: 使用kernel 劃過圖像,將區域的最大值賦給錨點位置。ios

  做用: 導致圖像的亮區擴展,能起到平滑邊緣的做用。app

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

3、邊緣檢測

邊緣檢測通常步驟:ide

  平滑去噪函數

          對比度加強工具

          計算梯度spa

          過濾判斷邊緣code

一、Canny 邊緣檢測

 1 // C++
 2 #include<opencv2\imgproc\imgproc.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

 二、 sobel

sobel kernel:

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

                                             

 

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)

4、二值圖像的輪廓分析

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
'''

5、 凸包 和 多邊形擬合

凸包:

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<opencv2\opencv.hpp>
#include<opencv2\imgproc\imgproc.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;
}
        
相關文章
相關標籤/搜索