Notes de développement OpenCV (quarante et un): Le gros homme rouge vous prend 8 minutes pour en savoir plus sur la détection des bords de l'opérateur du filtre scharr (graphique + facile à comprendre + code source du programme)

Si le texte est l'article original, ne doit pas être reproduit sans autorisation
de l'adresse du blog de blogueurs d' origine: https://blog.csdn.net/qq21497936
blogueurs d' origine Navigation blog: https://blog.csdn.net/qq21497936/article/details / 102478062
L'adresse du blog de cet article: https://blog.csdn.net/qq21497936/article/details/105425374
Lecteurs, les connaissances sont infinies et la main-d'œuvre est pauvre, soit modifiez la demande, soit trouvez un professionnel, soit étudiez par vous-même

Annuaire

Préface

Démo

Filtre Scharr et détection des bords de l'opérateur Sobel

Présentation

Opérateur Sobel et filtre Scharr

Principe

Étape 1: dérivation dans les directions x et y

Étape 2: trouver le gradient approximatif

La fonction Scharr est la même que Sobel, avec des étapes supplémentaires

Étape 1: Créez d'abord deux caches cv :: Mat

Étape 2: Trouvez le gradient dans la direction X

Étape 3: Trouvez le gradient dans la direction Y

Étape 4: fusion des dégradés (approximatifs)

Prototype de la fonction Scharr

Fonction de conversion des couleurs

Code source de démonstration

Modèle d'ingénierie: numéro de version correspondant v1.36.0


Colonne de développement OpenCV (cliquez sur le portail)

 

    Notes de développement OpenCV (quarante et un): Le gros homme rouge vous prend 8 minutes pour en savoir plus sur la détection des bords de l'opérateur du filtre scharr (graphique + facile à comprendre + code source du programme)

 

Préface

      Le gros homme rouge vient aussi! ! !

      Ce chapitre explique le filtre scharrr et compare la détection des bords de l'opérateur sobel.

 

Démo

            Diagramme d'emplacement du résultat de l'image de démonstration:

 

Filtre Scharr et détection des bords de l'opérateur Sobel

Présentation

      Comprenez d'abord la détection des bords de l'opérateur Sobel. Le filtre Scharr est en fait une transplantation de l'opération de programmation réelle de Sobel, mais il n'augmente que les données de la matrice du noyau. Sa précision est supérieure à celle de la détection des bords de l'opérateur Sobel. Nous comparons ici l'opérateur Sobel. Détection des sous-bords et filtre Scharr pour la détection des bords.

      Pour plus de détails sur la détection des bords de l'opérateur Sobel, veuillez consulter "Notes de développement OpenCV (39): Red Fat Man vous prend en 8 minutes pour en savoir plus sur la détection des bords de l'opérateur Sobel (graphiques + facile à comprendre + code source du programme)"

Opérateur Sobel et filtre Scharr

Le calcul de Sobel produit un meilleur effet de détection et a un effet de suppression en douceur sur le bruit, mais les bords obtenus sont plus épais et de faux bords peuvent apparaître.

Lorsque l'image est plus compliquée, la cible et l'arrière-plan ne peuvent pas être simplement séparés par un seuil. Dans ce cas , la seule méthode de détection de bord ou d'une région de plus en plus recours méthode. Et la méthode de détection de pointe le plus couramment utilisé est le Sobel opérateur.

L'opérateur Sobel a les avantages d'une méthode simple, d'une vitesse de traitement rapide et de bords lisses et continus. L'inconvénient est que les bords sont plus épais.En raison du processus de binarisation, les bords obtenus ont une grande relation avec la sélection du seuil.

Lorsque vous appelez Sobel (), vous pouvez réellement définir la taille ks :: SCHARR pour y parvenir, ou vous pouvez utiliser le filtre Scharr seul, qui est plus précis que l'opérateur Sobel. Par conséquent, lorsque vous choisissez le filtre 3x3, le filtre Scharr est préféré. La vitesse est aussi rapide que Sobel ().

Principe

Étape 1: dérivation dans les directions x et y

Supposons que l'image d'entrée soit I.

Changement horizontal: convolution des noyaux I et de taille impaire, par exemple, lorsque la taille du noyau est de 3, le résultat du calcul de Gx est:

      Changement vertical: convolution I avec un noyau de taille impaire. Par exemple, lorsque la taille du noyau est de 3, le résultat du calcul de Gy est:

