Reputation:
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:
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
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:
Input:
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()
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:
Upvotes: 4