Numpy Afbeelding vergroten/verkleinen

Ik wil een afbeelding maken en de schaal van de afbeelding wijzigen, terwijl het een numpy array is.

Ik heb bijvoorbeeld deze afbeelding van een coca-colafles:
fles-1

Wat zich vertaalt naar een numpy array van vormen (528, 203, 3)en ik wil dat formaat wijzigen om de grootte van deze tweede afbeelding te zeggen:
fles-2

Met de vorm (140, 54, 3).

Hoe verander ik de grootte van de afbeelding in een bepaalde vorm terwijl ik de originele afbeelding behoud? Andere antwoorden stellen voor om elke andere of derde rij eruit te halen, maar wat ik wil doen is in feite de afbeelding verkleinen zoals je zou doen via een afbeeldingseditor, maar in python-code. Zijn er bibliotheken om dit in numpy/SciPy te doen?


Antwoord 1, autoriteit 100%

Ja, je kunt opencvinstalleren (dit is een bibliotheek die wordt gebruikt voor beeldverwerking en computervisie) en de cv2.resizefunctie. En gebruik bijvoorbeeld:

import cv2
import numpy as np
img = cv2.imread('your_image.jpg')
res = cv2.resize(img, dsize=(54, 140), interpolation=cv2.INTER_CUBIC)

Hier is imgdus een numpy array die de originele afbeelding bevat, terwijl reseen numpy array is die de verkleindeafbeelding bevat. Een belangrijk aspect is de parameter interpolation: er zijn verschillende manieren om het formaat van een afbeelding te wijzigen. Vooral omdat je de afbeelding verkleint en de grootte van de originele afbeelding geeneen veelvoud is van de grootte van de afbeelding waarvan het formaat is gewijzigd. Mogelijke interpolatieschema’s zijn:

  • INTER_NEAREST– een naaste-buur-interpolatie
  • INTER_LINEAR– een bilineaire interpolatie (standaard gebruikt)
  • INTER_AREA– resampling met behulp van pixelgebiedrelatie. Het kan een voorkeursmethode zijn voor het decimeren van afbeeldingen, omdat het moiré-vrij geeft
    resultaten. Maar wanneer de afbeelding wordt ingezoomd, is deze vergelijkbaar met de
    INTER_NEARESTmethode.
  • INTER_CUBIC– een bicubische interpolatie over een omgeving van 4×4 pixels
  • INTER_LANCZOS4– een Lanczos-interpolatie over een buurt van 8×8 pixels

Zoals bij de meeste opties, is er geen “beste” optie in die zin dat er voor elk formaatwijzigingsschema scenario’s zijn waarbij de ene strategie de voorkeur kan krijgen boven de andere.


Antwoord 2, autoriteit 56%

Hoewel het mogelijk is om numpy alleen te gebruiken om dit te doen, is de bewerking niet ingebouwd. Dat gezegd hebbende, kun je scikit-image(dat is gebouwd op numpy) gebruiken om dit soort beeldmanipulatie uit te voeren.

Documentatie voor het herschalen van Scikit-Image is hier.

U kunt bijvoorbeeld het volgende doen met uw afbeelding:

from skimage.transform import resize
bottle_resized = resize(bottle, (140, 54))

Dit zorgt voor dingen zoals interpolatie, anti-aliasing, enz. Voor u.


3, Autoriteit 15%

Voor mensen die hier komen van Google op zoek naar een snelle manier naar downsample-afbeeldingen in numpyArrays voor gebruik in machine-leeraanvragen, hier is een Super Fast-methode (aangepast van hier ). Deze methode werkt alleen wanneer de ingangsdimensies een meervoudig van de uitgangsdimensies zijn.

De volgende voorbeelden van 128×128 tot 64×64 (dit kan eenvoudig worden gewijzigd).

Kanalen Laatste bestellen

# large image is shape (128, 128, 3)
# small image is shape (64, 64, 3)
input_size = 128
output_size = 64
bin_size = input_size // output_size
small_image = large_image.reshape((output_size, bin_size, 
                                   output_size, bin_size, 3)).max(3).max(1)

Kanalen eerst bestellen

# large image is shape (3, 128, 128)
# small image is shape (3, 64, 64)
input_size = 128
output_size = 64
bin_size = input_size // output_size
small_image = large_image.reshape((3, output_size, bin_size, 
                                      output_size, bin_size)).max(4).max(2)

Voor grijswaardenafbeeldingen wijzigt u gewoon de 3naar een 1zoals deze:

