如何在 OpenCV 和 C++ 中找到图像中两个对象(点)之间的距离(以 m 和像素为单位)?
How to find the distance(physical in m and pixels) between two object(points) in image in OpenCV and C+++?
我正在使用 OpenCV 和 C++。我已经完成了可以找到对象中心的代码。我也有关于相机和图像中物体之间距离的先验信息。
我需要计算图像中两个对象之间或这些对象的两个中心之间的距离(以米或厘米为单位的真实物理距离,以及以像素为单位的距离)。
这里是找到矩形对象中心矩的代码。类似的方法是找到其他形状(对象)的中心。
int main(int argc,char** argv)
{
Mat image = imread("000167.png");
Mat gray,bw,dil,erd, dst_final;
Mat new_src=image.clone();
for(int y = 0; y < image.rows; y++ )
{
for(int x = 0; x < image.cols; x++ )
{
for(int c = 0; c < 3; c++ )
{
new_src.at<Vec3b>(y,x)[c]= saturate_cast<uchar>( 1.5*(image.at<Vec3b>(y,x)[c] ));
}
}
}
cv::GaussianBlur(new_src, src_gray, cv::Size(3,3),1,1,BORDER_DEFAULT); //original
medianBlur(new_src, src_gray, 11);
blur( new_src, src_gray, Size(3,3) );
cvtColor(src_gray,gray,CV_BGR2GRAY);
Canny(gray,bw,600,1200,5,true);
Mat grad,bw1;
Mat morphKernel = getStructuringElement(MORPH_ELLIPSE, Size(20,10));
morphologyEx(bw, grad, MORPH_GRADIENT, morphKernel);
threshold(grad, bw1, 255.0, 255.0, THRESH_BINARY | THRESH_OTSU);
vector<vector<Point> > contours;
vector<vector<Point> > rough;
vector<vector<Point> >rough_color;
vector<vector<Point> >precise;
vector<Vec4i> hierarchy;
Mat dst = image.clone();
findContours(bw1.clone(), contours, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE);
vector<Point> approx;
for( int i = 0; i< contours.size(); i++ )
{
approxPolyDP(Mat(contours[i]), approx, arcLength(Mat(contours[i]), true) * 0.01, true);
if (fabs(contourArea(approx)) <2000 || fabs(contourArea(approx))>50000)
continue;
Rect r = boundingRect(contours[i]);
if( (float) (r.height/r.width) > 1.5 && (float) (r.height/r.width) <3)
{
rough.push_back(approx);
}
}
for(int i = 0; i < rough.size(); i++)
{
Rect bound=boundingRect(rough[i]);
Rect x, y, w, h = boundingRect(rough[i]);
rectangle(dst,Point(bound.br().x,bound.br().y), Point(bound.tl().x,bound.tl().y),Scalar(255, 0, 0),2);
RotatedRect rectPoint = minAreaRect(rough[i]);
Point2f fourPoint2f_rough[4];
rectPoint.points(fourPoint2f_rough);
vector<Point> fourPoint_rough;
for(int i = 0; i <4; i++)
{
fourPoint_rough.push_back(fourPoint2f_rough[i]);
}
{
line(dst, fourPoint2f_rough[i], fourPoint2f_rough[i + 1], Scalar(255,0,0), 3);
}
line(dst, fourPoint2f_rough[0], fourPoint2f_rough[3], Scalar(255,0,0), 3); */
}
if(rough.size() !=0 )
{
for( int i = 0; i< rough.size(); i++ )
{
vector<Moments> mu(1);
vector<Point2f> mc(1);
int gray_level;
// compute the central momment
mu[0] = moments( rough[i], false );
mc[0] = Point2f( mu[0].m10/mu[0].m00 , mu[0].m01/mu[0].m00 );
circle( dst, mc[0], 4, Scalar(0,0,255), -1, 8, 0 );
gray_level=gray.at<uchar>(mc[0]);
if(gray_level<200 && gray_level>20)
{rough_color.push_back(rough[i]);}
}
for(int i = 0; i < rough_color.size(); i++)
{
Rect bound=boundingRect(rough_color[i]);
Rect x, y, w, h = boundingRect(rough_color[i]);
RotatedRect rectPoint = minAreaRect(rough_color[i]);
Point2f fourPoint2f_color[4];
rectPoint.points(fourPoint2f_color);
vector<Point> fourPoint_color;
for(int i = 0; i <4; i++)
{
fourPoint_color.push_back(fourPoint2f_color[i]);
}
for (int i = 0; i < 3; i++)
{
line(dst, fourPoint2f_color[i], fourPoint2f_color[i + 1], Scalar(0,255,0), 3);
}
line(dst, fourPoint2f_color[0], fourPoint2f_color[3], Scalar(0,255,0), 3);
}
}
...
因此只需要一个代码来获取这两个中心矩(图像中对象的两个中心)之间的距离(以厘米或米为单位,以像素为单位)。我在矩形 window 上包含中心的结果图像(window 中的红点)。所以在这种情况下,我想计算 window 和 "OPEN" 框符号之间的距离。
这个答案是关于获取两点之间的公制距离。
如果:
- 两点在垂直于相机光轴的(几何)平面上
- 你有相机中心和平面之间的距离
然后可以使用投影基础知识计算这两点之间的公制距离:
- d_m: 两点之间的公制距离(m.)
- d_p: 两点之间的像素距离
- f: 焦点 (m.)
- k:相机传感器每米像素数(=1/ps,ps:pixel尺寸,通常为5到10 um)
- z_M: 两点之间的距离(m.)
我们有:d_p = k . f . d_M/Z_M
所以:d_M = d_p . z_M / (k.f)
如果不完全满足以上条件,会导致一些错误。从问题中不清楚这些要求是否得到满足。如果他们不是,那么可能无法得到答案。除非可能已知平面和轴之间的角度,在这种情况下将需要一些基本的三角计算。
我正在使用 OpenCV 和 C++。我已经完成了可以找到对象中心的代码。我也有关于相机和图像中物体之间距离的先验信息。 我需要计算图像中两个对象之间或这些对象的两个中心之间的距离(以米或厘米为单位的真实物理距离,以及以像素为单位的距离)。
这里是找到矩形对象中心矩的代码。类似的方法是找到其他形状(对象)的中心。
int main(int argc,char** argv)
{
Mat image = imread("000167.png");
Mat gray,bw,dil,erd, dst_final;
Mat new_src=image.clone();
for(int y = 0; y < image.rows; y++ )
{
for(int x = 0; x < image.cols; x++ )
{
for(int c = 0; c < 3; c++ )
{
new_src.at<Vec3b>(y,x)[c]= saturate_cast<uchar>( 1.5*(image.at<Vec3b>(y,x)[c] ));
}
}
}
cv::GaussianBlur(new_src, src_gray, cv::Size(3,3),1,1,BORDER_DEFAULT); //original
medianBlur(new_src, src_gray, 11);
blur( new_src, src_gray, Size(3,3) );
cvtColor(src_gray,gray,CV_BGR2GRAY);
Canny(gray,bw,600,1200,5,true);
Mat grad,bw1;
Mat morphKernel = getStructuringElement(MORPH_ELLIPSE, Size(20,10));
morphologyEx(bw, grad, MORPH_GRADIENT, morphKernel);
threshold(grad, bw1, 255.0, 255.0, THRESH_BINARY | THRESH_OTSU);
vector<vector<Point> > contours;
vector<vector<Point> > rough;
vector<vector<Point> >rough_color;
vector<vector<Point> >precise;
vector<Vec4i> hierarchy;
Mat dst = image.clone();
findContours(bw1.clone(), contours, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE);
vector<Point> approx;
for( int i = 0; i< contours.size(); i++ )
{
approxPolyDP(Mat(contours[i]), approx, arcLength(Mat(contours[i]), true) * 0.01, true);
if (fabs(contourArea(approx)) <2000 || fabs(contourArea(approx))>50000)
continue;
Rect r = boundingRect(contours[i]);
if( (float) (r.height/r.width) > 1.5 && (float) (r.height/r.width) <3)
{
rough.push_back(approx);
}
}
for(int i = 0; i < rough.size(); i++)
{
Rect bound=boundingRect(rough[i]);
Rect x, y, w, h = boundingRect(rough[i]);
rectangle(dst,Point(bound.br().x,bound.br().y), Point(bound.tl().x,bound.tl().y),Scalar(255, 0, 0),2);
RotatedRect rectPoint = minAreaRect(rough[i]);
Point2f fourPoint2f_rough[4];
rectPoint.points(fourPoint2f_rough);
vector<Point> fourPoint_rough;
for(int i = 0; i <4; i++)
{
fourPoint_rough.push_back(fourPoint2f_rough[i]);
}
{
line(dst, fourPoint2f_rough[i], fourPoint2f_rough[i + 1], Scalar(255,0,0), 3);
}
line(dst, fourPoint2f_rough[0], fourPoint2f_rough[3], Scalar(255,0,0), 3); */
}
if(rough.size() !=0 )
{
for( int i = 0; i< rough.size(); i++ )
{
vector<Moments> mu(1);
vector<Point2f> mc(1);
int gray_level;
// compute the central momment
mu[0] = moments( rough[i], false );
mc[0] = Point2f( mu[0].m10/mu[0].m00 , mu[0].m01/mu[0].m00 );
circle( dst, mc[0], 4, Scalar(0,0,255), -1, 8, 0 );
gray_level=gray.at<uchar>(mc[0]);
if(gray_level<200 && gray_level>20)
{rough_color.push_back(rough[i]);}
}
for(int i = 0; i < rough_color.size(); i++)
{
Rect bound=boundingRect(rough_color[i]);
Rect x, y, w, h = boundingRect(rough_color[i]);
RotatedRect rectPoint = minAreaRect(rough_color[i]);
Point2f fourPoint2f_color[4];
rectPoint.points(fourPoint2f_color);
vector<Point> fourPoint_color;
for(int i = 0; i <4; i++)
{
fourPoint_color.push_back(fourPoint2f_color[i]);
}
for (int i = 0; i < 3; i++)
{
line(dst, fourPoint2f_color[i], fourPoint2f_color[i + 1], Scalar(0,255,0), 3);
}
line(dst, fourPoint2f_color[0], fourPoint2f_color[3], Scalar(0,255,0), 3);
}
}
...
因此只需要一个代码来获取这两个中心矩(图像中对象的两个中心)之间的距离(以厘米或米为单位,以像素为单位)。我在矩形 window 上包含中心的结果图像(window 中的红点)。所以在这种情况下,我想计算 window 和 "OPEN" 框符号之间的距离。
这个答案是关于获取两点之间的公制距离。
如果:
- 两点在垂直于相机光轴的(几何)平面上
- 你有相机中心和平面之间的距离
然后可以使用投影基础知识计算这两点之间的公制距离:
- d_m: 两点之间的公制距离(m.)
- d_p: 两点之间的像素距离
- f: 焦点 (m.)
- k:相机传感器每米像素数(=1/ps,ps:pixel尺寸,通常为5到10 um)
- z_M: 两点之间的距离(m.)
我们有:d_p = k . f . d_M/Z_M
所以:d_M = d_p . z_M / (k.f)
如果不完全满足以上条件,会导致一些错误。从问题中不清楚这些要求是否得到满足。如果他们不是,那么可能无法得到答案。除非可能已知平面和轴之间的角度,在这种情况下将需要一些基本的三角计算。