利用opencv逼近二值图像的边界点,并过滤不需要的边界,达到寻边效果。(转载请说明出处)

来源:互联网 发布:1024最新 知乎 编辑:程序博客网 时间:2024/05/01 10:03

二值化图像;

利用黑白像素值求差,得到边缘点;

过滤边缘点找到合适区域;

利用cvFitLine2D拟合线。

 

做的比较粗糙,搜寻时间在10ms左右,希望有研究opencv的朋友斧正。

效果预览:

 

void CvProcess::FindLine( IplImage* orgImg ,//原始图像 IplImage*runImg,//显示用图像 CvRect rec,//roi int thredValue,//二值化阈值 int lineAccuracy,//搜索精度 int SearchDirection,//搜索方向 int EdgePolarity)//搜索方式 黑到白 白到黑{cvCopy(orgImg,runImg);//原始图像拷贝到显示图像用于显示IplImage* thrdImg = cvCreateImage(//创建一个单通道二值图像用于各种处理cvSize(orgImg->width,orgImg->height), IPL_DEPTH_8U, 1);//将原始图像转换为单通道灰度图像cvCvtColor(runImg,thrdImg,CV_BGR2GRAY);//二值化处理cvThreshold(thrdImg,thrdImg,thredValue,255,CV_THRESH_BINARY);// cvNamedWindow("");// cvShowImage("",thrdImg);if(rec.width>0&&rec.width<IMAGE_WIDTH&&rec.height>0&&rec.width<IMAGE_HEIGHT)//判断是否有适合的ROI区域{   //设置ROIcvSetImageROI(runImg,rec);cvSetImageROI(thrdImg,rec);//搜索边界CvPoint2D32f *EdgePoint2D = //用于存储搜索到的所有边界点(CvPoint2D32f *)malloc((IMAGE_HEIGHT*IMAGE_WIDTH) * sizeof(CvPoint2D32f));CvPoint2D32f *RelEdgePoint2D =//用于存储搜索到的正确的点(CvPoint2D32f *)malloc((IMAGE_HEIGHT*IMAGE_WIDTH) * sizeof(CvPoint2D32f));int EdgePoint2DCount=0;//点计数int RelEdgePoint2DCount=0;//真实点计数float *line = new float[4];//用于画逼近线byte ftData=0,secData=0;//搜索边界点所需资源//得到ROI区域内的搜索线std::vector<CLine> searchlines = GetRecLines(rec,lineAccuracy,SearchDirection);switch(SearchDirection)//搜索方向{case TB ://上到下纵向搜索for (int i=0;i<thrdImg->roi->width;i++){for (int j=0;j<thrdImg->roi->height-1;j++){   //上下搜索所有的差值大于200的点ftData=CV_IMAGE_ELEM(thrdImg,uchar,thrdImg->roi->yOffset+j,thrdImg->roi->xOffset+i);//利用宏直接得到结果//ftData=(thrdImg->imageData + i * thrdImg->widthStep)[j];//注意这里是 宽度用的是 widthStep 而不是 widthsecData=CV_IMAGE_ELEM(thrdImg,uchar,thrdImg->roi->yOffset+j+1,thrdImg->roi->xOffset+i);switch(EdgePolarity){case B2W:if(secData-ftData>200)//黑到白{for(int n=0;n<searchlines.size();n++)//搜索在搜索线上的点{if (searchlines[n].PTS.x==i&&searchlines[n].PTS.y<j&&searchlines[n].PTE.y>j){EdgePoint2D[EdgePoint2DCount]=cvPoint2D32f(i,j); }}if (EdgePoint2DCount>0)//大于2点时比较{bool realPoint=TRUE;//删除X坐标相同的纵向点,减少逼近时误判几率for (int m=1;m<=EdgePoint2DCount;m++){   if(EdgePoint2D[EdgePoint2DCount].x == EdgePoint2D[EdgePoint2DCount-m].x){realPoint=FALSE;                           }}  if(realPoint)//得到非重复点并画出{RelEdgePoint2D[RelEdgePoint2DCount]=cvPoint2D32f(i,j);cvCircle(runImg,cvPoint(i,j),1,CV_RGB(255,0,0),2, CV_AA,0);//画点RelEdgePoint2DCount++;}}   EdgePoint2DCount++;}break;case W2B:if(ftData-secData>200)//白到黑{for(int n=0;n<searchlines.size();n++)//搜索在搜索线上的点{if (searchlines[n].PTS.x==i&&searchlines[n].PTS.y<j&&searchlines[n].PTE.y>j){EdgePoint2D[EdgePoint2DCount]=cvPoint2D32f(i,j); }}if (EdgePoint2DCount>0)//大于2点时比较{bool realPoint=TRUE;//删除X坐标相同的纵向点,减少逼近时误判几率for (int m=1;m<=EdgePoint2DCount;m++){   if(EdgePoint2D[EdgePoint2DCount].x == EdgePoint2D[EdgePoint2DCount-m].x){realPoint=FALSE;                           }}  if(realPoint)//得到非重复点并画出{RelEdgePoint2D[RelEdgePoint2DCount]=cvPoint2D32f(i,j);cvCircle(runImg,cvPoint(i,j),1,CV_RGB(255,0,0),2, CV_AA,0);//画点RelEdgePoint2DCount++;}}   EdgePoint2DCount++;}break;}}} if(RelEdgePoint2DCount>2)//当找到的点大于2时在搜寻逼近线{//找出逼近线cvFitLine2D(RelEdgePoint2D,RelEdgePoint2DCount, CV_DIST_L1,NULL,0.01,0.01,line);  CvPoint FirstPoint;//起点CvPoint LastPoint;//终点FirstPoint.x=int (line[2]-1000*line[0]);FirstPoint.y=int (line[3]-1000*line[1]);LastPoint.x=int (line[2]+1000*line[0]);LastPoint.y=int (line[3]+1000*line[1]);cvLine( runImg, FirstPoint, LastPoint, CV_RGB(255,0,0), 1, CV_AA);//画出逼近线}break;case LR ://左到右横向搜索for (int j=0;j<thrdImg->roi->height;j++){for (int i=0;i<thrdImg->roi->width-1;i++){ftData=CV_IMAGE_ELEM(thrdImg,uchar,thrdImg->roi->yOffset+j,thrdImg->roi->xOffset+i);//利用宏直接得到结果//ftData=(thrdImg->imageData + i * thrdImg->widthStep)[j];//注意这里是 宽度用的是 widthStep 而不是 widthsecData=CV_IMAGE_ELEM(thrdImg,uchar,thrdImg->roi->yOffset+j,thrdImg->roi->xOffset+i+1);switch(EdgePolarity){case B2W:if(secData-ftData>200)//黑到白{for(int n=0;n<searchlines.size();n++)//point in searchlines{if (searchlines[n].PTS.y==j&&searchlines[n].PTS.x<i&&searchlines[n].PTE.x>i){EdgePoint2D[EdgePoint2DCount]=cvPoint2D32f(i,j); }}if (EdgePoint2DCount>0)//大于2点时比较{bool realPoint=TRUE;for (int m=1;m<=EdgePoint2DCount;m++)//删除y坐标相同的横向点{   if(EdgePoint2D[EdgePoint2DCount].y == EdgePoint2D[EdgePoint2DCount-m].y){realPoint=FALSE;                           }}  if(realPoint)//得到非重复点并画出{RelEdgePoint2D[RelEdgePoint2DCount]=cvPoint2D32f(i,j);cvCircle(runImg,cvPoint(i,j),1,CV_RGB(255,0,0),2, CV_AA,0);//画点RelEdgePoint2DCount++;}}   EdgePoint2DCount++;}break;case W2B:if(ftData-secData>200)//白到黑{for(int n=0;n<searchlines.size();n++)//找出在搜索线上的点{if (searchlines[n].PTS.y==j&&searchlines[n].PTS.x<i&&searchlines[n].PTE.x>i){EdgePoint2D[EdgePoint2DCount]=cvPoint2D32f(i,j); }}if (EdgePoint2DCount>0)//大于2点时比较{bool realPoint=TRUE;for (int m=1;m<=EdgePoint2DCount;m++)//删除X坐标相同的纵向点{   if(EdgePoint2D[EdgePoint2DCount].y == EdgePoint2D[EdgePoint2DCount-m].y){realPoint=FALSE;                           }}  if(realPoint)//得到非重复点并画出{RelEdgePoint2D[RelEdgePoint2DCount]=cvPoint2D32f(i,j);cvCircle(runImg,cvPoint(i,j),1,CV_RGB(255,0,0),2, CV_AA,0);//draw pointsRelEdgePoint2DCount++;}}   EdgePoint2DCount++;}break;}}} //搜索逼近线if(RelEdgePoint2DCount>2){cvFitLine2D(RelEdgePoint2D,RelEdgePoint2DCount, CV_DIST_L1,NULL,0.01,0.01,line);  CvPoint FirstPoint;//起点CvPoint LastPoint;//终点FirstPoint.x=int (line[2]-1000*line[0]);FirstPoint.y=int (line[3]-1000*line[1]);LastPoint.x=int (line[2]+1000*line[0]);LastPoint.y=int (line[3]+1000*line[1]);cvLine( runImg, FirstPoint, LastPoint, CV_RGB(255,0,0), 1, CV_AA);//画出逼近线}break;}//释放资源free(EdgePoint2D); free(RelEdgePoint2D);delete[] line;searchlines.clear();cvResetImageROI(runImg);cvResetImageROI(thrdImg);DrawRecLines(runImg,rec,lineAccuracy,SearchDirection);}//释放资源cvReleaseImage(&thrdImg);}//画ROI时候 连带画出搜索线void CvProcess::DrawRecLines(IplImage* runImg,CvRect rec,int lineAccuracy,int SearchDirection){cvRectangleR(runImg,rec,CV_RGB(0,255,0),1, CV_AA,0);CvPoint RecPS=cvPoint(rec.x,rec.y),RecPE=cvPoint(rec.x+rec.width,rec.y+rec.height);switch(SearchDirection){case TB :for (int i=1;i<lineAccuracy;i++){CvPoint Ps=cvPoint(((double)rec.width/lineAccuracy)*i+RecPS.x,RecPS.y);CvPoint Pe=cvPoint(((double)rec.width/lineAccuracy)*i+RecPS.x,RecPE.y);cvLine(runImg,Ps,Pe,CV_RGB(0,255,255),1, CV_AA,0);}      break;case LR :for (int i=1;i<lineAccuracy;i++){CvPoint Ps=cvPoint(RecPS.x,((double)rec.height/lineAccuracy)*i+RecPS.y);CvPoint Pe=cvPoint(RecPE.x,((double)rec.height/lineAccuracy)*i+RecPS.y);cvLine(runImg,Ps,Pe,CV_RGB(0,255,255),1, CV_AA,0);}      break;}}//得到ROI内部搜索线std::vector<CLine> CvProcess::GetRecLines(CvRect rec,int lineAccuracy,int SearchDirection){std::vector<CLine> SearchLines;CLine line;rec.x=0;//坐标转换值ROI区域rec.y=0;CvPoint RecPS=cvPoint(rec.x,rec.y),RecPE=cvPoint(rec.x+rec.width,rec.y+rec.height);switch(SearchDirection){case TB :for (int i=1;i<lineAccuracy;i++){line.PTS=cvPoint(((double)rec.width/lineAccuracy)*i+RecPS.x,RecPS.y);line.PTE=cvPoint(((double)rec.width/lineAccuracy)*i+RecPS.x,RecPE.y);SearchLines.push_back(line);}     break;case LR :for (int i=1;i<lineAccuracy;i++){line.PTS=cvPoint(RecPS.x,((double)rec.height/lineAccuracy)*i+RecPS.y);line.PTE=cvPoint(RecPE.x,((double)rec.height/lineAccuracy)*i+RecPS.y);SearchLines.push_back(line);}     break;}return SearchLines;