Jak zmienić rozmiar obrazu za pomocą OpenCV2.0 i Python2.6

163

Chcę używać OpenCV2.0 i Python2.6, aby wyświetlać obrazy o zmienionym rozmiarze. Użyłem i zaadaptowałem przykład ze strony http://opencv.willowgarage.com/documentation/python/cookbook.html, ale niestety ten kod jest przeznaczony dla OpenCV2.1 i wydaje się, że nie działa na 2.0. Tutaj mój kod:

import os, glob
import cv

ulpath = "exampleshq/"

for infile in glob.glob( os.path.join(ulpath, "*.jpg") ):
    im = cv.LoadImage(infile)
    thumbnail = cv.CreateMat(im.rows/10, im.cols/10, cv.CV_8UC3)
    cv.Resize(im, thumbnail)
    cv.NamedWindow(infile)
    cv.ShowImage(infile, thumbnail)
    cv.WaitKey(0)
    cv.DestroyWindow(name)

Ponieważ nie mogę użyć

cv.LoadImageM

użyłem

cv.LoadImage

zamiast tego, co nie stanowiło problemu w innych aplikacjach. Niemniej jednak cv.iplimage nie ma atrybutów wierszy, kolumn ani rozmiaru. Czy ktoś może mi podpowiedzieć, jak rozwiązać ten problem? Dzięki.

Bastian
źródło
4
Jeśli którakolwiek z odpowiedzi była prawidłowa, zaznacz ją, ponieważ pomoże to innym.
Michał

Odpowiedzi:

342

Jeśli chcesz używać CV2, musisz użyć tej resizefunkcji.

Na przykład spowoduje to zmianę rozmiaru obu osi o połowę:

small = cv2.resize(image, (0,0), fx=0.5, fy=0.5) 

a to zmieni rozmiar obrazu tak, aby miał 100 kolumn (szerokość) i 50 wierszy (wysokość):

resized_image = cv2.resize(image, (100, 50)) 

Inną opcją jest użycie scipymodułu poprzez:

small = scipy.misc.imresize(image, 0.5)

Jest oczywiście więcej opcji, które możesz przeczytać w dokumentacji tych funkcji ( cv2.resize , scipy.misc.imresize ).


Aktualizacja:
Zgodnie z dokumentacją SciPy :

imresizejest przestarzałe w SciPy 1.0.0 i zostanie usunięte w 1.2.0.
Użyj skimage.transform.resizezamiast tego.

Zwróć uwagę, że jeśli chcesz zmienić rozmiar o czynnik , możesz chcieć skimage.transform.rescale.

emem
źródło
1
czy funkcja resize () nie powoduje, że obraz traci informacje o sobie?
8
Tak, nie możesz zmniejszyć rozmiaru obrazu bez utraty informacji.
Rafael_Espericueta
1
Implementacja opencv (0,05 ms na obraz) wydaje się być znacznie szybsza niż implementacja scipy (obraz 0,33 ms). Zmieniłem rozmiar obrazów z 210 x 160 x 1 na 84 x 84 x 1 z bilinearną interpolacją.
gizzmole
@gizzmole Ciekawe spojrzenie. Nie testowałem wydajności wdrożeń, ani nie porównywałem wyników - więc efekt końcowy również może się nieznacznie różnić. Czy przetestowałeś, czy obrazy o zmienionym rozmiarze są zgodne bitowo?
emem
Dziękuję za wskazanie, że funkcja resize take (W * H), podczas gdy cv2 print as (H * W)
Shivam Kotwalia
59

Przykład podwojenia rozmiaru obrazu

Istnieją dwa sposoby zmiany rozmiaru obrazu. Nowy rozmiar można określić:

  1. Ręcznie;

    height, width = src.shape[:2]

    dst = cv2.resize(src, (2*width, 2*height), interpolation = cv2.INTER_CUBIC)

  2. Przez współczynnik skalowania.

    dst = cv2.resize(src, None, fx = 2, fy = 2, interpolation = cv2.INTER_CUBIC), gdzie fx jest współczynnikiem skalowania wzdłuż osi poziomej, a fy na osi pionowej.

Aby zmniejszyć obraz, generalnie będzie wyglądał najlepiej z interpolacją INTER_AREA, podczas gdy aby powiększyć obraz, będzie wyglądał najlepiej z INTER_CUBIC (wolno) lub INTER_LINEAR (szybciej, ale nadal wygląda OK).

Przykład zmniejszania obrazu, aby zmieścił się na maksymalnej wysokości / szerokości (zachowując proporcje)

import cv2

img = cv2.imread('YOUR_PATH_TO_IMG')

