1

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)

ronek22
  • 138
  • 1
  • 8

1 Answers1

2

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:

  • x=0, y=0 -> Angle is undefined. Probably returns 0.

  • x=255, y=0 -> Angle is 0° (gradient vector is along x axis).

  • x=0, y=255 -> Angle is 90° (gradient vector is along y axis).

  • x=255, y=255 -> Angle is 45°.

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.

Max Langhof
  • 23,383
  • 5
  • 39
  • 72
  • I did `mag, angle = cv2.cartToPolar(sobel_x, sobel_y)` and looked at both returned arrays. mag is self explanatory but do the entries in the ang array need to be multiplied by pi to convert to radians? Documentation is not clear. So if I get 1.56743 in the ang array that actually means 1.56743 * pi? – mLstudent33 Nov 25 '19 at 23:48
  • @mLstudent33 Without further information I would assume that they are already in radians. Note that 1.56743 is very close to PI/2 (i.e. 90°). Returning the angles as fractions of PI would be extremely unusual. – Max Langhof Nov 26 '19 at 12:21
  • I'm sorry but I was using `np.abs(dx)` and `np.abs(dy)`. That kept all angles returned from `cv2.cartToPolar()` at pi/2 or lower. – mLstudent33 Nov 26 '19 at 18:15