利用opencv逼近二值圖像的邊界點,並過濾不需要的邊界,達到尋邊效果

来源:互联网 发布:淘宝千里眼是什么 编辑:程序博客网 时间:2024/05/22 06:10
http://blog.csdn.net/c2716266/article/details/7191460 

二值化圖像;

利用黑白像素值求差,得到邊緣點;

過濾邊緣點找到合適區域;

利用cvFitLine2D擬合線。

 

做的比較粗糙,搜尋時間在10ms左右,希望有研究opencv的朋友斧正。

效果預覽:

 

[cpp] view plaincopy
  1. void CvProcess::FindLine(  
  2.                          IplImage* orgImg ,//原始圖像  
  3.                          IplImage*runImg,//顯示用圖像  
  4.                          CvRect rec,//roi  
  5.                          int thredValue,//二值化閾值  
  6.                          int lineAccuracy,//搜索精度  
  7.                          int SearchDirection,//搜索方向  
  8.                          int EdgePolarity)//搜索方式 黑到白 白到黑  
  9.   
  10. {     
  11.     cvCopy(orgImg,runImg);//原始圖像拷貝到顯示圖像用於顯示  
  12.     IplImage* thrdImg = cvCreateImage(//創建一個單通道二值圖像用於各種處理  
  13.         cvSize(orgImg->width,orgImg->height),   
  14.         IPL_DEPTH_8U,   
  15.         1);   
  16.     //將原始圖像轉換為單通道灰度圖像  
  17.     cvCvtColor(runImg,thrdImg,CV_BGR2GRAY);  
  18.     //二值化處理  
  19.     cvThreshold(              
  20.         thrdImg,  
  21.         thrdImg,  
  22.         thredValue,  
  23.         255,  
  24.         CV_THRESH_BINARY);  
  25.   
  26.     //  cvNamedWindow("");  
  27.     //  cvShowImage("",thrdImg);      
  28.     if(rec.width>0&&rec.width<IMAGE_WIDTH&&rec.height>0&&rec.width<IMAGE_HEIGHT)//判斷是否有適合的ROI區域  
  29.     {   //設置ROI  
  30.         cvSetImageROI(runImg,rec);  
  31.         cvSetImageROI(thrdImg,rec);       
  32.   
  33.         //搜索邊界  
  34.         CvPoint2D32f *EdgePoint2D = //用於存儲搜索到的所有邊界點  
  35.             (CvPoint2D32f *)malloc((IMAGE_HEIGHT*IMAGE_WIDTH) * sizeof(CvPoint2D32f));  
  36.         CvPoint2D32f *RelEdgePoint2D =//用於存儲搜索到的正確的點  
  37.             (CvPoint2D32f *)malloc((IMAGE_HEIGHT*IMAGE_WIDTH) * sizeof(CvPoint2D32f));  
  38.         int EdgePoint2DCount=0;//點計數  
  39.         int RelEdgePoint2DCount=0;  //真實點計數   
  40.         float *line = new float[4]; //用於畫逼近線  
  41.         byte ftData=0,secData=0;    //搜索邊界點所需資源  
  42.         //得到ROI區域內的搜索線  
  43.         std::vector<CLine> searchlines = GetRecLines(rec,lineAccuracy,SearchDirection);  
  44.         switch(SearchDirection)//搜索方向  
  45.         {  
  46.         case TB :     
  47.             //上到下縱向搜索  
  48.             for (int i=0;i<thrdImg->roi->width;i++)  
  49.             {  
  50.                 for (int j=0;j<thrdImg->roi->height-1;j++)  
  51.                 {   //上下搜索所有的差值大於200的點  
  52.                     ftData=CV_IMAGE_ELEM(thrdImg,uchar,thrdImg->roi->yOffset+j,thrdImg->roi->xOffset+i);//利用宏直接得到結果       
  53.                     //ftData=(thrdImg->imageData + i * thrdImg->widthStep)[j];//注意這裡是 寬度用的是 widthStep 而不是 width  
  54.                     secData=CV_IMAGE_ELEM(thrdImg,uchar,thrdImg->roi->yOffset+j+1,thrdImg->roi->xOffset+i);       
  55.                     switch(EdgePolarity)  
  56.                     {  
  57.                     case B2W:  
  58.                         if(secData-ftData>200)//黑到白  
  59.                         {  
  60.                             for(int n=0;n<searchlines.size();n++)//搜索在搜索線上的點  
  61.                             {  
  62.                                 if (searchlines[n].PTS.x==i&&searchlines[n].PTS.y<j  
  63.                                     &&searchlines[n].PTE.y>j)  
  64.                                 {  
  65.                                     EdgePoint2D[EdgePoint2DCount]=cvPoint2D32f(i,j);      
  66.                                 }  
  67.                             }                                     
  68.                             if (EdgePoint2DCount>0)//大於2點時比較  
  69.                             {                             
  70.                                 bool realPoint=TRUE;  
  71.                                 //刪除X坐標相同的縱向點,減少逼近時誤判幾率  
  72.                                 for (int m=1;m<=EdgePoint2DCount;m++)  
  73.                                 {     
  74.                                     if(EdgePoint2D[EdgePoint2DCount].x == EdgePoint2D[EdgePoint2DCount-m].x)  
  75.                                     {  
  76.                                         realPoint=FALSE;                             
  77.                                     }  
  78.                                 }                             
  79.                                 if(realPoint)//得到非重復點並畫出  
  80.                                 {                             
  81.                                     RelEdgePoint2D[RelEdgePoint2DCount]=cvPoint2D32f(i,j);  
  82.                                     cvCircle(runImg,cvPoint(i,j),  
  83.                                         1,CV_RGB(255,0,0),2, CV_AA,0);  //畫點  
  84.                                     RelEdgePoint2DCount++;                                                        
  85.                                 }  
  86.                             }     
  87.                             EdgePoint2DCount++;  
  88.                         }  
  89.                         break;  
  90.   
  91.                     case W2B:  
  92.                         if(ftData-secData>200)//白到黑  
  93.                         {  
  94.                             for(int n=0;n<searchlines.size();n++)//搜索在搜索線上的點  
  95.                             {  
  96.                                 if (searchlines[n].PTS.x==i&&searchlines[n].PTS.y<j  
  97.                                     &&searchlines[n].PTE.y>j)  
  98.                                 {  
  99.                                     EdgePoint2D[EdgePoint2DCount]=cvPoint2D32f(i,j);      
  100.                                 }  
  101.                             }                                     
  102.                             if (EdgePoint2DCount>0)//大於2點時比較  
  103.                             {                             
  104.                                 bool realPoint=TRUE;  
  105.                                 //刪除X坐標相同的縱向點,減少逼近時誤判幾率  
  106.                                 for (int m=1;m<=EdgePoint2DCount;m++)  
  107.                                 {     
  108.                                     if(EdgePoint2D[EdgePoint2DCount].x == EdgePoint2D[EdgePoint2DCount-m].x)  
  109.                                     {  
  110.                                         realPoint=FALSE;                             
  111.                                     }  
  112.                                 }                             
  113.                                 if(realPoint)//得到非重復點並畫出  
  114.                                 {                             
  115.                                     RelEdgePoint2D[RelEdgePoint2DCount]=cvPoint2D32f(i,j);  
  116.                                     cvCircle(runImg,cvPoint(i,j),  
  117.                                         1,CV_RGB(255,0,0),2, CV_AA,0);  //畫點  
  118.                                     RelEdgePoint2DCount++;                                                        
  119.                                 }  
  120.                             }     
  121.                             EdgePoint2DCount++;  
  122.                         }  
  123.                         break;  
  124.                     }  
  125.                 }  
  126.             }                             
  127.             if(RelEdgePoint2DCount>2)//當找到的點大於2時在搜尋逼近線  
  128.             {   //找出逼近線                   
  129.                 cvFitLine2D(RelEdgePoint2D,RelEdgePoint2DCount, CV_DIST_L1,NULL,0.01,0.01,line);      
  130.                 CvPoint FirstPoint;//起點  
  131.                 CvPoint LastPoint;//終點  
  132.                 FirstPoint.x=int (line[2]-1000*line[0]);  
  133.                 FirstPoint.y=int (line[3]-1000*line[1]);  
  134.                 LastPoint.x=int (line[2]+1000*line[0]);  
  135.                 LastPoint.y=int (line[3]+1000*line[1]);  
  136.                 cvLine( runImg, FirstPoint, LastPoint, CV_RGB(255,0,0), 1, CV_AA);//畫出逼近線         
  137.             }  
  138.             break;  
  139.   
  140.         case LR :  
  141.             //左到右橫向搜索  
  142.             for (int j=0;j<thrdImg->roi->height;j++)         
  143.             {  
  144.                 for (int i=0;i<thrdImg->roi->width-1;i++)  
  145.                 {  
  146.                     ftData=CV_IMAGE_ELEM(thrdImg,uchar,thrdImg->roi->yOffset+j,thrdImg->roi->xOffset+i);//利用宏直接得到結果       
  147.                     //ftData=(thrdImg->imageData + i * thrdImg->widthStep)[j];//注意這裡是 寬度用的是 widthStep 而不是 width  
  148.                     secData=CV_IMAGE_ELEM(thrdImg,uchar,thrdImg->roi->yOffset+j,thrdImg->roi->xOffset+i+1);       
  149.                     switch(EdgePolarity)  
  150.                     {  
  151.                     case B2W:  
  152.                         if(secData-ftData>200)//黑到白  
  153.                         {  
  154.                             for(int n=0;n<searchlines.size();n++)//point in searchlines  
  155.                             {  
  156.                                 if (searchlines[n].PTS.y==j&&searchlines[n].PTS.x<i  
  157.                                     &&searchlines[n].PTE.x>i)  
  158.                                 {  
  159.                                     EdgePoint2D[EdgePoint2DCount]=cvPoint2D32f(i,j);      
  160.                                 }  
  161.                             }                                     
  162.                             if (EdgePoint2DCount>0)//大於2點時比較  
  163.                             {                             
  164.                                 bool realPoint=TRUE;  
  165.                                 for (int m=1;m<=EdgePoint2DCount;m++)//刪除y坐標相同的橫向點  
  166.                                 {     
  167.                                     if(EdgePoint2D[EdgePoint2DCount].y == EdgePoint2D[EdgePoint2DCount-m].y)  
  168.                                     {  
  169.                                         realPoint=FALSE;                             
  170.                                     }  
  171.                                 }                             
  172.                                 if(realPoint)//得到非重復點並畫出  
  173.                                 {                             
  174.                                     RelEdgePoint2D[RelEdgePoint2DCount]=cvPoint2D32f(i,j);  
  175.                                     cvCircle(runImg,cvPoint(i,j),  
  176.                                         1,CV_RGB(255,0,0),2, CV_AA,0);  //畫點  
  177.                                     RelEdgePoint2DCount++;                                                        
  178.                                 }  
  179.                             }     
  180.                             EdgePoint2DCount++;  
  181.                         }  
  182.                         break;  
  183.   
  184.                     case W2B:  
  185.                         if(ftData-secData>200)//白到黑  
  186.                         {  
  187.                             for(int n=0;n<searchlines.size();n++)//找出在搜索線上的點  
  188.                             {  
  189.                                 if (searchlines[n].PTS.y==j&&searchlines[n].PTS.x<i  
  190.                                     &&searchlines[n].PTE.x>i)  
  191.                                 {  
  192.                                     EdgePoint2D[EdgePoint2DCount]=cvPoint2D32f(i,j);      
  193.                                 }  
  194.                             }                                     
  195.                             if (EdgePoint2DCount>0)//大於2點時比較  
  196.                             {                             
  197.                                 bool realPoint=TRUE;  
  198.                                 for (int m=1;m<=EdgePoint2DCount;m++)//刪除X坐標相同的縱向點  
  199.                                 {     
  200.                                     if(EdgePoint2D[EdgePoint2DCount].y == EdgePoint2D[EdgePoint2DCount-m].y)  
  201.                                     {  
  202.                                         realPoint=FALSE;                             
  203.                                     }  
  204.                                 }                             
  205.                                 if(realPoint)//得到非重復點並畫出  
  206.                                 {                             
  207.                                     RelEdgePoint2D[RelEdgePoint2DCount]=cvPoint2D32f(i,j);  
  208.                                     cvCircle(runImg,cvPoint(i,j),  
  209.                                         1,CV_RGB(255,0,0),2, CV_AA,0);  //draw points  
  210.                                     RelEdgePoint2DCount++;                                                        
  211.                                 }  
  212.                             }     
  213.                             EdgePoint2DCount++;  
  214.                         }  
  215.                         break;  
  216.                     }  
  217.                 }  
  218.             }   
  219.             //搜索逼近線                           
  220.             if(RelEdgePoint2DCount>2)  
  221.             {                     
  222.                 cvFitLine2D(RelEdgePoint2D,RelEdgePoint2DCount, CV_DIST_L1,NULL,0.01,0.01,line);      
  223.                 CvPoint FirstPoint;//起點  
  224.                 CvPoint LastPoint;//終點  
  225.                 FirstPoint.x=int (line[2]-1000*line[0]);  
  226.                 FirstPoint.y=int (line[3]-1000*line[1]);  
  227.                 LastPoint.x=int (line[2]+1000*line[0]);  
  228.                 LastPoint.y=int (line[3]+1000*line[1]);  
  229.                 cvLine( runImg, FirstPoint, LastPoint, CV_RGB(255,0,0), 1, CV_AA);//畫出逼近線             
  230.             }  
  231.             break;    
  232.         }  
  233.         //釋放資源  
  234.         free(EdgePoint2D);        
  235.         free(RelEdgePoint2D);  
  236.         delete[] line;  
  237.         searchlines.clear();  
  238.         cvResetImageROI(runImg);      
  239.         cvResetImageROI(thrdImg);  
  240.         DrawRecLines(runImg,rec,lineAccuracy,SearchDirection);  
  241.     }  
  242.   
  243.     //釋放資源  
  244.     cvReleaseImage(&thrdImg);  
  245. }  
  246.   
  247. //畫ROI時候 連帶畫出搜索線  
  248. void CvProcess::DrawRecLines(IplImage* runImg,CvRect rec,int lineAccuracy,int SearchDirection)  
  249. {  
  250.     cvRectangleR(runImg,rec,CV_RGB(0,255,0),1, CV_AA,0);  
  251.     CvPoint RecPS=cvPoint(rec.x,rec.y),  
  252.         RecPE=cvPoint(rec.x+rec.width,rec.y+rec.height);  
  253.     switch(SearchDirection)  
  254.     {  
  255.     case TB :  
  256.         for (int i=1;i<lineAccuracy;i++)  
  257.         {  
  258.             CvPoint Ps=cvPoint(((double)rec.width/lineAccuracy)*i+RecPS.x,RecPS.y);  
  259.             CvPoint Pe=cvPoint(((double)rec.width/lineAccuracy)*i+RecPS.x,RecPE.y);   
  260.             cvLine(runImg,Ps,Pe,CV_RGB(0,255,255),1, CV_AA,0);  
  261.         }        
  262.         break;  
  263.     case LR :  
  264.         for (int i=1;i<lineAccuracy;i++)  
  265.         {  
  266.             CvPoint Ps=cvPoint(RecPS.x,((double)rec.height/lineAccuracy)*i+RecPS.y);  
  267.             CvPoint Pe=cvPoint(RecPE.x,((double)rec.height/lineAccuracy)*i+RecPS.y);  
  268.             cvLine(runImg,Ps,Pe,CV_RGB(0,255,255),1, CV_AA,0);  
  269.         }        
  270.         break;  
  271.     }  
  272.   
  273. }  
  274.   
  275. //得到ROI內部搜索線  
  276. std::vector<CLine> CvProcess::GetRecLines(CvRect rec,int lineAccuracy,int SearchDirection)  
  277. {  
  278.     std::vector<CLine> SearchLines;  
  279.     CLine line;  
  280.     rec.x=0;//坐標轉換值ROI區域  
  281.     rec.y=0;  
  282.     CvPoint RecPS=cvPoint(rec.x,rec.y),  
  283.         RecPE=cvPoint(rec.x+rec.width,rec.y+rec.height);  
  284.     switch(SearchDirection)  
  285.     {  
  286.     case TB :  
  287.         for (int i=1;i<lineAccuracy;i++)  
  288.         {  
  289.             line.PTS=cvPoint(((double)rec.width/lineAccuracy)*i+RecPS.x,RecPS.y);  
  290.             line.PTE=cvPoint(((double)rec.width/lineAccuracy)*i+RecPS.x,RecPE.y);     
  291.             SearchLines.push_back(line);          
  292.         }       
  293.         break;  
  294.     case LR :  
  295.         for (int i=1;i<lineAccuracy;i++)  
  296.         {  
  297.             line.PTS=cvPoint(RecPS.x,((double)rec.height/lineAccuracy)*i+RecPS.y);  
  298.             line.PTE=cvPoint(RecPE.x,((double)rec.height/lineAccuracy)*i+RecPS.y);    
  299.             SearchLines.push_back(line);          
  300.         }       
  301.         break;    
  302.     }  
  303.   
  304.     return SearchLines;