如何将图像裁剪、缩放表示为仿射变换?

5
我有一张图片,需要被裁剪并调整大小以便适应图像输入大小。据我所知,这与仿射变换相同。
我试图简化下面的代码,使其通过使用以下函数实现相同的功能(类似于最后的示例):
scipy.ndimage.affine_transform() 

问题在于我并不真正理解那个函数的参数,因此我无法使用affine_transform()函数实现优雅的一行代码。 提供并解释代码的解决方案可能有助于我更好地理解这个affine_transform()函数。

import numpy as npy
import PIL.Image
import scipy.misc as smc
import scipy.ndimage as snd

#crop factor
s = 1.045    

#input image
img2crop = npy.float32(PIL.Image.open("input_image.jpg)")
h, w = img2crop.shape[:2]    #get the dimensions of the input image

#Box-crop values: calculate new crop Dimensions based on 's'
wcrop =  float(w) / (s)
hcrop =  float(wcrop) / (float(w) / float(h))
hcrop = int(round(hcrop))
wcrop = int(round(wcrop))

#crop applied from top-left to right and bottom
b_left = 0
b_top = 0
b_width = wcrop
b_height = hcrop
b_box = (b_left, b_top, b_width, b_height)

#cropped region
region = img2crop.crop(b_box)

#resize cropped region back to input size
resized_region = smc.imresize(region, (h, w), interp='nearest', mode=None)
#save cropped and resized region as new file in output folder
PIL.Image.fromarray(np.uint8(resized_newregion)).save("output_image.jpg")

问题: 如何将上面的裁剪和缩放代码表示为仿射变换?
此示例在所有4个边缘上均匀裁剪,中心定位。
s = 0.0065
cropped_and_resized_image = snd.affine_transform(input_image.jpg, [1-s,1-s,1], [h*s/2,w*s/2,0], order=1)
PIL.Image.fromarray(npy.uint8(cropped_and_resized_image)).save("output_image_at.jpg")

感谢您提前反馈。

3
数学上讲,裁剪并不是一种仿射变换,但如果您将仿射变换视为定在给定大小画布上,则任何裁剪都可以被视为目标画布大小和可能的平移的组合。调整大小只是缩放,这是一种仿射变换。 - hobbs
你说得对,裁剪不是仿射变换。我需要重新表述问题吗?但是,上面的代码能否被转码为affine_transform函数呢?我希望(并相信)它可以。但是怎么做呢? - snahl
在我看来,这似乎是不可能的。对图像应用裁剪和调整大小则完全没有问题。 - snahl
2个回答

1

这里是OpenCV的实现

# OpenCV implementation of crop/resize using affine transform

import numpy as np
from matplotlib import pyplot as plt
%matplotlib inline
import cv2

src_rgb = cv2.imread('test_img.jpg')

# Source width and height in pixels
src_w_px = 640 
src_h_px = 480 

# Target width and height in pixels
res_w_px = 640
res_h_px = 480

# Scaling parameter
s = 2.0

Affine_Mat_w = [s, 0, res_w_px/2.0 - s*src_w_px/2.0]
Affine_Mat_h = [0, s, res_h_px/2.0 - s*src_h_px/2.0]

M = np.c_[ Affine_Mat_w, Affine_Mat_h].T 
res = cv2.warpAffine(src_rgb, M, (res_w_px, res_h_px))

# Showing the result
plt.figure(figsize=(15,6))
plt.subplot(121); plt.imshow(src_rgb); plt.title('Original image');
plt.subplot(122); plt.imshow(res); plt.title('Image warped Affine transform');

0

使用仿射变换的OpenCV实现图像裁剪和缩放至(des_width,des_height)

import numpy as np
import cv2


def crop_resized_with_affine_transform(img_path, roi_xyxy, des_width, des_height):
    src_rgb = cv2.imread(img_path)

    '''
    image roi 
    (x0,y0)------------(x1,y1)
       |                  |
       |                  |
       |                  |
       |                  |
       |                  |
       |                  |
       |                  |
       |                  |
    (-,-)------------(x2, y2)
    '''
    src_points = [[roi_xyxy[0], roi_xyxy[1]], [roi_xyxy[2], roi_xyxy[1]], [roi_xyxy[2], roi_xyxy[3]]]
    src_points = np.array(src_points, dtype=np.float32)
                  
    des_points = [[0, 0], [des_width, 0], [des_width, des_height]]
    des_points = np.array(des_points, dtype=np.float32)

    M = cv2.getAffineTransform(src_points, des_points)
    crop_and_resized_with_affine_transform = cv2.warpAffine(src_rgb, M, (des_width, des_height))

    return crop_and_resized_with_affine_transform
    
    
def crop_resized(img_path, roi_xyxy, des_width, des_height):
    src_rgb = cv2.imread(img_path)    
    roi_img = src_rgb[roi_xyxy[1]:roi_xyxy[3], roi_xyxy[0]:roi_xyxy[2]]
    resized_roi_img = cv2.resize(roi_img, (des_width, des_height))
    
    return resized_roi_img

    

if __name__ == "__main__":
    '''
    Source image from 
    https://www.whitehouse.gov/wp-content/uploads/2021/04/P20210303AS-1901.jpg
    or
    https://en.wikipedia.org/wiki/Joe_Biden#/media/File:Joe_Biden_presidential_portrait.jpg
    '''
    img_path = "Joe_Biden_presidential_portrait.jpg"
    # xmin ymin xmax ymax
    roi_xyxy = [745, 265, 1675, 1520]
    des_width = 480
    des_height = 720
    crop_and_resized_with_affine_transform = crop_resized_with_affine_transform(img_path, roi_xyxy , des_width, des_height)
    resized_roi_img = crop_resized(img_path, roi_xyxy, des_width, des_height)
    cv2.imshow("crop_and_resized_with_affine_transform", crop_and_resized_with_affine_transform)
    cv2.imwrite("crop_and_resized_with_affine_transform.jpg", crop_and_resized_with_affine_transform)
    cv2.imshow("resized_roi_img", resized_roi_img)
    cv2.imwrite("resized_roi_img.jpg", resized_roi_img)
    cv2.waitKey(0)

源图像为维基百科:乔·拜登总统肖像.jpg


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接