it-swarm.com.de

Ändern Sie die Größe eines Bildes ohne Verzerrung von OpenCV

Ich verwende Python 3 und die neueste Version von openCV. Ich versuche, die Größe eines Bildes mithilfe der Funktion zur Größenänderung zu ändern. Nach der Größenänderung ist das Bild jedoch sehr verzerrt. 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')

Das Originalbild ist 480 x 640 (RGB, daher habe ich die 0 übergeben, um Graustufenbilder zu erhalten).

Gibt es eine Möglichkeit, die Größe zu ändern und die Verzerrung mithilfe von OpenCV oder einer anderen Bibliothek möglicherweise zu vermeiden? Ich beabsichtige, einen handschriftlichen Ziffernerkenner anzufertigen, und ich habe mein neuronales Netzwerk mit den MNIST-Daten trainiert.

12

Sie können es unten versuchen. Die Funktion behält die Seitenrate des Originalbilds bei.

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

Hier ist eine Beispielanwendung.

image = image_resize(image, height = 800)

Hoffe das hilft.

34
thewaywewere

Probieren Sie diese einfache Funktion in Python aus, die opencv verwendet. Übergeben Sie einfach das Bild und geben Sie die gewünschte Quadratgröße an.

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 (Bild, 28)

erklärung: Die Funktion nimmt eine beliebige Größe an und erzeugt ein quadratisches leeres Bild mit einer Größe, die größer als die Höhe und Breite des Eingabebildes ist. Sie legt das Originalbild in der Mitte des leeren Bildes ab. Anschließend wird dieses quadratische Bild in die gewünschte Größe gebracht, sodass die Form des ursprünglichen Bildinhalts erhalten bleibt.

hoffe, das wird dir helfen

4
vijay jha

Ich habe einen Datensatz von Handzeichnungen und ich musste kleine quadratische Bilder aus asymmetrischen Zeichnungen erstellen.

enter image description here

Dank @vijay jha habe ich square-Bilder erstellt und dabei das Seitenverhältnis des Originalbildes beibehalten. Ein Problem war jedoch, dass je mehr Sie herabgestuft wurden, desto mehr Informationen gingen verloren.

512x256 bis 64x64 würde folgendermaßen aussehen:

64x64

Ich habe den ursprünglichen Code ein wenig geändert, um das Bild reibungslos herunterzukalieren.

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

Die Antwort von @vijay jha ist zu fallspezifisch. Schließt auch zusätzliche unnötige Auffüllung ein. Ich schlage folgenden festen Code vor:

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)

Der Code ändert die Größe eines Bildes, um es quadratisch zu machen und gleichzeitig das Seitenverhältnis beizubehalten. Der Code eignet sich auch für 3-Kanal-Bilder (farbig) .. _. Anwendungsbeispiel:

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

Wenn Sie die Bildauflösung ändern und das Seitenverhältnis beibehalten müssen, verwenden Sie die Funktion imutils (siehe Dokumentation). etwas wie das:

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

hoffe das hilft, viel glück!

2
Andres Mitre

Der Code erhält einen window_height, mit dem er die window_width-Variable berechnet, während das Seitenverhältnis des Bildes beibehalten wird. Um zu verhindern, dass es zu Verzerrungen kommt.

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

Ich kann nicht mit dem zitieren, was die ursprüngliche Frage stellt, aber ich bin hier gelandet und habe nach einer Antwort auf eine ähnliche Frage gesucht. 

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

verkleinert das Bild auf die Hälfte der Originalgröße. Sie können es für jedes andere Verhältnis ändern Beachten Sie, dass das erste an resize () übergebene Argument img.shape [1] und nicht img.shape [0] ist. Dies kann kontraintuitiv sein. Es ist leicht, diese Umkehrung zu übersehen und ein sehr verzerrtes Bild zu erhalten.

0
Raja