jankrepl/pychubby

When i apply a transform to an image, it shrinks the image.

parkgeonwo opened this issue · 6 comments

code

from pychubby.actions import OpenEyes

a = OpenEyes(scale=-0.04)
new_lf, df = a.perform(lf)
new_lf.plot(show_landmarks=False)

original image

original

applied imgae

new_lf2

If you look at the top side of the applied image, the image is scaled down with a black area.

Is it possible to transform a face without this being made?

https://pychubby.readthedocs.io/en/latest/source/gallery.html
If you look at the LinearTransform gif on the pychubby official website, you will see the same phenomenon.

Thanks for providing a good reference.

When I transform the eyes, I want only the eyes to be transformed, not the entire image.

Hey there! And thank you for your interest!

That is actually a great question:) pychubby is built on top of a "4 corners logic". That means that the 4 corners will never be displaced. However, very often points on the edges are going to be displaced and it will lead to these black regions. Note that if it was not the case even weirder artefacts might show up.

Anyway, possible solutions

  1. Just crop the final image so that the black regions on the edges are not visible
  2. Get all the perfectly black pixels (RGB=(0, 0, 0)) and replace them with some other color. A cleaner way of doing this would be passing a custom color in cv.remap when doing the warping.
    warped_img = cv2.remap(img, tform_x, tform_y, order)
  3. Completely change the logic of pychubby and make sure that pixels on the edge of the image are not displaced

I would go for the first option:)

Hope that helps:)

Thank you for answer. Do you know how to prevent the pixels on the edges from being deformed?
Methods 1 and 2 do not seem to be able to solve my problem now.

Well, you would need to modify the source code. See below exactly the lines which implement the "fixed points" logic. Currently, it only "anchors" the 4 corners.

if anchor_corners:
corners = np.array([[0, 0],
[0, shape[0] - 1],
[shape[1] - 1, 0],
[shape[1] - 1, shape[0] - 1]])
new_points = np.vstack([new_points, corners])
old_points = np.vstack([old_points, corners])
points_delta_x = np.concatenate([points_delta_x, [0, 0, 0, 0]])
points_delta_y = np.concatenate([points_delta_y, [0, 0, 0, 0]])

See below a sketch of a possible change

Screenshot 2022-10-06 at 15 57 25

I guess you would have to play around and experiment a bit and see for yourself. You can add as many fixed points as you want. Note that by specifying these fixed points you are basically forcing the displacement at those given points to be 0.

Hope that makes sense:)

Transforming by adding anchor points at 50px spacing to each corner solved the problem. Thank you so very much.

corners_list = []
corners_list.append([0, 0])
corners_list.append([0, shape[0] -1])   # 0,y
corners_list.append([shape[1] -1, 0])   # x,0
corners_list.append([shape[1] -1, shape[0] -1])   # x,y

for i in range(1, shape[0]-1, 50):
    corners_list.append([0,i])
    corners_list.append([shape[1]-1,i])
for i in range(1, shape[1]-1, 50): 
    corners_list.append([i,0])
    corners_list.append([i,shape[0]-1])   

# print(shape[0], shape[1])
# print(corners_list)

if anchor_corners:
    corners = np.array(corners_list)  
    new_points = np.vstack([new_points, corners])
    old_points = np.vstack([old_points, corners])
    points_delta_x = np.concatenate([points_delta_x, [0 for i in range(len(corners_list))]]) 
    points_delta_y = np.concatenate([points_delta_y, [0 for i in range(len(corners_list))]])

Great!