Recuerda que en la informática cualquier problema casi siempre tiene diversas resoluciones, no obstante te enseñamos lo mejor y más óptimo.
Solución:
Usando OpenCV
Puedes usar resize()
en OpenCV para cambiar el tamaño de la imagen hacia arriba o hacia abajo al tamaño que necesita. Sin embargo, resize()
requiere que ingrese el tamaño de destino (en ambas dimensiones) o la escala (en ambas dimensiones), por lo que no puede simplemente poner uno u otro en 1000 y dejar que calcule el otro por usted. Entonces, la forma más sólida de hacer esto es encontrar la relación de aspecto y calcular cuál sería la dimensión más pequeña cuando la más grande se estira a 1000. Luego, puede cambiar el tamaño.
h, w = img.shape[:2]
aspect = w/h
Tenga en cuenta que si aspect
es mayor que 1, entonces la imagen está orientada horizontalmente, mientras que si es menor que 1, la imagen está orientada verticalmente (y es cuadrada si aspect = 1
).
Los diferentes métodos de interpolación se verán mejor dependiendo de si está ampliando la imagen a una resolución más grande o reduciéndola a una resolución más baja. Desde el resize()
docs:
Para reducir una imagen, generalmente se verá mejor con la interpolación CV_INTER_AREA, mientras que para agrandar una imagen, generalmente se verá mejor con CV_INTER_CUBIC (lento) o CV_INTER_LINEAR (más rápido pero aún se ve bien).
Entonces, después de cambiar el tamaño, terminaremos con un 1000xN
o Nx1000
imagen (donde N<=1000
) y tendremos que rellenarlo con el color de fondo que desee en ambos lados para rellenar la imagen 1000x1000
. Para esto puedes usar copyMakeBorder()
para una implementación pura de OpenCV, o como está usando Python, puede usar numpy.pad()
. Deberá decidir qué hacer en caso de que sea necesario agregar un número impar de píxeles para convertirlo 1000x1000
, como si el píxel adicional va hacia la izquierda o hacia la derecha (o hacia arriba o hacia abajo, según la orientación de su imagen).
Aquí hay un guión que define un resizeAndPad()
función que calcula automáticamente la relación de aspecto, escala en consecuencia y almohadillas según sea necesario, y luego la usa en una imagen horizontal, vertical y cuadrada:
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)
Y esto da las imágenes:
Usando ImageMagick
ImageMagick
es una interfaz de línea de comandos simple pero bien construida para realizar el procesamiento básico de imágenes. Es muy fácil hacer lo que quiera con un solo comando. Consulte aquí las descripciones de los comandos de cambio de tamaño.
$ 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
Produciendo las imágenes:
Sobre la base de la respuesta de Alexander-Reynolds anterior, aquí está el código que maneja todos los tamaños y situaciones posibles.
def resizeAndPad (img, tamaño, 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
valoraciones y reseñas
Eres capaz de añadir valor a nuestra información cooperando tu veteranía en los comentarios.