2
votes

Comment définir mathématiquement un contour bruyant?

Regardez l'image suivante:

 entrez la description de l'image ici

Comme vous pouvez le voir, certaines régions sont très bruyantes (bords très irréguliers avec beaucoup de changements soudains)

Je voudrais éliminer ces régions de l'image, mais pour ce faire, je dois être en mesure de déterminer ce que signifie ce "bruit".

Quelqu'un a-t-il des suggestions sur la façon de définir mathématiquement ces régions?


4 commentaires

La dimension fractale pourrait être excessive. Courbure intégrée?


Pour que votre mesure des changements d'angle soit significative, ils doivent être relatifs à une portée de taille fixe lors de la comparaison de parties de l'image. J'ai ajouté une suggestion sur la façon dont vous pourriez aborder cela, ci-dessous.


La vérification brute la plus simple qui pourrait fonctionner serait de vérifier le rapport périmètre / surface. Une meilleure façon serait de faire le tour du contour dans le sens des aiguilles d'une montre et de faire la somme de l'angle (absolu) d'un point à l'autre. Des angles très variables sur un contour donneront une très grande somme d'angles absolus. Cependant, ce n'est pas robuste à la taille du contour, donc vous voudrez peut-être prendre en compte le périmètre ou la zone avec une division. Il s'agit essentiellement d'une version pour les pauvres de la suggestion d'Andras de prendre la courbure intégrée. Edit: Je ne savais pas que vous aviez posté cette idée dans la question elle-même.


Avez-vous l'image sans les contours blancs? Les procédures de segmentation ne génèrent pas de contours épais (ou des contours du tout), il s'agit généralement d'un outil de visualisation. La réponse de flamelite semble faire le travail, mais il n'a tout simplement pas accès à des contours indépendants, donc le résultat est mauvais.


3 Réponses :


1
votes

Vous pouvez essayer ceci:

  1. Divisez la matrice d'image en une proportion parfaitement itérable.

  2. Pour chaque espace itéré, ajustez les pixels blancs à une régression linéaire dans l'espace.

  3. Stockez le RSME (Root Mean Squared Error) du modèle linéaire de chaque section.

  4. Calculez l'écart type pour toutes les sections itérées.

  5. Sélectionnez un écart type qui décrit le seuil de "bruit" tolérable.

Vous devrez tester différentes "tailles d'itération" pour trouver le meilleur descripteur du bruit.

Si vous souhaitez comparer les niveaux de bruit relatifs entre images, ce problème est mieux résolu en utilisant une conception d'apprentissage automatique à convolution.


5 commentaires

Je ne veux pas décrire l'image mathématiquement, je veux décrire mathématiquement les sections de bruit. c'est-à-dire que l'une de ces régions est un polygone Comment savoir si le polygone est bruyant?


J'ai mis à jour ma réponse. Faites-moi savoir si vous souhaitez obtenir de l'aide pour comprendre comment mettre en œuvre l'une des étapes.


J'ai une vendetta personnelle contre les NN


Vous n'avez pas besoin d'utiliser un réseau neuronal pour cela, un simple noyau linéaire est ce que vous voulez.


Juste une régression.



4
votes

J'ai essayé de définir les contours bruyants en analysant leurs valeurs de courbure. Voici les détails de l'implémentation:

#function to calculate the curvature values along a given contour and classify noisy contour
def contourCurvature(contourspt):
    #curvature value estimation using symmetric derivation
    # at points (i-step), i, (i+step)
    step = 5
    s1 = 2*step
    s2 = np.power(s1, 2)
    if len(contourspt) < s1:
        return False

    kp = []
    l = len(contourspt)
    ct = 0
    for i in range(l):
        p = i - step
        pp = i - s1
        if p < 0:
            p += l
            pp += l
        elif pp < 0:
            pp += l
        n = (i + step) % l
        nn = (i + s1) % l

        posPrev = contourspt[p][0]
        posPrevP = contourspt[pp][0]
        posCurr = contourspt[i][0]
        posNext = contourspt[n][0]
        posNextN = contourspt[nn][0]
        #first order derivative at point i w.r.t. x and y
        f1stderX = (posNext[0] - posPrev[0])/s1
        f1stderY = (posNext[1] - posPrev[1])/s1
        # second order derivative at point i w.r.t. x and y
        f2ndderX = (posNextN[0] - 2*posCurr[0] + posPrevP[0])/s2
        f2ndderY = (posNextN[1] - 2*posCurr[1] + posPrevP[1])/s2

        if f1stderX != 0 or f1stderY != 0:
            a = f2ndderX*f1stderY - f2ndderY*f1stderX
            b = np.power(np.power(f1stderX,2) + np.power(f1stderY,2), 3/2)
            curvature2D = float("{0:.5f}".format(a/b))

            #Check if contour contains any regular section of more than 
            # 20 percent of the contour length
            if np.abs(curvature2D) < 0.005:
                ct += 1
                if ct > l*0.2:
                    return True
            else:
                ct = 0
            if np.abs(curvature2D) < 0.0001 or np.abs(curvature2D) > 5: 
                curvature2D = 0 #local noise suppression
            #store the curvature values in a list
            kp.append(np.abs(curvature2D))

    # check the variance of curvatures values along the contour
    var = np.var(kp, ddof=1)
    if var < 0.01:
        print('Variance: ',var)
        return True
    return False


