簡體   English   中英

調整圖像大小而不失真 OpenCV

[英]Resize an image without distortion OpenCV

我正在使用 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。

你可以試試下面。 該功能將保持原始圖像的縱橫比。

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)

希望這可以幫助。

如果您需要修改圖像分辨率並保持寬高比,請使用函數imutils (查看文檔)。 像這樣的東西:

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

希望有幫助,祝你好運!

在使用 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(image, size=(28,28))

解釋:函數接受任何大小的輸入,並創建一個正方形的空白圖像,大小為圖像的高度或寬度,以較大者為准。 然后它將原始圖像放置在空白圖像的中心。 然后它將這個方形圖像調整為所需的大小,以便保留原始圖像內容的形狀。

希望對你有幫助

@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)

所有其他答案都使用填充來糾正縱橫比,當您嘗試為神經網絡創建標准化數據集時,這通常是非常糟糕的。 下面是一個簡單的裁剪和調整大小的實現,它保持縱橫比並且不創建填充。

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)

原來的:

原來的

調整大小:

在此處輸入圖像描述

與原始問題的要求不太一致,但我來到這里尋找類似問題的答案。

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
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 中裁剪(每個取決於縱橫比的比例)。

    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

我有一個手繪數據集,我需要從不對稱的圖紙中創建小方形圖像。

在此處輸入圖像描述

感謝@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

在此處輸入圖像描述

512x256 -> 28x28

在此處輸入圖像描述

代碼被賦予一個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()

來自Pillow lib 的簡單和最有效的方法
這里的widthheight將是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')

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM