【问题标题】:Computing gradient orientation in c++ using opencv functions使用 opencv 函数在 C++ 中计算梯度方向
【发布时间】:2021-01-06 14:50:09
【问题描述】:

谁能帮我解决这个问题?

我正在尝试使用 OpenCV 中的 Sobel 算子计算 x 和 y 方向的梯度。我正在使用 atan2 函数来计算以弧度为单位的正切,后来我将其转换为度数,但我得到的所有角度都在 0 到 90 度之间。

我的期望是获得 0 到 360 度之间的角度。我使用的图像是灰度的。代码段如下。

Mat PeripheralArea;
Mat grad_x, grad_y;  // this is the matrix for the gradients in x and y directions
int off_set_y = 0, off_set_x = 0;
int scale = 1, num_bins = 8, bin = 0;
int delta=-1 ;
int ddepth = CV_16S;

GaussianBlur(PeripheralArea, PeripheralArea, Size(3, 3), 0, 0, BORDER_DEFAULT);
Sobel(PeripheralArea, grad_y, ddepth, 0, 1,3,scale, delta, BORDER_DEFAULT);
Sobel(PeripheralArea, grad_x, ddepth, 1, 0,3, scale, delta, BORDER_DEFAULT);

for (int row_y1 = 0, row_y2 = 0; row_y1 < grad_y.rows / 5, row_y2 < grad_x.rows / 5; row_y1++, row_y2++) {
    for (int col_x1 = 0, col_x2 = 0; col_x1 < grad_y.cols / 5, col_x2 < grad_x.cols / 5; col_x1++, col_x2++) {
        gradient_direction_radians = (double) atan2((double) grad_y.at<uchar>(row_y1 + off_set_y, col_x1 + off_set_x), (double) grad_x.at<uchar>(row_y2 + off_set_y, col_x2 + off_set_x));
        gradient_direction_degrees = (int) (180 * gradient_direction_radians / 3.1415);
        gradient_direction_degrees = gradient_direction_degrees < 0
                                     ? gradient_direction_degrees+360
                                     : gradient_direction_degrees;

    }

}

注意off_set_xoff_set_y 变量不是计算的一部分 但要偏移到我最终想要的不同方块 计算直方图特征向量

