輪廓(查找和繪制輪廓、輪廓的表達與組織、輪廓的特性)

目錄

    • 1、輪廓的定義
    • 2、如何在圖像中找到輪廓
      • opencv自帶的查找輪廓函數:findContours()
    • 3、輪廓的表達方式
      • 1.頂點的序列
      • 2.Freeman鏈碼
    • 4、輪廓之間的組織方式
    • 5、輪廓的特點(這部分可以展開來詳細探討,這里不做過多解釋)
    • 6、輪廓的匹配
    • 7、繪制輪廓drawContours()
    • 8、例子
      • 動態檢測圖形的輪廓
        • 步驟
        • 理解
        • 演示效果

1、輪廓的定義

輪廓是構成任何一個形狀的邊界或外形線。

2、如何在圖像中找到輪廓

利用OpenCV提供的方法cvFindContours()可以很方便的查找輪廓。cvFindContours()方法從二值圖像中尋找輪廓。
因此此方法處理的圖像可以是從cvCanny()函數得到的有邊緣像素的圖像,或者從cvThreshold()及cvAdaptiveThreshold()得到的圖像,這時的邊緣是正和負區域之間的邊界。

opencv自帶的查找輪廓函數:findContours()

參數講解:
參數
參數
參數:
參數

1】檢測輪廓
//定義輪廓和層次結構
vector<vector<Point>> contours;			//每個輪廓存儲為一個點向量
vector<Vec4i>hierarchy;			//	Vec4i
findContours(srcImage,contours,		//輪廓數組hierarchy,RETR_EXTERNAL,		//獲取外輪廓CHAIN_APPROX_NONE			//獲取每個輪廓中的每個像素);

3、輪廓的表達方式

1.頂點的序列

序列是內存存儲器中可以存儲的一種對象。序列是某種結構的鏈表。序列在內存中被實現為一個雙端隊列,因此序列可以實習快速的隨機訪問,以及快速刪除頂端的元素,但是從中間刪除元素則稍慢些。
用多個頂點(或各點間的線段)來表達輪廓。假設要表達一個從(0,0)到(2,2)的矩形,
(1)如果用點來表示,那么依次存儲的可能是:(0,0),(1,0),(2,0),(2,1),(2,2),(1,2),(0,2),(0,1);
(2)如果用點間的線段來表達輪廓,那么依次存儲的可能是:(0,0),(2,0),(2,2),(0,2)。

2.Freeman鏈碼

Freeman鏈碼需要一個起點,以及從起點出發的一系列位移。每個位移有8個方向,從0~7分別指向從正北開始的8個方向。假設要用Freeman鏈碼表達從(0,0)到(2,2)的矩形,可能的表示方法是:起點(0,0),方向鏈2,2,4,4,6,6,0,0。

4、輪廓之間的組織方式

在查找到輪廓之后,不同輪廓是怎么組織的呢?根據不同的選擇,它們可能是:(1)列表;(2)雙層結構;(3)樹型結構。
從縱向上來看,列表只有一層,雙層結構有一或者兩層,樹型結構可能有一層或者多層。
如果要遍歷所有的輪廓,可以使用遞歸的方式。

5、輪廓的特點(這部分可以展開來詳細探討,這里不做過多解釋)

1.輪廓的多邊形逼近
輪廓的多邊形逼近指的是:使用多邊形來近似表示一個輪廓。
多邊形逼近的目的是為了減少輪廓的頂點數目。
多邊形逼近的結果依然是一個輪廓,只是這個輪廓相對要粗曠一些。 可以使用方法cvApproxPoly()

2.輪廓的關鍵點
輪廓的關鍵點是:輪廓上包含曲線信息比較多的點。關鍵點是輪廓頂點的子集。
可以使用cvFindDominantPoints函數來獲取輪廓上的關鍵點,該函數返回的結果一個包含 關鍵點在輪廓頂點中索引 的序列。再次強調:是索引,不是具體的點。如果要得到關鍵點的具體坐標,可以用索引到輪廓上去找。
3.輪廓的周長和面積
輪廓的周長可以用cvContourPerimeter或者cvArcLength函數來獲取。
輪廓的面積可以用cvContourArea函數來獲取。

4.輪廓的邊界框
有三種常見的邊界框:矩形、圓形、橢圓。
(1)矩形:在圖像處理系統中提供了一種叫Rectangle的矩形,不過它只能表達邊垂直或水平的特例;OpenCv中還有一種叫Box的矩形,它跟數學上的矩形一致,只要4個角是直角即可。
如果要獲取輪廓的Rectangle,可以使用cvBoundingRect函數。
如果要獲取輪廓的Box,可以使用cvMinAreaRect2函數。
(2)圓形
如果要獲取輪廓的圓形邊界框,可以使用cvMinEnclosingCircle函數。
(3)橢圓
如果要獲取輪廓的橢圓邊界框,可以使用cvFitEllipse2函數。
5.輪廓的矩
矩是通過對輪廓上所有點進行積分運算(或者認為是求和運算)而得到的一個粗略特征。
1空間矩
空間矩的實質為面積或者質量。可以通過一階矩計算質心/重心。
公式
重心:重心
2中心矩
中心矩體現的是圖像強度的最大和最小方向(中心矩可以構建圖像的協方差矩陣),其只具有平移不變性,所以用中心矩做匹配效果不會很好。
中心
3歸一化的中心矩
歸一化后具有尺度不變性。
距
4Hu矩
12
6.輪廓的輪廓樹
輪廓樹用來描述某個特定輪廓的內部特征。注意:輪廓樹跟輪廓是一一對應的關系;輪廓樹不用于描述多個輪廓之間的層次關系。
輪廓樹的創建過程:
從一個輪廓創建一個輪廓樹是從底端(葉子節點)到頂端(根節點)的。首先搜索三角形突出或者凹陷的形狀的周邊(輪廓上的每一個點都不是完全和它的相鄰點共線的)每個這樣的三角形被一條線段代替,這條線段通過連接非相鄰點的兩點得到;因此實際上三角形或者被削平或者被填滿。每個這樣的替換都把輪廓的頂點減少,并且給輪廓樹創建一個新節點。如果這樣的一個三角形的兩側有原始邊,那么她就是得到的輪廓樹的葉子;如果一側已是一個三角形,那么它就是那個三角形的父節點。這個過程的迭代最終把物體的外形簡稱一個四邊形,這個四邊形也被剖開;得到的兩個三角形是根節點的兩個子節點。
結果的二分樹最終將原始輪廓的形狀性比編碼。每個節點被它所對應的三角形的信息所注釋。
這樣建立的輪廓樹并不太魯棒,因為輪廓上小的改變也可能會徹底改變結果的樹,同時最初的三角形是任意選取的。為了得到較好的描述需要首先使用函數cvApproxPoly()之后將輪廓排列(運用循環移動)成最初的三角形不怎么收到旋轉影響的狀態。
可以用函數cvCreateContourTree來構造輪廓樹。
7.輪廓的凸包和凸缺陷
這塊內容會在后續詳細探討。
8.輪廓的成對幾何直方圖
成對幾何直方圖(pairwise geometrical histogram PGH)是鏈碼編碼直方圖(chain code histogram CCH)的一個擴展或者延伸。CCH是一種直方圖,用來統計一個輪廓的Freeman鏈碼編碼每一種走法的數字。這種直方圖的一個優良性質為當物體旋轉45度,那么新直方圖是老直方圖的循環平移。這樣就可以不受旋轉影響。
(1)輪廓保存的是一系列的頂點,輪廓是由一系列線段組成的多邊形。對于看起來光滑的輪廓(例如圓),只是線段條數比較多,線段長度比較短而已。實際上,電腦中顯示的任何曲線都由線段組成。
(2)每兩條線段之間都有一定的關系,包括它們(或者它們的延長線)之間的夾角,兩條線段的夾角范圍是:(0,180)。
(3)每兩條線段上的點之間還有距離關系,包括最短(小)距離、最遠(大)距離,以及平均距離。最大距離我用了一個偷懶的計算方法,我把輪廓外界矩形的對角線長度看作了最大距離。
(4)成對幾何直方圖所用的統計數據包括了夾角和距離。

6、輪廓的匹配

1.Hu矩匹配
輪廓的Hu矩對包括縮放、旋轉和鏡像映射在內的變化具有不變性。cvMatchShapes函數可以很方便的實現對2個輪廓間的匹配。
2.輪廓樹匹配
用樹的形式比較兩個輪廓。cvMatchContourTrees函數實現了輪廓樹的對比。
3.成對幾何直方圖匹配
在得到輪廓的成對幾何直方圖之后,可以使用直方圖對比的方法來進行匹配。

7、繪制輪廓drawContours()

輪廓的繪制比較簡單,用上面提到的方法取得輪廓的所有點,然后把這些點連接成一個多邊形即可。
使用函數drawContours(),更加方便。
1
2
使用例子:

//【2】繪制輪廓
//遍歷所有頂層的輪廓,用不同的顏色繪制出來
int index = 0;
for (; index >= 0; index = hierarchy[index][0])
{Scalar color(rand() & 255,rand() & 255,rand() & 255);		//隨機數drawContours(dstImage,		//outputImagecontours, 		//輪廓信息index, 			//當前輪廓的索引值color, 			//輪廓顏色FILLED, 		//繪制在輪廓內部8,				//8連通線型hierarchy);		//輪廓間的層次信息
}

8、例子

動態檢測圖形的輪廓

步驟

【1】讀取原圖,轉為灰度圖并高斯模糊
【2】canny檢測圖像邊緣(滑動條控制閾值)
【3】對canny算子掃描后的圖像進行查找輪廓
【4】繪制輪廓

理解

Canny之類的邊緣檢測算法可以根據像素間的差異檢測出輪廓邊界的像素,但是它并沒有將輪廓作為一個整體。
對canny掃描后的圖像查找輪廓是一種較好的選擇。

#include <opencv2/opencv.hpp>
#include <iostream>
#include "windows.h"
#include <stdio.h>
#define WINDOW_NAME "【程序窗口】"			//為窗口標題定義的宏using namespace cv;
using namespace std;
//===========================動態檢測圖形的輪廓====================//=================全局變量聲明=================
Mat g_srcImage;
Mat g_grayImage;
int g_nThresh = 80;
int g_nThresh_max = 255;
RNG g_rng(12345);
Mat g_cannyMat_output;
vector<vector<Point>> g_vContours;
vector<Vec4i> g_vHierarchy;//=============全局函數聲明===============
void on_ThreshChange(int,void*);
int main()
{// Read image 讀取圖像SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY | FOREGROUND_GREEN);		//字體為綠色//載入原圖g_srcImage = imread("D:\\opencv_picture_test\\lena.jpg",1);//Mat srcImage = imread("D:\\opencv_picture_test\\形態學操作\\孔洞.png", 0);	//讀取灰度圖//轉換成灰度并且模糊化降噪cvtColor(g_srcImage, g_grayImage, COLOR_BGR2GRAY);blur(g_grayImage, g_grayImage, Size(3, 3));//創建窗口namedWindow("原始圖窗口", WINDOW_AUTOSIZE);imshow("原始圖窗口", g_srcImage);//創建滑動條并初始化createTrackbar("canny 閾值", "原始圖窗口", &g_nThresh,g_nThresh_max, on_ThreshChange);on_ThreshChange(0,0);waitKey(0);return 0;
}
void on_ThreshChange(int, void*)
{//用Canny算子檢測邊緣Canny(g_grayImage, g_cannyMat_output, g_nThresh, g_nThresh * 2, 3);//尋找輪廓.findContours(g_cannyMat_output, g_vContours, g_vHierarchy,RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0));//繪出輪廓Mat drawing = Mat::zeros(g_cannyMat_output.size(), CV_8UC3);for (int i = 0; i < g_vContours.size(); i++){Scalar color = Scalar(g_rng.uniform(0, 255),g_rng.uniform(0, 255), g_rng.uniform(0, 255));//任意值drawContours(drawing, g_vContours, i, color, 2, 8, g_vHierarchy,0, Point());}//顯示效果圖imshow("輪廓圖",drawing);
}

演示效果

演示結果

參考鏈接:
主講輪廓的特性;
輪廓的矩;
輪廓的矩;
以及《《OpenCV3編程入門》毛星云編著_電子工業出版社》。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/378633.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/378633.shtml
英文地址,請注明出處:http://en.pswp.cn/news/378633.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

python如何操作oracle數據庫_python操作oracle數據庫

搜索熱詞下面是編程之家 jb51.cc 通過網絡收集整理的代碼片段。編程之家小編現在分享給大家&#xff0c;也給大家做個參考。# -*- mode: python; coding: utf-8 -*-## python operate oracle,contain insert、delete、update、select.## author liyulin# date 2014-11-07import…

可能用得上的jquery 插件

Chosen (github) 是一個強大的增強下拉選擇框的插件&#xff0c;支持自定義css樣式。同時你可以使用ajax增加一些回調函數&#xff0c;插件會給hidden input復制&#xff0c;這樣你可以在提交表單的時候獲得正確的值。 Turn.js 是一個 JavaScript 庫&#xff0c;使您的網頁內容…

草根創業回憶錄二: 都選擇的是什么人?

草根創業回憶錄二: 都選擇的是什么人&#xff1f; 前言&#xff1a;選合伙人和投資就像在選女朋友一樣&#xff0c;要謹慎&#xff0c;甚至有時候寧缺毋濫。 曾經以為有了錢&#xff0c;就會找到需要的人&#xff0c;后來發現不是這樣的。 也以為&#xff0c;隨便拉幾個關系好的…

float.equals_Java Float類equals()方法與示例

float.equals浮動類equals()方法 (Float class equals() method) equals() method is available in java.lang package. equals()方法在java.lang包中可用。 equals() method is used to check equality or inequality of this Object against the given Object or in other wo…

01-基本配置與測試

一、開發環境 使用的是Anaconda 3&#xff0c;其中Python版本為3.6.3 首先&#xff0c;在Anaconda下的Scripts文件夾下打開命令框 使用pip install -U selenium安裝selenium 打開Jupiter Notebook&#xff0c;輸入from selenium import webdriver進行測試 不報錯即安裝成功 …

Opencv——查找并繪制凸包、凸包與輪廓的關系

定義 給定二維平面上的點集&#xff0c;凸包就是將最外層的點連接起來構成的凸多邊型。 理解物體形狀或輪廓的一 種比較有用的方法便是計算一個物體的凸包&#xff0c;然后計算其凸缺陷(convexity defects)。 檢測凸包 opencv自帶函數&#xff1a;convexHull() 參數解釋&a…

EF Code First 簡單的示例

一對多&#xff1a; public class Category {public Category(){Id GuidComb.GenerateComb();}public Guid Id { get; set; }public string Name { get; set; }public string Description { get; set; }public virtual IList<Topic> Topics { get; set; } }public class…

線程同步 - 整理

線程同步機制為線程協同工作而設計&#xff0c;windows系統中有多種機制可以用于線程同步&#xff0c;最常用的有下面幾種&#xff1a; 互斥對象(Mutex)時間對象(Event)信號量(Semaphore)臨界區(critical section)可等待計時器(waitable Timer)同步過程中兩個重要的概念是同步對…

智能車復工日記【N】:圖像處理——環島debug記錄(持續更新)

博主聯系方式: QQ:1540984562 QQ交流群:892023501 群里會有往屆的smarters和電賽選手,群里也會不時分享一些有用的資料,有問題可以在群里多問問。 Debug記錄 代碼以及思路整理:系列文章4.10號更新5.4號更新5.5號更新代碼以及思路整理: 【智能車Code review】——環島的判…

java接口并發衡量_java 后端設計高并發接口總結

如何設置高并發接口一、并發隊列的選擇二、請求接口的合理設計三、高并發下的數據安全3.1 超發的原因3.2 悲觀鎖思路3.3 FIFO隊列思路3.4 樂觀鎖思路一、并發隊列的選擇Java的并發包提供了三個常用的并發隊列實現&#xff0c;分別是&#xff1a;ArrayBlockingQueue、Concurrent…

兩倍---C++

【問題描述】給定n個不同的正整數&#xff0c;你的任務是計算這些數里面有多少個數對滿足&#xff1a;數對中一個數是另一個數的兩倍&#xff0c;比如給定1 4 3 2 9 7 18 22&#xff0c;得到的答案是3&#xff0c;因為2是1的兩倍&#xff0c;4是2的兩倍&#xff0c;18是9的兩倍…

java bitset_Java BitSet cardinality()方法與示例

java bitsetBitSet類cardinality()方法 (BitSet Class cardinality() method) cardinality() method is available in java.util package. cardinality()方法在java.util包中可用。 cardinality() method is used to return the cardinality (i.e. the number of bits is set t…

LeetCode: Merge k Sorted Lists

自己寫的太復雜了&#xff0c;一開始想的是給開始的lists頭們排序&#xff0c;然后從這個序列的第一個抽出來&#xff0c;然后再重新用二分法進行排序&#xff0c;不過這個方法large超時了&#xff0c;看了網上的發現還是用很土地方法用一個for循環從前兩個開始merge到最后&…

JAVA 取得當前目錄的路徑

在寫java程序時不可避免要獲取文件的路徑...總結一下,遺漏的隨時補上 1.可以在servlet的init方法里 String path getServletContext().getRealPath("/"); 這將獲取web項目的全路徑 例如 :E:/eclipseM9/workspace/tree/ tree是我web項目的根目錄 2.你也可以隨時在任意…

golang mysql curd_Go 語言操作 MySQL 之 CURD 操作

本文轉載于SegmentFault社區作者&#xff1a;Meng小羽MySQL 是目前開發中最常見的關系型數據庫&#xff0c;使用 Go 語言進行操控數據庫需要使用 Go 自帶database/sql和驅動go-sql-driver/mysql來實現。創建好 Go 項目&#xff0c;需要引用驅動依賴&#xff1a;go get -u githu…

02.1-元素定位(find)

常用的一些方法 一、導包 from selenium import webdriver二、打開火狐&#xff08;空白頁&#xff09; b webdriver.Firefox()三、跳轉到指定的網站 b.get(https://www.baidu.com/)四、將瀏覽器頁面最大化 b.maximize_window()五、通過F12可查看當前的貼吧為超鏈接形式 …

快速傅里葉變換(FFT)——按時間抽取DIT的基

目錄【1】前言1、DIF計算量2、利用性質改善【2】公式推導1、N 到 2*N/2a、分解原序列b、分解后的DFT變換c、一系列化簡操作之后d、蝶形信號流e、計算量總結2、N/2 到 2*N/4a、分解X2(k)序列b、蝶形信號流&#xff08;2列&#xff09;3、N/4 到 2*N/8a、蝶形信號流&#xff08;3…

Python字符串| 帶示例的format()方法

String.format()方法 (String.format() Method) format() method is used to format the string (in other words - we can say to achieve the functionality like printf() in C language). format()方法用于格式化字符串(換句話說&#xff0c;我們可以說實現了C語言中類似于…

PLSQL Developer使用技巧

1、PL/SQL Developer記住登陸密碼在使用PL/SQL Developer時&#xff0c;為了工作方便希望PL/SQL Developer記住登錄Oracle的用戶名和密碼&#xff1b;設置方法&#xff1a;PL/SQL Developer 7.1.2 ->tools->Preferences->Oracle->Logon History &#xff0c; “St…

3月份的總結

租房子找了個黑中介&#xff0c;各種扣錢&#xff0c;合租的違約了&#xff0c;押金不要了直接一走了之&#xff0c;水費我們承擔&#xff0c;中介這會兒又把責任推得一干二凈&#xff0c;還耍小聰明&#xff0c;非說我是兩個人住的&#xff0c;各種費用要交兩份。。。我一時氣…