¿Cómo encontrar el diámetro de los objetos utilizando el procesamiento de imágenes en Python?

Dada una imagen con algunos objetos irregulares, quiero encontrar su diámetro individual.

Gracias a esta respuesta , sé cómo identificar los objetos. Sin embargo, ¿es posible medir el diámetro máximo de los objetos mostrados en la imagen?

He examinado la scipy-ndimage y no he encontrado una función dedicada.

Código para la identificación del objeto:

 import numpy as np from scipy import ndimage from matplotlib import pyplot as plt # generate some lowpass-filtered noise as a test image gen = np.random.RandomState(0) img = gen.poisson(2, size=(512, 512)) img = ndimage.gaussian_filter(img.astype(np.double), (30, 30)) img -= img.min() img /= img.max() # use a boolean condition to find where pixel values are > 0.75 blobs = img > 0.75 # label connected regions that satisfy this condition labels, nlabels = ndimage.label(blobs) # find their centres of mass. in this case I'm weighting by the pixel values in # `img`, but you could also pass the boolean values in `blobs` to compute the # unweighted centroids. r, c = np.vstack(ndimage.center_of_mass(img, labels, np.arange(nlabels) + 1)).T # find their distances from the top-left corner d = np.sqrt(r*r + c*c) # plot fig, ax = plt.subplots(1, 2, sharex=True, sharey=True, figsize=(10, 5)) ax[0].imshow(img) ax[1].hold(True) ax[1].imshow(np.ma.masked_array(labels, ~blobs), cmap=plt.cm.rainbow) for ri, ci, di in zip(r, c, d): ax[1].annotate('', xy=(0, 0), xytext=(ci, ri), arrowprops={'arrowstyle':'<-', 'shrinkA':0}) ax[1].annotate('d=%.1f' % di, xy=(ci, ri), xytext=(0, -5), textcoords='offset points', ha='center', va='top', fontsize='x-large') for aa in ax.flat: aa.set_axis_off() fig.tight_layout() plt.show() 

Imagen: introduzca la descripción de la imagen aquí

Podría usar skimage.measure.regionprops para determinar el cuadro delimitador de todas las regiones en su imagen. Para las gotas aproximadamente circulares, el diámetro del círculo de cierre mínimo se puede aproximar por el lado más grande del cuadro delimitador . Para hacerlo, solo necesita agregar el siguiente fragmento de código al final de su script:

 from skimage.measure import regionprops properties = regionprops(labels) print 'Label \tLargest side' for p in properties: min_row, min_col, max_row, max_col = p.bbox print '%5d %14.3f' % (p.label, max(max_row - min_row, max_col - min_col)) fig = plt.figure() ax = fig.add_subplot(111) ax.imshow(np.ma.masked_array(labels, ~blobs), cmap=plt.cm.gist_rainbow) ax.set_title('Labeled objects') plt.xticks([]) plt.yticks([]) for ri, ci, li in zip(r, c, range(1, nlabels+1)): ax.annotate(li, xy=(ci, ri), fontsize=24) plt.show() 

Y esta es la salida que obtienes:

 Label Largest side 1 106.000 2 75.000 3 79.000 4 56.000 5 161.000 6 35.000 7 47.000 

Objetos etiquetados

Yo propondría usar una transformada de distancia. Así que una vez que tienes tu imagen etiquetada lo haces:

 dt = ndimage.distance_transform_edt(blobs) slices = ndimage.find_objects(input=labels) radii = [np.amax(dt[s]) for s in slices] 

Esto da el círculo inscrito más grande (o esfera en 3D). La función find_objects es bastante útil. Devuelve una lista de objetos de segmentos de Python, que puede utilizar para indexar en la imagen en las ubicaciones específicas que contienen las manchas. Por supuesto, estos cortes se pueden usar para indexar en la imagen de transformación a distancia. Por lo tanto, el valor más grande de la transformación de distancia dentro de la división es el radio que está buscando.

Hay un potencial gothcha del código anterior: la rebanada es una sección cuadrada (o cúbica), por lo que podría contener pequeños trozos de otras manchas si están juntas. Puede solucionar esto con una lógica un poco más complicada de la siguiente manera:

 radii = [np.amax(dt[slices[i]]*(labels[slices[i]] == (i+1))) for i in range(nlabels)] 

La versión anterior de la lista de comprensión enmascara la transformación de distancia con el blob que se supone debe ser indexado por el sector, eliminando así cualquier interferencia no deseada de blobs vecinos.