寻找激光的交叉点

这是一个来自网友的提问:

这是一张激光图片,需要得到3横3竖的交点,其中的圆和X是用了测试仿射变换的。
一、图片分析
大像素、单通道。
 
二、思路分析
必须在量化的基础上,寻找这9个焦点的“固有特征”;至于9个点之间的排序,那是简单问题。
 
三、算法实践
1、这样一个图像,单通道所以无法做HSV分解;必须考虑到光照影响,所以不能采用OSTU;经验告诉我,直接bin能够得到较好效果。
2、得到的结果,可能会有孤立点,需要通过形态学方法去除
参考相关文章
需要做的是”开“运算。根据观察,我们采用5*5的核心。
得到的结果是奇异点全部消失,但是现有轮廓会有所衰弱。
3、进一步执行细化,精确定位;或者也会出现细微偏差
4、那么,这个图像质量,我们如何建立特征提取模型了?
对于这样一个点
4个象限,那么对于我们这些交点来说,肯定是有特征的,
比如上图表示,对于这幅图像中的所有的点,可以区分为1-4个象限;就目前这4个象限中来看,每个象限都存在有数据的区域。
但是经过编码发现,由于原图中有圆形等其他图像,干扰比较大,所以可以进一步增加约束为“寻找所有该点本身、其左边、右边、上边、下边都为255的点“
由于这是一个比较明显的特征,所以我们可以直接编写代码去提取。
    //遍历图像,这里我在遍历的时候缩了一个像素
    vector<PointvecPoints;
    for(int i=1;i<src.rows - 1;i++){     
        for(int j=1;j<src.cols - 1;j++){       
            if ( src.at<uchar>(i,j) == 255) //首先该像素要有数据
            {    
                if (src.at<uchar>(i-1,j) == 255 && src.at<uchar>(i+1,j) == 255 && src.at<uchar>(i,j-1) == 255 && src.at<uchar>(i,j+1)==255)
                {
                    vecPoints.push_back(Point(j,i));
                }
            }
                 
        }
    }
    //在底图上进行绘制
    cvtColor(srcClone,srcClone,COLOR_GRAY2BGR);
    for (int i = 0;i<vecPoints.size();i++)
    {
        circle(srcClone,vecPoints[i],10,Scalar(0,0,255),-1);
    }
并且在原图上进行绘图,得到以下结果
5、这个时候,我们要对得到的有限的点进行补全和排序
需要注意的是这几个点本身肯定是有位置关系的,如果基本符合横平竖直的条件的话,我们可以做投影。但是具体情况还是要根据项目原始需求进行。
//对得到的有限的点进行补全和排序
    vector<intvup;
    vector<intvdown;
    projection2(srcBoard,vup,vdown,1);
 
