本文主要參考opencv例程,該方法是比較常見的分割方式,先将彩色圖像轉成灰階圖像,然後用合适的門檻值進行二值話即可得到圖像輪廓,可供進一步處理使用。
圖像門檻值化分割是一種傳統的最常用的圖像分割方法,因其實作簡單、計算量小、性能較穩定而成為圖像分割中最基本和應用最廣泛的分割技術。它特别适用于目标和背景占據不同灰階級範圍的圖像。它不僅可以極大的壓縮資料量,而且也大大簡化了分析和處理步驟,是以在很多情況下,是進行圖像分析、特征提取與模式識别之前的必要的圖像預處理過程。圖像門檻值化的目的是要按照灰階級,對像素集合進行一個劃分,得到的每個子集形成一個與現實景物相對應的區域,各個區域内部具有一緻的屬性,而相鄰區域不具有這種一緻屬性。這樣的劃分可以通過從灰階級出發選取一個或多個門檻值來實作
主要代碼如下:
int thresholdSeg(IplImage *src)
{
IplImage *tmp = 0; //定義臨時圖像指針
IplImage *src_back = 0; //定義源圖像背景指針
IplImage *dst_gray = 0; //定義源檔案去掉背景後的目标灰階圖像指針
IplImage *dst_bw = 0; //定義源檔案去掉背景後的目标二值圖像指針
IplImage *dst_contours = 0; //定義輪廓圖像指針
IplConvKernel *element = 0; //定義形态學結構指針
int Number_Object =0; //定義目标對象數量
int contour_area_tmp = 0; //定義目标對象面積臨時寄存器
int contour_area_sum = 0; //定義目标所有對象面積的和
int contour_area_ave = 0; //定義目标對象面積平均值
int contour_area_max = 0; //定義目标對象面積最大值
if(NULL == src )
return -1;
if(src->nChannels !=1)
{
cout<<"It's not gray image!"<<endl;
return -1;
}
CvMemStorage *stor = 0;
CvSeq * cont = 0;
CvContourScanner contour_scanner;
CvSeq * a_contour= 0;
//2.估計圖像背景
tmp = cvCreateImage( cvGetSize(src), src->depth, src->nChannels);
src_back = cvCreateImage( cvGetSize(src), src->depth, src->nChannels);
//建立結構元素
element = cvCreateStructuringElementEx( 4, 4, 1, 1, CV_SHAPE_ELLIPSE, 0);
//用該結構對源圖象進行數學形态學的開操作後,估計背景亮度
cvErode( src, tmp, element, 10);//腐蝕
cvDilate( tmp, src_back, element, 10);//膨脹
//3.從源圖象中減區背景圖像
dst_gray = cvCreateImage( cvGetSize(src), src->depth, src->nChannels);
cvSub( src, src_back, dst_gray, 0);
//4.使用閥值操作将圖像轉換為二值圖像
dst_bw = cvCreateImage( cvGetSize(src), src->depth, src->nChannels);
cvThreshold( dst_gray, dst_bw ,50, 255, CV_THRESH_BINARY ); //取閥值為50把圖像轉為二值圖像
//cvAdaptiveThreshold( dst_gray, dst_bw, 255, CV_ADAPTIVE_THRESH_MEAN_C, CV_THRESH_BINARY, 3, 5 );
//5.檢查圖像中的目标對象數量
stor = cvCreateMemStorage(0);
cont = cvCreateSeq(CV_SEQ_ELTYPE_POINT, sizeof(CvSeq), sizeof(CvPoint), stor);
Number_Object = cvFindContours( dst_bw, stor, &cont, sizeof(CvContour),
CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, cvPoint(0,0) ); //找到所有輪廓
printf("Number_Object: %d\n", Number_Object);
//6.計算圖像中對象的統計屬性
dst_contours = cvCreateImage( cvGetSize(src), src->depth, src->nChannels);
cvThreshold( dst_contours, dst_contours ,0, 255, CV_THRESH_BINARY ); //在畫輪廓前先把圖像變成白色
for(;cont;cont = cont->h_next)
{
cvDrawContours( dst_contours, cont, CV_RGB(255, 0, 0), CV_RGB(255, 0, 0), 0, 1, 8, cvPoint(0, 0) ); //繪制目前輪廓
contour_area_tmp = fabs(cvContourArea( cont, CV_WHOLE_SEQ )); //擷取目前輪廓面積
if( contour_area_tmp > contour_area_max )
{
contour_area_max = contour_area_tmp; //找到面積最大的輪廓
}
contour_area_sum += contour_area_tmp; //求所有輪廓的面積和
}
contour_area_ave = contour_area_sum/ Number_Object; //求出所有輪廓的平均值
printf("contour_area_ave: %d\n", contour_area_ave );
printf("contour_area_max: %d\n", contour_area_max );
cvCopy(dst_contours,src,0);
cvReleaseImage(&tmp);
cvReleaseImage(&src_back);
cvReleaseImage(&dst_gray);
cvReleaseImage(&dst_bw);
cvReleaseImage(&dst_contours);
cvReleaseMemStorage(&stor);
system("pause");
return 0;
}
原圖像:
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIyVGduV2QvwVe0lmdhJ3ZvwFM38CXlZHbvN3cpR2Lc1TPB10QGtWUCpEMJ9CXsxWam9CXwADNvwVZ6l2c052bm9CXUJDT1wkNhVzLcRnbvZ2LcZXUYpVd1kmYr50MZV3YyI2cKJDT29GRjBjUIF2LcRHelR3LcJzLctmch1mclRXY39zM0cDOyEzM2EzNxITM1EDMy8CX0Vmbu4GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.jpg)
分割後圖像: