在不失真的情况下调整图像大小 OpenCV

问题描述 投票:0回答:12

我正在使用 python 3 和最新版本的 openCV。我正在尝试使用提供的调整大小功能调整图像大小,但调整大小后图像非常扭曲。代码:

import cv2
file = "/home/tanmay/Desktop/test_image.png"
img = cv2.imread(file , 0)
print(img.shape)
cv2.imshow('img' , img)
k = cv2.waitKey(0)
if k == 27:
    cv2.destroyWindow('img')
resize_img = cv2.resize(img  , (28 , 28))
cv2.imshow('img' , resize_img)
x = cv2.waitKey(0)
if x == 27:
    cv2.destroyWindow('img')

原始图像是 480 x 640(RGB 因此我传递了 0 将其转换为灰度)

有什么方法可以调整它的大小并避免使用 OpenCV 或任何其他库的扭曲吗?我打算制作一个手写数字识别器,并且我已经使用 MNIST 数据训练了我的神经网络,因此我需要图像为 28x28。

python image python-3.x opencv
12个回答
167
投票

您可以尝试以下。该功能将保持原始图像的纵横比。

def image_resize(image, width = None, height = None, inter = cv2.INTER_AREA):
    # initialize the dimensions of the image to be resized and
    # grab the image size
    dim = None
    (h, w) = image.shape[:2]

    # if both the width and height are None, then return the
    # original image
    if width is None and height is None:
        return image

    # check to see if the width is None
    if width is None:
        # calculate the ratio of the height and construct the
        # dimensions
        r = height / float(h)
        dim = (int(w * r), height)

    # otherwise, the height is None
    else:
        # calculate the ratio of the width and construct the
        # dimensions
        r = width / float(w)
        dim = (width, int(h * r))

    # resize the image
    resized = cv2.resize(image, dim, interpolation = inter)

    # return the resized image
    return resized

这是一个示例用法。

image = image_resize(image, height = 800)

36
投票

如果您需要修改图像分辨率并保持纵横比,请使用功能imutils(查看文档)。像这样的东西:

img = cv2.imread(file , 0)
img = imutils.resize(img, width=1280)
cv2.imshow('image' , img)

希望有帮助,祝你好运!


15
投票

在使用 OpenCV 的 python 中尝试这个简单的函数。只需传递图像并提及您想要的正方形的大小即可。

def resize_image(img, size=(28,28)):

    h, w = img.shape[:2]
    c = img.shape[2] if len(img.shape)>2 else 1

    if h == w: 
        return cv2.resize(img, size, cv2.INTER_AREA)

    dif = h if h > w else w

    interpolation = cv2.INTER_AREA if dif > (size[0]+size[1])//2 else 
                    cv2.INTER_CUBIC

    x_pos = (dif - w)//2
    y_pos = (dif - h)//2

    if len(img.shape) == 2:
        mask = np.zeros((dif, dif), dtype=img.dtype)
        mask[y_pos:y_pos+h, x_pos:x_pos+w] = img[:h, :w]
    else:
        mask = np.zeros((dif, dif, c), dtype=img.dtype)
        mask[y_pos:y_pos+h, x_pos:x_pos+w, :] = img[:h, :w, :]

    return cv2.resize(mask, size, interpolation)

用途: squared_image=get_square(图像, 大小=(28,28))

说明: 函数接受任何尺寸的输入,并创建一个方形空白图像,其尺寸为图像的高度或宽度,以较大者为准。 然后它将原始图像放置在空白图像的中心。然后它将这个方形图像调整为所需的大小,以便保留原始图像内容的形状。

希望这对你有帮助


11
投票

所有其他答案都使用 pad 来校正纵横比,当您尝试为神经网络创建标准化数据集时,这通常非常糟糕。下面是裁剪和调整大小的简单实现,它保持纵横比并且不创建焊盘。

def crop_square(img, size, interpolation=cv2.INTER_AREA):
    h, w = img.shape[:2]
    min_size = np.amin([h,w])

    # Centralize and crop
    crop_img = img[int(h/2-min_size/2):int(h/2+min_size/2), int(w/2-min_size/2):int(w/2+min_size/2)]
    resized = cv2.resize(crop_img, (size, size), interpolation=interpolation)

    return resized

示例:

img2 = crop_square(img, 300)

原文:

Original

调整大小:

enter image description here


8
投票

@vijay jha 提供的答案过于具体。还包括额外的不必要的填充。我建议下面的固定代码:

def resize2SquareKeepingAspectRation(img, size, interpolation): h, w = img.shape[:2] c = None if len(img.shape) < 3 else img.shape[2] if h == w: return cv2.resize(img, (size, size), interpolation) if h > w: dif = h else: dif = w x_pos = int((dif - w)/2.) y_pos = int((dif - h)/2.) if c is None: mask = np.zeros((dif, dif), dtype=img.dtype) mask[y_pos:y_pos+h, x_pos:x_pos+w] = img[:h, :w] else: mask = np.zeros((dif, dif, c), dtype=img.dtype) mask[y_pos:y_pos+h, x_pos:x_pos+w, :] = img[:h, :w, :] return cv2.resize(mask, (size, size), interpolation)

该代码调整图像大小,使其成为正方形并同时保持纵横比。该代码也适用于 3 通道(彩色)图像。 使用示例:

resized = resize2SquareKeepingAspectRation(img, size, cv2.INTER_AREA)
    

7
投票
与原来的问题不太相符,但我来到这里寻找类似问题的答案。

