【问题标题】:Plotting a Gradient Vector Field in OpenCV在 OpenCV 中绘制梯度向量场
【发布时间】:2015-12-30 16:53:02
【问题描述】:

我想计算灰度图像的梯度(代码中的smoothed_plane)并将其绘制为 OpenCV 中的矢量场,叠加到现有图像上。

我尝试应用一对 Sobel 运算符(我也尝试过 Scharr)来计算沿 x 和 y 的两个导数,如 OpenCV 文档中所述,但是当我尝试绘图时,矢量场似乎完全错误。我想了解我的错误是什么。

为了更清楚,我在这里放了一些代码。提前感谢您的帮助。

//img is a gray-scale image
Mat abs_grad_x, abs_grad_y, grad;
Mat g_img;
int ddepth = CV_16S;
int scale = 1;
int delta = 0;    

cvtColor(img,g_img,CV_GRAY2BGR);


smoothed_plane = Mat::zeros(image_height,image_width,CV_8UC1);
gradient_field = Mat::zeros(image_height,image_width,CV_32FC2);

// Smooth the dominant plane by convolution with a Gaussian
GaussianBlur(dominant_plane,smoothed_plane,Size(51,51),image_height*image_width*0.5);

/// Morphological opening (remove small objects from the foreground)
erode(smoothed_plane, smoothed_plane, getStructuringElement(MORPH_ELLIPSE, Size(40+1,40+1)));
dilate(smoothed_plane, smoothed_plane, getStructuringElement(MORPH_ELLIPSE, Size(40, 40)));
/// Morphological closing (fill small holes in the foreground)
dilate(smoothed_plane, smoothed_plane, getStructuringElement(MORPH_ELLIPSE, Size(40, 40)));
erode(smoothed_plane, smoothed_plane, getStructuringElement(MORPH_ELLIPSE, Size(40, 40)));

imshow("Eroded plane",smoothed_plane);

/// Gradient X
Scharr( smoothed_plane, grad_x, ddepth, 1, 0, scale, delta, BORDER_DEFAULT );
convertScaleAbs( grad_x, abs_grad_x );

/// Gradient Y
Scharr( smoothed_plane, grad_y, ddepth, 0, 1, scale, delta, BORDER_DEFAULT );
convertScaleAbs( grad_y, abs_grad_y );

for (int i = 0 ; i < image_height ; i ++){
    for (int j = 0 ; j < image_width ; j ++){
        gradient_field.at<Point2f>(Point2f(j,i)) = Point2f(abs_grad_x.at<float>(Point2f(j,i)),abs_grad_y.at<float>(Point2f(j,i)));
    }
}

for (int i = 0 ; i < image_height ; i += flowResolution){
    for (int j = 0 ; j < image_width ; j+= flowResolution){
        Point2f p(j,i);
        Point2f p2(gradient_field.at<Point2f>(p)+p);
        arrowedLine(g_img,p,p2,Scalar(0,0,255),1.5,8,0,0.1);
    }
}//*/

imshow("Gradient Vector Field", g_img);

编辑:

这是我的输入/输出结果的一对帧,根据需要

我尝试打印出一些值,但在某些点上我得到了非常高或非常低的值。 再次感谢

【问题讨论】:

    标签: c++ opencv vector field gradient


    【解决方案1】:

    在尝试直接使用您的代码后,以下内容对我有用

    Scharr(smoothed_plane,grad_x,ddepth,1,0,scale);
    Scharr(smoothed_plane,grad_y,ddepth,0,1,scale);
    
    for (int i = 0 ; i < image_height ; i ++){
        for (int j = 0 ; j < image_width ; j ++){
            Scalar xval = grad_x.at<uchar>(i,j); // Notice <uchar> not float
            Scalar yval = grad_y.at<uchar>(i,j);
            gradient_field.at<Point2f>(i,j) = Point2f(xval.val[0],yval.val[0]);
        }
    }
    

    建议给了我很高且无法使用的价值。

    【讨论】:

    • 是的,我认为这取决于您希望在 Scharr 运算符中为目标矩阵 (ddepth) 设置的深度。就我而言,我将其更改为 CV_32F,因此使用 对我有用。我想 应该适用于 CV_8U(CV_16S 也是?)。无论如何谢谢:)
    【解决方案2】:

    我解决了我的问题。主要错误在于偏导数矩阵grad_xgrad_y的存取方法。正如here 所述,at.() 方法返回一个 Scalar 对象,因此要访问像素强度值,应该使用 。 val[] 字段。这就是代码必须更改的方式:

    Scharr(smoothed_plane,grad_x,ddepth,1,0,scale);
    Scharr(smoothed_plane,grad_y,ddepth,0,1,scale);
    
    for (int i = 0 ; i < image_height ; i ++){
        for (int j = 0 ; j < image_width ; j ++){
            Scalar xval = grad_x.at<float>(i,j);
            Scalar yval = grad_y.at<float>(i,j);
            gradient_field.at<Point2f>(i,j) = Point2f(xval.val[0],yval.val[0]);
        }
    }
    

    这是预期的结果:

    【讨论】:

    • 你是如何设法缩小箭头的?我正在尝试您的初始代码,与您在上图中显示的相比,我得到了更大的箭头。
    • 是的,我只是为了可视化目的而缩小了箭头的大小。原来的箭头在我看来也更大。我之前没有说,因为这对我的问题来说是不必要的。基本上,我将每个箭头的终点设置为 cv::Point2f p2(p + gf_ptr[j]*0.1),其中 p 是起点
    • 好的,谢谢您的反馈。 gf_ptrPoint2f* gf_ptr = gradient_field.ptr&lt;Point2f&gt;(i); 对吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-16
    • 1970-01-01
    • 2012-05-12
    • 2023-03-06
    • 1970-01-01
    • 2018-12-30
    相关资源
    最近更新 更多