【问题标题】:Calculating image gradient direction using OpenCV's Sobel operation使用 OpenCV 的 Sobel 运算计算图像梯度方向
【发布时间】:2013-11-20 15:54:53
【问题描述】:

我正在尝试使用 OpenCV 的 Sobel 方法的结果来确定图像梯度方向。

我知道这应该是一项非常简单的任务,我想我理解了理论,但实现它比我想象的更具挑战性。

我希望渐变方向在 0-360 度之间,但是我的代码显示所有渐变都在 180 到 270 度之间。

我提交了此代码的先前版本,其中包含整数除法问题。我已经解决了这个问题,但它并没有解决方向角度受限的问题。

我已经浏览了所有代码,但我就是看不出哪里出错了?谁能发现我的错误?

谢谢。

void getGradients(IplImage* original, cv::Mat* gradArray)
{
cv::Mat original_Mat(original, true);

// Convert it to gray
cv::cvtColor( original_Mat, original_Mat, CV_RGB2GRAY );
//cv::blur(original_Mat, original_Mat, cv::Size(7,7));

/// Generate grad_x and grad_y
cv::Mat grad_x = cv::Mat::zeros(original->height, original->width, CV_16S); 
cv::Mat grad_y = cv::Mat::zeros(original->height, original->width, CV_16S);

/// Gradient X
cv::Sobel(original_Mat, grad_x, CV_16S, 1, 0, 3);

/// Gradient Y
cv::Sobel(original_Mat, grad_y, CV_16S, 0, 1, 3);

uchar* pixelX = grad_x.data;
uchar* pixelY = grad_y.data;
uchar* grad1 = gradArray[0].data;
uchar* grad2 = gradArray[1].data;
uchar* grad3 = gradArray[2].data;
uchar* grad4 = gradArray[3].data;
uchar* grad5 = gradArray[4].data;
uchar* grad6 = gradArray[5].data;
uchar* grad7 = gradArray[6].data;
uchar* grad8 = gradArray[7].data;
int count = 0;
int min = 999999;
int max = -1;

for(int i = 0; i < grad_x.rows * grad_x.cols; i++) 
{
        double directionRAD = atan2(pixelY[i], pixelX[i]);
        int directionDEG = (int)(180 + directionRAD / M_PI * 180);

        if(directionDEG < min){min = directionDEG;}
        if(directionDEG > max){max = directionDEG;}

        if(directionDEG >= 0 && directionDEG <= 45)         { grad1[i] = 255; count++;}         
        if(directionDEG >= 45 && directionDEG <= 90)        { grad2[i] = 255; count++;}         
        if(directionDEG >= 90 && directionDEG <= 135)       { grad3[i] = 255; count++;}         
        if(directionDEG >= 135 && directionDEG <= 190)      { grad4[i] = 255; count++;}         
        if(directionDEG >= 190 && directionDEG <= 225)      { grad5[i] = 255; count++;}         
        if(directionDEG >= 225 && directionDEG <= 270)      { grad6[i] = 255; count++;}     
        if(directionDEG >= 270 && directionDEG <= 315)      { grad7[i] = 255; count++;}
        if(directionDEG >= 315 && directionDEG <= 360)      { grad8[i] = 255; count++;}

        if(directionDEG < 0 || directionDEG > 360)
        {
            cout<<"Weird gradient direction given in method: getGradients.";
        }

}

}

【问题讨论】:

    标签: opencv image-processing computer-vision


    【解决方案1】:

    grad_xgrad_y 是 CV_16SC1 类型的 Mats,即其中的每个像素占用两个字节。

    但是,您将 pixelXpixelY 声明为指向 8 位字节的指针。因此pixelX[1]是第一个梯度的第二个字节,而不是第二个梯度。

    你需要

    short* pixelX = grad_x.ptr<short>(0);
    short* pixelY = grad_y.ptr<short>(0);
    

    【讨论】:

    • 非常感谢。由于您的解释,我终于明白了这个问题。我根本没有考虑过这样的问题,希望将来我能够更好地发现这样的问题。再次感谢。
    • 另外,当您遇到非连续的 Mat 时,您直接在 .data 上进行迭代的习惯会影响您 - 请参阅 docs.opencv.org/doc/tutorials/core/how_to_scan_images/…
    • 谢谢。是的,实际上我通常以与示例类似的方式执行此操作,但在这种情况下,我知道它是连续的,所以只是快速而肮脏地进行;)
    【解决方案2】:

    问题来了

    uchar* pixelX = grad_x.data;
    uchar* pixelY = grad_y.data;
    

    这里

     double directionRAD = atan2(pixelY[i], pixelX[i]);
    

    你不用 abs(),而是使用无符号指针。这就是为什么你不能得到 x 或 y 负数的原因。

    应该是:

    short* pixelX = (short*) grad_x.data;
    short* pixelY = (short*) grad_y.data;
    

     double directionRAD = atan2((double)pixelY[i], (double)pixelX[i]);
    

    【讨论】:

    • 非常感谢。似乎我的问题是缺乏对数据表示和正确使用指针的理解。看来我需要重温这些东西了!再次感谢。
    猜你喜欢
    • 2020-09-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-12
    • 2014-04-18
    相关资源
    最近更新 更多