2012-03-01 14 views
6

Tengo algunas imágenes monocromáticas (en blanco y negro, no en escala de grises) con algunos objetos con formas extrañas. Estoy intentando extraer cada objeto utilizando python27, PIL, SciPy & numpy y el siguiente método:Cuadro delimitador rectangular alrededor de blobs en una imagen monocromática usando python

  1. adaptarse a una caja alrededor de cada objeto se unió en marcha
  2. "Extract" cada objeto como una matriz - para cada objeto/cuadro delimitador

he tenido un vistazo a http://www.scipy.org/Cookbook/Watershed y http://scikits-image.org/docs/dev/auto_examples/plot_contours.html y éstos hacen el trabajo, pero estoy particularmente interesado en tener la caja de contorno rectangular para asegurarse de que todos los bits de "desconectado" ligeramente consiguen incluido en el cuadro delimitador. Lo ideal sería lidiar con los bits desconectados (por ejemplo, los blobs de la parte inferior izquierda) tendría algún tipo de control de umbral. ¿Alguna idea sobre qué caja de herramientas sería la más adecuada?

unbounded image example of image bounds

+2

Tenga una mirada en 'scipy.ndimage'. Tiene todo lo que necesitas. (particularmente 'label' y' find_objects', combinados con 'fill_holes' y un poco de difuminado y umbral para su tolerancia" difusa "). Me estoy quedando un poco corto de tiempo, así que espero que alguien más publique un ejemplo completo :) –

Respuesta

14

Este utiliza Joe Kington's find_paws function.

import numpy as np 
import scipy.ndimage as ndimage 
import scipy.spatial as spatial 
import scipy.misc as misc 
import matplotlib.pyplot as plt 
import matplotlib.patches as patches 

class BBox(object): 
    def __init__(self, x1, y1, x2, y2): 
     ''' 
     (x1, y1) is the upper left corner, 
     (x2, y2) is the lower right corner, 
     with (0, 0) being in the upper left corner. 
     ''' 
     if x1 > x2: x1, x2 = x2, x1 
     if y1 > y2: y1, y2 = y2, y1 
     self.x1 = x1 
     self.y1 = y1 
     self.x2 = x2 
     self.y2 = y2 
    def taxicab_diagonal(self): 
     ''' 
     Return the taxicab distance from (x1,y1) to (x2,y2) 
     ''' 
     return self.x2 - self.x1 + self.y2 - self.y1 
    def overlaps(self, other): 
     ''' 
     Return True iff self and other overlap. 
     ''' 
     return not ((self.x1 > other.x2) 
        or (self.x2 < other.x1) 
        or (self.y1 > other.y2) 
        or (self.y2 < other.y1)) 
    def __eq__(self, other): 
     return (self.x1 == other.x1 
       and self.y1 == other.y1 
       and self.x2 == other.x2 
       and self.y2 == other.y2) 

def find_paws(data, smooth_radius = 5, threshold = 0.0001): 
    # https://stackoverflow.com/questions/4087919/how-can-i-improve-my-paw-detection 
    """Detects and isolates contiguous regions in the input array""" 
    # Blur the input data a bit so the paws have a continous footprint 
    data = ndimage.uniform_filter(data, smooth_radius) 
    # Threshold the blurred data (this needs to be a bit > 0 due to the blur) 
    thresh = data > threshold 
    # Fill any interior holes in the paws to get cleaner regions... 
    filled = ndimage.morphology.binary_fill_holes(thresh) 
    # Label each contiguous paw 
    coded_paws, num_paws = ndimage.label(filled) 
    # Isolate the extent of each paw 
    # find_objects returns a list of 2-tuples: (slice(...), slice(...)) 
    # which represents a rectangular box around the object 
    data_slices = ndimage.find_objects(coded_paws) 
    return data_slices 

def slice_to_bbox(slices): 
    for s in slices: 
     dy, dx = s[:2] 
     yield BBox(dx.start, dy.start, dx.stop+1, dy.stop+1) 

def remove_overlaps(bboxes): 
    ''' 
    Return a set of BBoxes which contain the given BBoxes. 
    When two BBoxes overlap, replace both with the minimal BBox that contains both. 
    ''' 
    # list upper left and lower right corners of the Bboxes 
    corners = [] 

    # list upper left corners of the Bboxes 
    ulcorners = [] 

    # dict mapping corners to Bboxes. 
    bbox_map = {} 

    for bbox in bboxes: 
     ul = (bbox.x1, bbox.y1) 
     lr = (bbox.x2, bbox.y2) 
     bbox_map[ul] = bbox 
     bbox_map[lr] = bbox 
     ulcorners.append(ul) 
     corners.append(ul) 
     corners.append(lr)   

    # Use a KDTree so we can find corners that are nearby efficiently. 
    tree = spatial.KDTree(corners) 
    new_corners = [] 
    for corner in ulcorners: 
     bbox = bbox_map[corner] 
     # Find all points which are within a taxicab distance of corner 
     indices = tree.query_ball_point(
      corner, bbox_map[corner].taxicab_diagonal(), p = 1) 
     for near_corner in tree.data[indices]: 
      near_bbox = bbox_map[tuple(near_corner)] 
      if bbox != near_bbox and bbox.overlaps(near_bbox): 
       # Expand both bboxes. 
       # Since we mutate the bbox, all references to this bbox in 
       # bbox_map are updated simultaneously. 
       bbox.x1 = near_bbox.x1 = min(bbox.x1, near_bbox.x1) 
       bbox.y1 = near_bbox.y1 = min(bbox.y1, near_bbox.y1) 
       bbox.x2 = near_bbox.x2 = max(bbox.x2, near_bbox.x2) 
       bbox.y2 = near_bbox.y2 = max(bbox.y2, near_bbox.y2) 
    return set(bbox_map.values()) 

if __name__ == '__main__': 
    fig = plt.figure() 
    ax = fig.add_subplot(111) 

    data = misc.imread('image.png') 
    im = ax.imshow(data)  
    data_slices = find_paws(255-data, smooth_radius = 20, threshold = 22) 

    bboxes = remove_overlaps(slice_to_bbox(data_slices)) 
    for bbox in bboxes: 
     xwidth = bbox.x2 - bbox.x1 
     ywidth = bbox.y2 - bbox.y1 
     p = patches.Rectangle((bbox.x1, bbox.y1), xwidth, ywidth, 
           fc = 'none', ec = 'red') 
     ax.add_patch(p) 

    plt.show() 

produce enter image description here

+0

Hola, unutbu, gracias por esta respuesta ¡es increíble! Ese tutorial sobre las patas fue un buen descubrimiento, no lo había visto antes. Los sectores superpuestos funcionan para algunas imágenes (por ejemplo, la del ejemplo), pero no para otras. Por más que lo intente, no puedo entender la razón de esto. ¿Algunas ideas? – user714852

+0

Como esta es realmente una pregunta separada de la original, le pedí que la abriera en: http://stackoverflow.com/questions/9548758/how-can-i-find-and-delete-overlapped-slices-of- an-image-from-a-list – user714852

+1

El código ahora usa un KDTree para encontrar rectángulos superpuestos. Por favor pruébalo. Todavía tengo muchas dudas sobre mi algoritmo ad-hoc. El problema de encontrar rectángulos superpuestos parece ser un "problema clásico" y debería tener una respuesta clásica. Lo que sueño en un día es poco probable que sea tan bueno como lo que muchas personas inteligentes probablemente han ideado durante muchos años-hombre. – unutbu

Cuestiones relacionadas