此外,对可能出现的异常情况,也应该有很好的控制。
 
 
附录:
其实在这个程序中,比较关键的,处理解体思路之外,应该就是细化函数(来自GOCVHELPER/GITHUB)
//将 DEPTH_8U型二值图像进行细化  经典的Zhang并行快速细化算法
    //细化算法
    void thin(const Mat &srcMat &dstconst int iterations){
        const int height =src.rows -1;
        const int width  =src.cols -1;
        //拷贝一个数组给另一个数组
        if(src.data != dst.data)
            src.copyTo(dst);
        int n = 0,i = 0,j = 0;
        Mat tmpImg;
        uchar *pU, *pC, *pD;
        bool isFinished =FALSE;
        for(n=0; n<iterationsn++){
            dst.copyTo(tmpImg); 
            isFinished =FALSE;   //一次 先行后列扫描 开始
            //扫描过程一 开始
            for(i=1; i<height;  i++) {
                pU = tmpImg.ptr<uchar>(i-1);
                pC = tmpImg.ptr<uchar>(i);
                pD = tmpImg.ptr<uchar>(i+1);
                for(int j=1; j<widthj++){
                    if(pC[j] > 0){
                        int ap=0;
                        int p2 = (pU[j] >0);
                        int p3 = (pU[j+1] >0);
                        if (p2==0 && p3==1)
                            ap++;
                        int p4 = (pC[j+1] >0);
                        if(p3==0 && p4==1)
                            ap++;
                        int p5 = (pD[j+1] >0);
                        if(p4==0 && p5==1)
                            ap++;
                        int p6 = (pD[j] >0);
                        if(p5==0 && p6==1)
                            ap++;
                        int p7 = (pD[j-1] >0);
                        if(p6==0 && p7==1)
                            ap++;
                        int p8 = (pC[j-1] >0);
                        if(p7==0 && p8==1)
                            ap++;
                        int p9 = (pU[j-1] >0);
                        if(p8==0 && p9==1)
                            ap++;
                        if(p9==0 && p2==1)
                            ap++;
                        if((p2+p3+p4+p5+p6+p7+p8+p9)>1 && (p2+p3+p4+p5+p6+p7+p8+p9)<7){
                            if(ap==1){
                                if((p2*p4*p6==0)&&(p4*p6*p8==0)){                           
                                    dst.ptr<uchar>(i)[j]=0;
                                    isFinished =TRUE;                            
                                }
                            }
                        }                    
                    }
 
                } //扫描过程一 结束
                dst.copyTo(tmpImg); 
                //扫描过程二 开始
                for(i=1; i<height;  i++){
                    pU = tmpImg.ptr<uchar>(i-1);
                    pC = tmpImg.ptr<uchar>(i);
                    pD = tmpImg.ptr<uchar>(i+1);
                    for(int j=1; j<widthj++){
                        if(pC[j] > 0){
                            int ap=0;
                            int p2 = (pU[j] >0);
                            int p3 = (pU[j+1] >0);
                            if (p2==0 && p3==1)
                                ap++;
                            int p4 = (pC[j+1] >0);
                            if(p3==0 && p4==1)
                                ap++;
                            int p5 = (pD[j+1] >0);
                            if(p4==0 && p5==1)
                                ap++;
                            int p6 = (pD[j] >0);
                            if(p5==0 && p6==1)
                                ap++;
                            int p7 = (pD[j-1] >0);
                            if(p6==0 && p7==1)
                                ap++;
                            int p8 = (pC[j-1] >0);
                            if(p7==0 && p8==1)
                                ap++;
                            int p9 = (pU[j-1] >0);
                            if(p8==0 && p9==1)
                                ap++;
                            if(p9==0 && p2==1)
                                ap++;
                            if((p2+p3+p4+p5+p6+p7+p8+p9)>1 && (p2+p3+p4+p5+p6+p7+p8+p9)<7){
                                if(ap==1){
                                    if((p2*p4*p8==0)&&(p2*p6*p8==0)){                           
                                        dst.ptr<uchar>(i)[j]=0;
                                        isFinished =TRUE;                            
                                    }
                                }
                            }                    
                        }
                    }
                } //一次 先行后列扫描完成          
                //如果在扫描过程中没有删除点,则提前退出
                if(isFinished ==FALSE)
                    break
            }
        }
    }
// end of thin
 
全部代码:
#include "stdafx.h"
#include <iostream>
#include <vector>
#include "GOCVHelper.h"
 
using namespace cv;
using namespace std;
using namespace GO;
 
int main()
{
    Mat src = imread("E:/sandbox/cross/1.bmp",0);
    Mat srcClone = src.clone();
    Mat srcBoard(src.size(),CV_8U,Scalar::all(0));
    //阈值处理
    threshold(src,src,100,255,THRESH_BINARY);
    //形态学去噪音
    Mat element = getStructuringElement(MORPH_RECT,Size(5,5));
    morphologyEx(src,src,CV_MOP_OPEN,element);
    //二值图像细化处理
    GO::thin(src,src);
    //遍历图像,这里我在遍历的时候缩了一个像素
    vector<PointvecPoints;
    for(int i=1;i<src.rows - 1;i++){     
        for(int j=1;j<src.cols - 1;j++){       
            if ( src.at<uchar>(i,j) == 255) //首先该像素要有数据
            {    
                if (src.at<uchar>(i-1,j) == 255 && src.at<uchar>(i+1,j) == 255 && src.at<uchar>(i,j-1) == 255 && src.at<uchar>(i,j+1)==255)
                {
                    vecPoints.push_back(Point(j,i));
                }
            }
                 
        }
    }
    //在底图上进行绘制
    cvtColor(srcClone,srcClone,COLOR_GRAY2BGR);
    for (int i = 0;i<vecPoints.size();i++)
    {
        circle(srcClone,vecPoints[i],10,Scalar(0,0,255),-1);
        circle(srcBoard,vecPoints[i],1,Scalar(255),-1);
    }
    //对得到的有限的点进行补全和排序
    vector<intvup;
    vector<intvdown;
    projection2(srcBoard,vup,vdown,1);
 
    waitKey();
    return 0;
}
 





原文地址:https://www.cnblogs.com/jsxyhelu/p/10295373.html