我想在Python中从任何输入图片中获取一个1000 x 1000像素的图片,以便输入不会失去其长宽比。换句话说,我想调整输入大小,使其较长的一维为1000像素,并且“填充”另一维直到成为1000 x 1000正方形,背景颜色为原始图片的颜色。最终结果必须在中心位置。
我想在Python中从任何输入图片中获取一个1000 x 1000像素的图片,以便输入不会失去其长宽比。换句话说,我想调整输入大小,使其较长的一维为1000像素,并且“填充”另一维直到成为1000 x 1000正方形,背景颜色为原始图片的颜色。最终结果必须在中心位置。
您可以使用OpenCV中的resize()
将图像调整大小以适应所需的尺寸。但是,resize()
要求您输入目标大小(在两个维度上)或缩放比例(在两个维度上),因此您不能只输入一个参数为1000并让它计算另一个参数。因此,最可靠的方法是找到纵横比并计算大尺寸被伸展到1000时小尺寸会是多少。然后您就可以进行调整大小操作了。
h, w = img.shape[:2]
aspect = w/h
请注意,如果aspect
大于1,则图片会水平方向定位,如果它小于1,则图片会垂直方向定位(如果aspect = 1
,则为正方形)。resize()
文档中可以了解到:1000xN
或Nx1000
的图像(其中N<=1000
),然后需要在两侧使用任何背景颜色填充它以填充到1000x1000
的图像。为此,您可以使用纯OpenCV实现的copyMakeBorder()
,或者由于您正在使用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)
这将会显示以下图片:
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
生成图像:
aspect = w/h
替换为aspect = float(w)/h
就解决了。 - Marph4/2 = 2
,而float(4)/2 = 2.0
。在Python 3中,4/2 = 2.0
,因此不需要强制类型转换。也就是说,在Python 2中,除法是整数除法(所以5/3 = 1
),而在Python 3中,它总是浮点数(所以5/3 = 1.666666...7
)。 - alkasmfrom __future__ import division
。 - leoll2在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
伦敦小伙儿的C++版本
int resizeAndPad(cv::Mat &src, cv::Mat& dst /*output*/, Size size, int padColor = 0)
{
int h = src.rows;
int w = src.cols;
int sh = size.height;
int sw = size.width;
int interp;
int new_h;
int new_w;
float pad_horz, pad_left, pad_right, pad_top, pad_bot, pad_vert;
cv::Scalar bColor;
//interpolation method
if (h > sh || w > sw)//shrinking image
{
interp = cv::INTER_AREA;
}
else //stretching image
{
interp = cv::INTER_CUBIC;
}
//aspect ratio of image
float aspect = float(w) / h;
float saspect = float(sw) / sh;
//new horizontal image
if ( (saspect >= aspect) || ((saspect == 1) && (aspect <= 1)) )
{
new_h = sh;
new_w = int(new_h * aspect);
pad_horz = float(sw - new_w) / 2;
pad_left = int(pad_horz);
pad_right = int(pad_horz);
pad_top = 0;
pad_bot = 0;
}
//new vertical image
else if ( (saspect < aspect) || ((saspect == 1) && (aspect >= 1)))
{
new_w = sw;
new_h = int(float(new_w) / aspect);
pad_vert = float(sh - new_h) / 2;
pad_top = int(pad_vert);
pad_bot = int(pad_vert);
pad_left = 0;
pad_right = 0;
}
if (src.channels() == 3)
{
bColor = cv::Scalar(padColor, padColor, padColor);
}
else
{
bColor = cv::Scalar(padColor);
}
cv::resize(src, dst, Size(new_w, new_h),None,None,interp);
cv::copyMakeBorder(dst, dst, pad_top, pad_bot, pad_left, pad_right, cv::BORDER_CONSTANT, bColor);
return 0;
}
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
resize
将图像调整为最大尺寸1000,然后用copyMakeBorder
填充剩余的位。 - alkasm