c++opencvgradientgaussianmagnitude

cartToPolar returns not enough distinct angles


My goal is to colorize camera gradient magnitude with 3 colors based on angle using opencv.

To get gradient magnitude, I converted frame from camera to gray scale, then apply gaussian blur, then create sobel on x axis and y axis, and binarize them with threshold function. At final step I used function called cartToPolar(). But after debugging, angle matrix return by cartToPolar have only 3 distinct values.

Code responsible for create gradient magnitude and corresponding angles

cvtColor(frame, frame, COLOR_BGR2GRAY);
GaussianBlur(frame, gauss, Size(gauss_size, gauss_size), 2.0);

Sobel(gauss, sobel_x, CV_32F, 1.0, 0.0, 3);
threshold(sobel_x, sobel_x_bin, 20, 255, THRESH_BINARY);
Sobel(gauss, sobel_y, CV_32F, 0.0, 1.0, 3);
threshold(sobel_y, sobel_y_bin, 20, 255, THRESH_BINARY);
cartToPolar(sobel_x_bin, sobel_y_bin, gradient, angle, true);

Code responsible for coloring

gradient.copyTo(gradient_colored);
cvtColor(gradient_colored, gradient_colored, COLOR_GRAY2BGR);
gradient_colored.convertTo(gradient_colored, CV_8UC3, 255);
float angle_value;

Vec3b red = Vec3b(0, 0, 255);
Vec3b green = Vec3b(0, 255, 0);
Vec3b blue = Vec3b(255, 0, 0);
Vec3b white = Vec3b(255, 255, 255);

for (int i = 0; i < gradient.rows; i++) {
    for (int j = 0; j < gradient.cols; j++) {
        angle_value = angle.at<float>(i, j);
        // angle contains only three unique values 0, 44.9, 90, why?

        Vec3b *color = &gradient_colored.at<Vec3b>(i, j);
        if (angle_value > 45 && angle_value <= 135)
            * color = white;
        if (angle_value > 135 && angle_value <= 255)
            * color = blue;
        if (angle_value > 255 && angle_value <= 315)
            * color = green;
        if ((angle_value > 315 && angle_value <= 360) || (angle_value > 0 && angle_value <= 45))
            * color = red;

    }
}

I want tri-color(red,blue,green,white,black) gradient magnitude based on camera view, but actual output have one color(white,black,red)


Solution

  • You have two binary images (sobel_x_bin and sobel_y_bin) which you use as x and y components of the gradient at each pixel. Therefore, each pixel can only have four distinct gradient vectors, with only three different angles:

    Take a look at the arrays you are handing to cartToPolar and this should become clear.

    Why exactly are you thresholding your gradient images with a binary threshold? If you want to cut off all gradients below a certain magnitude then you can use a different threshold function (check the available options). But that should be done on a magnitude image (such as the one returned by cartToPolar), not the individual components.

    You should probably try this:

    cvtColor(frame, frame, COLOR_BGR2GRAY);
    GaussianBlur(frame, gauss, Size(gauss_size, gauss_size), 2.0);
    
    Sobel(gauss, sobel_x, CV_32F, 1.0, 0.0, 3);
    Sobel(gauss, sobel_y, CV_32F, 0.0, 1.0, 3);
    cartToPolar(sobel_x, sobel_y, gradient, angle, true);
    

    and then explore from there how to get what you need.