7
votes

Besoin d'aide pour mettre en œuvre un détecteur de bord spécial

Je suis en train de mettre en œuvre une approche d'un document de recherche. Une partie de l'approche appelle à un détecteur de bord majeur, que les auteurs décrivent comme suit:

  1. Obtenez une image CC (effectivement Downsample par 8 pour la largeur et la hauteur) li>
  2. Calculez le dégradé SOBEL de l'image DC LI>
  3. Seuil Sobel Image gradient (utilisant T = 120) LI>
  4. Opérations morphologiques pour nettoyer l'image de bord strong> li> ol>

    Notez que cette non forte> de la détection de bord de canny - ils ne se préoccupent pas avec des choses comme une suppression non maximale, etc. Je pouvais bien sûr faire cela avec une détection de bords de canneuse, mais Je veux mettre en œuvre des choses exactement comme ils sont exprimés dans le papier. P>

    Cette dernière étape est celle que je suis un peu coincé. P>

    Voici exactement ce que les auteurs disent IT: P>

    Après avoir obtenu le binaire carte de bord du processus de détection des bords, un morphologique binaire L'opération est utilisée pour éliminer les pixels de bord isolé, qui pourrait causer de fausses alarmes pendant la détection de bord p> blockQuote>

    Voici comment les choses sont censées ressembler à la fin de tout cela (les blocs de bord ont été remplis en noir): p>

     text alt p>

    Voici ce que j'ai si je saute la dernière étape: p>

     text alt p>

    Il semble être sur la bonne voie. Donc, voici ce qui se passe si je fais une érosion pour l'étape 4: p>

    texte alt p >

    J'ai essayé des combinaisons d'érosion et de dilatation pour obtenir le même résultat que possible, mais ne soyez nulle part près. Quelqu'un peut-il suggérer une combinaison d'opérateurs morphologiques qui me donnera le résultat souhaité? P>

    Voici la sortie de binarisation, au cas où n'importe qui veut jouer avec elle: p>

     texte alt p>

    et si vous êtes vraiment désolé, voici le code source (C ++): P >

    #include <cv.h>
    #include <highgui.h>
    #include <stdlib.h>
    #include <assert.h>
    
    using cv::Mat;
    using cv::Size;
    
    #include <stdio.h>
    
    #define DCTSIZE 8
    #define EDGE_PX 255
    
    /*
     * Display a matrix as an image on the screen.
     */
    void
    show_mat(char *heading, Mat const &m)
    {
        Mat clone = m.clone();
    
        Mat scaled(clone.size(), CV_8UC1);
        convertScaleAbs(clone, scaled);
    
        IplImage ipl = scaled;
    
        cvNamedWindow(heading, CV_WINDOW_AUTOSIZE); 
        cvShowImage(heading, &ipl);
        cvWaitKey(0);
    }
    
    /*
     * Get the DC components of the specified matrix as an image.
     */
    Mat
    get_dc(Mat const &m)
    {
        Size s = m.size();
        assert(s.width  % DCTSIZE == 0);
        assert(s.height % DCTSIZE == 0);
    
        Size dc_size = Size(s.height/DCTSIZE, s.width/DCTSIZE);
    
        Mat dc(dc_size, CV_32FC1);
        cv::resize(m, dc, dc_size, 0, 0, cv::INTER_AREA);
    
        return dc;
    }
    
    /*
     * Detect the edges:
     *
     * Sobel operator
     * Thresholding
     * Morphological operations
     */
    Mat
    detect_edges(Mat const &src, int T)
    {
        Mat sobelx    = Mat(src.size(), CV_32FC1);
        Mat sobely    = Mat(src.size(), CV_32FC1);
        Mat sobel_sum = Mat(src.size(), CV_32FC1);
    
        cv::Sobel(src, sobelx, CV_32F, 1, 0, 3, 0.5);
        cv::Sobel(src, sobely, CV_32F, 0, 1, 3, 0.5);
    
        cv::add(cv::abs(sobelx), cv::abs(sobely), sobel_sum);
    
        Mat binarized = src.clone();
        cv::threshold(sobel_sum, binarized, T, EDGE_PX, cv::THRESH_BINARY);
    
        cv::imwrite("binarized.png", binarized);
    
        //
        // TODO: this is the part I'm having problems with.
        //
    
    #if 0
        //
        // Try a 3x3 cross structuring element.
        //
        Mat elt(3,3, CV_8UC1);
        elt.at<uchar>(0, 1) = 0;
        elt.at<uchar>(1, 0) = 0;
        elt.at<uchar>(1, 1) = 0;
        elt.at<uchar>(1, 2) = 0;
        elt.at<uchar>(2, 1) = 0;
    #endif
    
        Mat dilated = binarized.clone();
        //cv::dilate(binarized, dilated, Mat());
    
        cv::imwrite("dilated.png", dilated);
    
        Mat eroded = dilated.clone();
        cv::erode(dilated, eroded, Mat());
    
        cv::imwrite("eroded.png", eroded);
    
        return eroded;
    }
    
    /*
     * Black out the blocks in the image that contain DC edges.
     */
    void
    censure_edge_blocks(Mat &orig, Mat const &edges)
    {
        Size s = edges.size();
        for (int i = 0; i < s.height; ++i)
        for (int j = 0; j < s.width;  ++j)
        {
            if (edges.at<float>(i, j) != EDGE_PX)
                continue;
    
            int row = i*DCTSIZE;
            int col = j*DCTSIZE;
    
            for (int m = 0; m < DCTSIZE; ++m)
            for (int n = 0; n < DCTSIZE; ++n)
                orig.at<uchar>(row + m, col + n) = 0;
        }
    }
    
    /*
     * Load the image and return the first channel.
     */
    Mat
    load_grayscale(char *filename)
    {
        Mat orig = cv::imread(filename);
        std::vector<Mat> channels(orig.channels());
        cv::split(orig, channels);
        Mat grey = channels[0];
        return grey;
    }
    
    int
    main(int argc, char **argv)
    {
        assert(argc == 3);
    
        int bin_thres = atoi(argv[2]);
    
        Mat orig = load_grayscale(argv[1]);
        //show_mat("orig", orig);
    
        Mat dc = get_dc(orig);
        cv::imwrite("dc.png", dc);
    
        Mat dc_edges = detect_edges(dc, bin_thres);
    
        cv::imwrite("dc_edges.png", dc_edges);
    
        censure_edge_blocks(orig, dc_edges);
        show_mat("censured", orig);
        cv::imwrite("censured.png", orig);
    
        return 0;
    }
    


