如何沿X轴和Y轴缩放图像并裁剪到特定的高度和宽度?

时间:2017-06-06 23:11:29

标签: python opencv image-processing

我需要在X和Y方向拉伸图像,但同时保持目标图像尺寸为300x300。我正在使用Open CV。每次我缩放图像然后调整大小时,我都会失去缩放比例,它看起来与我按比例缩放图像相同。我该如何做到这一点?

这是缩放的代码

def scale(infile,outfile,scx,scy):
    img = cv2.imread(infile,0)
    height, width = img.shape[:2]
    #aspectRatio = width / height
    rows,cols = img.shape
    if scx > 1 or scy > 1:
        scimg = cv2.resize(img,None, fx = scx, fy = scy, interpolation = cv2.INTER_LINEAR)
    else:
        scimg = cv2.resize(img,None, fx = scx, fy = scy, interpolation = cv2.INTER_CUBIC)

    #cheight, cwidth = scimg.shape[:2]
    #area = cheight * cwidth
    #nheight = math.sqrt(area / aspectRatio)
    #nwidth = nheight * aspectRatio
    #cv2.resize(scimg,((int)(nwidth), (int)(nheight)), interpolation = cv2.INTER_CUBIC)
    #top = (int) (0.2*rows)
    #bottom = (int) (0.2*rows)
    #left = (int) (0.2*cols)
    #right = (int) (0.2*cols);
    #cv2.copyMakeBorder(scimg,top,left,bottom,right,cv2.BORDER_CONSTANT,value=255)
    cv2.imwrite(outfile,scimg)

我将scale数组用于x和y比例因子:scales = [(1,2),(2,1)] 我希望最终图像应该是300x300,并且应该包含图像的缩放版本。 谢谢!!

1 个答案:

答案 0 :(得分:1)

如果您只想将其用于显示目的,最简单的方法是在裁剪后的图像上使用cv2.imshow()并使用cv2.resizeWindow()将窗口大小设置为原始图像大小。

import cv2
import numpy as np

img = cv2.imread('lena.png')
h, w = img.shape[:2]
scale = (0.6, 0.4) # define your scale
scaled_img = cv2.resize(img, None, fx=scale[0], fy=scale[1]) # scale image

cv2.namedWindow("Scaled image", cv2.WINDOW_NORMAL) # create a resizeable window
cv2.imshow("Scaled image", scaled_img) # display the image in the window
cv2.resizeWindow("Scaled image", w, h) # resize the window
cv2.waitKey(0)

将在窗口具有原始图像大小的窗口内显示缩放图像。通过裁剪图像的右侧和顶部(图像锚定在窗口的左下角),即使您缩放图像也可以使用此功能。请参阅输出窗口:

Scaled Lena display

但是,如果您希望将其保存到另一个矩阵中,则需要使用图像外部的任何颜色填充图像。最简单的方法是使用该颜色创建矩阵,然后创建与缩放图像大小相同的ROI,并将缩放后的图像放置在ROI中。

import cv2
import numpy as np

img = cv2.imread('lena.png')
scale = (0.6, 0.4) # define your scale
scaled_img = cv2.resize(img, None, fx=scale[0], fy=scale[1]) # scale image

sh, sw = scaled_img.shape[:2] # get h, w of scaled image
padded_scaled = np.zeros(img.shape, dtype=np.uint8)
padded_scaled[0:sh, 0:sw] = scaled_img

cv2.imshow("Scaled image", padded_scaled)
cv2.waitKey(0)

这会将缩放后的图片放在目标0,0中的padded_scaled

Padded and scaled image

如果你希望它显示在中心,你可以做一些简单的计算来获得图像的中心,然后将缩放图像的宽度和高度的一半移动到起始位置。

import cv2
import numpy as np

img = cv2.imread('lena.png')
scale = (0.6, 0.4) # define your scale
scaled_img = cv2.resize(img, None, fx=scale[0], fy=scale[1]) # scale image

h, w = img.shape[:2] # get h, w of image
sh, sw = scaled_img.shape[:2] # get h, w of scaled image
center_y = int(h/2 - sh/2)
center_x = int(w/2 - sw/2)
padded_scaled = np.zeros(img.shape, dtype=np.uint8) # using img.shape to obtain #channels
padded_scaled[center_y:center_y+sh, center_x:center_x+sw] = scaled_img

cv2.imshow("Scaled image", padded_scaled)
cv2.waitKey(0)

这会将缩放后的图像放在填充矩阵的中心:

Scaled and centered image

仅当图像比原始图像缩小时才会起作用,因为您将较小的图像放入较大的空白矩阵中。但是,如果要允许更大的缩放比例,那么此时您需要裁剪。您可以从缩放图像中裁剪与原始图像大小相同的区域。但是,如果比例在一个维度中大于1而在另一个维度中小于1,则您需要同时裁剪 pad。我将其分为if个语句的两个部分:首先创建一个结果,如果需要,通过裁剪创建最多的图像大小,然后然后填充,如果它更小。

import cv2
import numpy as np

img = cv2.imread('lena.png')
scale_x, scale_y = 13, .3 # define your scale
h, w = img.shape[:2] # get h, w of image

if scale_x > 1 or scale_y > 1:

    scaled_img = cv2.resize(img, None, fx=scale_x, fy=scale_y, interpolation = cv2.INTER_LINEAR) # scale image
    sh, sw = scaled_img.shape[:2] # get h, w of scaled image
    center_y = int(sh/2 - h/2)
    center_x = int(sw/2 - w/2)
    cropped = scaled_img[center_y:center_y+h, center_x:center_x+w]

    result = cropped

elif scale_x > 0 or scale_y > 0:
    scaled_img = cv2.resize(img, None, fx=scale_x, fy=scale_y, interpolation = cv2.INTER_CUBIC) # scale image
    result = scaled_img

else: # scale_x or scale_y is negative
    print("Scales must be greater than 0; returning the original image.")
    result = img

if result.shape < img.shape: # one of the dimensions was scaled smaller, so need to pad
    sh, sw = result.shape[:2] # get h, w of cropped, scaled image
    center_y = int(h/2 - sh/2)
    center_x = int(w/2 - sw/2)
    padded_scaled = np.zeros(img.shape, dtype=np.uint8)
    padded_scaled[center_y:center_y+sh, center_x:center_x+sw] = result
    result = padded_scaled

cv2.imshow("Scaled padded/cropped image", result)
cv2.waitKey(0)

在一个方向上有一个较大的拉伸而在另一个方向上的比例较小,这将导致图像显示如下:

Scaled, cropped, and padded image