輪廓檢測:
輪廓檢測的原理通俗的說就是掏空內部點,比如原圖中有3*3的矩形點。那么就可以將中間的那一點去掉。
一.關鍵函數
1.1 cvFindContours
函數功能:對圖像進行輪廓檢測,這個函數將生成一條鏈表以保存檢測出的各個輪廓信息,並傳出指向這條鏈表表頭的指針。
函數原型:
int cvFindContours(
CvArr* image, 第一個參數表示輸入圖像,必須為一個8位的二值圖像
CvMemStorage* storage, 第二參數表示存儲輪廓的容器。為CvMemStorage類型,定義在OpenCV的\core\types_c.h中
CvSeq** first_contour, 第三個參數為輸出參數,這個參數將指向用來存儲輪廓信息的鏈表表頭
int header_size=sizeof(CvContour), 第四個參數表示存儲輪廓鏈表的表頭大小,當第六個參數傳入CV_CHAIN_CODE時,
要設置成sizeof(CvChain),其它情況統一設置成sizeof(CvContour)。
int mode= CV_RETR_LIST, 第五個參數為輪廓檢測的模式,有如下取值:
CV_RETR_EXTERNAL : 只檢索最外面的輪廓;
CV_RETR_LIST: 檢索所有的輪廓,並將其保存到一條鏈表當中;
CV_RETR_CCOMP: 檢索所有的輪廓,並將他們組織為兩層:頂層是各部分的外部邊界,第二層是空洞的邊界;
CV_RETR_TREE: 檢索所有的輪廓,並重構嵌套輪廓的整個層次;
int method= CV_CHAIN_APPROX_SIMPLE, 第六個參數用來表示輪廓邊緣的近似方法的,常用值如下所示:
CV_CHAIN_CODE: 以Freeman鏈碼的方式輸出輪廓,所有其他方法輸出多邊形(頂點的序列)。
CV_CHAIN_APPROX_SIMPLE: 壓縮水平的、垂直的和斜的部分,也就是,函數只保留他們的終點部分。
CvPoint offset=cvPoint(0,0) 第七個參數表示偏移量,比如你要從圖像的(100, 0)開始進行輪廓檢測,那么就傳入(100, 0)。
);
--->使用cvFindContours函數能檢測出圖像的輪廓,將輪廓繪制出來則需要另一函數——cvDrawContours來配合了。下面介紹cvDrawContours函數。
1.2 cvDrawContours
函數功能:在圖像上繪制外部和內部輪廓
函數原型:
void cvDrawContours(
CvArr *img, 第一個參數表示輸入圖像,函數將在這張圖像上繪制輪廓。
CvSeq* contour, 第二個參數表示指向輪廓鏈表的指針
CvScalar external_color,
CvScalar hole_color, 第三個參數和第四個參數表示顏色,繪制時會根據輪廓的層次來交替使用這二種顏色
int max_level, 第五個參數表示繪制輪廓的最大層數,如果是0,只繪制contour;如果是1,追加繪制和
contour同層的所有輪廓;如果是2,追加繪制比contour低一層的輪廓,以此類推;如果
值是負值,則函數並不繪制contour后的輪廓,但是將畫出其子輪廓,一直到abs(max_level) - 1層。
int thickness=1, 第六個參數表示輪廓線的寬度,如果為CV_FILLED則會填充輪廓內部
int line_type=8, 第七個參數表示輪廓線的類型。
CvPoint offset=cvPoint(0,0) 第八個參數表示偏移量,如果傳入(10,20),那繪制將從圖像的(10,20)處開始
);
// ConsoleApplication1.cpp : 定義控制台應用程序的入口點。 // #include "stdafx.h" #include "iostream" using namespace std; #include "opencv2/opencv.hpp" const char *pImagePath = "E:/C_VC_code/Text_Photo/girl005.jpg"; const char *pWindowsTitle = "原圖"; const char *pWindowsGrayTitle = "灰度圖"; const char *pWindowsBinaryTitle = "二值圖"; const char *pWindowsOutLineTitle = "輪廓圖"; const char *pWindowsToolBar = "閥值"; IplImage *pImage=NULL,*pGrayImage, *pBinaryImage, *pOutLineImage; CvMemStorage *pMemStorage; CvSeq *pSeq; int nLevels = 3; void functionCallback(int pos) { cvThreshold(pGrayImage, pBinaryImage, pos, 255, CV_THRESH_BINARY); cvFindContours(pBinaryImage, pMemStorage, &pSeq ,sizeof(CvContour), CV_RETR_TREE,CV_CHAIN_APPROX_SIMPLE,cvPoint(0,0)); cvDrawContours(pOutLineImage, pSeq, CV_RGB(0,255,255), CV_RGB(255,0,0), nLevels, 2, 2); cvShowImage(pWindowsBinaryTitle, pBinaryImage); cvShowImage(pWindowsOutLineTitle, pOutLineImage); } void main() { //SourceImage turn to GrayImage pImage = cvLoadImage(pImagePath, CV_LOAD_IMAGE_UNCHANGED); pGrayImage = cvCreateImage(cvGetSize(pImage), IPL_DEPTH_8U, 1); cvCvtColor(pImage, pGrayImage, CV_BGR2GRAY); //create window cvNamedWindow(pWindowsTitle, CV_WINDOW_AUTOSIZE); cvNamedWindow(pWindowsGrayTitle, CV_WINDOW_AUTOSIZE); cvNamedWindow(pWindowsBinaryTitle, CV_WINDOW_AUTOSIZE); cvNamedWindow(pWindowsOutLineTitle, CV_WINDOW_AUTOSIZE); //為二值圖創建滑動條 int nPos = 0; cvCreateTrackbar(pWindowsToolBar,pWindowsBinaryTitle,&nPos,100,functionCallback); //GrayImage turn into BinaryImage pBinaryImage = cvCreateImage(cvGetSize(pGrayImage), IPL_DEPTH_8U, 1); //檢索輪廓並返回檢測到的輪廓的個數 pMemStorage = cvCreateMemStorage(); pSeq = NULL; //Create and show OutLineImage pOutLineImage = cvCreateImage(cvGetSize(pBinaryImage), IPL_DEPTH_8U, 3); //填充成白色 cvRectangle(pOutLineImage, cvPoint(0,0),cvPoint(pImage->width,pImage->height), CV_RGB(255,255,255), CV_FILLED); cvDrawContours(pOutLineImage, pSeq, CV_RGB(0,255,255), CV_RGB(255,0,0), nLevels, 2); cvShowImage(pWindowsTitle, pImage); cvShowImage(pWindowsGrayTitle, pGrayImage); cvShowImage(pWindowsBinaryTitle, pBinaryImage); cvShowImage(pWindowsOutLineTitle, pOutLineImage); functionCallback(100); //destroy object and release space cvWaitKey(0); cvDestroyWindow(pWindowsTitle); cvDestroyWindow(pWindowsGrayTitle); cvDestroyWindow(pWindowsBinaryTitle); cvDestroyWindow(pWindowsOutLineTitle); cvReleaseImage(&pImage); cvReleaseImage(&pGrayImage); cvReleaseImage(&pBinaryImage); cvReleaseImage(&pOutLineImage); }