IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Algorithmes et structures de données Discussion :

Segment maximal sur une courbe discrète


Sujet :

Algorithmes et structures de données

  1. #1
    Membre très actif
    Profil pro
    Inscrit en
    Novembre 2010
    Messages
    265
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2010
    Messages : 265
    Par défaut Segment maximal sur une courbe discrète
    Bonjour les amis,
    Je cherche à simplifier une courbe composée de pixels (épaisseur 1 pixel). J'ai plus ou moins compris la théorie des courbes ou segments discrets mais je butte sur le point principal.
    Nom : Segment de droite discrète.png
Affichages : 659
Taille : 9,5 Ko
    Partant d'un premier point, on passe au suivant et on calcule la pente entre les 2. On passe au troisième et on recalcule la pente toujours à partir du premier point et ce sur une certaine longueur de segment.
    J'imagine qu'à chaque fois qu'on recalcule la pente il faut vérifier que les points précédents appartiennent toujours à la droite médiane (distance < 1/2 pixel).
    Je me trompe sûrement sur le principe et peut-être avez-vous une idée car en fait j'aurais bien voulu éviter cette "marche arrière"?

  2. #2
    Rédacteur/Modérateur

    Homme Profil pro
    Ingénieur qualité méthodes
    Inscrit en
    Décembre 2013
    Messages
    4 229
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur qualité méthodes
    Secteur : Conseil

    Informations forums :
    Inscription : Décembre 2013
    Messages : 4 229
    Par défaut
    Ce que tu cherches à faire n'est pas clair.
    Le titre parle de segment maximal, et du coup on se dit que, peut-être, tu cherches à décomposer une courbe en succession de segments, et donc, tu cherches à quels endroits il faut considérer que la pente change. Peut-être ?

  3. #3
    Membre très actif
    Profil pro
    Inscrit en
    Novembre 2010
    Messages
    265
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2010
    Messages : 265
    Par défaut
    Oui c'est ça, je cherche à former le plus long segment (maximal rectiligne) où chaque pixel ne s'écarte pas de la moitié d'un pixel de la droite qui relie les pixels en cours.

  4. #4
    Expert confirmé
    Avatar de Mat.M
    Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2006
    Messages
    8 540
    Détails du profil
    Informations personnelles :
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Novembre 2006
    Messages : 8 540
    Par défaut
    Citation Envoyé par BBouille Voir le message
    Partant d'un premier point, on passe au suivant et on calcule la pente entre les 2. On passe au troisième et on recalcule la pente toujours à partir du premier point et ce sur une certaine longueur de segment.
    d'après ce que je comprends vous voulez faire le lissage d'une courbe par interpolations bref le tracé d'une Spline
    Chercher dans Google "spline C++" ou "spline Java" il y a des tas de bibliothéques qui existent pour ça

    Citation Envoyé par BBouille Voir le message
    Oui c'est ça, je cherche à former le plus long segment (maximal rectiligne) où chaque pixel ne s'écarte pas de la moitié d'un pixel de la droite qui relie les pixels en cours.
    à part procéder par interpolations je ne vois pas.

  5. #5
    Membre très actif
    Profil pro
    Inscrit en
    Novembre 2010
    Messages
    265
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2010
    Messages : 265
    Par défaut
    Non, justement je ne veux pas passer par les splines, je veux réduire le nombre de pixels utiles de la courbe dans l'image sinon je n'aurais pas posé la question.

  6. #6
    Rédacteur/Modérateur

    Homme Profil pro
    Ingénieur qualité méthodes
    Inscrit en
    Décembre 2013
    Messages
    4 229
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur qualité méthodes
    Secteur : Conseil

    Informations forums :
    Inscription : Décembre 2013
    Messages : 4 229
    Par défaut
    Dans ton premier message, tu parles d'éviter cette marche arrière. Pourquoi ? Si les volumes de données sont raisonnables, les temps de traitement ne devraient pas être un problème. Dans les pistes que je vois, il y a systématiquement des phases de recalcul.

    Par ailleurs, dans le plan que tu proposes, tu pars de la gauche vers la droite. Ce n'est pas symétrique.

    Imaginons ces points :
    Pour x entre 0 et 20 , y vaut 0.1389*x (arrondi à l'entier le plus proche)
    Puis pour x entre 20 et 40 , y vaut 0.1389*(40-x) (arrondi à l'entier le plus proche)
    J'ai donné 2 fois la formule pour x=20, mais ça donne le même point au final.
    Les 2 segments sont parfaitement symétriques

    Si tu pars de la gauche, tu vas considérer qu'il y a un segment qui va de (0,0) à (21,3). Puis partant de (21,3), tu vas galérer pour trouver une succession de segments qui collent à la courbe.

    En particulier, si tu as un segment qui part de (21,3) à (25,2), comment gères-tu l'arrondi ? Tu considères que le point (23,2) est sur ce segment ? Et (23,3) aussi est sur ce segment ?

    Dans mon esprit (mais ce n'est pas totalement clair), il faut regarder les 2 extrémités, et les relier par une droite. Si tous les points sont à moins de 0.5 de cette droite, tout va bien, sinon on retient le point le plus loin de cette droite. On place temporairement un sommet à ce point, et on recommence avec les 2 segments obtenus. Et ainsi de suite. Et au final, on va probablement supprimer certains sommets, s'il s'avère qu'ils sont inutiles. Mais ce n'est certainement pas suffisant.

    Sur mon exemple, c'est même pire que ça.
    Quand tu vas tester tes points 1 par 1, quand tu vas tester : Les points sont-ils tous très proches de la droite qui va de (0,0) à (20,3), tu vas considérer que non. Tu vas dire que la droite qui va de (0,0) à (20,3), pour x = 17, elle devrait donner y=3. Or dans les données, on a (17,2). Les points de x=0 à 20 ne semblent pas alignés.
    Et en effet, ma droite ne va pas tout à fait de (0,0) à (20,3) ; c'est bien l'équation d'une droite que j'ai donnée, mais une droite qui va de (0,0) à (20, 2.778) suivie d'une autre droite qui redescend de (20, 2.778) à (40,0).


    Autre question. Tu parles d'une succession de pixels. Est-ce que les pixels sont forcément avec des x de plus en plus grands, de gauche à droite, disons une courbe y=f(x). Ou bien tu as une courbe qui peut être comme une spirale.

  7. #7
    Membre très actif
    Homme Profil pro
    libre
    Inscrit en
    Juin 2019
    Messages
    205
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Autre

    Informations professionnelles :
    Activité : libre

    Informations forums :
    Inscription : Juin 2019
    Messages : 205
    Par défaut
    Tu peux jeter un coup d'oeil dans la partie polygone

    https://potrace.sourceforge.net/potrace.pdf

  8. #8
    Membre très actif
    Profil pro
    Inscrit en
    Novembre 2010
    Messages
    265
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2010
    Messages : 265
    Par défaut
    TBC: Je veux éviter les boucles dans le traitement graphique, ça augmente très vite le temps de calcul dès qu'on a une image d'une certaine taille.
    Avant d'avoir parcouru les pixels tu ne sais pas quelles sont les extrémités, c'est pourquoi je voudrais éviter de recalculer les points précédents.
    Je pars du haut vers le bas d'une image et de la gauche vers la droite.
    Dès que je rencontre un pixel noir j'applique la méthode.
    L'image a déjà été squelettisée donc je n'ai pas à me soucier de l'épaisseur du trait des courbes.
    Peu importe si je tombe sur le haut d'une courbe et que je doive parcourir le reste de la courbe dans l'autre sens ensuite, je les fusionne après.
    Justement je cherche à réduire au maximum les tronçons rectilignes.
    Ensuite pour des segments dont la pente varie "brusquement" j'applique une courbe de Bézier passant par 4, 3 ou 2 points selon les cas.
    Wheel: Tu as tapé dans le mille, j'ai lu pas mal d'articles traitant le sujet et notamment Potrace mais aucun n'indique le principal c'est-à-dire comment arriver à cette droite médiane. J'ai lu tout ce qui concerne les paths, etc de Potrace.
    Pour le moment je pars de 10 points à la queue-leu-leu par exemple et si le xième point n'est pas sur la droite formée par ces prédécesseurs j'arrête la boucle et je recommence pour les suivants mais ça ne me semble pas très élégant.

  9. #9
    Membre très actif
    Homme Profil pro
    libre
    Inscrit en
    Juin 2019
    Messages
    205
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Autre

    Informations professionnelles :
    Activité : libre

    Informations forums :
    Inscription : Juin 2019
    Messages : 205
    Par défaut
    Avant d’investir dans le Potrace qui est long est lourd avez-vous essayer avec les traditionnels algorithmes de réduction comme RamerDouglasPeucker et voir ce que ca donne,, si le resultat nest pas concluant tu pourrais passer au Potrace.

  10. #10
    Membre très actif
    Profil pro
    Inscrit en
    Novembre 2010
    Messages
    265
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2010
    Messages : 265
    Par défaut
    Vii Wheel j'ai essayé ça aussi mais ça ne donne pas le résultat escompté malgré différentes tolérances mais encore une fois j'utilise sûrement mal cette fonction comme d'autres et même il faut donner cette tolérance et je voudrais l'éviter.
    Je cherche à avoir les plus longs segments rectilignes possibles et plus il y a de petits mieux c'est, ça veut dire qu'on peut créer une courbe (de Bézier par exemple).

  11. #11
    Membre très actif
    Homme Profil pro
    libre
    Inscrit en
    Juin 2019
    Messages
    205
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Autre

    Informations professionnelles :
    Activité : libre

    Informations forums :
    Inscription : Juin 2019
    Messages : 205
    Par défaut
    Le Potrace donne un résultat équilibré pour différentes courbes mais trop long pour être retranscrit vers votre langage, le code est disponible sur sourceforge c'est la fichier trace.c qu'il faut utiliser.

    Je cherche à avoir les plus longs segments rectilignes possibles et plus il y a de petits mieux c'est, ça veut dire qu'on peut créer une courbe (de Bézier par exemple).
    Tu auras besoin d'utiliser RamerDouglasPeucker ou son équivalent avec une tolérance entre 1 et 1.4 au minimum pour supprimer les points sur la même ligne et après c'est au algo e reconstitution des beziers de merger ces petits segments.

    Potrace (polygones uniquement sans lissage)



    RamerDouglasPeucker tol : 1



    RamerDouglasPeucker tol : 1.2



    code de RamerDouglasPeucker en Delphi
    exemple d'utilisation Vectosize
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    {
    Copyright © 2019-2022 Angus Johnson
    Freeware released under Boost Software License
    https://www.boost.org/LICENSE_1_0.txt
    //------------------------------------------------------------------------------
    // RamerDouglasPeucker - and support functions
    //------------------------------------------------------------------------------ }
    type
     TPathD = array of TPoint;
     TArrayOfInteger = array of integer;
     
    function PerpendicularDistSqrd(const pt, l1, line2: TPoint): double;
    var
      a,b,c,d: double;
    begin
      a := pt.X - l1.X;
      b := pt.Y - l1.Y;
      c := line2.X - l1.X;
      d := line2.Y - l1.Y;
      if (c = 0) and (d = 0) then
        result := 0 else
        result := Sqr(a * d - c * b) / (c * c + d * d);
    end;
     
    procedure RDP(const path: TPathD; startIdx, endIdx: integer;
      epsilonSqrd: double; var flags: TArrayOfInteger);
    var
      i, idx: integer;
      d, maxD: double;
    begin
      idx := 0;
      maxD := 0;
      for i := startIdx +1 to endIdx -1 do
      begin
        //PerpendicularDistSqrd - avoids expensive Sqrt()
        d := PerpendicularDistSqrd(path[i], path[startIdx], path[endIdx]);
        if d <= maxD then Continue;
        maxD := d;
        idx := i;
      end;
      if maxD < epsilonSqrd then Exit;
      flags[idx] := 1;
      if idx > startIdx + 1 then RDP(path, startIdx, idx, epsilonSqrd, flags);
      if endIdx > idx + 1 then RDP(path, idx, endIdx, epsilonSqrd, flags);
    end;
    //------------------------------------------------------------------------------
     
    function RamerDouglasPeucker(const path: TPathD;
      epsilon: double): TPathD;
    var
      i,j, len: integer;
      buffer: TArrayOfInteger;
    begin
      len := length(path);
      if len < 5 then
      begin
        result := Copy(path, 0, len);
        Exit;
      end;
      SetLength(buffer, len); //buffer is zero initialized
     
      buffer[0] := 1;
      buffer[len -1] := 1;
      RDP(path, 0, len -1, Sqr(epsilon), buffer);
      j := 0;
      SetLength(Result, len);
      for i := 0 to len -1 do
        if buffer[i] = 1 then
        begin
          Result[j] := path[i];
          inc(j);
        end;
      SetLength(Result, j);
    end;

  12. #12
    Membre très actif
    Profil pro
    Inscrit en
    Novembre 2010
    Messages
    265
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2010
    Messages : 265
    Par défaut
    Merci Wheel,
    Oui j'ai commencé à traduire "trace.c" dans mon langage mais je ne suis pas sorti du bois c'est une belle tartine.
    Comme tu cites à nouveau Douglas-Peucker je vais m'y replonger, peut-être utilise-je une tolérance sur la courbe trop grande ou trop petite. Je reviens vers toi si je trouve enfin la solution.
    Je ne suis même pas fichu de télécharger le projet que tu as mis en lien si tu sais comment faire merci.

  13. #13
    Membre très actif
    Homme Profil pro
    libre
    Inscrit en
    Juin 2019
    Messages
    205
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Autre

    Informations professionnelles :
    Activité : libre

    Informations forums :
    Inscription : Juin 2019
    Messages : 205
    Par défaut
    Si tu trouves le code difficile tu pourrais essayer avec une version en C# plus intrusif ici CsPotrace
    Dans les deux codes ce sont les quatre fonctions suivantes et leurs dépendances qu'il faut récrire, le code restant est pour le lissage et l'optimisation des béziers tu peux le laisser après :

    CalcSums();
    CalcLon();
    BestPolygon();
    AdjustVertices();

    ..dépendances
    quadform
    cyclic
    ddist
    mod
    xprodi
    penalty3

    p->priv->Pt est le vecteur d'entrée
    p->priv->curve->vertex vecteur de sortie

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
          TRY(calc_sums(p->priv)); 
        TRY(calc_lon(p->priv));
        TRY(bestpolygon(p->priv));
        TRY(adjust_vertices(p->priv));
     
        if (p->sign == '-') {   /* reverse orientation of negative paths */
          reverse(&p->priv->curve);
        }

  14. #14
    Membre très actif
    Profil pro
    Inscrit en
    Novembre 2010
    Messages
    265
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2010
    Messages : 265
    Par défaut
    Je ne vais pas dire que je n'ai pas de mal, parfois je coince mais petit à petit j'avance. Le problème c'est qu'il y a énormément de procédures à traduire.
    Mais merci pour tout ce que tu m'as expliqué et apporté.
    Je continue aussi à essayer de piger les décompositions d’une courbe discrète en arcs de cercle et segments de droite qui ont l'avantage d'après ce que j'ai lu d'être très rapides et robustes.
    Voici ce que j'étudie pour le moment, pas si simple pour mon cerveau: https://hal.univ-lorraine.fr/tel-01746364/document
    J'ai tendance à créer mes propres méthodes pour d'abord pouvoir les comprendre, les améliorer, etc.
    J'essaie de créer des méthodes où il y a un minimum de boucles car ça consomme beaucoup en temps d'exécution, je préfère beaucoup de if que de boucles.
    Je suis pas trop loin de faire un truc ultra-rapide et simple pour la squelettisation qui est la partie la plus importante il me semble, si j'y arrive je poste ça directement.

  15. #15
    Membre très actif
    Profil pro
    Inscrit en
    Novembre 2010
    Messages
    265
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2010
    Messages : 265
    Par défaut
    Wheel, je voulais te poser une question pour le cas où tu avais déjà traité le sujet.
    J'ai reconsidéré l'algorithme de Douglas-Peucker et ça donne de bons résultats c'est vrai.
    Par contre une fois les courbes "simplifiées", as-tu une idée pour isoler les droites des courbes?
    Je me trompe sûrement mais on dirait que Potrace adoucit toutes les courbes, c'est-à-dire que même un tronçon droit pour notre oeil est inclus à une courbe de Bézier et sera donc légèrement arrondi.

  16. #16
    Membre très actif
    Homme Profil pro
    libre
    Inscrit en
    Juin 2019
    Messages
    205
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Autre

    Informations professionnelles :
    Activité : libre

    Informations forums :
    Inscription : Juin 2019
    Messages : 205
    Par défaut
    Oui mais ce lissage est a échelle de pixel donc pour améliorer l'affichage des objets de petite taille,, Il est possible de l'ignorer pour les segments d'une certaine longueur (voir les photos)..

    (j'en ai fait pour convertir les vecteurs en béziers) mais transformer des pixels en vecteurs il y a le problème de crénelage qu'il faut réduire pour cela:

    Avant le traitement augmenter l'echelle de l'image par x2, x3,
    Sur cette nouvelle image appliquer une opération "antialiasing"
    Transformation en vecteurs
    Réduire l'echelle des vecteurs par l'inverse du facteur appliquer l'entrée pour trouver la taille originale

    Regarder dans cette exemple pour avoir une idée https://potrace.sourceforge.net/mkbitmap.html




    la fonction Smooth est très réduite tu peux la réécrire facilement

  17. #17
    Membre très actif
    Profil pro
    Inscrit en
    Novembre 2010
    Messages
    265
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2010
    Messages : 265
    Par défaut
    Merci Wheel tu es trop top, justement mon problème est quand alpha est supérieur à 1 donc quand on a des droites plutôt que des courbes mais je vais continuer à creuser.
    Mon souci depuis longtemps est de conserver les tronçons rectilignes par rapport aux segments qu'on peut assimiler à une courbe de Bézier, on peut tout passer dans une courbe de Bézier, j'aimerais me fixer une limite mais je ne sais pas où!

  18. #18
    Membre très actif
    Homme Profil pro
    libre
    Inscrit en
    Juin 2019
    Messages
    205
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Autre

    Informations professionnelles :
    Activité : libre

    Informations forums :
    Inscription : Juin 2019
    Messages : 205
    Par défaut
    alpha ce paramètre est dépendant aussi à la longueur de ligne,
    s'il dépasse le AlphaMax (par défaut = 1) le lissage n'aurait pas lieu.


  19. #19
    Expert confirmé
    Avatar de Mat.M
    Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2006
    Messages
    8 540
    Détails du profil
    Informations personnelles :
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Novembre 2006
    Messages : 8 540
    Par défaut
    Citation Envoyé par BBouille Voir le message
    J'essaie de créer des méthodes où il y a un minimum de boucles car ça consomme beaucoup en temps d'exécution, je préfère beaucoup de if que de boucles.
    pour ça il faut créer des quadtrees un exemple ici

  20. #20
    Membre très actif
    Profil pro
    Inscrit en
    Novembre 2010
    Messages
    265
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2010
    Messages : 265
    Par défaut
    Wheel: Encore une chose intéressante que tu m'apprends. Justement je suis toujours en train de me fixer un critère de sélection de tronçon rectiligne ou faisant plutôt partie d'une courbe.
    Je continue.
    Mat.M: Arf encore quelque chose de nouveau, merci, ça a l'air puissant ça.
    J'espère pouvoir terminer un jour ce que je suis en train de faire, ce n'est pas ce qu'il y a de plus rigoureux mathématiquement ou informatiquement parlant mais c'est ultra-rapide, le filtrage, la squelettisation et le repérage des points dominants sur une image en une passe.
    Si j'y arrive je poste ça aussitôt.

Discussions similaires

  1. Simuler un bruit sur une courbe
    Par mimil18 dans le forum C++
    Réponses: 3
    Dernier message: 16/05/2007, 15h36
  2. Réponses: 2
    Dernier message: 27/03/2007, 18h58
  3. comments placer des delimiteurs sur une courbe?
    Par brindacier dans le forum MATLAB
    Réponses: 4
    Dernier message: 26/03/2007, 19h19
  4. Texture sur une courbe
    Par newe95 dans le forum Graphisme
    Réponses: 3
    Dernier message: 15/05/2006, 01h54
  5. [TChart] Comment utiliser le curseur sur une courbe ?
    Par marsupilami34 dans le forum Composants VCL
    Réponses: 4
    Dernier message: 29/09/2005, 16h49

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo