user16541277
user16541277

Reputation:

Coloring edges in python cv2 and C# emgu cv

So I'm trying to reproduce a cool filter I did a while back in C# (emgucv) in Python cv2. Despite my hopes it's not going very smoothly. The programs suppose to highlight edges and color them with a cool looking gradient.

The code in C#:

        {
        Image<Gray, byte> gray= imgColored.Convert<Gray, byte>();
        Image<Gray, float> photo_dx = gray.Sobel(1, 0, 3);
        Image<Gray, float> photo_dy = gray.Sobel(0, 1, 3);
        Image<Gray, float> photo_grad = new Image<Gray, float>(gray.Size);
        Image<Gray, float> photo_angle = new Image<Gray, float>(gray.Size);
        CvInvoke.CartToPolar(photo_dx, photo_dy, photo_grad, photo_angle, true);
        Image<Hsv, float> coloredEdges = gray.Convert<Hsv, float>(); 

        for (int j = 0; j < coloredEdges.Cols; j++)
            for (int i = 0; i < coloredEdges.Rows; i++)
            {
                Hsv pix = coloredEdges[i, j];

                pix.Hue = photo_angle[i, j].Intensity;
                pix.Satuation = 1;
                pix.Value = photo_grad[i, j].Intensity;

                coloredEdges[i, j] = pix;
            }

        coloredEdges.Save("test.jpg");
       }

The code in Python:

def LSD_ify(image, mag, angle):
     image = image = image.astype(np.float64)
     height, width, depth = image.shape

     for x in range(0, height):
         for y in range(0, width):
            image[x, y, 0] = angle[x, y]
            image[x, y, 1] = 1
            image[x, y, 2] = mag[x, y]

    return image

def main():
       image = plt.imread(str(sys.argv[1]))
       gray_image = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
       g2bgr = cv.cvtColor(gray_image, cv.COLOR_GRAY2BGR) #cv2 cant convert gray to HSV directly, so i had to convert back to colored and finally to HSV

       gx = cv.Sobel(gray_image, cv.CV_64F, 1, 0, ksize = 3)
       gy = cv.Sobel(gray_image, cv.CV_64F, 0, 1, ksize = 3)

       mag, angle = cv.cartToPolar(gx, gy, angleInDegrees = True)
       hsv_image = cv.cvtColor(g2bgr, cv.COLOR_BGR2HSV)

       lsd = LSD_ify(hsv_image, mag, angle)

       cv.imwrite("test.jpg", lsd)

if __name__ == "__main__":
      main()

The code is mostly identical(i think?), the results they produce however are different. The input image: enter image description here

C# program: enter image description here

Python script: enter image description here

Does anyone have any insight on what I'd have to do to get identical results in Python? I'm not sure how things work in the background in Python.

Upvotes: 2

Views: 818

Answers (1)

fmw42
fmw42

Reputation: 53081

I think this is what you are trying to do in Python/OpenCV. Python HSV hue is limited to range 0 to 180 so your angle needs to be scaled to that range. Similarly the magnitude is greater than 255 and also needs to be scaled to the range 0 to 255. The saturation you want would be a constant 255. I use Skimage to do the scaling. I have printed out the shape and min and max values at various places to show you these issues.

I believe the process is as follows:

  • Read the input
  • Convert it to gray
  • Get the Sobel x and y derivatives
  • Compute the magnitude and angle from the derivatives and scale mag to range 0 to 255 and angle to range 0 to 180
  • Merge the angle, the magnitude and the magnitude into a 3 channel image as if HSV with angle first, then the magnitudes.
  • Replace the second channel (channel 1) with 255 for the saturation
  • Convert this HSV image to BGR as the result
  • Save the result

Input:

enter image description here

import cv2
import numpy as np
import skimage.exposure as exposure

# read the image
img = cv2.imread('rabbit.jpg')

# convert to gray
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# apply sobel derivatives
sobelx = cv2.Sobel(gray, cv2.CV_64F, 1, 0, ksize=3)
sobely = cv2.Sobel(gray, cv2.CV_64F, 0, 1, ksize=3)

print(sobelx.shape, np.amin(sobelx), np.amax(sobelx))
print(sobely.shape, np.amin(sobely), np.amax(sobely))
print("")

# get magnitude and angle
mag, angle = cv2.cartToPolar(sobelx, sobely, angleInDegrees = True)

print(mag.shape, np.amin(mag), np.amax(mag))
print(angle.shape, np.amin(angle), np.amax(angle))
print("")

# normalize mag to range 0 to 255 and angle to range 0 to 180
mag = exposure.rescale_intensity(mag, in_range='image', out_range=(0,255)).clip(0,255).astype(np.uint8)
angle = exposure.rescale_intensity(angle, in_range='image', out_range=(0,180)).clip(0,180).astype(np.uint8)

print(mag.shape, np.amin(mag), np.amax(mag))
print(angle.shape, np.amin(angle), np.amax(angle))

# combine channels as if hsv where angle becomes the hue and mag becomes the value. (saturation is not important since it will be replace by 255)
hsv = cv2.merge([angle, mag, mag])
hsv[:,:,1] = 255

# convert hsv to  bgr
result = cv2.cvtColor(hsv, cv2.COLOR_HSV2BGR)

# save results
cv2.imwrite('rabbit_color_edges.jpg', result)

# show result
cv2.imshow('result', result)  
cv2.waitKey(0)
cv2.destroyAllWindows()

enter image description here

ADDITION

If I scale the magnitude (or gray) by doubling "out_range":

mag = exposure.rescale_intensity(mag, in_range='image', out_range=(0,255)).clip(0,255).astype(np.uint8) 

to

mag = exposure.rescale_intensity(mag, in_range='image', out_range=(0,510)).clip(0,255).astype(np.uint8)

Then I get very close to your result:

enter image description here

Upvotes: 4

Related Questions