日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

图像孔洞填充与小连通域的删除

發布時間:2025/3/21 编程问答 48 豆豆
生活随笔 收集整理的這篇文章主要介紹了 图像孔洞填充与小连通域的删除 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

圖像孔洞填充與小連通域的刪除

?

cvFindContours

?從二值圖像中檢索輪廓,并返回檢測到的輪廓的個數。first_contour的值由函數填充返回,它的值將為第一個外輪廓的指針,當沒有輪廓被檢測到時為NULL。其它輪廓可以使用h_next和v_next連接,從first_contour到達。

int?cvFindContours(?CvArr*?image,?CvMemStorage*?storage,?CvSeq**?first_contour,???????????????????????????????????????????????????????????????????????????????????????????????

??????????????????int?header_size=sizeof(CvContour),?int?mode=CV_RETR_LIST,????????????????????????????????????????

??????????????????int?method=CV_CHAIN_APPROX_SIMPLE,?CvPoint?offset=cvPoint(0,0)?);?????????

image

8比特單通道的源二值圖像。非零像素作為1處理,0像素保存不變。從一個灰度圖像得到二值圖像的函數有:cvThreshold,cvAdaptiveThreshold和cvCanny。

storage

返回輪廓的容器。

first_contour

輸出參數,用于存儲指向第一個外接輪廓。

header_size

header序列的尺寸.如果選擇method?=?CV_CHAIN_CODE,?則header_size?>=?sizeof(CvChain);其他,則

header_size?>=?sizeof(CvContour)。

mode

CV_RETR_EXTERNAL:只檢索最外面的輪廓;

CV_RETR_LIST:檢索所有的輪廓,并將其放入list中;

CV_RETR_CCOMP:檢索所有的輪廓,并將他們組織為兩層:頂層是各部分的外部邊界,第二層是空洞的邊界;

CV_RETR_TREE:檢索所有的輪廓,并重構嵌套輪廓的整個層次。

?

藍色表示v_next,綠色表示h_next

method

邊緣近似方法(除了CV_RETR_RUNS使用內置的近似,其他模式均使用此設定的近似算法)。可取值如下:

CV_CHAIN_CODE:以Freeman鏈碼的方式輸出輪廓,所有其他方法輸出多邊形(頂點的序列)。

CV_CHAIN_APPROX_NONE:將所有的連碼點,轉換成點。

CV_CHAIN_APPROX_SIMPLE:壓縮水平的、垂直的和斜的部分,也就是,函數只保留他們的終點部分。

CV_CHAIN_APPROX_TC89_L1,CV_CHAIN_APPROX_TC89_KCOS:使用the?flavors?of?Teh-Chin?chain近似算法

的一種。

CV_LINK_RUNS:通過連接水平段的1,使用完全不同的邊緣提取算法。使用CV_RETR_LIST檢索模式能使用此方法。

offset

偏移量,用于移動所有輪廓點。當輪廓是從圖像的ROI提取的,并且需要在整個圖像中分析時,這個參數將很有用。

討論部分cvDrawContours中的案例顯示了任何使用輪廓檢測連通區域。輪廓可以用于形狀分析和目標識別——可以參考文件夾OpenCV?sample中的squares.c

?

?

cvDrawContours

cvDrawContours:在圖像上繪制外部和內部輪廓

函數cvDrawContours用于在圖像上繪制外部和內部輪廓。當thickness?>=?0?時,繪制輪廓線;否則填充由輪廓包圍的部分。

void?cvDrawContours(?CvArr?*img,?CvSeq*?contour,CvScalar?external_color,?CvScalar?hole_color,??????????????????????????????????????????????????????

??????????????????????int?max_level,?int?thickness=1,?int?line_type=8,?CvPoint?offset=cvPoint(0,0)?);???????????????????????????????????????????????????????????????????????????????????????????????????

Img?要在其上繪制輪廓的圖像。和在其他繪圖函數里一樣,輪廓是ROI的修剪結果。

Contour??指向第一個輪廓的指針。

external_color??外輪廓的顏色。

hole_color????內輪廓的顏色。??????

max_level???畫輪廓的最大層數。如果是0,只繪制contour;如果是1,將繪制contour后和contour同層的所有??

????????????輪廓;如果是2,繪制contour后所有同層和低一層的輪廓,以此類推;如果值是負值,則函數并不

????????????繪制contour后的輪廓,但是將畫出其子輪廓,一直到abs(max_level)?-?1層。

thickness

繪制輪廓線的寬度。如果為負值(例如,等于CV_FILLED),則contour內部將被繪制。

line_type

輪廓線段的類型,具體查看cvLine的描述。

offset

按給定值移動所有點的坐標。

?

?

