OpenCV距离变换输出的图像与输入图像完全相同

11

我正在使用OpenCV进行一些检测工作,需要使用距离变换。 但是在opencv中,距离变换功能给出的图像与我的源图像完全相同。 有人知道我做错了什么吗? 这是我的代码部分:

cvSetData(depthImage, m_rgbWk, depthImage->widthStep);

//gotten openCV image in "depthImage"           

IplImage *single_channel_depthImage = cvCreateImage(cvSize(320, 240), 8, 1);
cvSplit(depthImage, single_channel_depthImage, NULL, NULL, NULL);

//smoothing
IplImage *smoothed_image = cvCreateImage(cvSize(320, 240), 8, 1);
cvSmooth(single_channel_depthImage, smoothed_image, CV_MEDIAN, 9, 9, 0, 0);

//do canny edge detector
IplImage *edges_image = cvCreateImage(cvSize(320, 240), 8, 1);
cvCanny(smoothed_image, edges_image, 100, 200);

//invert values
IplImage *inverted_edges_image = cvCreateImage(cvSize(320, 240), 8, 1);
cvNot(edges_image, inverted_edges_image);

//calculate the distance transform
IplImage *distance_image = cvCreateImage(cvSize(320, 240), IPL_DEPTH_32F, 1);
cvZero(distance_image);

cvDistTransform(inverted_edges_image, distance_image, CV_DIST_L2, CV_DIST_MASK_PRECISE, NULL, NULL);

简单来说,我从Kinect获取图像,将其转换为一通道图像,进行平滑处理,运行Canny边缘检测器,反转数值,然后进行距离变换。但是,变换后的图像看起来与输入图像完全相同。有什么问题吗?

谢谢!


我认为在边缘检测之前使用中值滤波器不是一个好主意:高斯滤波器会更好,因为它不会引入任何伪影等。 - BIOStheZerg
4个回答

27

我认为关键在于它们看起来相同。这里是我写的一个小程序,展示它们的区别:

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>

using namespace std;
using namespace cv;

int main(int argc, char** argv)
{
    Mat before = imread("qrcode.png", 0);

    Mat dist;
    distanceTransform(before, dist, CV_DIST_L2, 3);

    imshow("before", before);
    imshow("non-normalized", dist);

    normalize(dist, dist, 0.0, 1.0, NORM_MINMAX);
    imshow("normalized", dist);
    waitKey();
    return 0;
}
在非正常化的图像中,你看到了这个:
enter image description here

尽管看起来好像什么也没有改变,但是由于imshow将图像从32位浮点型转换为8位以进行显示,距离步长与整体值范围[0, 255]相比非常小,我们看不到差异,所以让我们对其进行正则化处理...
现在我们得到了这个:
enter image description here

值本身应该是正确的,但是在显示时,你需要对图像进行正则化才能看到差异。
编辑: 以下是来自dist矩阵左上角的一个10x10样本,展示了值实际上是不同的:
[10.954346, 10.540054, 10.125763, 9.7114716, 9.2971802, 8.8828888, 8.4685974, 8.054306, 7.6400146, 7.6400146;
  10.540054, 9.5850525, 9.1707611, 8.7564697, 8.3421783, 7.927887, 7.5135956, 7.0993042, 6.6850128, 6.6850128;
  10.125763, 9.1707611, 8.2157593, 7.8014679, 7.3871765, 6.9728851, 6.5585938, 6.1443024, 5.730011, 5.730011;
  9.7114716, 8.7564697, 7.8014679, 6.8464661, 6.4321747, 6.0178833, 5.6035919, 5.1893005, 4.7750092, 4.7750092;
  9.2971802, 8.3421783, 7.3871765, 6.4321747, 5.4771729, 5.0628815, 4.6485901, 4.2342987, 3.8200073, 3.8200073;
  8.8828888, 7.927887, 6.9728851, 6.0178833, 5.0628815, 4.1078796, 3.6935883, 3.2792969, 2.8650055, 2.8650055;
  8.4685974, 7.5135956, 6.5585938, 5.6035919, 4.6485901, 3.6935883, 2.7385864, 2.324295, 1.9100037, 1.9100037;
  8.054306, 7.0993042, 6.1443024, 5.1893005, 4.2342987, 3.2792969, 2.324295, 1.3692932, 0.95500183, 0.95500183;
  7.6400146, 6.6850128, 5.730011, 4.7750092, 3.8200073, 2.8650055, 1.9100037, 0.95500183, 0, 0;
  7.6400146, 6.6850128, 5.730011, 4.7750092, 3.8200073, 2.8650055, 1.9100037, 0.95500183, 0, 0]

抱歉,我已经尝试了一段时间,但似乎无法解决。您如何获取刚才所做的示例?我一直在尝试使用printf将像素值打印到屏幕上,但只得到垃圾值。我该如何将IPL_DEPTH_8U和IPL_DEPTH_32F打印到屏幕上?谢谢。 - Mina Almasry
@MinaAlmasry 实际上,这个问题值得在 Stack Overflow 上发布一个新的帖子;我没有看到有人问过,所以未来的其他人可能也想知道如何做!我相信我自己或另一个 OpenCV 爱好者会很乐意帮助你回答它。 - mevatron

4
我刚刚发现了这个问题。OpenCV distanceTransform函数可以计算源图像中每个像素到最近零像素的距离。因此,该函数预期您的边缘图像为负数。
您需要做的就是对边缘图像取反即可。
edges = 255 - edges;

为什么要使用edges = 255 - edges;而不是简单地使用Notbitwise_not)? - user719662

1

Mat格式

  • 输入: CV_8U
  • 距离: CV_32F
  • 归一化: CV_8U

normalize(Mat_dist, Mat_norm, 0, 255, NORM_MINMAX, CV_8U);

如果您想要可视化结果,则需要将归一化缩放到0 ... 255,而不是0 ... 1,否则所有内容都会看起来是黑色的。在缩放到0 ... 1的图像上使用imshow();可以工作,但可能会在下一个处理步骤中引起问题。至少在我的情况下是这样的。


1

在执行归一化函数之前,您可以使用以下代码打印这些值:

for(int x=0; x<10;x++)
  { 
     cout<<endl;
     for(int y=0; y<10;y++)
         cout<<std::setw(10)<<dist.at<float>(x, y);
  }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接