使用opencv函数在c ++中计算梯度方向

时间:2014-07-27 21:44:33

标签: opencv

任何人都可以帮我解决这个问题吗?

我正在尝试使用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变量不是计算的一部分  但要偏移到我最终想要的不同方块  计算直方图特征向量

2 个答案:

答案 0 :(得分:5)

您已指定Sobel()的目标深度为CV_16S。 但是,当您访问grad_xgrad_y时,您使用的是.at<uchar>(),这意味着它们的元素是8位无符号数,而实际上它们是16位有符号的。您可以使用.at<short>()代替,但对我来说,您的代码看起来有很多问题,其中最重要的是有一个OpenCV函数完全符合您的要求。

使用cv::phase(),并用

替换for循环
    cv::Mat gradient_angle_degrees;
    bool angleInDegrees = true;

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

答案 1 :(得分:0)

当我开始使用 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 :)

上查看更多有关数字图像处理的源代码