Partage
  • Partager sur Facebook
  • Partager sur Twitter

Colorer l'interieur d'un contour en SDL

    22 juillet 2010 à 1:25:10

    Bonjour les amis :)
    Je suis en train travailler sur une application Dont l utilisateur va dessiner avec la souris un contour quelquonque;
    le programme va recuperer les coordonné de tout les pixels formant le contour.
    j'ai deja depassé cette étape .
    dans une deuxieme etape ,je dois colorer l'interieur du contour .et là mon probleme ;
    J'ai déja fait une solution qui ne marche pas dans tout les cas je vais la publier plus tard pour ne pas orienter les reponses.
    Bon , pas d'idees ? ou fonctions sdl qui peuvent m'aider?
    merci pour toute reponse a l'avance .

    configuration :codeblock; sdl
    • Partager sur Facebook
    • Partager sur Twitter
      22 juillet 2010 à 9:28:43

      Là, comme çà, de bon matin, je vois une méthode :p

      Tu récupères les coordonnées de chacun de tes pixels formant ton contour et, pour chacun de ces pixels contour, tu effectues un parcours horizontal : Tu pars du pixel, et tu colorises (tu ajoutes un pixel coloré) tant que la case x+1 n'est pas un pixel contour ! ;)
      • Partager sur Facebook
      • Partager sur Twitter
        22 juillet 2010 à 10:07:14

        C'est l'algo du pot de peinture. tu peux faire ça récursivement (en 4 - 5 lignes) ou itérativement en utilisant une structure de pile.
        • Partager sur Facebook
        • Partager sur Twitter

        Recueil de code C et C++  http://fvirtman.free.fr/recueil/index.html

          22 juillet 2010 à 18:48:02

          @MrFlow:merci pour ta réponse , en fait c'est la meme idée que j'ai fait .avec une petite difference que j''ai pensé à faire une balayage vericale suivant les Y.
          Bon elle n'est pas mal regarde ce qu'elle peut faire cette idée :
          contour dessiné par l'utilisateur
          http://www.siteduzero.com/upload-216.h [...] extarea=intro

          et voila son remplissage :
          http://www.siteduzero.com/upload-216.h [...] extarea=texte
          mais la limite de cette methode est grave si le contour est de la forme :
          http://www.siteduzero.com/upload-216.h [...] extarea=texte

          voila le resultat c dommage :euh:
          http://www.siteduzero.com/upload-216.h [...] extarea=texte

          @Fvirtman merci pour l'idée qui parait interessante , mais gé rien trouvé sur cet algorithme , Tu peux nous parler sur ce qu'il fait sinon un lien :p ?
          • Partager sur Facebook
          • Partager sur Twitter
            22 juillet 2010 à 21:23:09

            Qui est "gé" ? Gérard ?
            • Partager sur Facebook
            • Partager sur Twitter

            Recueil de code C et C++  http://fvirtman.free.fr/recueil/index.html

              22 juillet 2010 à 21:45:51

              gé= j'ai:)
              alors pas d'idée ?
              • Partager sur Facebook
              • Partager sur Twitter
                23 juillet 2010 à 11:24:45

                J'ajoute mon petit grain de sel... à mon avis dans pas 1er étape, il ne faut pas stocker tous les points (dans une variable), mais juste colorer chaque pixel voulu (c'est vraiment moins lourd) avec :

                *((Uint32*)(map->pixels) + x + y * map->w) = color;
                


                (à la position x, y, sur la surface map, on met la couleur color)
                • Partager sur Facebook
                • Partager sur Twitter
                  23 juillet 2010 à 13:56:39

                  XX3 je n'ai pas eu accès a tes liens, mais utilises ma méthode (pas optimale mais fonctionnelle) et ça devrait marcher.
                  Ou sinon balance ton algorithme ici !
                  • Partager sur Facebook
                  • Partager sur Twitter
                    30 juillet 2010 à 16:30:24

                    Je suis desolé pour le retard , j'ai pas eu le temps pour repondre ;
                    Mrflow :
                    voici mon code :
                    int j;
                    int verif=0;int a,b;
                    
                    for(  int i=min; i<max;i++)
                    {
                    
                    //if (max<i) {i=640;j=480;}
                    
                    //{
                    verif=0;
                    for ( j=0;j<480;j++)
                    
                    
                    
                    {
                    
                    if (t[i][j] &&!verif) { a=j;verif=1;}
                    if (t[i][j]&&verif) b=j;
                    
                    
                    
                    }
                    
                    
                    if (a<b)
                    {
                    for (int k=a;k<b;k++)
                    {
                    position.x=i;
                    
                    t[i][k]=1;
                    
                    
                    position.y=k;
                    SDL_FillRect(rectangle, NULL, SDL_MapRGB(ecran->format, 255, 255, 255)); // Remplissage de la surface avec du blanc
                    SDL_BlitSurface(rectangle, NULL, ecran, &position);
                    SDL_Flip(ecran);
                    
                    
                    }
                    }
                    



                    et voila son execution :
                    Image utilisateur
                    Image utilisateur
                    Image utilisateur
                    Image utilisateur

                    Mrflow esperant que tu passes par ici tu vois bien que cette idée donne des resultats tres mauvaise pour certain forme !
                    @Fvirtman vraiment merci pour ton aide mais je sais pas pourquoi l algorithme de remplissage ne permet pas de colorer qu'une surface qui occupe 60000 pixel c beaucoup tres inferieur a ma surface qui occppe 480*640 pixel ; c dommage ; pas de solution ?
                    • Partager sur Facebook
                    • Partager sur Twitter
                      30 juillet 2010 à 16:57:44

                      Tu as du te planter. Un bon algo de pot de peinture bien récursif peut etre bien efficace.
                      • Partager sur Facebook
                      • Partager sur Twitter

                      Recueil de code C et C++  http://fvirtman.free.fr/recueil/index.html

                        2 août 2010 à 17:31:43

                        Citation : XX3

                        Je suis desolé pour le retard , j'ai pas eu le temps pour repondre ;
                        Mrflow :
                        voici mon code :

                        int j;
                        int verif=0;int a,b;
                        
                        for(  int i=min; i<max;i++)
                        {
                        
                        //if (max<i) {i=640;j=480;}
                        
                        //{
                        verif=0;
                        for ( j=0;j<480;j++)
                        
                        
                        
                        {
                        
                        if (t[i][j] &&!verif) { a=j;verif=1;}
                        if (t[i][j]&&verif) b=j;
                        
                        
                        
                        }
                        
                        
                        if (a<b)
                        {
                        for (int k=a;k<b;k++)
                        {
                        position.x=i;
                        
                        t[i][k]=1;
                        
                        
                        position.y=k;
                        SDL_FillRect(rectangle, NULL, SDL_MapRGB(ecran->format, 255, 255, 255)); // Remplissage de la surface avec du blanc
                        SDL_BlitSurface(rectangle, NULL, ecran, &position);
                        SDL_Flip(ecran);
                        
                        
                        }
                        }
                        




                        et voila son execution :
                        Image utilisateur
                        Image utilisateur
                        Image utilisateur
                        Image utilisateur

                        Mrflow esperant que tu passes par ici tu vois bien que cette idée donne des resultats tres mauvaise pour certain forme !
                        @Fvirtman vraiment merci pour ton aide mais je sais pas pourquoi l algorithme de remplissage ne permet pas de colorer qu'une surface qui occupe 60000 pixel c beaucoup tres inferieur a ma surface qui occppe 480*640 pixel ; c dommage ; pas de solution ?



                        J'ai un peu peur, mais je me lance quand même: rectangle c'est un rectangle de 1px*1px?! => utilise direct l'écrire d'un pixel sur une surface (voir mon commentaire qq post au dessus...)
                        Et y'a de gros pb d'optimisation (genre réécrire position.x=i (b-a) fois...)

                        Par contre je vois pas en quoi le résultat est mauvais pour certaines formes... çà m'a l'air plutot pas mal (même si c'est non antialiasé! ^^)
                        t[][] c'est quoi? un tableau avec la position de tous les points? (voir mon commentaire qq post au dessus...)
                        • Partager sur Facebook
                        • Partager sur Twitter
                          4 août 2010 à 23:59:56

                          je pense qu'il parlait du 2ème essai, où son remplissage déborde verticalement
                          • Partager sur Facebook
                          • Partager sur Twitter
                            5 août 2010 à 9:27:57

                            Ah oui, j'ai pas les yeux en face des trous!
                            Je pense voir ou est le problème. En fait, quand tu fais "if (t[i][j]&&verif) b=j; " dans ta boucle et qu'il y a un zigzag, b est setté plusieurs fois, dont la dernière valeur est le dernier zigzag, d'ou un remplissage trop important...

                            int i, j; // en C, on déclare les variables au début...
                            int a, b;
                            
                            for(i=min; i<max;i++)
                            {
                                a = -1;
                                b = -1;
                            
                                for (j=0; j<480; j++)
                                {
                                    if (t[i][j] && a == -1)
                                    {
                                        a = j; 
                                    }
                                    else if (t[i][j]&& b == -1)
                                    {
                                        b=j;
                                    }
                            
                                    if (a<b)
                                    {
                                        position.x=i; 
                                        for (position.y=a; position.y<b; position.y++)
                                        {
                                            t[i][position.y]=1;
                                            SDL_FillRect(rectangle, NULL, SDL_MapRGB(ecran->format, 255, 255, 255)); // Remplissage de la surface avec du blanc
                                            SDL_BlitSurface(rectangle, NULL, ecran, &position);
                                            SDL_Flip(ecran);
                                        }
                                        a = -1;
                                        b = -1;
                                    }
                                }
                            }
                            
                            • Partager sur Facebook
                            • Partager sur Twitter
                              8 août 2010 à 0:40:10

                              Citation : AstroB

                              Ah oui, j'ai pas les yeux en face des trous!
                              Je pense voir ou est le problème. En fait, quand tu fais "if (t[i][j]&&verif) b=j; " dans ta boucle et qu'il y a un zigzag, b est setté plusieurs fois, dont la dernière valeur est le dernier zigzag, d'ou un remplissage trop important...

                              int i, j; // en C, on déclare les variables au début...
                              int a, b;
                              
                              for(i=min; i<max;i++)
                              {
                                  a = -1;
                                  b = -1;
                              
                                  for (j=0; j<480; j++)
                                  {
                                      if (t[i][j] && a == -1)
                                      {
                                          a = j; 
                                      }
                                      else if (t[i][j]&& b == -1)
                                      {
                                          b=j;
                                      }
                              
                                      if (a<b)
                                      {
                                          position.x=i; 
                                          for (position.y=a; position.y<b; position.y++)
                                          {
                                              t[i][position.y]=1;
                                              SDL_FillRect(rectangle, NULL, SDL_MapRGB(ecran->format, 255, 255, 255)); // Remplissage de la surface avec du blanc
                                              SDL_BlitSurface(rectangle, NULL, ecran, &position);
                                              SDL_Flip(ecran);
                                          }
                                          a = -1;
                                          b = -1;
                                      }
                                  }
                              }
                              


                              j ai bien aimé ton idée, AstroB ,mais , l execution est parfois tres mal alors que la modification que tu as fait parait logique , voila son execution :
                              Image utilisateur
                              Image utilisateur

                              Image utilisateur
                              Image utilisateur
                              Image utilisateur
                              Image utilisateur
                              tu m as posé la question sur le tableau t[][] ,pour moi c est une matrice booleenne de taille 640*480 contenant
                              des 0 a l'etat initial .
                              en dessinant avec la souris un contour quelquonque;
                              le programme va recuperer les coordonné de tout les pixels formant le contour par marker des 1 dans le tableau t [][].
                              en remplacant juste cet algorithme par un algorithme recursive basé sur l idée de remplissage par diffusion on obtient un resultat qui parait parfait :
                              Image utilisateur

                              Image utilisateur

                              le probleme que si la taille de la surface a colorer depasse une certaine valeur , il se plante , et j ai pas trouvé de raison logique pour expliquer .
                              si mon algorithme permet de colorer les petites surfaces , pourquoi pas pour les grandes surfaces ?????????? :colere2:














                              • Partager sur Facebook
                              • Partager sur Twitter
                                8 août 2010 à 0:50:58

                                tu fais exploser la pile...

                                flood fill
                                edit :je précise en 2010, je ne vois même pas comment tu t'y prend pour faire exploser la pile en faisant un flood fill récusrif...
                                • Partager sur Facebook
                                • Partager sur Twitter
                                Zeste de Savoir, le site qui en a dans le citron !
                                  8 août 2010 à 1:54:44

                                  Citation : GurneyH




                                  je précise en 2010, je ne vois même pas comment tu t'y prend pour faire exploser la pile en faisant un flood fill récusrif...


                                  Je precise en 2010 , je ne vois meme pas comment cette pile explose avant moins de 60000 appelle a une fonction contenant une seule instruction !! o_O ????
                                  • Partager sur Facebook
                                  • Partager sur Twitter
                                    8 août 2010 à 1:56:02

                                    tu as des appels inutiles! ;)
                                    • Partager sur Facebook
                                    • Partager sur Twitter
                                    Zeste de Savoir, le site qui en a dans le citron !
                                      8 août 2010 à 2:01:40

                                      Citation : GurneyH

                                      tu as des appels inutiles! ;)


                                      non aucun appel n'est inutile , voila la condition sur l appel
                                      if( y <250&& x<250&& x >=0&& y>=0&&!t[x][y])
                                      

                                      @GurneyH :p
                                      • Partager sur Facebook
                                      • Partager sur Twitter
                                        8 août 2010 à 2:03:36

                                        donc tu ne fais aucun appel sur des pixels déjà coloriés? o_O

                                        edit: bon bah, alors pas d'autres solutions que passer par une pile et faire sauter la récusrion...

                                        Etonné tout de même...
                                        • Partager sur Facebook
                                        • Partager sur Twitter
                                        Zeste de Savoir, le site qui en a dans le citron !
                                          8 août 2010 à 2:13:22

                                          Citation : GurneyH

                                          donc tu ne fais aucun appel sur des pixels déjà coloriés? o_O


                                          non car lorsque une pixel est colorié , je met t[x][y] a 1.


                                          Citation : GurneyH


                                          Etonné tout de même...


                                          moi aussi !

                                          Citation : GurneyH


                                          bon bah, alors pas d'autres solutions que passer par une pile et faire sauter la récusrion...


                                          merci je vais voir si ceci va marcher :)

                                          • Partager sur Facebook
                                          • Partager sur Twitter
                                            8 août 2010 à 2:20:04

                                            Citation : XX3


                                            non car lorsque une pixel est colorié , je met t[x][y] a 1.


                                            malgré tout tu utilises un tableau en trop!

                                            les données de ton images suffisent à savoir si un pixel est coloré ou pas(je pense).
                                            • Partager sur Facebook
                                            • Partager sur Twitter
                                            Zeste de Savoir, le site qui en a dans le citron !
                                              8 août 2010 à 2:33:31

                                              je peux pas tester sur les couleurs des pixel car
                                              l utilisateurs va dessiner sur des ecran dont le font est une image reelle et en plus choisi par lui ,ceci est d'une part
                                              d autre part j ai besoin de ce tableau pour le reste de traittement :-°
                                              • Partager sur Facebook
                                              • Partager sur Twitter
                                                8 août 2010 à 2:40:24

                                                ok!

                                                N'empêche c'est bien, avec tes bêtises tu m'as donné envie de refaire un flood fill! :p

                                                J'ai déjà fait(il y a longtemps), mais les résolutions n'étaient pas les même...
                                                Par contre la récursion c'était pas possible.

                                                Bon courage, et désolé pour les fausses pistes.

                                                Le lien que je t'ai filé est une bonne piste, par contre.
                                                ;)
                                                • Partager sur Facebook
                                                • Partager sur Twitter
                                                Zeste de Savoir, le site qui en a dans le citron !
                                                  8 août 2010 à 10:38:03

                                                  Je vois que ça parle d'explosion de pile.

                                                  Le nombre d'appel limite n'est pas énorme, et ne dépend pas que du nombre d'appels mais également des variables locales.

                                                  En effet, si tu considères une fonction récursive qui embarque par exemple un int tab[5000], tu fais sauter ta pile en très peu d'appels.
                                                  Sinon, oui, pour le floodfill, il est conseillé de casser la récursion par l'utilisation d'une structure de pile et un while
                                                  • Partager sur Facebook
                                                  • Partager sur Twitter

                                                  Recueil de code C et C++  http://fvirtman.free.fr/recueil/index.html

                                                    8 août 2010 à 10:51:24

                                                    Je m'étais bien avancé effectivement en récursif, on fait vite sauter la pile sur un flood fill.

                                                    Je l'ai recodé en faisant un parcours en profondeur dans les 4 directions.
                                                    #include <sdl/sdl.h>
                                                    #include <assert.h>
                                                    
                                                    typedef struct
                                                    {
                                                        int x, y;
                                                    } Pos;
                                                    
                                                    typedef struct node
                                                    {
                                                        Pos p;
                                                        struct node *p_nxt;
                                                    } Node;
                                                    
                                                    Uint32 getpixel( SDL_Surface *surface, int x, int y )
                                                    {
                                                        int bpp = surface->format->BytesPerPixel;
                                                        /* Here p is the address to the pixel we want to retrieve */
                                                        Uint8 *p = ( Uint8 * )surface->pixels + y * surface->pitch + x * bpp;
                                                    
                                                        switch ( bpp ) {
                                                            case 1:
                                                                return *p;
                                                    
                                                            case 2:
                                                                return *( Uint16 * )p;
                                                    
                                                            case 3:
                                                                if ( SDL_BYTEORDER == SDL_BIG_ENDIAN )
                                                                    return p[0] << 16 | p[1] << 8 | p[2];
                                                                else
                                                                    return p[0] | p[1] << 8 | p[2] << 16;
                                                    
                                                            case 4:
                                                                return *( Uint32 * )p;
                                                    
                                                            default:
                                                                return 0;
                                                        }
                                                    }
                                                    
                                                    void putpixel( SDL_Surface *surface, int x, int y, Uint32 pixel )
                                                    {
                                                        int bpp = surface->format->BytesPerPixel;
                                                        /* Here p is the address to the pixel we want to set */
                                                        Uint8 *p = ( Uint8 * )surface->pixels + y * surface->pitch + x * bpp;
                                                    
                                                        switch ( bpp ) {
                                                            case 1:
                                                                *p = pixel;
                                                                break;
                                                    
                                                            case 2:
                                                                *( Uint16 * )p = pixel;
                                                                break;
                                                    
                                                            case 3:
                                                                if ( SDL_BYTEORDER == SDL_BIG_ENDIAN ) {
                                                                    p[0] = ( pixel >> 16 ) & 0xff;
                                                                    p[1] = ( pixel >> 8 ) & 0xff;
                                                                    p[2] = pixel & 0xff;
                                                                }
                                                                else {
                                                                    p[0] = pixel & 0xff;
                                                                    p[1] = ( pixel >> 8 ) & 0xff;
                                                                    p[2] = ( pixel >> 16 ) & 0xff;
                                                                }
                                                                break;
                                                    
                                                            case 4:
                                                                *( Uint32 * )p = pixel;
                                                                break;
                                                    
                                                            default:
                                                                break;           /* shouldn't happen, but avoids warnings */
                                                        }
                                                    }
                                                    
                                                    void push( Node **this, Pos p )
                                                    {
                                                        Node *p_new = malloc( sizeof * p_new );
                                                        if( p_new == NULL )
                                                        {
                                                            fprintf( stderr, "Not enough memory." );
                                                            exit( EXIT_FAILURE );
                                                        }
                                                        p_new->p = p;
                                                        p_new->p_nxt = *this;
                                                        *this = p_new;
                                                    }
                                                    
                                                    
                                                    Pos pop( Node **this )
                                                    {
                                                        Pos p = { -1, -1};
                                                        if( *this != NULL )
                                                        {
                                                            Node *p_tmp = ( *this )->p_nxt;
                                                            p = ( *this )->p;
                                                            free( *this ), *this = NULL;
                                                            *this = p_tmp;
                                                        }
                                                        return p;
                                                    }
                                                    
                                                    
                                                    #define N_DIR   4
                                                    static void fill( SDL_Surface *s, Sint16 x, Sint16 y, Uint32 dstclr )
                                                    {
                                                        static Pos dir[N_DIR] = {{ -1, 0}, {0, 1}, {1, 0}, {0, -1}};
                                                        Uint32 srcclr = getpixel( s, x, y );
                                                        Node *stack = NULL;
                                                        Pos p;
                                                        p.x = x;
                                                        p.y = y;
                                                    
                                                        push( &stack, p );
                                                        while( stack != NULL )
                                                        {
                                                            int i;
                                                            p = pop( &stack );
                                                            putpixel( s, p.x, p.y, dstclr );
                                                    
                                                            for( i = 0; i < N_DIR; i++ )
                                                            {
                                                                Pos nxtp;
                                                                nxtp.x = p.x + dir[i].x;
                                                                nxtp.y = p.y + dir[i].y;
                                                                if( nxtp.x >= 0 && nxtp.x < s->w
                                                                        && nxtp.y > 0 && nxtp.y < s->h
                                                                        && getpixel( s, nxtp.x, nxtp.y ) == srcclr )
                                                                    push( &stack, nxtp );
                                                            }
                                                        }
                                                    
                                                    }
                                                    
                                                    
                                                    int main ( int argc, char *argv[] )
                                                    {
                                                        SDL_Surface *screen;
                                                        SDL_Surface *gfx;
                                                        SDL_Rect rect;
                                                    
                                                        if ( SDL_Init( SDL_INIT_VIDEO ) < 0 )
                                                        {
                                                            printf( "Unable to init SDL: %s\n", SDL_GetError() );
                                                            return EXIT_FAILURE;
                                                        }
                                                    
                                                        screen = SDL_SetVideoMode( 640, 480, 16,
                                                                                   SDL_SWSURFACE );
                                                        if ( !screen )
                                                        {
                                                            printf( "Unable to set video mode: %s\n", SDL_GetError() );
                                                            return EXIT_FAILURE;
                                                        }
                                                    
                                                        gfx = SDL_LoadBMP( "test.bmp" );
                                                        assert( gfx != NULL );
                                                        rect.x = screen->w / 2 - gfx->w / 2;
                                                        rect.y = screen->h / 2 - gfx->h / 2;
                                                    
                                                        SDL_BlitSurface( gfx, NULL, screen, NULL );
                                                        SDL_Flip( screen );
                                                    
                                                        fill( screen, screen->w / 2, screen->h / 2,
                                                              SDL_MapRGB( screen->format, 0, 255, 0 ) );
                                                    
                                                        SDL_Flip( screen );
                                                    
                                                        while( !SDL_QuitRequested() )
                                                            ;
                                                    
                                                        SDL_Quit();
                                                    
                                                    
                                                        return 0;
                                                    }
                                                    


                                                    et un petit test
                                                    Image utilisateurImage utilisateur

                                                    edit: correction d'une bourde sur les limites de l'écran.
                                                    edit2: comme je ne pars que dans 4 directions, ça ne fonctionne pas pour colorier une bordure fine.
                                                    • Partager sur Facebook
                                                    • Partager sur Twitter
                                                    Zeste de Savoir, le site qui en a dans le citron !
                                                      8 août 2010 à 11:01:49

                                                      Un très bon code GurneyH, je pense qu'il marche dans tous les cas, et bien sur sans aucun risque de stack overflow :)
                                                      • Partager sur Facebook
                                                      • Partager sur Twitter

                                                      Recueil de code C et C++  http://fvirtman.free.fr/recueil/index.html

                                                        8 août 2010 à 11:07:02

                                                        Merci pour ce code sa va me permettre d'apprendre encore plus sans faire de recherche :p(surtout pour mon Lecteur MP3 et j'en profite justement car j'ai besoin d'aide ici)

                                                        PS : SDL_BYTEORDER == SDL_BIG_ENDIAN ??? on peut m'expliquer s'il vous plait
                                                        • Partager sur Facebook
                                                        • Partager sur Twitter
                                                          8 août 2010 à 11:08:57

                                                          Si tu es débutant, prend les fonctions GetPixel et SetPixel comme magiques :)
                                                          Sinon, si tu es curieux, regarde du coté de l'endianness
                                                          • Partager sur Facebook
                                                          • Partager sur Twitter

                                                          Recueil de code C et C++  http://fvirtman.free.fr/recueil/index.html

                                                          Colorer l'interieur d'un contour en SDL

                                                          × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                                                          × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                                                          • Editeur
                                                          • Markdown