Anamorphosis in Python

842 views Asked by At

I tried to do anamorphosis on an image by following this link

https://github.com/aydal/Cylinderical-Anamorphosis/blob/master/anamorph.py

It gives an anamorphic image but it gives that image in the half circle. But I want the output in a full circle size. I tried with

warp[c-j, i-1] = img[p-1, q-1]
warp[c+j, i-1] = img[p-1, q-1]

Instead of warp[c-j, i-1] = img[p-1, q-1]

But it doesn't give one image in the full circle rather creates same output twice!

Can anyone please help me.

Complete Code:

import math
from cv2 import *
import numpy as np

img = imread("test.jpg")
(rows, cols) = (img.shape[0], img.shape[1])
r = 0  #offset-gives space to keep cylinder and height of the image from bottom: original: math.trunc(.25*rows)
c = rows  #this will be the decisive factor in size of output image-maximum radius of warped image: original: c = r+rows
warp = np.zeros([c,2*c,3], dtype=np.uint8)


def convert(R, b):
    return math.trunc(b*rows/(2*math.asin(1))), math.trunc(c-R)


for i in range(0, 2*c):
    for j in range(1, c):
        b = math.atan2(j, i-c)
        R = math.sqrt(j*j+math.pow(i-c, 2))
        if R>=r and R<=c:
            (q, p) = convert(R, b)
            warp[c-j, i-1] = img[p-1, q-1]
            #warp[c+j, i-1] = img[p-1, q-1]

imshow("Output", warp)
waitKey()

The original image enter image description here

My output image (half circle) enter image description here

Desired output image enter image description here

1

There are 1 answers

1
a_guest On BEST ANSWER

Similar to the column offset you should include an offset for the rows as well when computing b and R. Since the warped image has c rows the offset is c//2:

b = math.atan2(j - c//2, i-c)
R = math.sqrt((j - c//2)**2 + math.pow(i-c, 2))

Note that the warped image is not a perfect circle as you specified it be double as wide as high. If you want a full circle you should also adjust the upper boundary check for R to be c//2 as this is the max. radius along the rows:

if r <= R <= c//2:
    ...

And similarly you need to adjust the computation in convert:

return ..., math.trunc(c//2 - R)

But then, in any case, you could just use a square image right from the beginning, i.e. specify warp.shape == (c, c).

Edit

Updated code, uses original dimensions for warped image:

import math
import cv2
import numpy as np

img = cv2.imread("/tmp/img.jpg")
(rows, cols) = (img.shape[0], img.shape[1])
r = 0
c = rows // 2
warp = np.zeros([rows, cols, 3], dtype=np.uint8)


def convert(R, b):
    return math.trunc(c * (1 - b/math.pi)), 2*math.trunc(c - R) - 1


for i in range(0, cols):
    for j in range(0, rows):
        b = math.atan2(j - c, i - c)
        R = math.sqrt((j - c)**2 + (i - c)**2)
        if r <= R <= c:
            q, p = convert(R, b)
            warp[j, i] = img[p, q]

cv2.imshow("Output", warp)
cv2.waitKey()

And output image:

Output image