天天看點

OpenCV findContours函數參數

目錄

OpenCV findContours函數參數

python檢測外輪廓:

c++輪廓檢測:

一、mode取值“CV_RETR_EXTERNAL”,method取值“CV_CHAIN_APPROX_NONE”,即隻檢測最外層輪廓,并且儲存輪廓上所有點:

二、 mode取值“CV_RETR_LIST”,method取值“CV_CHAIN_APPROX_SIMPLE”,即檢測所有輪廓,但各輪廓之間彼此獨立,不建立等級關系,并且僅儲存輪廓上拐點資訊:

三、mode取值“CV_RETR_TREE”,method取值“CV_CHAIN_APPROX_NONE”,即檢測所有輪廓,輪廓間建立外層、内層的等級關系,并且儲存輪廓上所有點。

四、Point()偏移量設定

OpenCV findContours函數參數

輪廓面積:

cv2.contourArea()

1.輸入為二值圖像,黑色為背景,白色為目标

單通道圖像矩陣,可以是灰階圖,但更常用的是二值圖像,一般是經過Canny、拉普拉斯等邊

                     緣檢測算子處理過的二值圖像;

2.該函數會修改原圖像,是以若想保留原圖像在,則需拷貝一份,在拷貝圖裡修改。

mode參數

參數名稱 功能
cv2.RETR_EXTERNAL 隻檢測外輪廓
cv2.RETR_LIST 檢測的輪廓不建立等級關系,都是同級,不存在父輪廓或内嵌輪廓,
cv2.RETR_CCOMP 建立兩個等級的輪廓,上面一層為外邊界,裡面一層為内孔的邊界資訊
cv2.RETR_TREE 建立一個等級樹結構的輪廓

method參數

參數名稱 功能
cv2.RETR_EXTERNAL 隻檢測外輪廓
cv2.RETR_LIST 檢測的輪廓不建立等級關系,都是同級
cv2.RETR_CCOMP 建立兩個等級的輪廓,上面一層為外邊界,裡面一層為内孔的邊界資訊
cv2.RETR_TREE 建立一個等級樹結構的輪廓

offset:輪廓點的偏移量,格式為tuple,如(-10,10)表示輪廓點沿X負方向偏移10個像素點,沿Y正方向偏移10個像素點

傳回值

contours:輪廓點。清單格式,每一個元素為一個3維數組(其形狀為(n,1,2),其中n表示輪廓點個數,2表示像素點坐标),表示一個輪廓

hierarchy:輪廓間的層次關系,為三維數組,形狀為(1,n,4),其中n表示輪廓總個數,4指的是用4個數表示各輪廓間的互相關系。第一個數表示同級輪廓的下一個輪廓編号,第二個數表示同級輪廓的上一個輪廓的編号,第三個數表示該輪廓下一級輪廓的編号,第四個數表示該輪廓的上一級輪廓的編号。

# ## -*- coding: utf-8 -*-
import cv2
import imutils
import numpy as np

def RGB_GRAY(img):
    img = cv2.resize(img, (640, 480))
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    gray = cv2.bilateralFilter(gray, 13, 15, 15)
    return img, gray

def edge(img):
    #  cv2.Canny(source_image,thresholdValue 1,thresholdValue 2)
    edged = cv2.Canny(img, 30, 200)
    cv2.imshow('img', edged)
    cv2.waitKey(0)
    contours = cv2.findContours(edged.copy(), cv2.RETR_TREE,
                                cv2.CHAIN_APPROX_SIMPLE)
    contours = imutils.grab_contours(contours)
    contours = sorted(contours, key=cv2.contourArea, reverse=True)[:10]
    return contours


def solve(img):
    img, gray = RGB_GRAY(img)
    contours = edge(gray)


if __name__ == '__main__':
    img_path = './22222.jpg'
    img = cv2.imread(img_path)
    solve(img)
           

           取值三:CV_RETR_CCOMP  檢測所有的輪廓,但所有輪廓隻建立兩個等級關系,外圍為頂層,若外圍

                  内的内圍輪廓還包含了其他的輪廓資訊,則内圍内的所有輪廓均歸屬于頂層

           取值四:CV_RETR_TREE, 檢測所有輪廓,所有輪廓建立一個等級樹結構。外層輪廓包含内層輪廓,内

                   層輪廓還可以繼續包含内嵌輪廓。

