您的位置:首页 > 运维架构

调用OpenCV的cvFindContours方法获取图像边界

2012-04-20 10:36 686 查看
//得到图像的外边框

procedure TFrmMain.Button3Click(Sender: TObject);

var

oImg, oImg2: PIplImage;

contours: PCvSeq;

p: Pchar;

pSeq: PCvSeq;

oMem: TCvMemStorage;

I, nCnt, area: Integer;

stor: pCvMemStorage;

cont: pCvSeq;

rr:CvRect;

sFileName: string;

begin

OpenDialog1.InitialDir := ExtractFilePath(ParamStr(0)) + 'pic';

if OpenDialog1.Execute then

sFileName := OpenDialog1.FileName

else

Exit;

stor := cvCreateMemStorage(0);

cont := cvCreateSeq(0, sizeof(CvSeq), sizeof(CvPoint), stor);

oImg := cvLoadImage(PChar(sFileName), CV_LOAD_IMAGE_GRAYSCALE);

oImg2 := cvCreateImage(cvSize_(oImg.Width, oImg.Height), IPL_DEPTH_8U, 1);

cvSmooth(oImg, oImg, CV_MEDIAN, 5, 5);

cvAdaptiveThreshold(oImg, oImg, 255, CV_ADAPTIVE_THRESH_MEAN_C, CV_THRESH_BINARY, StrToInt(Edit1.Text), StrToInt(Edit2.Text));

//cvSaveImage('C:\1.bmp', oImg);

cvNamedWindow('Example1', CV_WINDOW_AUTOSIZE);

cvNamedWindow('Example2', CV_WINDOW_AUTOSIZE);

//侵蚀

cvErode(oImg, oImg, 0, 2);

//查找轮廓

(*mode   检索模式,可取值如下:   

CV_RETR_EXTERNAL:只检索最外面的轮廓;   

CV_RETR_LIST:检索所有的轮廓,并将其放入list中;   

CV_RETR_CCOMP:检索所有的轮廓,并将他们组织为两层:顶层是各部分的外部边界,第二层是空洞的边界;   

CV_RETR_TREE:检索所有的轮廓,并重构嵌套轮廓的整个层次。

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检索模式能使用此方法。

*)

//nCnt := cvFindContours(oImg, stor, @cont, sizeof(CvContour), CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, cvPoint_(0,0) ); //找到所有轮廓

nCnt := cvFindContours(oImg, stor, @cont, SizeOf(CvContour), CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, cvPoint_(0, 0));

while cont <> nil do

begin

rr := pCvContour(cont).Rect;

area:=cont.total;

cvRectangle(oImg2, cvPoint_(rr.x, rr.y), cvPoint_(rr.x + rr.width, rr.y + rr.height), CV_RGB(255,0,0), 2, 8, 0);

//count := count + 1;

cont := cont.h_next;

end;

cvShowImage('Example1', oImg);

cvShowImage('Example2', oImg2);

cvWaitKey(0);

cvDestroyWindow('Example1');

cvDestroyWindow('Example2');

cvReleaseImage(oImg);

end;

//使用Freeman链码进行边界绘制.

//设置cvFindContours函数的method为CV_CHAIN_CODE,可以获取到freeman链码,从而可得到所有的边界点,尝试使用cvStartReadChainPoints和cvReadChainPoint读取其中的点总是报错,最后找到一种替代的方案,先进行多边形逼近,在将Seq转换为数组,读取到逼近的多边形点.

procedure TFrmMain.BtnFreeManClick(Sender: TObject);

var

oImg, oImg2, oImg3: PIplImage;

contours: PCvSeq;

p: Pchar;

pSeq: PCvSeq;

oMem: TCvMemStorage;

I, nCnt, nMaxArea, total: Integer;

stor: pCvMemStorage;

cont: pCvSeq;

pnt:CvPoint;

sFileName: string;

pChain: PCvChain;

nDistance: Integer;

nDelay: Integer;

IsDeflection: Boolean;

seqReader: CvSeqReader;

pChainReader: PCvChainPtReader;

chainReader: CvChainPtReader;

c: PCvChain;

arr: TIntegerArr;

begin

nMaxArea := 0;

OpenDialog1.InitialDir := ExtractFilePath(ParamStr(0)) + 'pic';

if OpenDialog1.Execute then

sFileName := OpenDialog1.FileName

else

Exit;

nDelay := THelp.GetSysTickCount64;

stor := cvCreateMemStorage(0);

cont := cvCreateSeq(0, sizeof(CvSeq), sizeof(CvPoint), stor);

oImg := cvLoadImage(PChar(sFileName), CV_LOAD_IMAGE_GRAYSCALE);

oImg3 := cvCreateImage(cvSize_(oImg.Width, oImg.Height), oImg.Depth, oImg.NChannels);

//oImg2 := cvCreateImage(cvSize_(oImg.Width, oImg.Height), IPL_DEPTH_8U, 1);

oImg2 := cvCloneImage(oImg);

//cvSmooth(oImg, oImg, CV_MEDIAN, 5, 5);

cvAdaptiveThreshold(oImg, oImg3, 255, CV_ADAPTIVE_THRESH_MEAN_C, CV_THRESH_BINARY, 11, 5);

cvCanny(oImg, oImg, StrToInt(EdtCanny_P1.Text), StrToInt(EdtCanny_P2.Text));

cvSaveImage('C:\1.bmp', oImg3);

//侵蚀

//cvErode(oImg, oImg, 0, 5);

//cvSmooth(oImg, oImg, CV_MEDIAN, 15, 15);

cvSaveImage('C:\2.bmp', oImg);

cvNamedWindow('Example1', CV_WINDOW_AUTOSIZE);

cvNamedWindow('Example2', CV_WINDOW_AUTOSIZE);

pChain := nil;

nCnt := cvFindContours(oImg, stor, @pChain, SizeOf(CvChain), CV_RETR_LIST, CV_CHAIN_CODE, cvPoint_(0,0));

cont := cvApproxChains(PCvSeq(pChain), stor, CV_CHAIN_APPROX_SIMPLE, 0, 0, 1); //多边形逼近

cvZero(oImg);

//可以调用cvDrawContours或下面的代码手动绘边界图

//cvDrawContours(oImg, cont, cvScalar_(255), cvScalar_(255), MaxInt, 1, 8, cvPoint_(0, 0));

//使用多边形逼近得到线段进行绘制图像

while cont <> nil do

begin

if cont.total > 2 then

begin

SetLength(arr, cont.total * 2);

cvCvtSeqToArray(cont, @arr[0], CvSlice_(0, CV_WHOLE_SEQ_END_INDEX));

for i := Low(arr) to High(arr) div 2 do

begin

if (i + 1) * 2 < High(arr) then

cvLine(oImg, cvPoint_(arr[i * 2], arr[i * 2 + 1]), cvPoint_(arr[(i + 1) * 2], arr[(i + 1) * 2 + 1]), CV_RGB(255, 255, 255), 1);

end;

end;

cont := cont.h_next;

end;

cvSaveImage('C:\2.bmp', oImg3);

cvShowImage('Example1', oImg);

cvShowImage('Example2', oImg3);

cvWaitKey(0);

cvReleaseImage(oImg);

cvReleaseImage(oImg2);

cvDestroyWindow('Example1');

cvDestroyWindow('Example2');

end;



原图

二值化图像

多边形逼近绘图


原图


多边形逼近绘图
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: