调整图像画布大小以保持Python,OpenCv中的方形纵横比

Hen*_*rik 5 python opencv image-processing aspect-ratio

我想从任何输入图片中获取一张1000 x 1000的Python图片,这样输入就不会丢失它的宽高比.换句话说,我想调整输入的大小,使其较长的尺寸为1000像素,并用背景颜色"填充"另一个尺寸,直到它变为1000 x 1000平方.原件必须在最后的中心.

alk*_*asm 21

使用OpenCV

您可以resize()在OpenCV 中使用上/下调整图像大小到您需要的大小.但是,resize()要求您输入目标大小(在两个维度中)或缩放(在两个维度中),因此您不能只将一个或另一个放入1000中,并让它为您计算另一个.因此,最有效的方法是找到宽高比并计算当较大的尺寸拉伸到1000时较小的尺寸.然后您可以调整大小.

h, w = img.shape[:2]
aspect = w/h
Run Code Online (Sandbox Code Playgroud)

请注意,如果aspect大于1,则图像水平定向,而如果小于1,则图像垂直定向(如果大于等aspect = 1).

根据您是将图像拉伸到更大的分辨率,还是将其缩小到更低的分辨率,不同的插值方法看起来会更好.来自resize()文档:

要缩小图像,通常使用CV_INTER_AREA插值看起来最佳,而放大图像时,通常使用CV_INTER_CUBIC(慢)或CV_INTER_LINEAR(更快但看起来还不错)看起来最佳.

因此,在调整大小后,我们将最终得到一个1000xNNx1000图像(在哪里N<=1000),我们需要用两侧所需的任何背景颜色填充它以填充图像1000x1000.为此,您可以使用copyMakeBorder()纯OpenCV实现,或者您可以使用Python numpy.pad().你需要决定做什么,以防万一需要添加奇数个像素来制作它1000x1000,就像附加像素是向左还是向右(或顶部或底部,取决于图像的方向) ).

这是一个脚本,它定义了一个resizeAndPad()功能,可以自动计算宽高比,相应地缩放,并根据需要填充,然后在水平,垂直和方形图像上使用它:

import cv2
import numpy as np

def resizeAndPad(img, size, padColor=0):

    h, w = img.shape[:2]
    sh, sw = size

    # interpolation method
    if h > sh or w > sw: # shrinking image
        interp = cv2.INTER_AREA
    else: # stretching image
        interp = cv2.INTER_CUBIC

    # aspect ratio of image
    aspect = w/h  # if on Python 2, you might need to cast as a float: float(w)/h

    # compute scaling and pad sizing
    if aspect > 1: # horizontal image
        new_w = sw
        new_h = np.round(new_w/aspect).astype(int)
        pad_vert = (sh-new_h)/2
        pad_top, pad_bot = np.floor(pad_vert).astype(int), np.ceil(pad_vert).astype(int)
        pad_left, pad_right = 0, 0
    elif aspect < 1: # vertical image
        new_h = sh
        new_w = np.round(new_h*aspect).astype(int)
        pad_horz = (sw-new_w)/2
        pad_left, pad_right = np.floor(pad_horz).astype(int), np.ceil(pad_horz).astype(int)
        pad_top, pad_bot = 0, 0
    else: # square image
        new_h, new_w = sh, sw
        pad_left, pad_right, pad_top, pad_bot = 0, 0, 0, 0

    # set pad color
    if len(img.shape) is 3 and not isinstance(padColor, (list, tuple, np.ndarray)): # color image but only one color provided
        padColor = [padColor]*3

    # scale and pad
    scaled_img = cv2.resize(img, (new_w, new_h), interpolation=interp)
    scaled_img = cv2.copyMakeBorder(scaled_img, pad_top, pad_bot, pad_left, pad_right, borderType=cv2.BORDER_CONSTANT, value=padColor)

    return scaled_img

v_img = cv2.imread('v.jpg') # vertical image
scaled_v_img = resizeAndPad(v_img, (200,200), 127)

h_img = cv2.imread('h.jpg') # horizontal image
scaled_h_img = resizeAndPad(h_img, (200,200), 127)

sq_img = cv2.imread('sq.jpg') # square image
scaled_sq_img = resizeAndPad(sq_img, (200,200), 127)
Run Code Online (Sandbox Code Playgroud)

这给出了图像:

缩放的垂直图像 缩放的水平图像 缩放的方形图像

使用ImageMagick

ImageMagick是一个简单但精心构建的命令行界面,用于执行基本图像处理.使用单个命令即可轻松完成所需操作.有关调整大小命令的说明,请参见此处.

$ convert v.jpg -resize 200x200 -background skyblue -gravity center -extent 200x200 scaled-v-im.jpg
$ convert h.jpg -resize 200x200 -background skyblue -gravity center -extent 200x200 scaled-h-im.jpg
$ convert sq.jpg -resize 200x200 -background skyblue -gravity center -extent 200x200 scaled-sq-im.jpg
Run Code Online (Sandbox Code Playgroud)

制作图像:

缩放的垂直图像 缩放的水平图像 缩放的方形图像


Lon*_*guy 7

基于上面的 Alexander-Reynolds 答案,这里是处理所有可能的大小和情况的代码。

def resizeAndPad(img, size, padColor=255):

    h, w = img.shape[:2]
    sh, sw = size

    # interpolation method
    if h > sh or w > sw: # shrinking image
        interp = cv2.INTER_AREA

    else: # stretching image
        interp = cv2.INTER_CUBIC

    # aspect ratio of image
    aspect = float(w)/h 
    saspect = float(sw)/sh

    if (saspect > aspect) or ((saspect == 1) and (aspect <= 1)):  # new horizontal image
        new_h = sh
        new_w = np.round(new_h * aspect).astype(int)
        pad_horz = float(sw - new_w) / 2
        pad_left, pad_right = np.floor(pad_horz).astype(int), np.ceil(pad_horz).astype(int)
        pad_top, pad_bot = 0, 0

    elif (saspect < aspect) or ((saspect == 1) and (aspect >= 1)):  # new vertical image
        new_w = sw
        new_h = np.round(float(new_w) / aspect).astype(int)
        pad_vert = float(sh - new_h) / 2
        pad_top, pad_bot = np.floor(pad_vert).astype(int), np.ceil(pad_vert).astype(int)
        pad_left, pad_right = 0, 0

    # set pad color
    if len(img.shape) is 3 and not isinstance(padColor, (list, tuple, np.ndarray)): # color image but only one color provided
        padColor = [padColor]*3

    # scale and pad
    scaled_img = cv2.resize(img, (new_w, new_h), interpolation=interp)
    scaled_img = cv2.copyMakeBorder(scaled_img, pad_top, pad_bot, pad_left, pad_right, borderType=cv2.BORDER_CONSTANT, value=padColor)

    return scaled_img
Run Code Online (Sandbox Code Playgroud)