Calcul automatique des seuils bas et élevés pour l'opération Cany à opencv

dans openCV, les seuils bas et haut pour l'opérateur rusé sont obligatoires:

cvCanny(input,output,thresh1,thresh2)

dans Matlab, il y a une option pour les calculer automatiquement:

edge(input,'canny')

j'ai regardé dans le code de Matlab pour edge, et ce n'est vraiment pas simple pour les calculer automatiquement.

Êtes-vous au courant d'une quelconque mise en œuvre de l'opérateur canny avec le calcul automatique du seuil pour opencv?

merci

29
demandé sur hoffer 2010-11-27 18:05:38

7 réponses

je suis tombé sur cette réponse alors que je cherchais un moyen de calculer automatiquement les valeurs seuils de Canny.

espérons que cela aidera quiconque vient à la recherche d'une bonne méthode pour déterminer les valeurs de seuil automatiques pour L'algorithme de Canny...


si votre image est constituée d'un premier plan et d'un arrière-plan distincts, alors le bord de l'objet premier plan peut être utilisé extrait comme suit:

  1. calculer le seuil D'Otsu en utilisant:

    double otsu_thresh_val = cv::threshold(
        orig_img, _img, 0, 255, CV_THRESH_BINARY | CV_THRESH_OTSU
    );
    

    nous n'avons pas besoin de _img. Nous ne sommes intéressés que par les otsu_thresh_val mais malheureusement, il n'y a actuellement aucune méthode dans OpenCV qui vous permet de calculer seulement la valeur de seuil.

  2. utilisez la valeur de seuil de L'Otsu comme seuil supérieur et la moitié du même que le seuil inférieur pour L'algorithme de Canny.

    double high_thresh_val  = otsu_thresh_val,
           lower_thresh_val = otsu_thresh_val * 0.5;
    cv::Canny( orig_img, cannyOP, lower_thresh_val, high_thresh_val );
    

vous trouverez de plus amples informations à ce sujet dans cet article: L'étude sur Application de la Méthode d'Otsu dans les Futés de l'Opérateur. Une explication de la mise en œuvre D'Otsu peut être trouvée ici.

42
répondu VP. 2017-03-21 02:48:34

vous pouvez utiliser la valeur moyenne de l'image à l'échelle de gris de votre entrée et définir des seuils inférieurs et supérieurs en utilisant l'écart-type. Vous pouvez avoir des explications plus détaillées et le code opencv ici: http://www.kerrywong.com/2009/05/07/canny-edge-detection-auto-thresholding/

16
répondu Luca Del Tongo 2011-01-11 01:35:54

aussi, il y a du code disponible pour le faire automatiquement, en le mettant dans la construction OpenCV. Je l'ai trouvé sur la liste de diffusion OpenCV-users, donc aucune garantie. :)

Discussion: http://opencv-users.1802565.n2.nabble.com/Automatic-thresholding-in-cvCanny-td5871024.html GitHub (code):https://gist.github.com/756833

7
répondu Dan 2011-12-13 13:24:23

j'ai regardé le code source de Matlab Canny edge detection et j'ai réussi à l'écrire en Java avec OpenCV 3.