Kanalen eerst bestellen

# large image is shape (1, 128, 128)
# small image is shape (1, 64, 64)
input_size = 128
output_size = 64
bin_size = input_size // output_size
small_image = large_image.reshape((1, output_size, bin_size,
                                      output_size, bin_size)).max(4).max(2)

Deze methode maakt gebruik van het equivalent van Max Pooling. Het is de snelste manier om dit te doen die ik heb gevonden.


4, Autoriteit 10%

Als iemand hier kwam op zoek naar een eenvoudige methode om een ​​afbeelding in Python te schalen / formatteren, zonder extra bibliotheken te gebruiken, is hier een zeer eenvoudige beeldseize-functie:

#simple image scaling to (nR x nC) size
def scale(im, nR, nC):
  nR0 = len(im)     # source number of rows 
  nC0 = len(im[0])  # source number of columns 
  return [[ im[int(nR0 * r / nR)][int(nC0 * c / nC)]  
             for c in range(nC)] for r in range(nR)]

Voorbeeldgebruik: het wijzigen van een (30 x 30) afbeelding naar (100 x 200):

import matplotlib.pyplot as plt
def sqr(x):
  return x*x
def f(r, c, nR, nC):
  return 1.0 if sqr(c - nC/2) + sqr(r - nR/2) < sqr(nC/4) else 0.0
# a red circle on a canvas of size (nR x nC)
def circ(nR, nC):
  return [[ [f(r, c, nR, nC), 0, 0] 
             for c in range(nC)] for r in range(nR)]
plt.imshow(scale(circ(30, 30), 100, 200))

Uitgang:

Dit werkt om afbeeldingen te verkleinen / te schalen en werkt prima met numpy arrays.


5, Autoriteit 6%

One-line numpy oplossing voor downsampling (met 2):

smaller_img = bigger_img[::2, ::2]

en upsampling (met 2):

bigger_img = smaller_img.repeat(2, axis=0).repeat(2, axis=1)

(hierbij wordt uitgegaan van een HxBxC-vormige afbeelding. h/t naar L. Kärkkäinen in de opmerkingen hierboven. merk op dat deze methode alleen de grootte van hele gehele getallen mogelijk maakt (bijv. 2x maar niet 1,5x))


Antwoord 6

Zijn er bibliotheken om dit te doen in numpy/SciPy

Natuurlijk. Dit kan zonder OpenCV, scikit-image of PIL.

Afbeelding vergroten/verkleinen is in feite het in kaart brengen van de coördinaten van elke pixel van de originele afbeelding naar de gewijzigde positie.

Aangezien de coördinaten van een afbeelding gehele getallen moeten zijn (beschouw het als een matrix), als de toegewezen coördinaat decimale waarden heeft, moet u de pixelwaarde interpoleren om deze te benaderen naar de gehele positie (bijv. de dichtstbijzijnde pixel verkrijgen positie staat bekend als Nearest-buur-interpolatie).

Alles wat je nodig hebt is een functie die deze interpolatie voor je doet. SciPy heeft interpolate.interp2d.

Je kunt het gebruiken om het formaat van een afbeelding in numpy array te wijzigen, zeg arr, als volgt:

W, H = arr.shape[:2]
new_W, new_H = (600,300)
xrange = lambda x: np.linspace(0, 1, x)
f = interp2d(xrange(W), xrange(H), arr, kind="linear")
new_arr = f(xrange(new_W), xrange(new_H))

Als je afbeelding RGB is, moet je natuurlijk de interpolatie voor elk kanaal uitvoeren.

Als je meer wilt weten, raad ik je aan Afbeeldingen verkleinen – Computerfielte bekijken.


Antwoord 7

Voor mensen die een batch numpy arrays willen verkleinen (interpoleren), biedt pytorch een snellere functienaam torch.nn.functional.interpolate, vergeet niet om eerst np.transpose te gebruiken om het kanaal te wijzigen van batchxBxHx3 naar batchx3xBxH.


Antwoord 8

import cv2
import numpy as np
image_read = cv2.imread('filename.jpg',0) 
original_image = np.asarray(image_read)
width , height = 452,452
resize_image = np.zeros(shape=(width,height))
for W in range(width):
    for H in range(height):
        new_width = int( W * original_image.shape[0] / width )
        new_height = int( H * original_image.shape[1] / height )
        resize_image[W][H] = original_image[new_width][new_height]
print("Resized image size : " , resize_image.shape)
cv2.imshow(resize_image)
cv2.waitKey(0)

Other episodes