height, width = img.shape[:2]
max_height = 300
max_width = 300

# only shrink if img is bigger than required
if max_height < height or max_width < width:
    # get scaling factor
    scaling_factor = max_height / float(height)
    if max_width/float(width) < scaling_factor:
        scaling_factor = max_width / float(width)
    # resize image
    img = cv2.resize(img, None, fx=scaling_factor, fy=scaling_factor, interpolation=cv2.INTER_AREA)

cv2.imshow("Shrinked image", img)
key = cv2.waitKey()

Używanie kodu z cv2

import cv2 as cv

im = cv.imread(path)

height, width = im.shape[:2]

thumbnail = cv.resize(im, (round(width / 10), round(height / 10)), interpolation=cv.INTER_AREA)

cv.imshow('exampleshq', thumbnail)
cv.waitKey(0)
cv.destroyAllWindows()
João Cartucho
źródło
Twoje rozwiązanie wykorzystujące współczynniki skalowania zwraca błąd w cv2.resize (), mówiąc: „src nie jest tablicą numpy, ani skalarem”. proszę doradź?
BenP
zrobiłeś: src = cv2.imread('YOUR_PATH_TO_IMG')i zmieniłeś „YOUR_PATH_TO_IMG” na ścieżkę własnego obrazu?
João Cartucho
robi cv2.resizeautomatycznie używa dopełnienie? jaki jest rozmiar okna utworzonego przy użyciu żądanego rozmiaru wyjściowego (width/10, height/10)?
seralouk
@makaros otrzymujesz obraz, który jest 10 razy mniejszy zarówno pod względem szerokości, jak i wysokości
João Cartucho
@ JoãoCartucho tak, rozumiem to. Ale kiedy używa się najbliższego_neighbors, wówczas okno powinno zostać zastosowane za kulisami. O to właśnie proszę…
seralouk
8

Możesz użyć funkcji GetSize, aby uzyskać te informacje, cv.GetSize (im) zwróci krotkę z szerokością i wysokością obrazu. Możesz także użyć im.depth i img.nChan, aby uzyskać więcej informacji.

Aby zmienić rozmiar obrazu, użyłbym nieco innego procesu, z innym obrazem zamiast matrycy. Lepiej jest spróbować pracować z tym samym typem danych:

size = cv.GetSize(im)
thumbnail = cv.CreateImage( ( size[0] / 10, size[1] / 10), im.depth, im.nChannels)
cv.Resize(im, thumbnail)

Mam nadzieję że to pomoże ;)

Julien

jlengrand
źródło
6
def rescale_by_height(image, target_height, method=cv2.INTER_LANCZOS4):
    """Rescale `image` to `target_height` (preserving aspect ratio)."""
    w = int(round(target_height * image.shape[1] / image.shape[0]))
    return cv2.resize(image, (w, target_height), interpolation=method)

def rescale_by_width(image, target_width, method=cv2.INTER_LANCZOS4):
    """Rescale `image` to `target_width` (preserving aspect ratio)."""
    h = int(round(target_width * image.shape[0] / image.shape[1]))
    return cv2.resize(image, (target_width, h), interpolation=method)
AndyP
źródło
robi cv2.resizeautomatycznie używa dopełnienie? jaki jest rozmiar okna utworzonego za pomocą (w, target_height)argumentów?
seralouk
4

Oto funkcja zwiększania lub zmniejszania obrazu o żądaną szerokość lub wysokość przy zachowaniu współczynnika proporcji

# Resizes a image and maintains aspect ratio
def maintain_aspect_ratio_resize(image, width=None, height=None, inter=cv2.INTER_AREA):
    # Grab the image size and initialize dimensions
    dim = None
    (h, w) = image.shape[:2]

    # Return original image if no need to resize
    if width is None and height is None:
        return image

    # We are resizing height if 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)
    # We are resizing width if height is none
    else:
        # Calculate the ratio of the width and construct the dimensions
        r = width / float(w)
        dim = (width, int(h * r))

    # Return the resized image
    return cv2.resize(image, dim, interpolation=inter)

Stosowanie

import cv2

image = cv2.imread('1.png')
cv2.imshow('width_100', maintain_aspect_ratio_resize(image, width=100))
cv2.imshow('width_300', maintain_aspect_ratio_resize(image, width=300))
cv2.waitKey()

Na podstawie tego przykładowego obrazu

wprowadź opis obrazu tutaj

Po prostu przeskaluj w dół do width=100(w lewo) lub w górę do width=300(w prawo)

wprowadź opis obrazu tutaj wprowadź opis obrazu tutaj

nathancy
źródło