import cv2 def resize_and_letter_box(image, rows, cols): """ Letter box (black bars) a color image (think pan & scan movie shown on widescreen) if not same aspect ratio as specified rows and cols. :param image: numpy.ndarray((image_rows, image_cols, channels), dtype=numpy.uint8) :param rows: int rows of letter boxed image returned :param cols: int cols of letter boxed image returned :return: numpy.ndarray((rows, cols, channels), dtype=numpy.uint8) """ image_rows, image_cols = image.shape[:2] row_ratio = rows / float(image_rows) col_ratio = cols / float(image_cols) ratio = min(row_ratio, col_ratio) image_resized = cv2.resize(image, dsize=(0, 0), fx=ratio, fy=ratio) letter_box = np.zeros((int(rows), int(cols), 3)) row_start = int((letter_box.shape[0] - image_resized.shape[0]) / 2) col_start = int((letter_box.shape[1] - image_resized.shape[1]) / 2) letter_box[row_start:row_start + image_resized.shape[0], col_start:col_start + image_resized.shape[1]] = image_resized return letter_box
    

5
投票
img = cv2.resize(img, (int(img.shape[1]/2), int(img.shape[0]/2)))

会将图像大小调整为原始大小的一半。您可以将其修改为任何其他比率。 请注意,传递给 resize() 的第一个参数是 img.shape[1],而不是 img.shape[0]。这可能是违反直觉的。人们很容易忽视这种逆转并得到非常扭曲的画面。


4
投票
我刚刚在为神经网络准备数据集时遇到了同样的问题,为了避免扭曲图像,我创建了一个函数,可以最小化调整和裁剪图像以适应目标大小。它的工作原理是首先通过比较输入图像长宽比与目标长宽比来选择是否在 y 或 x 方向进行裁剪。然后,它将输入图像的大小调整为目标宽度或高度,然后在 x 或 y 方向上进行裁剪(每个取决于长宽比的比率)。

def crop_and_resize(img, w, h): im_h, im_w, channels = img.shape res_aspect_ratio = w/h input_aspect_ratio = im_w/im_h if input_aspect_ratio > res_aspect_ratio: im_w_r = int(input_aspect_ratio*h) im_h_r = h img = cv2.resize(img, (im_w_r , im_h_r)) x1 = int((im_w_r - w)/2) x2 = x1 + w img = img[:, x1:x2, :] if input_aspect_ratio < res_aspect_ratio: im_w_r = w im_h_r = int(w/input_aspect_ratio) img = cv2.resize(img, (im_w_r , im_h_r)) y1 = int((im_h_r - h)/2) y2 = y1 + h img = img[y1:y2, :, :] if input_aspect_ratio == res_aspect_ratio: img = cv2.resize(img, (w, h)) return img
    

3
投票
我有一个手绘图数据集,我需要从不对称图画创建小方形图像。

enter image description here

感谢

@vijay jha,我创建了方形图像,同时保持了原始图像的纵横比。但有一个问题是,规模缩小得越多,丢失的信息就越多。

512x25664x64 看起来像这样:

64x64

我修改了一些

原始代码以平滑地缩小图像。

from skimage.transform import resize, pyramid_reduce def get_square(image, square_size): height, width = image.shape if(height > width): differ = height else: differ = width differ += 4 # square filler mask = np.zeros((differ, differ), dtype = "uint8") x_pos = int((differ - width) / 2) y_pos = int((differ - height) / 2) # center image inside the square mask[y_pos: y_pos + height, x_pos: x_pos + width] = image[0: height, 0: width] # downscale if needed if differ / square_size > 1: mask = pyramid_reduce(mask, differ / square_size) else: mask = cv2.resize(mask, (square_size, square_size), interpolation = cv2.INTER_AREA) return mask

512x256 -> 64x64

enter image description here

512x256 -> 28x28

enter image description here


3
投票
代码被赋予一个

window_height

,通过它计算 
window_width
 变量,同时保持图像的长宽比。以免变形。

import cv2 def resize(self,image,window_height = 500): aspect_ratio = float(image.shape[1])/float(image.shape[0]) window_width = window_height/aspect_ratio image = cv2.resize(image, (int(window_height),int(window_width))) return image img = cv2.imread(img_source) #image location img_resized = resize(img,window_height = 800) cv2.imshow("Resized",img_resized) cv2.waitKey(0) cv2.destroyAllWindows()
    

1
投票
来自

Pillow

 lib
的简单且最有效的方法 这里
width
height
 将是 
400

from PIL import Image imgPath = './forest.jpg' img = Image.open(imgPath) print('The size of img is: ', img.size) print('After applying thumbnail() function') img.thumbnail((400, 400)) img.save('image_thumbnail.jpg')
    

0
投票
使用imutils库调整大小,然后用白色背景对图像进行信箱处理

import cv2 import imutils import numpy as np def resize(image, to_height, to_width): result = np.ones((to_height, to_width, 3), dtype = np.uint8) result = 255 * result if image.shape[0] > image.shape[1]: new_img = imutils.resize(image, width=to_width) dy = int((to_height - new_img.shape[0]) / 2) result[dy:dy + new_img.shape[0], 0 : new_img.shape[1]] = new_img else: new_img = imutils.resize(image, height=to_height) dx = int((to_width - new_img.shape[1]) / 2) result[0:new_img.shape[0], dx : dx + new_img.shape[1]] = new_img return result image = cv2.imread('./sample.jpg') image = resize(image, to_height=300, to_width=400) print(image.shape) cv2.imshow('Sample', image) cv2.waitKey(0)
    
© www.soinside.com 2019 - 2024. All rights reserved.