cvContourArea

double?cvContourArea(?const?CvArr*?contour,?CvSliceslice=CV_WHOLE_SEQ?);
contour:輪廓(頂點的序列或數組)。
slice:感興趣區輪廓部分的起點和終點,默認計算整個輪廓的面積。
函數cvContourArea計算整個或部分輪廓的面積。在計算部分輪廓的情況時,由輪廓弧線和連接兩端點的弦
圍成的區域總面積被計算

?

?

?

  • ?
  • ?
  • ?
  • #include <stdio.h>

  • #include <cv.h>

  • #include <cxcore.h>

  • #include <highgui.h>

  • ?
  • ?
  • // 內輪廓填充

  • // 參數:

  • // 1. pBinary: 輸入二值圖像,單通道,位深IPL_DEPTH_8U。

  • // 2. dAreaThre: 面積閾值,當內輪廓面積小于等于dAreaThre時,進行填充。

  • void FillInternalContours(IplImage *pBinary, double dAreaThre)

  • {

  • double dConArea;

  • CvSeq *pContour = NULL; //創建一序列

  • CvSeq *pConInner = NULL;

  • CvMemStorage *pStorage = NULL; //用來創建一個內存存儲器,來統一管理各種動態對象的內存,比如說序列,這個函數返回一個新創建的內存存儲器指針。

  • ?
  • ?
  • // 執行條件

  • if (pBinary)

  • {

  • // 查找所有輪廓

  • pStorage = cvCreateMemStorage(0); //創建一個內存存儲器,為0時內存塊默認大小為64k,申請一塊內存來存儲找到的輪廓序列

  • cvFindContours(pBinary, pStorage, &pContour, sizeof(CvContour), CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE); //從二值圖像中檢索輪廓,并返回檢測到的輪廓的個數

  • // 源二值圖、容器、第一個外輪廓指針、head序列大小、輪廓分兩層、邊緣只保留終點

  • cvDrawContours(pBinary, pContour, CV_RGB(255, 255, 255), CV_RGB(255, 255, 255), 2, CV_FILLED, 8, cvPoint(0, 0)); //在圖像上繪制外部和內部輪廓

  • // 源二值圖、第一個輪廓的指針、外輪廓的顏色、內輪廓的顏色、畫兩層輪廓、繪制輪廓線的寬度、輪廓線段的類型、按給定值移動所有點的坐標。

  • // 外輪廓循環

  • int wai = 0;

  • int nei = 0;

  • for (; pContour != NULL; pContour = pContour->h_next) //對檢測到的輪廓進行逐一處理,h_next為下一個輪廓

  • {

  • wai++;

  • // 內輪廓循環

  • for (pConInner = pContour->v_next; pConInner != NULL; pConInner = pConInner->h_next)

  • {

  • nei++;

  • dConArea = fabs(cvContourArea(pConInner, CV_WHOLE_SEQ));// 內輪廓面積

  • printf("%f\n", dConArea);

  • if (dConArea <= dAreaThre) //只處理滿足條件的輪廓,不滿足條件的輪廓扔掉

  • {

  • cvDrawContours(pBinary, pConInner, CV_RGB(255, 255, 255), CV_RGB(255, 255, 255), 0, CV_FILLED, 8, cvPoint(0, 0));

  • } // 源二值圖、第一個輪廓的指針、外輪廓的顏色、內輪廓的顏色、畫第一個外輪廓、繪制輪廓線的寬度、輪廓線段的類型、按給定值移動所有點的坐標。

  • }

  • }

  • printf("wai = %d, nei = %d", wai, nei);

  • cvReleaseMemStorage(&pStorage);

  • pStorage = NULL;

  • }

  • }

  • ?
  • int Otsu(IplImage* src)

  • {

  • int height=src->height;

  • int width=src->width;

  • ?
  • //histogram

  • float histogram[256] = {0};

  • for(int i=0; i < height; i++)

  • {

  • unsigned char* p=(unsigned char*)src->imageData + src->widthStep * i;

  • for(int j = 0; j < width; j++)

  • {

  • histogram[*p++]++;

  • }

  • }

  • //normalize histogram

  • int size = height * width;

  • for(int i = 0; i < 256; i++)

  • {

  • histogram[i] = histogram[i] / size;

  • }

  • ?
  • //average pixel value

  • float avgValue=0;

  • for(int i=0; i < 256; i++)

  • {

  • avgValue += i * histogram[i]; //整幅圖像的平均灰度

  • }

  • ?
  • int threshold;

  • float maxVariance=0;

  • float w = 0, u = 0;

  • for(int i = 0; i < 256; i++)

  • {

  • w += histogram[i]; //假設當前灰度i為閾值, 0~i 灰度的像素(假設像素值在此范圍的像素叫做前景像素) 所占整幅圖像的比例

  • u += i * histogram[i]; // 灰度i 之前的像素(0~i)的平均灰度值: 前景像素的平均灰度值

  • ?
  • float t = avgValue * w - u;

  • float variance = t * t / (w * (1 - w) );

  • if(variance > maxVariance)

  • {

  • maxVariance = variance;

  • threshold = i;

  • }

  • }

  • ?
  • return threshold;

  • }

  • ?
  • ?
  • ?
  • void DeleteIslet(IplImage* pic1,IplImage** pic0)

  • {

  • /************刪除二值化圖像中面積較小的連通域****************************/

  • CvSeq* contour = NULL;

  • double minarea =300.0;

  • double tmparea = 0.0;

  • ?
  • CvMemStorage* storage = cvCreateMemStorage(0);

  • ?
  • IplImage* img_Clone=cvCloneImage(pic1);

  • //訪問二值圖像每個點的值

  • uchar *pp;

  • IplImage* img_dst = cvCreateImage(cvGetSize(pic1),IPL_DEPTH_8U,1);

  • ?
  • //------------搜索二值圖中的輪廓,并從輪廓樹中刪除面積小于某個閾值minarea的輪廓-------------//

  • CvScalar color = cvScalar(255,0,0);//CV_RGB(128,0,0);

  • CvContourScanner scanner = NULL;

  • scanner = cvStartFindContours(pic1,storage,sizeof(CvContour),CV_RETR_CCOMP,CV_CHAIN_APPROX_NONE,cvPoint(0,0));

  • //開始遍歷輪廓樹

  • CvRect rect;

  • while (contour==cvFindNextContour(scanner))

  • {

  • tmparea = fabs(cvContourArea(contour));

  • rect = cvBoundingRect(contour,0);

  • if (tmparea < minarea/*||tmparea>4900*/)

  • {

  • ?
  • //當連通域的中心點為黑色時,而且面積較小則用白色進行填充

  • pp=(uchar*)(img_Clone->imageData + img_Clone->widthStep*(rect.y+rect.height/2)+rect.x+rect.width/2);

  • if (pp[0]==0)

  • {

  • for(int y = rect.y;y<rect.y+rect.height;y++)

  • {

  • for(int x =rect.x;x<rect.x+rect.width;x++)

  • {

  • pp=(uchar*)(img_Clone->imageData + img_Clone->widthStep*y+x);

  • ?
  • if (pp[0]==0)

  • {

  • pp[0]=255;

  • }

  • }

  • }

  • }

  • ?
  • }

  • }

  • ?
  • *pic0=img_Clone;

  • }

  • ?
  • ?
  • ?
  • ?
  • ?
  • ?
  • ?
  • ?
  • int main( )

  • {

  • IplImage* oringin=cvLoadImage("test.bmp",1);

  • IplImage* pic1=cvLoadImage("test.bmp",0);

  • IplImage* pic2=NULL;

  • DeleteIslet(pic1,&pic2); //刪除小聯通域

  • ?
  • IplImage* pic3=cvCloneImage(pic2); //取反再刪除

  • cvNot(pic2,pic3);

  • IplImage* pic4=NULL;

  • DeleteIslet(pic3,&pic4);

  • ?
  • /**************孔洞填充*********************/

  • IplImage* pic5 = cvCreateImage(cvGetSize(pic4), 8, 1);

  • int thresh = Otsu(pic4);

  • cvThreshold(pic4,pic5, thresh, 255, CV_THRESH_BINARY);

  • ?
  • FillInternalContours(pic5, 200);

  • ?
  • IplImage* pic6 = cvCreateImage(cvGetSize(pic5), 8, 1);

  • cvNot(pic5,pic6);

  • ?
  • //cvSaveImage("out2.bmp",pic6);

  • ?
  • cvNamedWindow("oringin");

  • cvShowImage("oringin", oringin);

  • ?
  • cvNamedWindow("刪除小聯通域");

  • cvShowImage("刪除小聯通域", pic2);

  • ?
  • cvNamedWindow("孔洞填充");

  • cvShowImage("孔洞填充", pic6);

  • ?
  • cvWaitKey(0);

  • ?
  • cvDestroyWindow( "oringin" );

  • cvDestroyWindow( "刪除小聯通域" );

  • cvDestroyWindow( "孔洞填充" );

  • cvReleaseImage(&oringin);

  • cvReleaseImage(&pic2);

  • cvReleaseImage(&pic6);

  • ?
  • return 0;

  • ?
  • }

  • ?

    總結

    以上是生活随笔為你收集整理的图像孔洞填充与小连通域的删除的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。