天天看點

基于opencv的門檻值分割

      本文主要參考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;

}

原圖像:

基于opencv的門檻值分割

分割後圖像:

基于opencv的門檻值分割