2016-05-04 30 views
6

Ho bisogno di riempire i buchi nelle immagini usando python. Questa è l'immagine con gli oggetti che sono riuscito ad ottenere - sono davvero bordi degli oggetti che voglio, quindi ho bisogno di riempirli. enter image description hereRiempienti buchi di riempimento in un'immagine

sembrava molto semplice utilizzando ndimage.binary_fill_holes(A), ma il problema è che si produce questo (riempito manualmente con il colore rosso):

enter image description here

ma ho bisogno di questo:

enter image description here

In ogni modo questo può essere risolto?

Questa è la prima immagine senza gli assi, se si vuole fare un tentativo: enter image description here

+0

Bel problema. Pensavo di poterlo risolvere con la gerarchia dei contorni di OpenCV come descritto qui http://docs.opencv.org/3.1.0/d9/d8b/tutorial_py_contours_hierarchy.html#gsc.tab=0 ma questo non funziona poiché il contorno critico è nessun vero bambino. Puoi vedere rapidamente che questo non funziona utilizzando il file di esempio su https://github.com/Itseez/opencv/blob/master/samples/python/contours.py – tfv

+0

Grazie, @tfv! Anche il risultato negativo è un risultato ... – Phlya

+0

Direi che l'immagine che offri non consente di prendere la decisione che stai cercando. C'è un limite (che deve essere rimosso se ci si aspetta che l'algoritmo ti prenda quello che vuoi), che quando lo attraversi e poi ne incroci un altro, sei ancora all'interno di un buco, il che non avrebbe senso per tutti i casi normali. – roadrunner66

risposta

2

credo di aver trovato una soluzione. È un po 'lungo da quando ho finito il tempo, ma forse aiuta. Ho codificato se solo per questo problema, ma dovrebbe essere facile generalizzarlo per molte immagini.

Alcune convenzioni di denominazione prime:

  • mi definiscono "regioni di primo livello" o regioni compatti che sono racchiusi dal backround. Tali regioni di primo livello possono essere costituite da diverse sottoregioni.
  • Una regione di primo livello che comprende più di una sottoregione è chiamata area critica.

La mia idea di base è quella di confrontare le lunghezze dei contorni di due sottoregioni che fanno parte di una regione critica. Tuttavia, Non confronto la loro lunghezza del contorno completa, ma solo il segmento che è vicino allo sfondo. Quello con il segmento di contorno più corto vicino allo sfondo è considerato un buco.

Inizierò prima con le immagini dei risultati.

Alcuni panoramica di ciò di cui stiamo parlando, vizualizing le convenzioni di denominazione sopra:

enter image description here

I due sub-regioni della regione critica. I due segmenti di bordo di ciascuna delle regioni vicine allo sfondo sono contrassegnati in diversi colori (molto sottile, blu e rosso scuro, ma visibile). Questi segmenti non sono ovviamente perfetta (aree "sottile" causano errori), ma sufficiente per confrontare la loro lunghezza:

enter image description here

Il risultato finale. Nel caso in cui desideri avere il foro "chiuso", fammi sapere, devi solo assegnare i contorni neri originali alle regioni anziché allo sfondo ([EDIT] Ho incluso tre linee di codice marcate che assegnano i bordi alle regioni, come si voleva):

enter image description here

codice è collegato qui. Ho usato la funzione di contorno OpenCV, che è piuttosto stravagante, e alcune tecniche di mascheramento.Il codice è leggibile a causa delle sue visualizzazioni, mi dispiace per la sua leggibilità limitata, ma non sembra esserci una soluzione a due linee per questo problema.

Alcune osservazioni finali: prima ho provato a fare una corrispondenza dei contorni usando serie di punti, che eviterebbero i loop e consentire l'uso di set.intersection per determinare i due segmenti del contorno vicino allo sfondo, ma poiché le linee nere sono piuttosto spessi, i contorni sono lievemente disadattati. Ho provato la scheletrizzazione dei contorni, ma questo ha aperto un'altra lattina di vermi, quindi ho lavorato con un approccio di scarico facendo un ciclo e una distanza di calcolo tra i punti del contorno. Potrebbe esserci un modo più carino per fare quella parte, ma funziona.

Inoltre, ho preso in considerazione l'utilizzo del modulo Shapely, potrebbero esserci dei modi per trarne un vantaggio, ma non ne ho trovato nessuno, quindi l'ho rilasciato nuovamente.

import numpy as np 
import scipy.ndimage as ndimage 
from matplotlib import pyplot as plt 
import cv2 


img= ndimage.imread('image.png') 

# Label digfferentz original regions 
labels, n_regions = ndimage.label(img) 
print "Original number of regions found: ", n_regions 
# count the number of pixels in each region 
ulabels, sizes = np.unique(labels, return_counts=True) 
print sizes 

# Delete all regions with size < 2 and relabel 
mask_size = sizes < 2 
remove_pixel = mask_size[labels] 
labels[remove_pixel] = 0 
labels, n_regions = ndimage.label(labels) #,s) 
print "Number of regions found (region size >1): ", n_regions 
# count the number of pixels in each region 
ulabels, sizes = np.unique(labels, return_counts=True) 
print ulabels 
print sizes 


# Determine large "first level" regions 
first_level_regions=np.where(labels ==1, 0, 1) 
labeled_first_level_regions, n_fl_regions = ndimage.label(first_level_regions) 
print "Number of first level regions found: ", n_fl_regions 


# Plot regions and first level regions 
fig = plt.figure() 
a=fig.add_subplot(2,3,1) 
a.set_title('All regions') 
plt.imshow(labels, cmap='Paired', vmin=0, vmax=n_regions) 
plt.xticks([]), plt.yticks([]), plt.colorbar() 
a=fig.add_subplot(2,3,2) 
a.set_title('First level regions') 
plt.imshow(labeled_first_level_regions, cmap='Paired', vmin=0, vmax=n_fl_regions) 
plt.xticks([]), plt.yticks([]), plt.colorbar() 


for region_label in range(1,n_fl_regions): 
    mask= labeled_first_level_regions!=region_label 
    result = np.copy(labels) 
    result[mask]=0  
    subregions = np.unique(result).tolist()[1:] 
    print region_label, ": ", subregions 

    if len(subregions) >1: 
     print " Element 4 is a critical element: ", region_label 
     print " Subregions: ", subregions 

     #Critical first level region 
     crit_first_level_region=np.ones(labels.shape) 
     crit_first_level_region[mask]=0 

     a=fig.add_subplot(2,3,4) 
     a.set_title('Crit. first level region') 
     plt.imshow(crit_first_level_region, cmap='Paired', vmin=0, vmax=n_regions) 
     plt.xticks([]), plt.yticks([]) 

     #Critical Region Contour 
     im = np.array(crit_first_level_region * 255, dtype = np.uint8) 
     _, contours0, hierarchy = cv2.findContours(im.copy(), cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE) 
     crit_reg_contour = [contours0[0].flatten().tolist()[i:i+2] for i in range(0, len(contours0[0].flatten().tolist()), 2)] 
     print crit_reg_contour 
     print len(crit_reg_contour) 



     #First Subregion 
     mask2= labels!=subregions[1] 
     first_subreg=np.ones(labels.shape) 
     first_subreg[mask2]=0 

     a=fig.add_subplot(2,3,5) 
     a.set_title('First subregion: '+str(subregions[0])) 
     plt.imshow(first_subreg, cmap='Paired', vmin=0, vmax=n_regions) 
     plt.xticks([]), plt.yticks([])   

     #First Subregion Contour 
     im = np.array(first_subreg * 255, dtype = np.uint8) 
     _, contours0, hierarchy = cv2.findContours(im.copy(), cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE) 
     first_sub_contour = [contours0[0].flatten().tolist()[i:i+2] for i in range(0, len(contours0[0].flatten().tolist()), 2)] 
     print first_sub_contour 
     print len(first_sub_contour) 




     #Second Subregion 
     mask3= labels!=subregions[0] 
     second_subreg=np.ones(labels.shape) 
     second_subreg[mask3]=0 

     a=fig.add_subplot(2,3,6) 
     a.set_title('Second subregion: '+str(subregions[1])) 
     plt.imshow(second_subreg, cmap='Paired', vmin=0, vmax=n_regions) 
     plt.xticks([]), plt.yticks([])  

     #Second Subregion Contour 
     im = np.array(second_subreg * 255, dtype = np.uint8) 
     _, contours0, hierarchy = cv2.findContours(im.copy(), cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE) 
     second_sub_contour = [contours0[0].flatten().tolist()[i:i+2] for i in range(0, len(contours0[0].flatten().tolist()), 2)] 
     print second_sub_contour 
     print len(second_sub_contour) 


     maxdist=6 
     print "Points in first subregion close to first level contour:" 
     close_1=[] 
     for p1 in first_sub_contour: 
      for p2 in crit_reg_contour: 
       if (abs(p1[0]-p2[0])+abs(p1[1]-p2[1]))<maxdist: 
        close_1.append(p1) 
        break 

     print close_1 
     print len(close_1) 

     print "Points in second subregion close to first level contour:" 
     close_2=[] 
     for p1 in second_sub_contour: 
      for p2 in crit_reg_contour: 
       if (abs(p1[0]-p2[0])+abs(p1[1]-p2[1]))<maxdist: 
        close_2.append(p1) 
        break 

     print close_2 
     print len(close_2)  


     for p in close_1: 
      result[p[1],p[0]]=1 

     for p in close_2: 
      result[p[1],p[0]]=2 


     if len(close_1)>len(close_2): 
      print "first subregion is considered a hole:", subregions[0] 
      hole=subregions[0] 
     else:    
      print "second subregion is considered a hole:", subregions[1] 
      hole=subregions[1] 


     #Plot Critical region with subregions 
     a=fig.add_subplot(2,3,3) 
     a.set_title('Critical first level region with subregions') 
     plt.imshow(result, cmap='Paired', vmin=0, vmax=n_regions) 
     plt.xticks([]), plt.yticks([]) 

     result2=result.copy() 


#Plot result 
fig2 = plt.figure() 
a=fig2.add_subplot(1,1,1) 
a.set_title('Critical first level region with subregions and bordering contour segments') 
plt.imshow(result2, cmap='flag', vmin=0, vmax=n_regions) 
plt.xticks([]), plt.yticks([]) 


#Plot result 
mask_hole=np.where(labels ==hole, True, False) 
labels[mask_hole]=1 
labels=np.where(labels > 1, 2, 1) 

# [Edit] Next two lines include black borders into final result 
mask_borders=np.where(img ==0, True, False) 
labels[mask_borders]=2 


fig3 = plt.figure() 
a=fig3.add_subplot(1,1,1) 
a.set_title('Final result') 
plt.imshow(labels, cmap='flag', vmin=0, vmax=n_regions) 
plt.xticks([]), plt.yticks([]) 


plt.show() 
+0

grazie! Sembra che tu sia riuscito a fare esattamente ciò di cui ho bisogno! (Solo i contorni devono essere una parte delle regioni, che 'abbastanza importante) lo controllerò più in dettaglio più tardi e probabilmente accetterò la tua risposta. – Phlya

+1

Ho incluso tre righe contrassegnate per farlo e ho modificato l'immagine finale di conseguenza. – tfv