平面检测(HoughTransform)

夫变换大多都用在二维平面中的线、圆检测,这里将其扩展到三维空间点的平面检测。其中建立的霍夫变换空间如下:
在这里插入图片描述
在这里插入图片描述
核心代码:

#include <iostream>
#include <opencv2/opencv.hpp>
#include <string>
#include <math.h>
#include <vector>
#include "depthtoRGB.h"
#include "My_Img.h"

#define MO_CAMERA_IMAGE_WIDTH	(1280)
#define MO_CAMERA_IMAGE_HEIGHT	(720)

/* camera output */
float fBF;
float fBase;

/* show image */
cv::Mat RefImg;
cv::Mat DepImg;

using namespace std;
using namespace cv;

struct my_point
{
    double x;
    double y;
    double z;
};

struct my_hough
{
    int m;
    int n;
    int r;
    int num;
};


// 排序法则,其中:< 升序    >降序
bool comparison(my_hough a,my_hough b)
{
 return a.num > b.num ;
}

int main()
{
    Mat RefImg = cv::Mat::zeros(720, 1280, CV_8UC3);        // 定义RGB图像
    Mat DepImg(720,1280,CV_8UC3,Scalar(0,0,0));             // 定义伪深度图像
    Mat dep_iarray = cv::Mat::zeros(720, 1280, CV_32SC1);   // 定义深度图像
    float fBF, fBase;                                       // 定义相机参数
    string path = "../data/";                               // 数据路径


    My_Img(path, RefImg, dep_iarray, &fBF, &fBase);         // 获取待处理图像

    int ***ResFlag;                                         // 定义待检测区域范围坐标点是否存在数据,为了提高检测速度,范围为x:-20到20,y:-20到20,z:0到150,(dm)
    ResFlag = new int**[40];
    for(int x=0; x<40; x++)
    {
        ResFlag[x] = new int*[40];
    }
    for(int x=0; x<40; x++)
    {
        for(int y=0; y<40; y++)
        {
            ResFlag[x][y] = new int[150];
            for(int z=0; z<150; z++)
            {
                ResFlag[x][y][z] = 0;
            }
        }
    }

    for(int i=0; i<720; i++)
    {
        for(int j=0; j<1280; j++)
        {
            if(dep_iarray.at<int>(i,j) > 5)
            {
                DepImg.at<Vec3b>(i,j) = depthToRGB(dep_iarray.at<int>(i,j));
                int x = round(32.0*fBase*(double)(j-640)/(double)(dep_iarray.at<int>(i,j))/100.0);
                int y = round(32.0*fBase*(double)(i-360)/(double)(dep_iarray.at<int>(i,j))/100.0);
                int z = round(32.0*fBF/(double)(dep_iarray.at<int>(i,j))/100.0);

                if(z > 13 && z < 149 && abs(x) < 19 && abs(y) < 19)     // 判断检测区域没对应坐标点是否存在点,相当于一次滤波
                {
                    ResFlag[x+20][y+20][z]++;                           // 存在点,对给区域点进行合并,并进行自加
                }
            }
        }
    }

    vector<my_point> points;                // 待检测点容器
    my_point point_temp;                    // 临时点
    for(int x=0; x<40; x++)
    {
        for(int y=0; y<40; y++)
        {
            for(int z=13; z<150; z++)
            {
                if(ResFlag[x][y][z] > 0)
                {
                    point_temp.x = x-20;        // 转为实际坐标点
                    point_temp.y = y-20;
                    point_temp.z = z;
                    points.push_back(point_temp);
                }
            }
        }
    }


    int ***hist;            // 定义直方图 其大小为180*360*310
    hist = new int**[180];
    for(int m=0; m<180; m++)
    {
        hist[m] = new int*[360];
    }
    for(int m=0; m<180; m++)
    {
        for(int n=0; n<360; n++)
        {
            hist[m][n] = new int[310];
            for(int r=0; r<310; r++)
            {
                hist[m][n][r] = 0;
            }
        }
    }

    // 为了提高效率,先计算各个角度,直接调动
    double msin_array[180] = {0};
    double mcos_array[180] = {0};
    double nsin_array[360] = {0};
    double ncos_array[360] = {0};
    for(int m=0; m<180; m++)
    {
        msin_array[m] = sin(m*3.1415/180);
        mcos_array[m] = cos(m*3.1415/180);
    }
    for(int n=0; n<360; n++)
    {
        nsin_array[n] = sin((n-180)*3.1415/180);
        ncos_array[n] = cos((n-180)*3.1415/180);
    }


    int step = 2;                           // 设置步长,即检测精度
    for(int k=0; k<points.size(); k++)      // 对每个点进行处理
    {
        for(int m=0; m<180; m+=step)
        {
            for(int n=0; n<360; n+=step)
            {
                int r = (int)(points.at(k).x*msin_array[m]*ncos_array[n]
                        + points.at(k).y*msin_array[m]*nsin_array[n]
                        + points.at(k).z*mcos_array[m] + 155);
                if(r<310)
                {
                    hist[m][n][r]++;
                }

            }
        }
    }

    vector<my_hough> houghs;        // 定义直方图容器,对直方图进行排序
    my_hough hough_temp;
    for(int m=0; m<180; m+=step)
    {
        for(int n=0; n<360; n+=step)
        {
            for(int r=0; r<310; r++)
            {
                if(hist[m][n][r] > 100)
                {
                    hough_temp.m = m;
                    hough_temp.n = n;
                    hough_temp.r = r;
                    hough_temp.num = hist[m][n][r];
                    houghs.push_back(hough_temp);
                }
            }
        }
    }
    sort(houghs.begin(), houghs.end(), comparison);     // 排序

    for(int k=0; k<1; k++)
    {
        for(int i=0; i<720; i++)
        {
            for(int j=0; j<1280; j++)
            {
                if(dep_iarray.at<int>(i,j) > 5)
                {
                    double x = 32.0*fBase*(double)(j-640)/(double)(dep_iarray.at<int>(i,j))/100.0;
                    double y = 32.0*fBase*(double)(i-360)/(double)(dep_iarray.at<int>(i,j))/100.0;
                    double z = 32.0*fBF/(double)(dep_iarray.at<int>(i,j))/100.0;
                    if(abs(houghs.at(k).r - (x*msin_array[houghs.at(k).m]*ncos_array[houghs.at(k).n]
                                     + y*msin_array[houghs.at(k).m]*nsin_array[houghs.at(k).n]
                                     + z*mcos_array[houghs.at(k).m] + 155)) < 2)            // 绘制直方图最大值的点云
                    {
                        RefImg.at<Vec3b>(i,j)[0] =0;
                        RefImg.at<Vec3b>(i,j)[1] =0;
                        RefImg.at<Vec3b>(i,j)[2] =255;
                    }
                }
            }
        }
    }

    cout << "最大点云参数:" << houghs.at(0).m << "," << houghs.at(0).n << "," << houghs.at(0).r << endl;

    imshow("RefImg", RefImg);
    imshow("DepImg", DepImg);
    waitKey(0);
    return 0;
}
源码即数据下载链接:https://download.csdn.net/download/OEMT_301/12101536

最终效果:
原图:
在这里插入图片描述

深度图:
在这里插入图片描述
检测结果:
在这里插入图片描述
参考:https://blog.csdn.net/OEMT_301/article/details/103153458

发布了37 篇原创文章 · 获赞 5 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/OEMT_301/article/details/103958624