日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

opencv函数findcontours_OpenCV 中的轮廓应用

發布時間:2025/3/15 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 opencv函数findcontours_OpenCV 中的轮廓应用 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

目錄:

  • 輪廓常用函數
  • 第一個應用
  • 第二個應用
  • 輪廓就是連接所有連續點(沿著邊界)的曲線,具有相同的顏色或灰度值。輪廓是形狀分析、物體檢測和識別的有用工具。為了提高提取輪廓的精確度,需要先通過閾值處理或canny邊緣檢測將圖像轉換為二值圖像。

    在 OpenCV 中,尋找輪廓就像從黑色背景中尋找白色物體,所以要找到的物體應該是白色的,背景應該是黑色的。

    只羅列和輪廓相關的幾個函數沒啥意思,通過兩個例子可以對其用法有更深入的理解。

    一、輪廓常用函數

    1、查找輪廓

    在二值圖像中獲取輪廓:

    import cv2 im = cv2.imread('test.jpg') imgray = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY) ret, thresh = cv2.threshold(imgray, 127, 255, 0) contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

    cv2.findContours() 函數中有三個參數:

    • thresh:源圖像
    • cv2.RETR_TREE:表示輪廓檢索模式
    • cv2.CHAIN_APPROX_SIMPLE:表示輪廓近似方法

    返回值為獲取到的輪廓 contours 和hierarchy。contours為包含圖像中所有輪廓的python列表(三維數組),每個輪廓是包含邊界所有坐標點(x, y)的Numpy數組。hierarchy 是一個三維數組,它儲存了所有等高線(輪廓)的層級結構,詳情可以查看 1 和 2。

    輪廓是具有相同灰度值的形狀的邊界,即一個輪廓可以看做是一個等高線。它存儲形狀邊界的(x, y)坐標。我們可以使用第三個參數來指定是否存儲形狀邊界的所有坐標點。

    第二個參數決定 hierarchy 采取什么樣的格式輸出。第三個參數可以指定兩個值,如果是 cv2.CHAIN_APPROX_NONE,則存儲形狀邊界的所有坐標點。但有時我們不需要所有的點,比如一個矩形的輪廓,我們只需要矩形的四個端點就可以了。這時我們就可以傳入 cv2.CHAIN_APPROX_SIMPLE,它會移除所有冗余的點并壓縮輪廓,從而節省內存。

    比如下面這個例子,我們標記出矩形所有輪廓點,第一張圖片是使用 cv2.CHAIN_APPROX_NONE 得到的結果,一共有734個點;第二張圖片是使用 cv2.CHAIN_APPROX_SIMPLE 得到的結果,只有4個點。

    2、繪制輪廓

    可以使用 cv2.drawContours() 函數來繪制輪廓,只要有輪廓的邊界點,就可以用來繪制任何形狀的輪廓。

    下面是繪制輪廓的三個例子:

    # To draw all the contours in an image: cv2.drawContours(img, contours, -1, (0,255,0), 3) # To draw an individual contour, say 4th contour: cv2.drawContours(img, contours, 3, (0,255,0), 3) # But most of the time, below method will be useful: cnt = contours[4] cv2.drawContours(img, [cnt], 0, (0,255,0), 3)

    cv2.drawContours() 函數中有三個參數,第一個參數是源圖像;第二個參數是應該包含輪廓的Python列表;第三個參數是列表索引,用來選擇要繪制的輪廓,為-1時表示繪制所有輪廓;第四個參數是輪廓顏色、第五個參數是輪廓線的寬度,為-1時表示填充。

    注意:指定輪廓顏色的值要和圖像通道數一致。

    3、輪廓外接矩形

    輪廓外接矩形分為正矩形和最小矩形。使用 cv2.boundingRect(cnt) 來獲取輪廓的外接正矩形,它不考慮物體的旋轉,所以該矩形的面積一般不會最小;使用 cv.minAreaRect(cnt) 可以獲取輪廓的外接最小矩形。

    兩者區別如下圖所示,綠線表示外接正矩形,紅線表示外接最小矩形:

    cv2.boundingRect(cnt) 的返回值包含四個值,矩形框左上角的坐標(x, y)、寬度w和高度h。

    x,y,w,h = cv2.boundingRect(cnt)

    cv.minAreaRect(cnt) 的返回值中還包含旋轉信息,返回值信息為包括中心點坐標(x,y),寬高(w, h)和旋轉角度。

    然而我們繪制矩形需要矩形的四個頂點坐標,可以通過 cv.boxPoints() 來獲取,如下代碼所示:

    rect = cv2.minAreaRect(cnt) print(rect) # center(x, y), (width, height), angle of rotation box = cv2.boxPoints(rect) # box.shape=(4, 2) box = np.int0(box) cv2.drawContours(img,[box],0,(0,0,255),2)

    angle的范圍為 (-90,-0],如上圖中的角

    (與矩形框最低點相連的右邊的線),一個矩形逆時針旋轉, 的值變化為:-0 -> -30 -> -60 -> -0,然后不斷循環。

    4、輪廓面積

    我們可以通過 cv2.contourArea(cnt) 來獲取輪廓的面積,這里的面積表示該形狀內包含的像素點數量。

    5、輪廓周長

    通過 cv2.arcLength(cnt,True) 來繪制輪廓周長或者曲線長度,第二個參數指定形狀是為閉合輪廓(True)還是普通曲線。這里的周長/長度表示該形狀邊界上的像素點數量。

    6、輪廓近似

    我們可以將一個輪廓/曲線近似為另一個頂點數量較少的輪廓/曲線,使得它們之間的距離小于或等于指定的精度,通過 cv2.approxPolyDP(cnt, epsilon, True) 來實現。第二個參數用于輪廓近似的精度,表示原始輪廓與其近似輪廓的最大距離,值越小,近似輪廓越擬合原輪廓。第三個參數指定近似輪廓是否是閉合的。

    比如下面這張圖,其中物體的原始輪廓(紅線所示)如第一張圖所,第二張圖中綠線就是epsilon為原始輪廓周長的10%時的近似輪廓,第三張圖中綠線就是epsilon為原始輪廓周長的1%時的近似輪廓。

    二、第一個應用

    原圖為:

    現在我們只想獲取圖中圓形的內圓,不包含黑色邊緣部分,就使用我們上面介紹過的函數實現。

    先讀取圖像并將其轉換為灰度圖:

    import cv2 import numpy as npimg = cv2.imread("shapes.jpg") gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

    使用閾值處理將其轉換為二值圖:

    ret, threshed = cv2.threshold(gray, 200, 255, cv2.THRESH_BINARY_INV|cv2.THRESH_OTSU)

    然后就可以查找二值圖中的輪廓:

    contours, _ = cv2.findContours(threshed, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

    二值圖和查找到的輪廓如下所示:

    我們得到了很多輪廓,但是只想要最中間的那個內圓輪廓,所以我們需要對這些輪廓進行篩選:

    # 按輪廓面積將輪廓進行升序排列 cnts = sorted(contours, key=cv2.contourArea) H, W = img.shape[:2] for cnt in cnts:# 獲取輪廓外接矩形的坐標和長寬x,y,w,h = cv2.boundingRect(cnt)# 得到第一個滿足條件的輪廓,就退出循環if cv2.contourArea(cnt) > 100 and (0.8 < w/h < 1.2) and (W/4 < x + w//2 < W*3/4) and (H/4 < y + h//2 < H*3/4):circle = cntbreak

    仔細觀察原圖,可以發現我們想獲取的那個圓形輪廓面積足夠大,長寬比接近1,所以滿足條件:

    cv2.contourArea(cnt) > 100 and (0.8 < w/h < 1.2)

    而且該圓形輪廓的中心點在圖像的正中間部分,所以有:

    (W/4 < x + w//2 < W*3/4) and (H/4 < y + h//2 < H*3/4)

    當通過滿足上述條件時,我們就可以獲取到我們想要的內圓輪廓。

    創建輪廓掩碼并與原圖進行逐位與運算:

    mask = np.zeros(img.shape[:2], np.uint8) cv2.drawContours(mask, [circle], -1, 255, -1) dst = cv2.bitwise_and(img, img, mask=mask)

    得到最終結果:

    三、第二個應用

    在這個例子中我們使用輪廓相關知識把這個人物給摳出來,類似于摳圖。

    還是先讀取圖像,并轉換為灰度圖,還要對其進行高斯模糊,事先過濾掉不同輪廓之間的細線連接。

    第一個應用我們通過閾值處理得到二值圖,這里使用 Canny 邊緣檢測,得到二值圖,然后對其進行膨脹和腐蝕操作,方便稍后提取輪廓。關于形態學操作的內容可以參考這篇文章。

    import cv2 import numpy as npimg = cv2.imread('Levi.jpg') gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)blur = cv2.GaussianBlur(gray, (3, 3), 0)edges = cv2.Canny(blur, 10, 200) # Edge detection edges = cv2.dilate(edges, None) # 默認(3x3) edges = cv2.erode(edges, None)

    邊緣圖,膨脹圖和腐蝕圖如下所示:

    接下來我們就可以獲取處理后的圖像中的輪廓。

    先使用 cv2.findContours 獲取所有輪廓,再根據輪廓面積進行降序排列,并獲取到面積最大的輪廓,即圖中人物的輪廓。

    接下來通過 cv2.arcLength 得到輪廓周長,并將周長的0.1%作為近似輪廓的精度。然后再使用 cv2.approxPolyDP 得到近似輪廓。

    # Find contours in edges(binary image) contours, _ = cv2.findContours(edges, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) contours = sorted(contours, key=cv2.contourArea, reverse=True) max_contour = contours[0]epsilon = 0.001*cv2.arcLength(max_contour, True) approx = cv2.approxPolyDP(max_contour, epsilon, True)

    然后根據近似輪廓建立一個輪廓的掩碼mask,在其上繪制出最大輪廓對應的填充多邊形,用于下一步摳圖。

    對掩碼進行高斯模糊用于平滑邊緣,可以消除鋸齒。

    mask = np.zeros(img.shape[:2], np.uint8) cv2.drawContours(mask, [approx], -1, 255, -1)mask = cv2.GaussianBlur(mask, (5, 5), 0) cv2.imshow('mask', mask)dst = cv2.bitwise_and(img, img, mask=mask) cv2.imshow('dst', dst)

    最后一步就是將掩碼和原圖像進行求與運算,即得到最終結果。

    掩碼圖和結果如下所示:

    這里說個題外話,這里我們通過 edges = cv2.Canny(blur, 10, 200) 得到二值圖,但是要手動設置兩個閾值參數,不想手動設置的話可以使用如下函數來手動設置:

    def auto_canny(image, sigma=0.33):# compute the median of the single channel pixel intensitiesv = np.median(image)# construct two thresholds using the medianlower = int(max(0, (1.0 - sigma) * v))upper = int(min(255, (1.0 + sigma) * v))edged = cv2.Canny(image, lower, upper)return edged

    所以將 edges = cv2.Canny(blur, 10, 200) 替換為 edges = auto_canny(blur, sigma=0.33) 即可。

    當需要框出目標的輪廓時,推薦使用 cv2.Canny() 邊緣檢測而非閾值處理生成二值圖。理由:

  • 提取邊緣與閾值處理不同,邊緣提取可以識別圖片中目標的形狀、輪廓,而不是簡單的區分出圖片中的高光與暗調,可以簡單地提取圖片中顏色分布位于中間調上的目標(中間調是指色階值接近中值(128)的圖像像素);
  • 使用Canny邊緣檢測,提取結果的白點數量更少,對等高線檢測的混淆因素減少;
  • 不同邊緣檢測算法中,Canny邊緣檢測效果好(雖然對性能要求高);
  • 參考:

    邊緣檢測,框出物體的輪廓

    幾何形狀識別與測量

    Contour Features

    remove the background of image:1,2


    如果覺得有用,點個贊吧(? ??_??)?。

    與50位技術專家面對面20年技術見證,附贈技術全景圖

    總結

    以上是生活随笔為你收集整理的opencv函数findcontours_OpenCV 中的轮廓应用的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。