二值化图像;
利用黑白像素值求差,得到边缘点;
过滤边缘点找到合适区域;
利用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区域
- { //设置ROI
- cvSetImageROI(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 而不是 width
- secData=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 而不是 width
- secData=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 points
- RelEdgePoint2DCount++;
- }
- }
- 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;