夫变换大多都用在二维平面中的线、圆检测,这里将其扩展到三维空间点的平面检测。其中建立的霍夫变换空间如下:
核心代码:
#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