0 commentaires

4 Réponses :


2
votes

Je ne peux imaginer aucune combinaison d'opérations morphologiques qui produiraient les mêmes bords que ceux détectés par le résultat soi-disant correct, étant donné votre résultat partiel comme entrée.

Je note que l'image sous-jacente est différente; Cela contribue probablement à la raison pour laquelle vos résultats sont si différents. L'image Lena va bien pour indiquer le type de résultat mais pas pour les comparaisons. Avez-vous exactement la même image que les auteurs originaux?


7 commentaires

Vous avez raison de noter que l'image sous-jacente est différente. Dans le cas des auteurs, ils ont compressé JPEG à environ 0,3 ppp. Cependant, je ne pense pas que cela ferait une différence pour la détection des bords, car cela est fait en utilisant l'image CC, pas l'image d'origine. La compression Afaik JPEG ne modifie pas les coefficients CC - il s'agit principalement de marteaux les composants de fréquence supérieure pendant la quantification.


Premièrement, je ne crois pas que votre fonction get_dc () donne les mêmes données que les auteurs d'origine utilisent dans leur algorithme. IIRC Le composant DC peut être quantifié dans JPEG, juste à une précision plus élevée que les autres composants. Deuxièmement, c'est l'image Lena; Il est bien connu que cette image a été copiée et modifiée tant de fois qu'il est largement recommandé de ne pas l'utiliser pour les comparaisons: même si votre méthode Get_DC est la même, l'image source est probablement différente.


Ouais, je sais que ce n'est pas facile de faire confiance à Lena Images car il y en a beaucoup d'entre eux. Malheureusement, les auteurs du papier ne fournissent aucun autre exemple ni de sortie intermédiaire. Merci d'avoir essayé d'aider.


Pouvez-vous donner une référence pour le papier? Je pense que si vous avez l'image de test réelle à la comparaison, vous ne pouvez pas être sûr que votre mise en œuvre est fausse.


"Mesure aveugle de la DCT-domaines efficace et réduction des artefacts de blocage" de Liu et de Bovik. Malheureusement, c'est derrière un wambad.


Avez-vous essayé de contacter les auteurs? Vous pouvez être surpris de savoir à quel point les chercheurs disposent de répondre aux demandes de détails sur un message poli. IMHO Toute chercheur raisonnable devrait pouvoir fournir un lien pour tester les données de comparaison à tout le moins. Vous pourriez même être capable de saisir leur propre mise en œuvre. P.s. La prochaine fois, veuillez donner une année et un journal pour une référence: bien que les papiers puissent être derrière des wagons de paie, un autre article par les mêmes auteurs décrivant la version précédente / suivante de l'algorithme est disponible gratuitement.


J'ai abandonné et je suis juste utilisé Canny au lieu de Sobel - il donne des résultats similaires, mais est plus lent (ce qui est correct pour le code de la recherche). Si je vraiment besoin de cela pour travailler la façon dont ils ont décrit, je pourrais les déposer une ligne, mais pour l'instant, c'est assez bon. Merci pour votre contribution.



1
votes

Quels sont les auteurs décrits pourraient être mis en œuvre avec une analyse des composants connectés, en utilisant la connectivité de 8Way. Je n'appellerais pas ce morphologique cependant.

Je pense que vous manquez quelque chose d'autre: leur image n'a pas d'arêtes plus épaisses qu'un pixel. Le tien a. Le paragraphe que vous avez cité seulement des discussions sur l'élimination des pixels isolés. Il doit donc y avoir une étape que vous avez manquée ou mise en œuvre différemment.

bonne chance!


1 commentaires

Cela peut être fait de différentes manières (algorithme de suppression ou de habilité non maximale, par exemple). Comme vous le soulignez, ce n'est pas vraiment une méthode morphologique. J'ai mis en œuvre des choses à la lettre jusqu'à présent, alors je commence à soupçonner qu'il manque quelque chose de l'approche du journal.



0
votes

Je pense que ce dont vous avez besoin est une sorte d'érode ou d'ouverture qui est, dans un sens, à 4 voies et pas à 8 voies. Le noyau morphologique par défaut pour OpenCV est un rectangle 3x3 ( iplconvkernel avec forme = cv_shape_rect ). C'est assez dur sur les bords minces.

Vous voudrez peut-être essayer d'éroder avec un iplconvkernel 3x3 avec forme = cv_shape_cross . Si vous avez besoin d'un filtre encore plus fin, vous pouvez essayer d'essayer d'éroder avec 4 différents cv_shape_rect des noyaux de taille 1x2, 2x1 avec l'ancre dans (0,1) et (1,0) pour chacun. < / p>


0 commentaires

0
votes

Tout d'abord, votre image d'entrée a une résolution beaucoup plus élevée que l'image d'entrée de test, qui peut expliquer le fait que les autres bords sont détectés - les modifications sont plus lisses.

second de tous, puisque les bords sont seuils à 0, essayez de dilatation sur des quartiers plus petits (par exemple comparer chaque pixels avec 4 voisins originaux (de manière non sérieuse)) pour se débarrasser des bords isolés.


0 commentaires