Zählen der Anzahl der 1er-Gruppen in einer booleschen Karte von numpy.array

  • Ich beschäftige mich gerade mit Bildverarbeitung in Python über PIL (Python Image Library). Mein Hauptziel ist das Zählen der Anzahl farbiger Zellen in einem immunhistochemischen Bild. Ich weiß, dass es relevante Programme, Bibliotheken, Funktionen und Anleitungen dazu gibt, und ich habe fast alle von ihnen überprüft. Mein Hauptziel ist es, den Code von Hand so gut wie möglich von Hand zu schreiben. Daher versuche ich zu vermeiden, viele externe Bibliotheken und Funktionen zu verwenden. Ich habe das meiste Programm geschrieben. So geht es Schritt für Schritt:

    Das Programm nimmt die Bilddatei: Zählen der Anzahl der 1er-Gruppen in einer booleschen Karte von numpy.array

    und verarbeitet es für die roten Zellen (im Grunde genommen werden die RGB-Werte unterhalb eines bestimmten Schwellenwerts für Rot deaktiviert): Zählen der Anzahl der 1er-Gruppen in einer booleschen Karte von numpy.array

    Und erstellt die boolesche Karte (gonna paste) ein Teil davon, da es groß ist), was im Grunde nur 1 dort setzt, wo es mit einem roten Pixel in dem verarbeiteten zweiten Bild oben trifft.

     22222222222222222222222222222222222222222
    20000000111111110000000000000000000000002
    20000000111111110000000000000000000000002
    20000000111111110000000000000000000000002
    20000000011111100000000000000000001100002
    20000000001111100000000000000000011111002
    20000000000110000000000000000000011111002
    20000000000000000000000000000000111111002
    20000000000000000000000000000000111111102
    20000000000000000000000000000001111111102
    20000000000000000000000000000001111111102
    20000000000000000000000000000000111111002
    20000000000000000000000000000000010000002
    20000000000000000000000000000000000000002
    22222222222222222222222222222222222222222
     

    Ich habe absichtlich dieses Frame-ähnliche Ding an den Grenzen mit 2s generiert, um mir beim Zählen der Anzahl der Gruppen zu helfen von 1s in dieser booleschen Karte.

    Meine Frage an Sie, wie kommt es, dass ich die Anzahl der Zellen (Gruppen von 1s) in dieser Art von boolescher Karte effizient zählen kann? Ich habe http://en.wikipedia.org/wiki/Connected-component_labeling gefunden Sieht extrem verwandt und ähnlich aus, aber soweit ich sehe, ist es auf Pixelebene. Meins ist auf der booleschen Ebene. Nur 1s und 0s.

    Vielen Dank.

    31 May 2012
    John Topleyrtfminc
3 answers
  • Sie können ndimage.label , das ist eine schöne Möglichkeit, dies zu tun. Es gibt ein neues Array zurück, wobei jedes Feature einen eindeutigen Wert und die Anzahl der Features hat. Sie können auch ein Verbindungselement angeben.

     import scipy
    from scipy import ndimage
    import matplotlib.pyplot as plt
    
    #flatten to make greyscale, using your second red-black image as input.
    im = scipy.misc.imread('blobs.jpg',flatten=1)
    #smooth and threshold as image has compression artifacts (jpg)
    im = ndimage.gaussian_filter(im, 2)
    im[im<10]=0
    blobs, number_of_blobs = ndimage.label(im)
    print 'Number of blobls:', number_of_blobs
    
    plt.imshow(blobs)
    plt.show()
    
    #Output is:
    Number of blobls: 30
     

    Zählen der Anzahl der 1er-Gruppen in einer booleschen Karte von numpy.array

    23 March 2018
    j08lue
  • Etwas brutales Vorgehen, jedoch durch Invertieren des Problems, um Sammlungen von Pixeln zu indizieren, um Regionen zu finden, anstatt über das Array zu rastern.

     [pre> data = """\
    000000011111111000000000000000000000000
    000000011111111000000000000000000000000
    000000011111111000000000000000000000000
    000000001111110000000001000000000110000
    000000000111110000000011000000001111100
    000000000011100000000000100000011111100
    000000000000000000000000000000011111100
    000000000000000000000000000000011111110
    000000000000000000000000000000111111110
    000000000000000000000000000000111111110
    000000000000000000000000000000011111100
    000000000000000000000000000000001000000
    000000000000000000000000000000000000000"""
    
    from collections import namedtuple
    Point = namedtuple('Point', 'x y')
    
    def points_adjoin(p1, p2):
        # to accept diagonal adjacency, use this form
        #return -1 <= p1.x-p2.x <= 1 and -1 <= p1.y-p2.y <= 1
        return (-1 <= p1.x-p2.x <= 1 and p1.y == p2.y or
                 p1.x == p2.x and -1 <= p1.y-p2.y <= 1)
    
    def adjoins(pts, pt):
        return any(points_adjoin(p,pt) for p in pts)
    
    def locate_regions(datastring):
        data = map(list, datastring.splitlines())
        regions = []
        datapts = [Point(x,y) 
                    for y,row in enumerate(data) 
                        for x,value in enumerate(row) if value=='1']
        for dp in datapts:
            # find all adjoining regions
            adjregs = [r for r in regions if adjoins(r,dp)]
            if adjregs:
                adjregs[0].add(dp)
                if len(adjregs) > 1:
                    # joining more than one reg, merge
                    regions[:] = [r for r in regions if r not in adjregs]
                    regions.append(reduce(set.union, adjregs))
            else:
                # not adjoining any, start a new region
                regions.append(set([dp]))
        return regions
    
    def region_index(regs, p):
        return next((i for i,reg in enumerate(regs) if p in reg), -1)
    
    def print_regions(regs):
        maxx = max(p.x for r in regs for p in r)
        maxy = max(p.y for r in regs for p in r)
        allregionpts = reduce(set.union, regs)
        for y in range(-1,maxy+2):
            line = []
            for x in range(-1,maxx+2):
                p = Point(x, y)
                if p in allregionpts:
                    line.append(str(region_index(regs, p)))
                else:
                    line.append('.')
            print ''.join(line)
        print
    
    
    # test against data set
    regs = locate_regions(data)
    print len(regs)
    print_regions(regs)
     

    Druckt:

     4
    ........................................
    ........00000000........................
    ........00000000........................
    ........00000000........................
    .........000000.........1.........33....
    ..........00000........11........33333..
    ...........000...........2......333333..
    ................................333333..
    ................................3333333.
    ...............................33333333.
    ...............................33333333.
    ................................333333..
    .................................3......
    ........................................
     
    31 May 2012
  • Mehr von einem erweiterten Kommentar als einer Antwort:

    Da @interjay angedeutet hat, in einem Binärbild, dh einem, in dem nur 2 Farben vorhanden sind, die Pixel können entweder den Wert 1 oder 0 annehmen. Dies kann in dem von Ihnen verwendeten Bilddarstellungsformat zutreffend sein, in der 'konzeptuellen' Darstellung Ihres Bildes ist dies jedoch zutreffend. Lassen Sie sich bei diesem Problem nicht durch Implementierungsdetails verwirren. Eines dieser Implementierungsdetails ist die Verwendung von 2s um den Bildrand. Dies ist eine absolut sinnvolle Methode, um die Totzone um das Bild herum zu identifizieren, ohne jedoch die binäre Bildqualität qualitativ zu beeinflussen.

    Zur Untersuchung der Pixel N, NE, NW und W: Dies bezieht sich auf die Konnektivität von Pixeln bei der Bildung der Komponente. Jedes Pixel (Balken der Grenzsonderfälle) hat 8 Nachbarn (N, S, E, W, NE, NW, SE, SW), aber welche sind Kandidaten für die Aufnahme in dieselbe Komponente? Manchmal werden Komponenten, die sich nur an Ecken treffen (NE, NW, SE, SW), nicht als verbunden betrachtet, manchmal sind sie auch so.

    Sie müssen entscheiden, was für Ihre Bewerbung geeignet ist. Ich schlage vor, dass Sie einige Vorgänge des sequentiellen Algorithmus von Hand ausarbeiten und für jedes Pixel verschiedene Nachbarn prüfen, um ein Gefühl dafür zu bekommen, was los ist.

    31 May 2012