private static Mat getpartialedge(Mat image){
    double nonEdgeRate = 0.6;
    double thresholdRate = 0.6;
    double w = image.cols();
    double h = image.rows();
    int bins = 256;
    Mat sobel = new Mat();
    Mat sobelx = new Mat();
    Mat sobely = new Mat();
    Mat sobelxabs = new Mat();
    Mat sobelyabs = new Mat(); 
    Size gsz = new Size(5, 5);
    if(false) {
        Imgproc.Canny(image, sobel, 41, 71);
    }else {

        //Imgproc.GaussianBlur(graycopy,graycopy, gsz, 2);
        //Imgproc.dilate(image, image, kernel8);
        Imgproc.GaussianBlur(image, image, gsz, 2);


        int apertureSize = 3;
        Imgproc.Sobel(image, sobelx, CvType.CV_16S, 1, 0, apertureSize, 1, 0);
        Core.convertScaleAbs(sobelx, sobelxabs);
        Imgproc.Sobel(image, sobely, CvType.CV_16S, 0, 1, apertureSize, 1, 0);
        Core.convertScaleAbs(sobely, sobelyabs);
        Core.addWeighted(sobelxabs, 1, sobelyabs, 1, 0, sobel);
        sobel.convertTo(sobel, CvType.CV_8U);


        Mat equalized = new Mat();
        Imgproc.equalizeHist(sobel, equalized);
        Imgcodecs.imwrite(filePath + "aftersobel(eq).png", equalized);
        Imgcodecs.imwrite(filePath + "aftersobel.png", sobel);


        Mat hist = new Mat();
        List<Mat> matList = new ArrayList<Mat>();
        matList.add(sobel);
        Imgproc.calcHist(matList, new MatOfInt(0), new Mat(), hist, new MatOfInt(bins), new MatOfFloat(0f, 256f));
        float accu = 0;
        float t = (float) (nonEdgeRate * w * h);
        float bon = 0;
        float[] accutemp = new float[bins];
        for (int i = 0; i < bins; i++) {
            float tf[] = new float[1];
            hist.get(i, 0, tf);
            accu = accu + tf[0];
            accutemp[i] = accu;
            if (accu > t) {
                bon = (float) i;
                break;
            }
        }
        Imgproc.threshold(sobel, sobel, bon, 255, Imgproc.THRESH_BINARY);
        double ut = bon;
        double lt = thresholdRate * bon;


        Imgproc.Canny(image, sobel, lt, ut);
        //Imgproc.dilate(sobel, sobel, kernel2);
    }
    return sobel;
}

Le filepath est l'endroit pour tenir les images de sortie. Et l'image d'entrée devrait être une image à échelle de gris avec le type de données U8. Le principe de base est d'exclure le pixel non-edge(60%) comme pixel non-edge par la luminosité. Un histogramme est utilisé pour trier la luminosité et le seuil supérieur sera défini de sorte qu'il y ait 60% de pixels en dessous. Inférieur le seuil est fixé en multipliant le seuil supérieur par le seuil(0,6).

notez que le double nonedgerate = 0.6 et le double thresholdRate = 0.6 est accordé par moi-même dans mon cas d'utilisation spécifique. TH les valeurs originales sont de 0.7 et 0.4 séparément dans matlab.

3
répondu fangzhan shi 2017-03-26 14:10:35

consultez ce lien: http://www.pyimagesearch.com/2015/04/06/zero-parameter-automatic-canny-edge-detection-with-python-and-opencv/

ils implémentent une solution similaire en utilisant statistiques de base pour déterminer le seuil bas et haut pour la détection de bord Canny.

def auto_canny(image, sigma=0.33):
     # compute the median of the single channel pixel intensities
     v = np.median(image)

    # apply automatic Canny edge detection using the computed median
    lower = int(max(0, (1.0 - sigma) * v))
    upper = int(min(255, (1.0 + sigma) * v))
    edged = cv2.Canny(image, lower, upper)

    # return the edged image
    return edged
2
répondu Ryan Marten 2017-07-19 16:34:52

j'ai une autre approche pour le même problème. Cette solution implique également la sélection de seuils optimaux pour la détection des arêtes.

  • calculez d'Abord le médiane de l'échelle de gris de l'image.
  • choisir deux valeurs (seuils inférieur et supérieur) en fonction de la médiane valeur de l'image à l'échelle grise.

le pseudo-code suivant vous montre comment il est fait:

v = np.median(gray_img)
sigma = 0.33

#---- apply optimal Canny edge detection using the computed median----
lower_thresh = int(max(0, (1.0 - sigma) * v))
upper_thresh = int(min(255, (1.0 + sigma) * v))

fixez ces seuils comme paramètres dans le bord canny fonction de détection.

Figure: si vous observez une courbe gaussienne dans les statistiques, les valeurs entre 0.33 des deux côtés de la courbe sont considérées dans la distribution. Toute valeur en dehors de ces points est supposée être aberrante. Puisque les images sont considérées comme des données, ce concept est supposé ici.

1
répondu Jeru Luke 2017-02-20 12:00:41

comme Luca Del Tongo l'a suggéré, vous pouvez calculer les seuils à partir de l'image grise, par exemple en Java en utilisant OpenCV...

MatOfDouble mu = new MatOfDouble();
MatOfDouble stddev = new MatOfDouble();
Core.meanStdDev(greyMat, mu, stddev);
threshold1 = mu.get(0, 0)[0];
threshold2 = stddev.get(0, 0)[0];
Imgproc.Canny(greyMat, outputMat, threshold1, threshold2);
0
répondu Buddhisthead 2016-12-22 17:36:17