wake-up-neo.com

Ausschnittmittelteil eines numpy Bildes

Angenommen, ich habe ein numpy-Bild mit einer Breite x und einer Höhe y. Ich muss den mittleren Teil des Bildes auf Breite und Höhe beschneiden. Angenommen, cropx und cropy sind positive ganze Zahlen ungleich Null und kleiner als die jeweilige Bildgröße. Wie wende ich das Slicing am besten für das Ausgabebild an?

20
Gert Gottschalk

Etwas in diese Richtung -

def crop_center(img,cropx,cropy):
    y,x = img.shape
    startx = x//2-(cropx//2)
    starty = y//2-(cropy//2)    
    return img[starty:starty+cropy,startx:startx+cropx]

Probelauf -

In [45]: img
Out[45]: 
array([[88, 93, 42, 25, 36, 14, 59, 46, 77, 13, 52, 58],
       [43, 47, 40, 48, 23, 74, 12, 33, 58, 93, 87, 87],
       [54, 75, 79, 21, 15, 44, 51, 68, 28, 94, 78, 48],
       [57, 46, 14, 98, 43, 76, 86, 56, 86, 88, 96, 49],
       [52, 83, 13, 18, 40, 33, 11, 87, 38, 74, 23, 88],
       [81, 28, 86, 89, 16, 28, 66, 67, 80, 23, 95, 98],
       [46, 30, 18, 31, 73, 15, 90, 77, 71, 57, 61, 78],
       [33, 58, 20, 11, 80, 25, 96, 80, 27, 40, 66, 92],
       [13, 59, 77, 53, 91, 16, 47, 79, 33, 78, 25, 66],
       [22, 80, 40, 24, 17, 85, 20, 70, 81, 68, 50, 80]])

In [46]: crop_center(img,4,6)
Out[46]: 
array([[15, 44, 51, 68],
       [43, 76, 86, 56],
       [40, 33, 11, 87],
       [16, 28, 66, 67],
       [73, 15, 90, 77],
       [80, 25, 96, 80]])
30
Divakar

Eine allgemeinere Lösung basierend auf der Antwort von @Divakar:

def cropND(img, bounding):
    start = Tuple(map(lambda a, da: a//2-da//2, img.shape, bounding))
    end = Tuple(map(operator.add, start, bounding))
    slices = Tuple(map(slice, start, end))
    return img[slices]

und wenn wir ein Array haben a

>>> a = np.arange(100).reshape((10,10))

array([[ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9],
       [10, 11, 12, 13, 14, 15, 16, 17, 18, 19],
       [20, 21, 22, 23, 24, 25, 26, 27, 28, 29],
       [30, 31, 32, 33, 34, 35, 36, 37, 38, 39],
       [40, 41, 42, 43, 44, 45, 46, 47, 48, 49],
       [50, 51, 52, 53, 54, 55, 56, 57, 58, 59],
       [60, 61, 62, 63, 64, 65, 66, 67, 68, 69],
       [70, 71, 72, 73, 74, 75, 76, 77, 78, 79],
       [80, 81, 82, 83, 84, 85, 86, 87, 88, 89],
       [90, 91, 92, 93, 94, 95, 96, 97, 98, 99]])

Wir können es mit cropND(a, (5,5)) ausschneiden, Sie erhalten:

>>> cropND(a, (5,5))

array([[33, 34, 35, 36, 37],
       [43, 44, 45, 46, 47],
       [53, 54, 55, 56, 57],
       [63, 64, 65, 66, 67],
       [73, 74, 75, 76, 77]])

Es funktioniert nicht nur mit 2D-Bildern, sondern auch mit 3D-Bildern.

Einen schönen Tag noch.

14
Losses Don

Danke, Divakar.

Ihre Antwort brachte mich in die richtige Richtung. Ich habe mir das ausgedacht, indem ich negative Slice-Offsets verwendet habe, um "vom Ende an" zu zählen:

def cropimread(crop, xcrop, ycrop, fn):
    "Function to crop center of an image file"
    img_pre= msc.imread(fn)
    if crop:
        ysize, xsize, chan = img_pre.shape
        xoff = (xsize - xcrop) // 2
        yoff = (ysize - ycrop) // 2
        img= img_pre[yoff:-yoff,xoff:-xoff]
    else:
        img= img_pre
    return img
1
Gert Gottschalk

Eine einfache Modifikation von @Divakars Antwort, die den Bildkanal beibehält:

    def crop_center(self, img, cropx, cropy):
       _, y, x = img.shape
       startx = x // 2 - (cropx // 2)
       starty = y // 2 - (cropy // 2)
       return img[:, starty:starty + cropy, startx:startx + cropx]
0
Kevin Debugging