Python 在不失真的情况下调整图像大小 OpenCV
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/44650888/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Resize an image without distortion OpenCV
提问by Tanmay Bhatnagar
I am using python 3 and latest version of openCV. I am trying to resize an image using the resize function provided but after resizing the image is very distorted. Code :
我正在使用 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')
The original image is 480 x 640 (RGB therefore i passed the 0 to get it to grayscale)
原始图像为 480 x 640(RGB 因此我通过了 0 使其变为灰度)
Is there any way i could resize it and avoid the distortion using OpenCV or any other library perhaps? I intend to make a handwritten digit recogniser and i have trained my neural network using the MNIST data therefore i need the image to be 28x28.
有什么方法可以调整它的大小并避免使用 OpenCV 或任何其他库的失真?我打算制作一个手写数字识别器,并且我已经使用 MNIST 数据训练了我的神经网络,因此我需要图像为 28x28。
回答by thewaywewere
You may try below. The function will keep the aspect rate of the original image.
你可以试试下面。该功能将保持原始图像的纵横比。
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
Here is an example usage.
这是一个示例用法。
image = image_resize(image, height = 800)
Hope this helps.
希望这可以帮助。
回答by Andres Mitre
If you need to modify the image resolution and keep your aspect ratio use the function imutils(check documentation). something like this:
如果您需要修改图像分辨率并保持纵横比,请使用imutils函数(查看文档)。像这样:
img = cv2.imread(file , 0)
img = imutils.resize(img, width=1280)
cv2.imshow('image' , img)
hope that helps, good luck !
希望有帮助,祝你好运!
回答by vijay jha
Try this simple function in python that uses OpenCV. just pass the image and mention the size of square you want.
在使用 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)
usage: squared_image=get_square(image, size=(28,28))
用法:squared_image=get_square(image, size=(28,28))
explanation: function takes input of any size and it creates a squared shape blank image of size image's height or width whichever is bigger. it then places the original image at the center of the blank image. and then it resizes this square image into desired size so the shape of original image content gets preserved.
解释: 函数接受任何大小的输入,并创建一个正方形的空白图像,其大小为图像的高度或宽度,以较大者为准。然后将原始图像放置在空白图像的中心。然后它将这个方形图像调整为所需的大小,以便保留原始图像内容的形状。
hope , this will help you
希望能帮到你
回答by Alexey Antonenko
The answer, provided by @vijay jhais too case specific. Also includes additional unnecessary padding. I propose fixed code below:
@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)
The code resizes an image making it square and keeping aspect ration at the same time. Also the code is suitable for 3 channels (colored) images as well. Example of usage:
该代码调整图像大小,使其成为方形并同时保持纵横比。该代码也适用于 3 通道(彩色)图像。用法示例:
resized = resize2SquareKeepingAspectRation(img, size, cv2.INTER_AREA)
回答by Shikhar Johri
The code is given a window_height
by which it calculates the window_width
variable while maintaining the aspect ratio of the image. In order to prevent it from any distortion.
代码给出了一个,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()
回答by Arthur
I have a dataset of hand drawings and i needed to create small square images from asymmetric drawings.
我有一个手绘图数据集,我需要从不对称的图纸中创建小方形图像。
Thanks to @vijay jhai created square imageswhile maintaining the aspect ratio of the original image. One issue though was that the more you downscaled the more information was lost.
感谢@vijay jha,我创建了方形图像,同时保持了原始图像的纵横比。但一个问题是,您缩小的比例越多,丢失的信息就越多。
512x256to 64x64would look like this:
512x256到64x64看起来像这样:
I modified a bit the original codeto smoothly downscale the image.
我修改了一些原始代码以平滑缩小图像。
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
512x256 -> 64x64
512x256 -> 28x28
512x256 -> 28x28
回答by Raja
img = cv2.resize(img, (int(img.shape[1]/2), int(img.shape[0]/2)))
will resize the image to half the original size. You can modify it for any other ratio. Note that the first argument passed to resize() is img.shape[1], and not img.shape[0]. This may be counter-intuitive. It is easy to overlook this reversal and get a very distorted picture.
将图像大小调整为原始大小的一半。您可以将其修改为任何其他比率。请注意,传递给 resize() 的第一个参数是 img.shape[1],而不是 img.shape[0]。这可能是违反直觉的。很容易忽略这种逆转并得到非常扭曲的画面。
回答by orangepips
May not quote align with what the original question is asking, but I landed here searching for an answer to a similar question.
可能引用的内容与原始问题的要求不一致,但我来到这里寻找类似问题的答案。
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
回答by user27443
I've just run into the same issue while preparing a dataset for a neural net, and in order to avoid having to distort the image, I've made a function which resizes and crops the image minimally to fit the destination size. It works by first choosing whether to crop in the y or x by comparing the input image aspect ratio to the destination aspect ratio. Then it resizes the input image to the destination width or height, and then cropping in the x or y (each depending on if ratio of aspect ratios).
我在为神经网络准备数据集时遇到了同样的问题,为了避免扭曲图像,我制作了一个函数,可以最小化调整图像大小并裁剪图像以适应目标尺寸。它的工作原理是首先通过比较输入图像的纵横比和目标纵横比来选择是在 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