Étape 2: trouver le gradient approximatif

À chaque point de l'image, combinez Gx et Gy pour trouver le gradient approximatif:

De plus, vous pouvez également utiliser une annonce publique plus simple à la place:

La fonction Scharr est la même que Sobel, avec des étapes supplémentaires

Étape 1: Créez d'abord deux caches cv :: Mat

// 使用Scharr滤波器
// 步骤一:先分别创建2个矩阵,共4个
cv::Mat gradXMat, absGradXMat;
cv::Mat gradYMat, absGradYMat;
// copy
mat = windowMat(cv::Range(srcMat.rows * 2, srcMat.rows * 3),
                cv::Range(srcMat.cols * 0, srcMat.cols * 1));

Étape 2: Trouvez le gradient dans la direction X

// 步骤二:求X方向的梯度
//cv::Sobel(grayMat3Channels, gradXMat, CV_16S, 1, 0, 3, 1, 1);
cv::Scharr(grayMat3Channels, gradXMat, CV_16S, 1, 0, 1, 0,);
cv::convertScaleAbs(gradXMat, absGradXMat);

Étape 3: Trouvez le gradient dans la direction Y

// 步骤三:求Y方向的梯度
//cv::Sobel(grayMat3Channels, gradYMat, CV_16S, 0, 1, 3, 1, 1);
cv::Scharr(grayMat3Channels, gradXMat, CV_16S, 0, 1, 1, 0,);
cv::convertScaleAbs(gradYMat, absGradYMat);

Étape 4: fusion des dégradés (approximatifs)

// 步骤四:合并梯度(近似)
cv::addWeighted(absGradXMat, 0.5, absGradYMat, 0.5, 0, dstMat);

Prototype de la fonction Scharr

void Scharr( InputArray src,
           OutputArray dst,
           int ddepth,
           int dx,
           int dy, 
           double scale = 1,
           double delta = 0,
           int borderType = BORDER_DEFAULT );
  • Paramètre un: image de type InputArray, généralement cv :: Mat;
  • Paramètre 2: dst de type OutputArray, de la même taille que l'image d'entrée;
  • Trois paramètres: type int ddepth, la profondeur de l'image de sortie , 8-bit résultat image d'entrée d'origine est tronquée, il a la composition suivante:

  • Paramètre quatre: int type dx, ordre différentiel dans la direction x, 1 ou 0;
  • Paramètre cinq: type int dy, ordre différentiel dans la direction y, 1 ou 0;
  • Paramètre six: échelle de type double, facteur d'échelle facultatif pour la valeur dérivée du calcul de l'échelle; la valeur par défaut est 1, indiquant qu'aucune échelle n'est effectuée;
  • Paramètre 7: un detal et un delta de type double sont ajoutés au résultat avant de le stocker dans dst;
  • Paramètre huit: borderType de type int, n'a généralement pas besoin de faire attention;

Fonction de conversion des couleurs

void convertScaleAbs(InputArray src,
                   OutputArray dst,
                   double alpha = 1,
                   double beta = 0);
  • Paramètre un: image de type InputArray, généralement cv :: Mat;
  • Paramètre 2: dst de type OutputArray, image de sortie;
  • Troisième paramètre: appha de type double;
  • Paramètre 4: profondeur de type double;

