Le procédé de détection dépend beaucoup de combien généralité vous avez besoin: est l'exposition et le contraste va passer d'une image à une autre? La largeur typique des lignes va-t-elle changer? Dans la suite, je suppose que ces paramètres ne varient pas beaucoup pour vos applications, corrigez-moi si je me trompe.
Je vais utiliser scikit-image, un logiciel commun de traitement d'image pour Python. Si vous n'êtes pas familier avec ce paquet, la documentation peut être trouvée sur http://scikit-image.org/, et le paquet est livré avec toutes les installations de Scientific Python. Cependant, les algorithmes que j'utilise sont également disponibles dans d'autres outils, comme opencv.
Ma solution est écrite ci-dessous. Fondamentalement, le principe est
d'abord, dénouer l'image. La vie est généralement plus simple après une étape de débruitage. Ici, j'utilise un filtre de variation totale, car il en résulte une image par morceaux constante qui sera plus facile à franchir. J'améliore les régions sombres en utilisant une érosion morphologique (sur l'image en niveaux de gris).
puis d'appliquer un seuil adaptatif qui varie localement dans l'espace, car le contraste varie à travers l'image. Cette opération entraîne une image binaire.
érode l'image binaire pour briser les liens parasites entre les régions et ne conserve que les grandes régions.
calculer une mesure de l'allongement des régions pour ne garder que les plus allongés. Ici j'utilise le rapport des valeurs propres du tenseur d'inertie.
Les paramètres les plus difficiles à régler sont la taille de bloc pour le seuillage adaptatif et la taille minimale des zones à conserver. J'ai également essayé un filtre Canny sur l'image débruitées (skimage.filters.canny), et les résultats étaient assez bons, mais les bords n'étaient pas toujours fermés, vous pouvez aussi essayer une méthode de détection de bord telle qu'un filtre Canny.
Le résultat est présenté ci-dessous:
# Import modules
import numpy as np
from skimage import io, measure, morphology, restoration, filters
from skimage import img_as_float
import matplotlib.pyplot as plt
# Open the image
im = io.imread('sand_lines.png')
im = img_as_float(im)
# Denoising
tv = restoration.denoise_tv_chambolle(im, weight=0.4)
ero = morphology.erosion(tv, morphology.disk(5))
# Threshold the image
binary = filters.threshold_adaptive(ero, 181)
# Clean the binary image
binary = morphology.binary_dilation(binary, morphology.disk(8))
clean = morphology.remove_small_objects(np.logical_not(binary), 4000)
labels = measure.label(clean, background=0) + 1
# Keep only elongated regions
props = measure.regionprops(labels)
eigvals = np.array([prop.inertia_tensor_eigvals for prop in props])
eigvals_ratio = eigvals[:, 1]/eigvals[:, 0]
eigvals_ratio = np.concatenate(([0], eigvals_ratio))
color_regions = eigvals_ratio[labels]
# Plot the result
plt.figure()
plt.imshow(color_regions, cmap='spectral')