Resize an image without distortion OpenCV
我正在使用python 3和最新版本的openCV。 我正在尝试使用提供的调整大小功能来调整图像大小,但是调整图像大小后会非常失真。 代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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。
您可以在下面尝试。该功能将保持原始图像的宽高比。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | 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 |
这是一个示例用法。
1 | image = image_resize(image, height = 800) |
希望这可以帮助。
如果需要修改图像分辨率并保持宽高比,请使用imutils函数(请参阅文档)。像这样的东西:
1 2 3 | img = cv2.imread(file , 0) img = imutils.resize(img, width=1280) cv2.imshow('image' , img) |
希望有帮助,祝你好运!
在使用OpenCV的python中尝试使用此简单函数。只需传递图像并提及您想要的正方形大小即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | 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))
说明:
函数接受任何大小的输入,并创建大小为图像高度或宽度较大的正方形空白图像。
然后将原始图像放置在空白图像的中心。然后将方形图像调整为所需大小,以便保留原始图像内容的形状。
希望这个能对您有所帮助
@vijay jha提供的答案也因情况而异。还包括其他不必要的填充。我在下面提出固定代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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通道(彩色)图像。
用法示例:
1 | resized = resize2SquareKeepingAspectRation(img, size, cv2.INTER_AREA) |
该代码被赋予一个
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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() |
我有手绘图的数据集,我需要根据非对称图创建小正方形图像。
感谢@vijay jha,我在保持原始图像的纵横比的同时创建了正方形图像。但是,一个问题是,您缩小比例越多,丢失的信息就越多。
512x256到64x64看起来像这样:
我修改了一些原始代码以平滑缩小图像。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | 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-> 28x28
与原始问题的要求不太吻合,但是我在这里着陆以寻找类似问题的答案。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | 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 |
1 | img = cv2.resize(img, (int(img.shape[1]/2), int(img.shape[0]/2))) |
将图像尺寸调整为原始尺寸的一半。您可以将其修改为任何其他比率。
请注意,传递给resize()的第一个参数是img.shape [1],而不是img.shape [0]。这可能是违反直觉的。很容易忽略这种逆转并获得非常扭曲的画面。
在准备神经网络数据集时,我遇到了同样的问题,为了避免图像失真,我制作了一个函数,该函数可以最小化图像的大小和裁剪以适合目标尺寸。它通过首先比较输入图像的宽高比和目标的宽高比来选择是裁切y还是x来工作。然后,它将输入图像的大小调整为目标宽度或高度,然后按x或y进行裁切(每个裁切取决于纵横比的比率)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | 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 |