web-dev-qa-db-fra.com

Redimensionner une image sans distorsion OpenCV

J'utilise Python 3 et la dernière version d'openCV. J'essaie de redimensionner une image à l'aide de la fonction de redimensionnement fournie, mais après le redimensionnement, l'image est très déformée. Code:

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

L'image originale est de 480 x 640 (RVB donc j'ai passé le 0 pour le faire passer en niveaux de gris)

Existe-t-il un moyen de le redimensionner et d’éviter les distorsions avec OpenCV ou toute autre bibliothèque? J'ai l'intention de faire une reconnaissance manuscrite des chiffres et j'ai formé mon réseau de neurones en utilisant les données MNIST. J'ai donc besoin que l'image soit au format 28x28.

12
Tanmay Bhatnagar

Vous pouvez essayer ci-dessous. La fonction conservera le taux d'aspect de l'image d'origine.

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

Voici un exemple d'utilisation.

image = image_resize(image, height = 800)

J'espère que cela t'aides.

34
thewaywewere

Essayez cette fonction simple en python qui utilise opencv. il suffit de passer l'image et de mentionner la taille du carré que vous voulez.

def get_square(image,square_size):

    height,width=image.shape
    if(height>width):
      differ=height
    else:
      differ=width
    differ+=4

    mask = np.zeros((differ,differ), dtype="uint8")   
    x_pos=int((differ-width)/2)
    y_pos=int((differ-height)/2)
    mask[y_pos:y_pos+height,x_pos:x_pos+width]=image[0:height,0:width]
    mask=cv2.resize(mask,(square_size,square_size),interpolation=cv2.INTER_AREA)

    return mask 

usage: squared_image = get_square (image, 28)

explication: function prend une entrée de toute taille et crée une image vierge de forme carrée de taille supérieure à la hauteur et à la largeur de l'image d'entrée . elle place ensuite l'image d'origine au centre de l'image vierge. et ensuite, il redimensionne cette image carrée à la taille souhaitée afin de préserver la forme du contenu de l'image d'origine.

J'espère que ceci vous aidera

4
vijay jha

J'ai un jeu de données de dessins à la main et j'avais besoin de créer de petites images carrées à partir de dessins asymétriques.

enter image description here

Merci à @vijay jha i créé images carrées tout en maintenant le rapport de format de l'image d'origine. Un problème cependant était que plus vous réduisiez, plus d’informations étaient perdues.

512x256 à 64x64 ressemblerait à ceci:

64x64

J'ai modifié un peu le code d'origine pour réduire progressivement l'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

enter image description here

512x256 -> 28x28

enter image description here

3
Arthur

La réponse fournie par @vijay jha est aussi spécifique à la casse. Comprend également un remplissage inutile supplémentaire. Je propose le code fixe ci-dessous:

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)

Le code redimensionne une image en la rendant carrée et en conservant le rapport d'aspect en même temps. De plus, le code convient également aux images à 3 canaux (couleurs) . Exemple d'utilisation:

resized = resize2SquareKeepingAspectRation(img, size, cv2.INTER_AREA)
3
Alexey Antonenko

Si vous devez modifier la résolution de l’image et conserver votre rapport de format, utilisez la fonction imutils (consultez la documentation). quelque chose comme ça:

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

espérons que cela aide, bonne chance!

2
Andres Mitre

Le code reçoit un window_height qui calcule la variable window_width tout en maintenant les proportions de l'image. Afin d'éviter toute distorsion.

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()
2
Shikhar Johri

La citation ne correspond peut-être pas à la question d'origine, mais j'ai atterri ici pour chercher une réponse à une question similaire. 

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
orangepips
img = cv2.resize(img, (int(img.shape[1]/2), int(img.shape[0]/2)))

redimensionnera l'image à la moitié de la taille d'origine. Vous pouvez le modifier pour tout autre ratio . Notez que le premier argument transmis à resize () est img.shape [1] et non img.shape [0]. Cela peut être contre-intuitif. Il est facile d’ignorer ce retournement et d’obtenir une image très déformée.

0
Raja