主頁 > 後端開發 > Python OpenCV 輪廓檢測與輪廓特征,加影像金字塔知識補充一點點

Python OpenCV 輪廓檢測與輪廓特征,加影像金字塔知識補充一點點

2021-02-25 11:39:09 後端開發

Python OpenCV 365 天學習計劃,與橡皮擦一起進入影像領域吧,本篇博客是這個系列的第 48 篇,
該系列文章導航參考:https://blog.csdn.net/hihell/category_10688961.html

Python OpenCV

    • 學在前面
    • 輪廓檢測與輪廓特征
    • cv2.findContours 函式
      • 回傳值 contours
    • 輪廓特征
      • 輪廓面積
      • 輪廓周長
      • 外接矩形
      • 其余補充學習
    • 橡皮擦的小節

學在前面

影像金字塔學習的時候,就要想著有個金字塔在你眼前,這個金字塔最底部是你的原影像(源影像),

關于影像金字塔的基本知識,可以翻閱咱們之前的博客 Python OpenCV 之影像金字塔,高斯金字塔與拉普拉斯金字塔 學習,

學習高斯金字塔首先接觸的概念是,向下采樣方法,注意在金字塔,向下是縮小圖片的含義,越靠近金字塔頂部,影像越小,相應的向上采樣法,是方法影像,

好了,影像金字塔一點點的補充已經完畢,

輪廓檢測與輪廓特征

輪廓檢測的基礎學習,請參照 Python OpenCV 基于影像邊緣提取的輪廓發現函式 這篇博客,今天要補充的內容是在進行影像輪廓檢測的時候,cv2.findContours 函式中輪廓檢索模式引數,一般情況下建議使用 RETR_TREE 也就是檢測所有輪廓,

查看一下測驗代碼吧,

import cv2 as cv

src = cv.imread("./t223.jpg")

gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
gaussian = cv.GaussianBlur(gray, (3, 3), 0)

edges = cv.Canny(gaussian, 70, 210)
# 尋找輪廓
contours, hierarchy = cv.findContours(
    edges, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)

# 繪制輪廓
cv.drawContours(src, contours, -1, (0, 0, 255), 1)

cv.imshow('src', src)
cv.waitKey(0)

尋找邊緣使用的是 Canny 函式,找到所有邊緣之后,通過 cv2.drawContours 函式繪制輪廓,
Python OpenCV 輪廓檢測與輪廓特征,加影像金字塔知識補充一點點
在學習 cv2.drawContours 函式的時候需要注意,有的博客中會提示使用該函式在原圖繪制輪廓之后,會將原圖進行覆寫,但是在橡皮擦使用的這個 opencv 版本中,并未出現上述情況,可能是不同版本導致的,注意下即可,

cv2.findContours 函式

該函式有兩個回傳值,contourshierarchy,其中一個是輪廓本身,另一個就是每條輪廓對應的屬性,
整體測驗代碼與影像使用下述內容,

import cv2 as cv

src = cv.imread("./t22331.jpg")

gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
gaussian = cv.GaussianBlur(gray, (3, 3), 0)

edges = cv.Canny(gaussian, 50, 150)
# 尋找輪廓
contours, hierarchy = cv.findContours(
    edges, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)

# 繪制輪廓
cv.drawContours(src, contours, -1, (0, 0, 255), 2)

cv.imshow('src', src)
cv.waitKey(0)

Python OpenCV 輪廓檢測與輪廓特征,加影像金字塔知識補充一點點

回傳值 contours

通過下述代碼,先確定一下該引數的基本資料,

# 輪廓詳情
print(type(contours))
print(type(contours[0]))
print(len(contours))

得到的結果是:

<class 'list'>
<class 'numpy.ndarray'>
46

contours 引數是 list 型別、其中每一項都是 numpy.ndarray 型別,串列的長度等于輪廓數量,
合計獲取到 46 個輪廓,可以根據索引去繪制制定輪廓,例如:

# 繪制輪廓
cv.drawContours(src, contours, 1, (0, 0, 255), 2)
cv.drawContours(src, contours, 45, (0, 0, 255), 2)

回傳值 hierarchy 暫時略過,因為和接下來的內容關聯性不強,

輪廓特征

這部分內容又叫做物件測量,在Python OpenCV 物件檢測,影像處理取經之旅第 37 篇 進行了最基礎的學習,本篇繼續對其進行擴展,

咱們的首要目標是學會通過呼叫方法檢測輪廓的不同特征,例如面積、周長、質心、邊界框,

這部分在學習的時候,會用到大量的常見場景和數學知識,由于咱們現在還沒有辦法將這些內容直接應用到真實的案例中,所以數學相關知識與應用場景后置,先學習應用層,了解不同函式實作的結果即可,

接下來拋出不同的概念吧,

在這個階段,只需要知道矩指的是影像的矩,它可以幫助我們計算影像的質心,面積等內容,如果你想提前學習一下數學相關的內容,我也幫你把目前橡皮擦能找到的幾篇不錯的博客貼了出來,你可以先學習一下,后面我們也會迭代學習到,

  • 影像的矩特征
  • 矩、中心矩、質心、patch 方向
  • 影像中矩的概念

大佬們還是咱們努力學習的方向呀,相信不久就能再見面了,

以上內容你可以直接略過,進入正題

先在工具中輸入如下代碼,獲取運行結果,方便后面的學習:

import cv2 as cv

src = cv.imread("./t22331.jpg")

gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
gaussian = cv.GaussianBlur(gray, (3, 3), 0)

edges = cv.Canny(gaussian, 50, 150)
# 尋找輪廓
contours, hierarchy = cv.findContours(
    edges, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)

# 繪制輪廓
cv.drawContours(src, contours, 1, (0, 0, 255), 2)
cv.drawContours(src, contours, 45, (0, 0, 255), 2)
# 選中的第一個輪廓
cnt = contours[0]
# 通過 moments 函式計算的所有矩值的字典
M = cv.moments(cnt)
print(M)

運行之后展示的內容如下:

{'m00': 51.0, 'm10': 12277.833333333332, 'm01': 13028.166666666666, 'm20': 2956012.333333333, 'm11': 3136429.25, 'm02': 3328298.333333333, 'm30': 711743823.85, 'm21': 755128136.4666667, 'm12': 801262936.2, 'm03': 850328986.1500001, 'mu20': 224.26742919441313, 'mu11': 4.5642701531760395, 'mu02': 197.80991285433993, 'mu30': 23.924903512001038, 'mu21': 30.072836493171053, 'mu12': -27.494554918412177, 'mu03': -25.694735527038574, 'nu20': 0.0862235406360681, 'nu11': 0.0017548135921476508, 'nu02': 0.0760514851419992, 'nu30': 0.0012880263706323274, 'nu21': 0.0016190078435839353, 'nu12': -0.0014802029093220657, 'nu03': -0.0013833074364813173}

注意看都是以 m.. 或者 nu.. 開始的各種資料,

輪廓面積

輪廓的面積可以使用函式 cv2.contourArea() 計算得到,也可以使用矩(0 階矩), 即剛才結果中的 M["m00"] 獲取,

# 輪廓面積
area = cv.contourArea(cnt)
print(area)
# 0 階矩
print(M['m00'])

輪廓周長

也稱為弧長,使用函式 cv.arcLength() 計算得到,該函式的第二引數可以用來指定物件的形狀是閉合的(True),還是打開的(一條曲線),如果曲線閉合,那以上 2 種方法計算結果一致,如果是開曲線,則兩者計算結果不同,其中閉合的方法,會在最后將起始點和終止點連一起的長度加進去,

# 輪廓周長
perimeter = cv.arcLength(cnt,True)
print(perimeter)

后面的內容因為涉及到不同的輪廓,為了檢測出希望操作的輪廓,我遍歷了所有輪廓,找到了周長合適的那個圓形,

for index in range(len(contours)):
    print("索引是:",index)
    cnt = contours[index]
    # 通過 moments 函式計算的所有矩值的字典
    M = cv.moments(cnt)
    # print(M)

    # 輪廓面積
    area = cv.contourArea(cnt)
    print(area)
    # 0 階矩
    print(M['m00'])
    # 輪廓周長
    perimeter = cv.arcLength(cnt,True)
    print(perimeter)

cv.imshow("image",src)
cv.waitKey()

Python OpenCV 輪廓檢測與輪廓特征,加影像金字塔知識補充一點點

外接矩形

通過下述代碼獲取上圖黃色圓形的外界矩形,外接矩形也叫做邊界矩形或者包圍盒,

