Reputation: 508
I am trying to create an effect similar to the one shown in the following image using Python:
My idea is to create a blank image and map a pixel in the input image to an appropriate pixel in each position in the output image (i.e. reverse mapping).
I was thinking of using the position of the pixels in polar form and play with the angle of each pixel. I tried creating an 'offset' variable to simulate the archimedean spiral that increased in value with each iteration, but this wasn't giving the desired output.
Can anyone help me build on my current code and come up with a function/way to achieve the desired effect on the output image?
def cart2pol(x, y):
rho = np.sqrt(x**2 + y**2)
phi = np.arctan2(y, x)
return(rho, phi)
def pol2cart(rho, phi):
x = rho * np.cos(phi)
y = rho * np.sin(phi)
return(x, y)
def raster2cart(y, x, center):
x = x - center[1]
y = center[0] - y
return x, y
def cart2raster(y, x, center):
x+= center[1]
y = center[0] - y
return x, y
def effect(img, center, r):
img_output = np.zeros(img.shape, dtype=img.dtype)
for row in range(len(img_output[0])):
for col in range(len(img_output[1])):
x, y = raster2cart(col, row , center)
if x**2 + y**2 <= r**2:
rho, phi = cart2pol(x,y)
### DO SOMETHING
x, y = pol2cart(rho, phi)
x, y = cart2raster(y, x, center)
img_output[row, col] = img[int(x), int(y)]
# else:
# img_output[row, col] = img[int(row), int(col)]
return img_output
cv2.imshow('Input', img)
cv2.imshow('Out', effet(img))
cv2.waitKey(0)
Upvotes: 0
Views: 819
Reputation: 10682
Since you are using opencv, use remap to do this as it can handle the interpolation for you.
As for the transformation, looks like it's a spiral, so, I tried to generate a General Archimedean spiral in the code below. Hope I got it right, but please correct if there are any mistakes.
You can adjust the parameters a, b, and c to control the transform.
im = cv.imread("flower.jpg")
# parameters controlling the transform
# (cx, cy) is the center, here I'm using the mid point, but you can use other values
cx = im.shape[1]/2
cy = im.shape[0]/2
# a, b and c are General Archimedean spiral parameters
a = -1
b = 2
c = 1
# select the region around (cx, cy) to apply the transform
r = 1
x = np.linspace(0, im.shape[1], im.shape[1], dtype=np.float32)
y = np.linspace(0, im.shape[0], im.shape[0], dtype=np.float32)
xv, yv = np.meshgrid(x - cx, y - cy)
mag, ang = cv.cartToPolar(xv, yv)
nmag = cv.normalize(mag, None, norm_type=cv.NORM_MINMAX)
sxv, syv = cv.polarToCart(mag, (ang + (a + b*np.pi*nmag**(1.0/c))*(nmag < r)))
spiral = cv.remap(im,
sxv + cx,
syv + cy,
cv.INTER_LINEAR)
Outputs:
center is the image center:
center is (300, 300):
Upvotes: 7