【问题讨论】:

  • 请编辑您的代码。很难阅读。
  • 没有阅读代码:你还记得 arctan 总是产生介于 -pi/2 和 pi/2 (en.wikipedia.org/wiki/…) 之间的值吗?
  • @mistapink 但atan2() 产生介于 -pi 和 pi 之间的值,请参阅 cplusplus.com/reference/cmath/atan2
  • @B...嗯,我不知何故读到了 atan。一定错过了那边的那两个:(

标签: opencv


【解决方案1】:

您已指定Sobel() 的目标深度为CV_16S。 然而,当您访问grad_xgrad_y 时,您使用.at&lt;uchar&gt;(),这意味着它们的元素是8 位无符号数,而实际上它们是16 位有符号数。您可以改用.at&lt;short&gt;(),但在我看来,您的代码存在许多问题,其中最重要的是有一个 OpenCV 函数可以完全满足您的需求。

使用cv::phase(),并将你的for循环替换为

    cv::Mat gradient_angle_degrees;
    bool angleInDegrees = true;

    cv::phase(grad_x, grad_y, gradient_angle_degrees, angleInDegrees);

【讨论】:

    【解决方案2】:

    当我开始使用 C++ 进行边缘检测时,我解决了这个需求。

    对于渐变的方向,我使用了 artan2(),这个标准 API 定义了它的 +y 和 +x,就像我们通常遍历 2D 图像的方式一样。

    绘制它以向您展示我的理解。

    ///////////////////////////////
    // Quadrants of image:
    // 3(-dx,-dy) | 4(+dx,-dy)      [-pi,0]
    // ------------------------->+x
    // 2(-dx,+dy) | 1(+dx,+dy)      [0,pi]
    //            v
    //            +y
    ///////////////////////////////
    // Definition of arctan2():
    // -135(-dx,-dy) | -45(+dx,-dy)
    // ------------------------->+x
    //  135(-dx,+dy) | +45(+dx,+dy)
    //               v
    //               +y
    ///////////////////////////////
    

    渐变效果如何:

    bool gradient(double*& magnitude, double*& orientation, double* src, int width, int height, string file) {
    if (src == NULL)
        return false;
    if (width <= 0 || height <= 0)
        return false;
    
    double gradient_x_correlation[3*3] = {-0.5, 0.0, 0.5,
                                          -0.5, 0.0, 0.5,
                                          -0.5, 0.0, 0.5};
    double gradient_y_correlation[3*3] = {-0.5,-0.5,-0.5,
                                           0.0, 0.0, 0.0,
                                           0.5, 0.5, 0.5};
    
    double *Gx = NULL;
    double *Gy = NULL;
    
    this->correlation(Gx, src, gradient_x_correlation, width, height, 3);
    this->correlation(Gy, src, gradient_y_correlation, width, height, 3);
    
    if (Gx == NULL || Gy == NULL) 
        return false;
    
    //magnitude
    magnitude = new double[sizeof(double)*width*height];
    if (magnitude == NULL)
        return false;
    memset(magnitude, 0, sizeof(double)*width*height);
    double gx = 0.0;
    double gy = 0.0;
    double gm = 0.0; 
    for (int j=0; j<height; j++) {
        for (int i=0; i<width; i++) {
            gx = pow(Gx[i+j*width],2);
            gy = pow(Gy[i+j*width],2);
            gm = sqrt(pow(Gx[i+j*width],2)+pow(Gy[i+j*width],2));
            if (gm >= 255.0) {
                return false;
            }
            magnitude[i+j*width] = gm;
        }
    }
    
    //orientation
    orientation = new double[sizeof(double)*width*height];
    if (orientation == NULL)
        return false;
    memset(orientation, 0, sizeof(double)*width*height);
    double ori = 0.0;
    
    double dtmp = 0.0;
    double ori_normalized = 0.0;
    for (int j=0; j<height; j++) {
        for (int i=0; i<width; i++) {
            gx = (Gx[i+j*width]);
            gy = (Gy[i+j*width]);
            ori = atan2(Gy[i+j*width], Gx[i+j*width])/PI*(180.0); //[-pi,+pi]
            if (gx >= 0 && gy >= 0) { //[Qudrant 1]:[0,90] to be [0,63] 
                if (ori < 0) {
                    printf("[Err1QUA]ori:%.1f\n", ori);
                    return false;
                }
                ori_normalized = (ori)*255.0/360.0; 
                if (ori != 0.0 && dtmp != ori) {
                    printf("[Qudrant 1]orientation: %.1f to be %.1f(%d)\n", ori, ori_normalized, (uint8_t)ori_normalized);
                    dtmp = ori;
                }
            }
            else if (gx >= 0 && gy < 0) { //[Qudrant 4]:[270,360) equal to [-90, 0) to be [191,255]
                if (ori > 0) {
                    printf("[Err4QUA]orientation:%.1f\n", ori);
                    return false;
                }
                ori_normalized = (360.0+ori)*255.0/360.0;
                if (ori != 0.0 && dtmp != ori) {
                    printf("[Qudrant 4]orientation:%.1f to be %.1f(%d)\n", ori, ori_normalized, (uint8_t)ori_normalized);
                    dtmp = ori;
                }
            }
            else if (gx < 0 && gy >= 0) { //[Qudrant 2]:(90,180] to be [64,127]
                if (ori < 0) {
                    printf("[Err2QUA]orientation:%.1f\n", ori);
                    return false;
                }
                ori_normalized = (ori)*255.0/360.0; 
                if (ori != 0.0 && dtmp != ori) {
                    printf("[Qudrant 2]orientation: %.1f to be %.1f(%d)\n", ori, ori_normalized, (uint8_t)ori_normalized);
                    dtmp = ori;
                }
            }
            else if (gx < 0 && gy < 0) { //[Qudrant 3]:(180,270) equal to (-180, -90) to be [128,190] 
                if (ori > 0) {
                    printf("[Err3QUA]orientation:%.1f\n", ori);
                    return false;
                }
                ori_normalized = (360.0+ori)*255.0/360.0; 
                if (ori != 0.0 && dtmp != ori) { 
                    printf("[Qudrant 3]orientation:%.1f to be %.1f(%d)\n", ori, ori_normalized, (uint8_t)ori_normalized);
                    dtmp = ori;
                }
            }
            else {
                printf("[EXCEPTION]orientation:%.1f\n", ori);
                return false;
            }
            orientation[i+j*width] = ori_normalized;
        }
    }
    return true;
    }
    

    我如何进行互相关:

    bool correlation(double*& dst, double* src, double* kernel, int width, int height, int window) {
    if (src == NULL || kernel == NULL)
        return false;
    if (width <= 0 || height <= 0 || width < window || height < window )
        return false;
    dst = new double[sizeof(double)*width*height];
    if (dst == NULL)
        return false;
    memset(dst, 0, sizeof(double)*width*height);
    
    int ii = 0;
    int jj = 0;
    int nn = 0;
    int mm = 0;
    
    double max = std::numeric_limits<double>::min();
    double min = std::numeric_limits<double>::max();
    double range = std::numeric_limits<double>::max();
    
    for (int j=0; j<height; j++) {
        for (int i=0; i<width; i++) {
            for (int m=0; m<window; m++) {
                for (int n=0; n<window; n++) {
                    ii = i+(n-window/2);
                    jj = j+(m-window/2);
                    nn = n;
                    mm = m;
                    if (ii >=0 && ii<width && jj>=0 && jj<height) {
                        dst[i+j*width] += src[ii+jj*width]*kernel[nn+mm*window];
                    }
                    else {
                        dst[i+j*width] += 0;
                    }
                }
            }
            if (dst[i+j*width] > max) 
                max = dst[i+j*width];
            else if (dst[i+j*width] < min)
                min = dst[i+j*width];
        }
    }
    
    //normalize double matrix to be an uint8_t matrix
    range = max - min;
    double norm  = 0.0;
    printf("correlated matrix max:%.1f, min:%.1f, range:%.1f\n", max, min, range);
    for (int j=0; j<height; j++) {
        for (int i=0; i<width; i++) {
            norm = dst[i+j*width];
            norm = 255.0*norm/range;
            dst[i+j*width] = norm;
        }
    }
    return true;
    }
    

    对我来说,我用的是像一个空心矩形的图像,你可以在my sample下载。

    我的示例图像的空心矩形部分的渐变方向将从顺时针方向从 0 移动到 360(象限 1 到 2 到 3 到 4)。

    这是我的印刷品,描述了方向的痕迹:

    [Qudrant 1]orientation: 45.0 to be 31.9(31)
    [Qudrant 1]orientation: 90.0 to be 63.8(63)
    [Qudrant 2]orientation: 135.0 to be 95.6(95)
    [Qudrant 2]orientation: 180.0 to be 127.5(127)
    [Qudrant 3]orientation:-135.0 to be 159.4(159)
    [Qudrant 3]orientation:-116.6 to be 172.4(172)
    [Qudrant 4]orientation:-90.0 to be 191.2(191)
    [Qudrant 4]orientation:-63.4 to be 210.1(210)
    [Qudrant 4]orientation:-45.0 to be 223.1(223)
    

    你可以在我的GitHub看到更多关于数字图像处理的源代码:)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-09-12
      • 1970-01-01
      • 1970-01-01
      • 2015-01-21
      相关资源
      最近更新 更多