它需要找到圖形物件最高點、最低點、最左點、最右點,畫出一個矩形邊界,
使用函式 cv2.boundingRect 計算之后,將結果進行回傳,其中(x,y)為矩形左上角的坐標,(w,h)是矩形的寬和高,

# 外接矩形
x, y, w, h = cv.boundingRect(cnt)
cv.rectangle(src, (x, y), (x + w, y + h), (0, 255, 0), 2)

cv.imshow("src",src)
cv.waitKey()

還可以繪制圓形的最小外接矩形,也叫做旋轉邊界包圍盒,例如下述代碼,回傳 Box2D 結構,包含左上角坐標(x,y),矩形寬,高 (w,h),以及旋轉角度,

# 最小外接矩形
rect = cv.minAreaRect(cnt)
box = np.int0(cv.boxPoints(rect))
cv.drawContours(src, [box], 0, (255, 0, 0), 2)
cv.imshow("src",src)

整體運行結果,略微存在差異,
Python OpenCV 輪廓檢測與輪廓特征,加影像金字塔知識補充一點點

其余補充學習

有了上述的基本知識概念之后,剩下的就非常容易學習了

最小外接圓
代碼如下,這里我切換了一張圖片,畢竟用圓形做外接圓不太合適,

(x,y),radius = cv.minEnclosingCircle(cnt)
center = (int(x),int(y))
radius = int(radius)
cv.circle(src,center,radius,(0,255,0),2)
cv.imshow("src",src)
cv.waitKey()

Python OpenCV 輪廓檢測與輪廓特征,加影像金字塔知識補充一點點
橢圓擬合

ellipse = cv.fitEllipse(cnt)
cv.ellipse(src,ellipse,(0,255,0),2)

擬合一條線

# 擬合一條直線
rows, cols = src.shape[:2]
[vx, vy, x, y] = cv.fitLine(cnt, cv.DIST_L2, 0, 0.01, 0.01)
lefty = int((-x*vy/vx) + y)
righty = int(((cols-x)*vy/vx)+y)
cv.line(src, (cols-1, righty), (0, lefty), (0, 255, 0), 2)

Python OpenCV 輪廓檢測與輪廓特征,加影像金字塔知識補充一點點
以上所有方法的前提都是找到輪廓,如果沒有找到輪廓,所有函式都不會有結果展示,

輪廓近似與凸包相關知識點,依舊后置,這些知識的學習沒有應用場景,很容易被遺忘,

相關資料提前學習,可以檢索 cv2.approxPolyDPcv2.convexHull 函式,

輪廓性質可以由輪廓特征計算得出,包括但不限于,寬高比、輪廓面積與邊界矩形面積的比、 輪廓面積與凸包面積的比、獲取與輪廓面積相等的圓形直徑、方向、輪廓的掩膜與像素點、最大值和最小值及它們的位置、平均顏色及平均灰度、極點、凸缺陷、形狀匹配

橡皮擦的小節

希望今天的 1 個小時你有所識訓,我們下篇博客見~

相關閱讀


技術專欄

  1. Python 爬蟲 100 例教程,超棒的爬蟲教程,立即訂閱吧
  2. Python 爬蟲小課,精彩 9 講

今天是持續寫作的第 90 / 100 天,
如果你想跟博主建立親密關系,可以關注同名公眾號 夢想橡皮擦,近距離接觸一個逗趣的互聯網高級網蟲,
博主 ID:夢想橡皮擦,希望大家點贊評論收藏

夢想橡皮擦 CSDN認證博客專家 高級產品經理 互聯網從業者 業余編程愛好者
10 年互聯網從業經驗,Python 爬蟲 100 例作者,藍橋簽約作者,同名公眾號【夢想橡皮擦】

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/263453.html

標籤:python

上一篇:Python演算法的分享(一)

下一篇:Python中collections模塊學習

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【C++】Microsoft C++、C 和匯編程式檔案

    ......

    uj5u.com 2020-09-10 00:57:23 more
  • 例外宣告

    相比于斷言適用于排除邏輯上不可能存在的狀態,例外通常是用于邏輯上可能發生的錯誤。 例外宣告 Item 1:當函式不可能拋出例外或不能接受拋出例外時,使用noexcept 理由 如果不打算拋出例外的話,程式就會認為無法處理這種錯誤,并且應當盡早終止,如此可以有效地阻止例外的傳播與擴散。 示例 //不可 ......

    uj5u.com 2020-09-10 00:57:27 more
  • Codeforces 1400E Clear the Multiset(貪心 + 分治)

    鏈接:https://codeforces.com/problemset/problem/1400/E 來源:Codeforces 思路:給你一個陣列,現在你可以進行兩種操作,操作1:將一段沒有 0 的區間進行減一的操作,操作2:將 i 位置上的元素歸零。最終問:將這個陣列的全部元素歸零后操作的最少 ......

    uj5u.com 2020-09-10 00:57:30 more
  • UVA11610 【Reverse Prime】

    本人看到此題沒有翻譯,就附帶了一個自己的翻譯版本 思考 這一題,它的第一個要求是找出所有 $7$ 位反向質數及其質因數的個數。 我們應該需要質數篩篩選1~$10^{7}$的所有數,這里就不慢慢介紹了。但是,重讀題,我們突然發現反向質數都是 $7$ 位,而將它反過來后的數字卻是 $6$ 位數,這就說明 ......

    uj5u.com 2020-09-10 00:57:36 more
  • 統計區間素數數量

    1 #pragma GCC optimize(2) 2 #include <bits/stdc++.h> 3 using namespace std; 4 bool isprime[1000000010]; 5 vector<int> prime; 6 inline int getlist(int ......

    uj5u.com 2020-09-10 00:57:47 more
  • C/C++編程筆記:C++中的 const 變數詳解,教你正確認識const用法

    1、C中的const 1、區域const變數存放在堆疊區中,會分配記憶體(也就是說可以通過地址間接修改變數的值)。測驗代碼如下: 運行結果: 2、全域const變數存放在只讀資料段(不能通過地址修改,會發生寫入錯誤), 默認為外部聯編,可以給其他源檔案使用(需要用extern關鍵字修飾) 運行結果: ......

    uj5u.com 2020-09-10 00:58:04 more
  • 【C++犯錯記錄】VS2019 MFC添加資源不懂如何修改資源宏ID

    1. 首先在資源視圖中,添加資源 2. 點擊新添加的資源,復制自動生成的ID 3. 在解決方案資源管理器中找到Resource.h檔案,編輯,使用整個專案搜索和替換的方式快速替換 宏宣告 4. Ctrl+Shift+F 全域搜索,點擊查找全部,然后逐個替換 5. 為什么使用搜索替換而不使用屬性視窗直 ......

    uj5u.com 2020-09-10 00:59:11 more
  • 【C++犯錯記錄】VS2019 MFC不懂的批量添加資源

    1. 打開資源頭檔案Resource.h,在其中預先定義好宏 ID(不清楚其實ID值應該設定多少,可以先新建一個相同的資源項,再在這個資源的ID值的基礎上遞增即可) 2. 在資源視圖中選中專案資源,按F7編輯資源檔案,按 ID 型別 相對路徑的形式添加 資源。(別忘了先把檔案拷貝到專案中的res檔案 ......

    uj5u.com 2020-09-10 01:00:19 more
  • C/C++編程筆記:關于C++的參考型別,專供新手入門使用

    今天要講的是C++中我最喜歡的一個用法——參考,也叫別名。 參考就是給一個變數名取一個變數名,方便我們間接地使用這個變數。我們可以給一個變數創建N個參考,這N + 1個變數共享了同一塊記憶體區域。(參考型別的變數會占用記憶體空間,占用的記憶體空間的大小和指標型別的大小是相同的。雖然參考是一個物件的別名,但 ......

    uj5u.com 2020-09-10 01:00:22 more
  • 【C/C++編程筆記】從頭開始學習C ++:初學者完整指南

    眾所周知,C ++的學習曲線陡峭,但是花時間學習這種語言將為您的職業帶來奇跡,并使您與其他開發人員區分開。您會更輕松地學習新語言,形成真正的解決問題的技能,并在編程的基礎上打下堅實的基礎。 C ++將幫助您養成良好的編程習慣(即清晰一致的編碼風格,在撰寫代碼時注釋代碼,并限制類內部的可見性),并且由 ......

    uj5u.com 2020-09-10 01:00:41 more
最新发布
  • Rust中的智能指標:Box<T> Rc<T> Arc<T> Cell<T> RefCell<T> Weak

    Rust中的智能指標是什么 智能指標(smart pointers)是一類資料結構,是擁有資料所有權和額外功能的指標。是指標的進一步發展 指標(pointer)是一個包含記憶體地址的變數的通用概念。這個地址參考,或 ” 指向”(points at)一些其 他資料 。參考以 & 符號為標志并借用了他們所 ......

    uj5u.com 2023-04-20 07:24:10 more
  • Java的值傳遞和參考傳遞

    值傳遞不會改變本身,參考傳遞(如果傳遞的值需要實體化到堆里)如果發生修改了會改變本身。 1.基本資料型別都是值傳遞 package com.example.basic; public class Test { public static void main(String[] args) { int ......

    uj5u.com 2023-04-20 07:24:04 more
  • [2]SpinalHDL教程——Scala簡單入門

    第一個 Scala 程式 shell里面輸入 $ scala scala> 1 + 1 res0: Int = 2 scala> println("Hello World!") Hello World! 檔案形式 object HelloWorld { /* 這是我的第一個 Scala 程式 * 以 ......

    uj5u.com 2023-04-20 07:23:58 more
  • 理解函式指標和回呼函式

    理解 函式指標 指向函式的指標。比如: 理解函式指標的偽代碼 void (*p)(int type, char *data); // 定義一個函式指標p void func(int type, char *data); // 宣告一個函式func p = func; // 將指標p指向函式func ......

    uj5u.com 2023-04-20 07:23:52 more
  • Django筆記二十五之資料庫函式之日期函式

    本文首發于公眾號:Hunter后端 原文鏈接:Django筆記二十五之資料庫函式之日期函式 日期函式主要介紹兩個大類,Extract() 和 Trunc() Extract() 函式作用是提取日期,比如我們可以提取一個日期欄位的年份,月份,日等資料 Trunc() 的作用則是截取,比如 2022-0 ......

    uj5u.com 2023-04-20 07:23:45 more
  • 一天吃透JVM面試八股文

    什么是JVM? JVM,全稱Java Virtual Machine(Java虛擬機),是通過在實際的計算機上仿真模擬各種計算機功能來實作的。由一套位元組碼指令集、一組暫存器、一個堆疊、一個垃圾回收堆和一個存盤方法域等組成。JVM屏蔽了與作業系統平臺相關的資訊,使得Java程式只需要生成在Java虛擬機 ......

    uj5u.com 2023-04-20 07:23:31 more
  • 使用Java接入小程式訂閱訊息!

    更新完微信服務號的模板訊息之后,我又趕緊把微信小程式的訂閱訊息給實作了!之前我一直以為微信小程式也是要企業才能申請,沒想到小程式個人就能申請。 訊息推送平臺🔥推送下發【郵件】【短信】【微信服務號】【微信小程式】【企業微信】【釘釘】等訊息型別。 https://gitee.com/zhongfuch ......

    uj5u.com 2023-04-20 07:22:59 more
  • java -- 緩沖流、轉換流、序列化流

    緩沖流 緩沖流, 也叫高效流, 按照資料型別分類: 位元組緩沖流:BufferedInputStream,BufferedOutputStream 字符緩沖流:BufferedReader,BufferedWriter 緩沖流的基本原理,是在創建流物件時,會創建一個內置的默認大小的緩沖區陣列,通過緩沖 ......

    uj5u.com 2023-04-20 07:22:49 more
  • Java-SpringBoot-Range請求頭設定實作視頻分段傳輸

    老實說,人太懶了,現在基本都不喜歡寫筆記了,但是網上有關Range請求頭的文章都太水了 下面是抄的一段StackOverflow的代碼...自己大修改過的,寫的注釋挺全的,應該直接看得懂,就不解釋了 寫的不好...只是希望能給視頻網站開發的新手一點點幫助吧. 業務場景:視頻分段傳輸、視頻多段傳輸(理 ......

    uj5u.com 2023-04-20 07:22:42 more
  • Windows 10開發教程_編程入門自學教程_菜鳥教程-免費教程分享

    教程簡介 Windows 10開發入門教程 - 從簡單的步驟了解Windows 10開發,從基本到高級概念,包括簡介,UWP,第一個應用程式,商店,XAML控制元件,資料系結,XAML性能,自適應設計,自適應UI,自適應代碼,檔案管理,SQLite資料庫,應用程式到應用程式通信,應用程式本地化,應用程式 ......

    uj5u.com 2023-04-20 07:22:35 more