(Supplément: en fait, cela est similaire au réglage du contraste et de la luminosité, mais ce n'est pas le cas, car lorsque le résultat du calcul est inférieur à 0, il ne sera pas traité, ce qui entraînera la valeur empruntée vers l'avant, mais devenue blanche

 

Code source de démonstration

void OpenCVManager::testScharr()
{
    QString fileName1 = "E:/qtProject/openCVDemo/openCVDemo/modules/openCVManager/images/11.jpg";
    cv::Mat srcMat = cv::imread(fileName1.toStdString());

    if(!srcMat.data)
    {
        qDebug() << __FILE__ << __LINE__
                 << "Failed to load image:" << fileName1;
        return;
    }

    int width = 300;
    int height = 200;
    cv::resize(srcMat, srcMat, cv::Size(width, height));

    cv::String windowName = _windowTitle.toStdString();
    cvui::init(windowName);


    cv::Mat dstMat;
    dstMat = cv::Mat::zeros(srcMat.size(), srcMat.type());
    cv::Mat windowMat = cv::Mat(cv::Size(dstMat.cols * 3, dstMat.rows * 4),
                                srcMat.type());
    int ksize = 1;   // 核心大小
    int sigmaX = 0;  // x方向的标准偏差
    int sigmaY = 0;  // y方向的标准偏差

    int ksize2 = 1;

    int sigmaS = 160;
    int sigmaR = 2;

    cvui::window(windowMat, dstMat.cols, 0, dstMat.cols, dstMat.rows, "settings");
    cv::Mat grayMat;
    cv::Mat grayMat3Channels;
    cv::Mat mat;
    cv::cvtColor(srcMat, grayMat, CV_BGR2GRAY);
    cv::cvtColor(grayMat, grayMat3Channels, CV_GRAY2BGR);
    while(true)
    {
        windowMat = cv::Scalar(0, 0, 0);
        // 原图先copy到左边
        cv::Mat leftMat = windowMat(cv::Range(0, srcMat.rows),
                                    cv::Range(0, srcMat.cols));
        cv::addWeighted(leftMat, 1.0f, srcMat, 1.0f, 0.0f, leftMat);
        // 中间为调整滤波参数的相关设置
        cvui::printf(windowMat, width * 2 + 75, 20, "ksize = size *  2 + 1");
        cvui::trackbar(windowMat, width * 2 + 75, 30, 165, &ksize, 0, 10);

        cvui::printf(windowMat, width * 2 + 75, 80, "sigmaX");
        cvui::trackbar(windowMat, width * 2 + 75, 90, 165, &sigmaX, 0, 100);

        cvui::printf(windowMat, width * 2 + 75, 140, "sigmaY");
        cvui::trackbar(windowMat, width * 2 + 75, 150, 165, &sigmaY, 0, 100);

        // 复制灰度图像
        {
            cv::Mat rightMat = windowMat(cv::Range(srcMat.rows * 1, srcMat.rows * 2),
                                         cv::Range(srcMat.cols * 1, srcMat.cols * 2));
            cv::addWeighted(rightMat, 0.0f, grayMat3Channels, 1.0f, 0.0f, rightMat);
        }

        {
            // 高斯滤波
            cv::Mat mat;
            cv::GaussianBlur(grayMat3Channels, mat, cv::Size(ksize * 2 + 1, ksize * 2 + 1), sigmaX / 10.f, sigmaY / 10.f);

            // 高斯滤波后进行边缘检测
            // 使用Sobel边缘检测
            // 步骤一:先分别创建2个矩阵,共4个
            cv::Mat gradXMat, absGradXMat;
            cv::Mat gradYMat, absGradYMat;
            // 步骤二:求X方向的梯度
            cv::Sobel(mat, gradXMat, CV_16S, 1, 0, ksize2 * 2 + 1, 1, 1);
            cv::convertScaleAbs(gradXMat, absGradXMat);
            // 步骤三:求Y方向的梯度
            cv::Sobel(mat, gradYMat, CV_16S, 0, 1, ksize2 * 2 + 1, 1, 1);
            cv::convertScaleAbs(gradYMat, absGradYMat);
            // 步骤四:合并梯度(近似)
            cv::addWeighted(absGradXMat, 0.5, absGradYMat, 0.5, 0, dstMat);
            cv::Mat rightMat2 = windowMat(cv::Range(srcMat.rows * 1, srcMat.rows * 2),
                                          cv::Range(srcMat.cols * 0, srcMat.cols * 1));
            cv::addWeighted(rightMat2, 0.0f, dstMat, 1.0f, 0.0f, rightMat2);

        }
        {
            // 使用Sobel边缘检测
            // 步骤一:先分别创建2个矩阵,共4个
            cv::Mat gradXMat, absGradXMat;
            cv::Mat gradYMat, absGradYMat;
            // 步骤二:求X方向的梯度
            cv::Sobel(grayMat3Channels, gradXMat, CV_16S, 1, 0, ksize2 * 2 + 1, 1, 1);
            cv::convertScaleAbs(gradXMat, absGradXMat);
            // 步骤三:求Y方向的梯度
            cv::Sobel(grayMat3Channels, gradYMat, CV_16S, 0, 1, ksize2 * 2 + 1, 1, 1);
            cv::convertScaleAbs(gradYMat, absGradYMat);
            // 步骤四:合并梯度(近似)
            cv::addWeighted(absGradXMat, 0.5, absGradYMat, 0.5, 0, dstMat);
            // copy
            mat = windowMat(cv::Range(srcMat.rows * 2, srcMat.rows * 3),
                            cv::Range(srcMat.cols * 0, srcMat.cols * 1));
            cv::addWeighted(mat, 0.0f, dstMat, 1.0f, 0.0f, mat);
        }
        cvui::printf(windowMat, 75 + width * 2, height * 2 + 20, "sigmaS");
        cvui::trackbar(windowMat, 75 + width * 2, height * 2 + 50, 165, &sigmaS, 101, 10000);
        cvui::printf(windowMat, 75 + width * 2, height * 2 + 90, "sigmaR");
        cvui::trackbar(windowMat, 75 + width * 2, height * 2 + 120, 165, &sigmaR, 1, 100);
        cvui::printf(windowMat,
                     srcMat.cols * 2 + 75,
                     srcMat.rows * 1 + 100, "ksize");
        cvui::trackbar(windowMat,
                       srcMat.cols * 2 + 75,
                       srcMat.rows * 1 + 130,
                       165,
                       &ksize2,
                       0,
                       3);
        {
            // 使用自适应流形应用高维滤波。
            cv::Mat tempMat;
            cv::Ptr<cv::ximgproc::AdaptiveManifoldFilter> pAdaptiveManifoldFilter
                    = cv::ximgproc::createAMFilter(sigmaS/100.0f, sigmaR/100.0f, true);
            pAdaptiveManifoldFilter->filter(grayMat, tempMat);
            cv::cvtColor(tempMat, tempMat, CV_GRAY2BGR);
            // 使用Sobel边缘检测
            // 步骤一:先分别创建2个矩阵,共4个
            cv::Mat gradXMat, absGradXMat;
            cv::Mat gradYMat, absGradYMat;
            // 步骤二:求X方向的梯度
            cv::Sobel(tempMat, gradXMat, CV_16S, 1, 0, ksize2 * 2 + 1, 1, 1);
            cv::convertScaleAbs(gradXMat, absGradXMat);
            // 步骤三:求Y方向的梯度
            cv::Sobel(tempMat, gradYMat, CV_16S, 0, 1, ksize2 * 2 + 1, 1, 1);
            cv::convertScaleAbs(gradYMat, absGradYMat);
            // 步骤四:合并梯度(近似)
            cv::addWeighted(absGradXMat, 0.5, absGradYMat, 0.5, 0, dstMat);
            // copy
            mat = windowMat(cv::Range(srcMat.rows * 3, srcMat.rows * 4),
                            cv::Range(srcMat.cols * 0, srcMat.cols * 1));
            cv::addWeighted(mat, 0.0f, dstMat, 1.0f, 0.0f, mat);
        }

        {
            // 高斯滤波
            cv::Mat mat;
            cv::GaussianBlur(grayMat3Channels, mat, cv::Size(ksize * 2 + 1, ksize * 2 + 1), sigmaX / 10.f, sigmaY / 10.f);

            // 高斯滤波后进行边缘检测
            // 使用Sobel边缘检测
            // 步骤一:先分别创建2个矩阵,共4个
            cv::Mat gradXMat, absGradXMat;
            cv::Mat gradYMat, absGradYMat;
            // 步骤二:求X方向的梯度
//            cv::Sobel(mat, gradXMat, CV_16S, 1, 0, ksize2 * 2 + 1, 1, 1);
            cv::Scharr(mat, gradXMat, CV_16S, 1, 0, 1, 1);
            cv::convertScaleAbs(gradXMat, absGradXMat);
            // 步骤三:求Y方向的梯度
//            cv::Sobel(mat, gradYMat, CV_16S, 0, 1, ksize2 * 2 + 1, 1, 1);
            cv::Scharr(mat, gradYMat, CV_16S, 1, 0, 1, 1);
            cv::convertScaleAbs(gradYMat, absGradYMat);
            // 步骤四:合并梯度(近似)
            cv::addWeighted(absGradXMat, 0.5, absGradYMat, 0.5, 0, dstMat);
            cv::Mat rightMat2 = windowMat(cv::Range(srcMat.rows * 1, srcMat.rows * 2),
                                          cv::Range(srcMat.cols * 1, srcMat.cols * 2));
            cv::addWeighted(rightMat2, 0.0f, dstMat, 1.0f, 0.0f, rightMat2);
        }

        {
            // 使用Sobel边缘检测
            // 步骤一:先分别创建2个矩阵,共4个
            cv::Mat gradXMat, absGradXMat;
            cv::Mat gradYMat, absGradYMat;
            // 步骤二:求X方向的梯度
//            cv::Sobel(grayMat3Channels, gradXMat, CV_16S, 1, 0, ksize2 * 2 + 1, 1, 1);
            cv::Scharr(grayMat3Channels, gradXMat, CV_16S, 1, 0, 1, 1);
            cv::convertScaleAbs(gradXMat, absGradXMat);
            // 步骤三:求Y方向的梯度
//            cv::Sobel(grayMat3Channels, gradYMat, CV_16S, 0, 1, ksize2 * 2 + 1, 1, 1);
            cv::Scharr(grayMat3Channels, gradYMat, CV_16S, 1, 0, 1, 1);
            cv::convertScaleAbs(gradYMat, absGradYMat);
            // 步骤四:合并梯度(近似)
            cv::addWeighted(absGradXMat, 0.5, absGradYMat, 0.5, 0, dstMat);
            // copy
            mat = windowMat(cv::Range(srcMat.rows * 2, srcMat.rows * 3),
                            cv::Range(srcMat.cols * 1, srcMat.cols * 2));
            cv::addWeighted(mat, 0.0f, dstMat, 1.0f, 0.0f, mat);
        }
        {
            // 使用自适应流形应用高维滤波。
            cv::Mat tempMat;
            cv::Ptr<cv::ximgproc::AdaptiveManifoldFilter> pAdaptiveManifoldFilter
                    = cv::ximgproc::createAMFilter(sigmaS/100.0f, sigmaR/100.0f, true);
            pAdaptiveManifoldFilter->filter(grayMat, tempMat);
            cv::cvtColor(tempMat, tempMat, CV_GRAY2BGR);
            // 使用Sobel边缘检测
            // 步骤一:先分别创建2个矩阵,共4个
            cv::Mat gradXMat, absGradXMat;
            cv::Mat gradYMat, absGradYMat;
            // 步骤二:求X方向的梯度
//            cv::Sobel(tempMat, gradXMat, CV_16S, 1, 0, ksize2 * 2 + 1, 1, 1);
            cv::Scharr(tempMat, gradXMat, CV_16S, 1, 0, 1, 1);
            cv::convertScaleAbs(gradXMat, absGradXMat);
            // 步骤三:求Y方向的梯度
//            cv::Sobel(tempMat, gradYMat, CV_16S, 0, 1, ksize2 * 2 + 1, 1, 1);
            cv::Scharr(tempMat, gradYMat, CV_16S, 1, 0, 1, 1);
            cv::convertScaleAbs(gradYMat, absGradYMat);
            // 步骤四:合并梯度(近似)
            cv::addWeighted(absGradXMat, 0.5, absGradYMat, 0.5, 0, dstMat);
            // copy
            mat = windowMat(cv::Range(srcMat.rows * 3, srcMat.rows * 4),
                            cv::Range(srcMat.cols * 1, srcMat.cols * 2));
            cv::addWeighted(mat, 0.0f, dstMat, 1.0f, 0.0f, mat);
        }
        // 更新
        cvui::update();
        // 显示
        cv::imshow(windowName, windowMat);
        // esc键退出
        if(cv::waitKey(25) == 27)
        {
            break;
        }
    }
}

.

Modèle d'ingénierie: numéro de version correspondant v1.36.0

      Numéro de version correspondant v1.36.0

 

Adresse du blog du blogueur d'origine: https://blog.csdn.net/qq21497936
Navigation du blog du blogueur d'origine: https://blog.csdn.net/qq21497936/article/details/102478062
L'adresse du blog de cet article: https: // blog .csdn.net / qq21497936 / article / détails / 105425374

Publié 260 articles originaux · loué 411 · 520 000 vues

Je suppose que tu aimes

Origine blog.csdn.net/qq21497936/article/details/105425374
conseillé
Classement