def main():
    gray = cv2.imread('D:/cnt.png', 0)
    #threshold the image using 250 as threhold value
    ret,th1 = cv2.threshold(gray,250,255,cv2.THRESH_BINARY)
    img1,contours,hierarchy = cv2.findContours(th1, cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
    img = cv2.cvtColor(gray, cv2.COLOR_GRAY2RGB)
    #iterate through each contour
    for cnt in contours:
        if(len(cnt)>50): #neglect the small contours as noise
            flag = contourCurvature(cnt)
            if(flag):
                cv2.drawContours(img,[cnt],0,(0,0,255),3)

    cv2.imshow('Final image', img)
    cv2.waitKey(0)

if __name__ == "__main__":
    main()

Voici l'implémentation Python des étapes ci-dessus. Ici, j'utilise l'équation d'estimation de courbure pour le système de coordonnées cartésiennes tel que défini ici

1. Threshold the gray scale image using fixed threshold value of 250 to retrieve the white edges

2.Extract the contours in the threshold image

3.Calculate the curvature values along each contour

4.From the curvature data we can observer that the noisy contour's curvature values has higher variance value, therefore we can classify such
noisy contours using certain threshold value.

Voici l'image de sortie montrant uniquement les contours non bruyants (vrais). entrez la description de l'image ici

Bien que l'image de sortie finale manque quelques vrais contours, toute autre idée pour améliorer cet algorithme est la bienvenue ici.


6 commentaires

mm c'est étrange car il y a des contours visuellement moins bruyants que vous n'avez pas détectés. Je dirais que l'étape d'extraction est mauvaise. Vous devez identifier les zones de couleurs plates indépendantes et saisir le contour des pixels blancs voisins autour de ces couleurs plates. Cela dit, il est probable que OP ait réellement les contours, car la plupart du temps ces lignes blanches proviennent de la visualisation, car la procédure de segmentation n'ajoute pas de contours entre les blobs


Le défi que j'ai eu ici est que quelques contours contiennent des points lisses dans la plupart de leur longueur, mais dans une certaine région, ils se composent d'une section très irrégulière, de sorte qu'une telle partie irrégulière ajoute les valeurs de variance fait du contour bruyant au total. C'est peut-être le cas si nous ajoutons un contrôle pour les contours qui ont une section de valeurs de courbure régulières avec une longueur supérieure à une certaine valeur de seuil, puis les détectons comme un contour vrai.


Ce que je ferais, ce n'est pas d'indiquer la valeur maximale, mais d'intégrer et de normaliser. Calculez tous les angles du contour, ajoutez-les ensemble et divisez le nombre de points. Ensuite, il y a un seuil heuristique à définir, mais cela devrait fonctionner


Oui, cela semble une approche faisable, je vais essayer cela. Je viens de mettre à jour ma réponse comme mentionné dans le commentaire.


Est-il possible de vous demander de commenter un peu plus votre solution? Cela semble aller dans la bonne direction (testez-le maintenant) mais certaines parties ne sont pas tout à fait claires pour moi. Merci d'avance.


J'ai ajouté quelques commentaires dans le code, veuillez me le faire savoir si vous avez des questions spécifiques.



1
votes

Vous pouvez d'abord approximer chaque contour (ou une partie de celui-ci) avec une courbe polygonale en utilisant Douglas-Peucker, de sorte que l'erreur maximale soit globalement bornée, puis peut-être considérer

  1. Comparaison du périmètre de l'approximation avec le périmètre de la courbe d'origine
  2. Calculez la distance de chaque point de la courbe d'origine à la courbe polygonale approximative, puis calculez l'écart type de cet ensemble de données.

Ou vous pouvez prendre une approximation brute et une approximation polygonale fine du même contour et compter le nombre de segments dans l'approximation fine par longueur de l'approximation brute.


0 commentaires