第五個參數:int型的method,定義輪廓的近似方法:

           取值一:CV_CHAIN_APPROX_NONE 儲存物體邊界上所有連續的輪廓點到contours向量内

           取值二:CV_CHAIN_APPROX_SIMPLE 僅儲存輪廓的拐點資訊,把所有輪廓拐點處的點儲存入contours

                   向量内,拐點與拐點之間直線段上的資訊點不予保留

           取值三和四:CV_CHAIN_APPROX_TC89_L1,CV_CHAIN_APPROX_TC89_KCOS使用teh-Chinl chain 近

                   似算法

第六個參數:Point偏移量,所有的輪廓資訊相對于原始圖像對應點的偏移量,相當于在每一個檢測出的輪廓點上加

            上該偏移量,并且Point還可以是負值!

下邊用效果圖對比一下findContours函數中各參數取不同值時,向量contours和hierarchy的内容如何變化,有何

異同。

python檢測外輪廓:

這個可以檢測水準輪廓:

cnts, hierarchy = cv2.findContours(imgray.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
           

檢測不到水準輪廓:

cnts,hierarchy = cv2.findContours(edged.copy(), cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
           
import cv2
import numpy as np
# 讀入圖像
img = cv2.imread(r"D:\360MoveData\Users\KID\Desktop\1.jpg", cv2.IMREAD_UNCHANGED)

# 二值化
ret, thresh = cv2.threshold(
    cv2.cvtColor(img.copy(), cv2.COLOR_BGR2GRAY),  # 轉換為灰階圖像,
    130, 255,   # 大于130的改為255  否則改為0
    cv2.THRESH_BINARY)  # 黑白二值化

# 搜尋輪廓
contours, hierarchy = cv2.findContours(  thresh,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_NONE)

for c in contours:

    x, y, w, h = cv2.boundingRect(c)
    """
    傳入一個輪廓圖像,傳回 x y 是左上角的點, w和h是矩形邊框的寬度和高度
    """
    cv2.rectangle(img, (x, y), (x+w, y+h), (0, 255, 0), 2)
    """
    畫出矩形
        img 是要畫出輪廓的原圖
        (x, y) 是左上角點的坐标
        (x+w, y+h) 是右下角的坐标
        0,255,0)是畫線對應的rgb顔色
        2 是畫出線的寬度
    """

    # 獲得最小的矩形輪廓 可能帶旋轉角度
    rect = cv2.minAreaRect(c)
    # 計算最小區域的坐标
    box = cv2.boxPoints(rect)
    # 坐标規範化為整數
    box = np.int0(box)
    # 畫出輪廓
    cv2.drawContours(img, [box], 0, (0, 0, 255), 3)

    # 計算最小封閉圓形的中心和半徑
    (x, y), radius = cv2.minEnclosingCircle(c)
    # 轉換成整數
    center = (int(x), int(y))
    radius = int(radius)
    # 畫出圓形
    img = cv2.circle(img, center, radius, (0, 255, 0), 2)

# 畫出輪廓
cv2.drawContours(img, contours, -1, (255, 0, 0), 1)
cv2.imshow("contours", img)
cv2.waitKey()
cv2.destroyAllWindows()
           

c++輪廓檢測:

#include "core/core.hpp"

#include "highgui/highgui.hpp"

#include "imgproc/imgproc.hpp"

#include "iostream"


using namespace std;

using namespace cv;


int main(int argc,char *argv[])

{

Mat imageSource=imread(argv[1],0);

imshow("Source Image",imageSource);

Mat image;

GaussianBlur(imageSource,image,Size(3,3),0);

Canny(image,image,100,250);

vector<vector<Point>> contours;

vector<Vec4i> hierarchy;

findContours(image,contours,hierarchy,RETR_TREE,CHAIN_APPROX_SIMPLE,Point());

Mat imageContours=Mat::zeros(image.size(),CV_8UC1);

Mat Contours=Mat::zeros(image.size(),CV_8UC1); //繪制

for(int i=0;i<contours.size();i++)

{

//contours[i]代表的是第i個輪廓,contours[i].size()代表的是第i個輪廓上所有的像素點數

for(int j=0;j<contours[i].size();j++)

{

//繪制出contours向量内所有的像素點

Point P=Point(contours[i][j].x,contours[i][j].y);

Contours.at<uchar>(P)=255;

}


//輸出hierarchy向量内容

char ch[256];

sprintf(ch,"%d",i);

string str=ch;

cout<<"向量hierarchy的第" <<str<<" 個元素内容為:"<<endl<<hierarchy[i]<<endl<<endl;


//繪制輪廓

drawContours(imageContours,contours,i,Scalar(255),1,8,hierarchy);

}

imshow("Contours Image",imageContours); //輪廓

imshow("Point of Contours",Contours); //向量contours内儲存的所有輪廓點集

waitKey(0);

return 0;

}
           

程式中所用原始圖像如下:

OpenCV findContours函數參數

通過調整第四個參數mode——輪廓的檢索模式、第五個參數method——輪廓的近似方式和不同的偏移量Point(),就可以得到以下效果。

一、mode取值“CV_RETR_EXTERNAL”,method取值“CV_CHAIN_APPROX_NONE”,即隻檢測最外層輪廓,并且儲存輪廓上所有點:

輪廓:

OpenCV findContours函數參數

隻有最外層的輪廓被檢測到,内層的輪廓被忽略

contours向量内所有點集:

OpenCV findContours函數參數

儲存了所有輪廓上的所有點,圖像表現跟輪廓一緻

hierarchy向量:

OpenCV findContours函數參數

重溫一下hierarchy向量————向量中每個元素的4個整形分别對應目前輪廓的後一個輪廓、前一個輪廓、父輪廓、内

嵌輪廓的索引編号。

本次參數配置下,hierarchy向量内有3個元素,分别對應于3個輪廓。以第2個輪廓(對應向量内第1個元素)為例,

内容為[2,0,-1,-1], “2”表示目前輪廓的後一個輪廓的編号為2,“0”表示目前輪廓的前一個輪廓編号為0,其後2

個“-1”表示為空,因為隻有最外層輪廓這一個等級,是以不存在父輪廓和内嵌輪廓。

二、 mode取值“CV_RETR_LIST”,method取值“CV_CHAIN_APPROX_SIMPLE”,即檢測所有輪廓,但各輪廓之間彼此獨立,不建立等級關系,并且僅儲存輪廓上拐點資訊:

檢測到的輪廓跟上文“一”中是一緻的,不再顯示。

contours向量内所有點集:

OpenCV findContours函數參數

contours向量中所有的拐點資訊得到了保留,但是拐點與拐點之間直線段的部分省略掉了。

hierarchy向量(截取一部分):

OpenCV findContours函數參數

本次參數配置下,檢測出了較多輪廓。第1、第2個整形值分别指向上一個和下一個輪廓編号,由于本次配置mode取

值“RETR_LIST”,各輪廓間各自獨立,不建立等級關系,是以第3、第4個整形參數為空,設為值-1。

三、mode取值“CV_RETR_TREE”,method取值“CV_CHAIN_APPROX_NONE”,即檢測所有輪廓,輪廓間建立外層、内層的等級關系,并且儲存輪廓上所有點。

contours向量内所有點集:

OpenCV findContours函數參數

所有内外層輪廓都被檢測到,contours點集組成的圖形跟輪廓表現一緻。

hierarchy向量(截取一部分)

OpenCV findContours函數參數

本次參數配置要求檢測所有輪廓,每個輪廓都被劃分等級,最外圍、第一内圍、第二内圍等等,是以除第1個最後一

個輪廓外,其他輪廓都具有不為-1的第3、第4個整形參數,分别指向目前輪廓的父輪廓、内嵌輪廓索引編号。

四、Point()偏移量設定

使用三中的參數配置,設定偏移量Point為Point(45,30)。

此時輪廓圖像為:

OpenCV findContours函數參數

可以看到輪廓圖像整體向右下角有一個偏轉,偏轉量就是設定的(45,30)。

這個偏移量的設定不能過大或過小(負方向上的過小),若圖像上任一點加上該偏移量後超出圖像邊界,程式會記憶體

溢出報錯。

findContours函數的各參數就探讨到此,其他參數配置的情況大同小異。值得關注一下的是繪制輪廓的函數

drawContours中最後一個參數是一個Point類型的offset,這個offset跟findContours函數中的offset含義一緻,設定之

後所繪制的輪廓是原始輪廓上所有像素點加上該偏移量offset後的效果。

當所分析圖像是另外一個圖像的ROI的時候,這個offset偏移量就可以大顯身手了。通過加減這個偏移量,就可以把

ROI圖像的檢測結果投影到原始圖像對應位置上。

繼續閱讀