OpenCV開発ノート(41):赤いデブ男は、scharrフィルターオペレーターのエッジ検出について詳しく学ぶために8分でかかります

記事がオリジナルの記事である場合、許可なく複製することはできません。
元のブロガーのブログアドレス:https : //blog.csdn.net/qq21497936
オリジナルのブロガーのブログナビゲーション:https : //blog.csdn.net/qq21497936/article/details / 102478062
この記事のブログアドレス:https : //blog.csdn.net/qq21497936/article/details/105425374
読者、知識は無限大、人材は乏しい、需要を変える、専門家を見つける、または自分で勉強する

ディレクトリ

序文

デモ

ScharrフィルターとSobelオペレーターのエッジ検出

概観

SobelオペレーターとScharrフィルター

原理

ステップ1:xおよびy方向の導出

ステップ2:おおよその勾配を見つける

Scharr関数はSobelと同じですが、追加のステップがあります。

ステップ1:最初に2つのcv :: Matキャッシュを作成する

ステップ2:X方向の勾配を見つける

ステップ3:Y方向のグラデーションを見つける

ステップ4:グラデーションのマージ(概算)

シャール関数プロトタイプ

色変換機能

デモのソースコード

エンジニアリングテンプレート:対応するバージョン番号v1.36.0


OpenCV 開発コラム(ポータルをクリック)

 

    OpenCV開発ノート(41):scharrフィルターオペレーターのエッジ検出の詳細(グラフィック+理解しやすい+プログラムのソースコード)を学ぶために、8分かかります。

 

序文

      赤いデブ男も来ます!

      この章では、scharrrフィルターについて説明し、ソーベル演算子のエッジ検出を比較します。

 

デモ

            デモ画像の結果の場所の図:

 

ScharrフィルターとSobelオペレーターのエッジ検出

概観

      まず、ソーベル演算子のエッジ検出を理解します。Scharrフィルターは、実際にはソーベルの実際のプログラミング操作の移植ですが、カーネルマトリックスのデータを増やすだけであり、その精度はソーベル演算子のエッジ検出よりも高くなります。エッジ検出用のサブエッジ検出とScharrフィルター。

      Sobelオペレーターエッジ検出の詳細については、「OpenCV開発ノート(39):Sobelオペレーターエッジ検出(グラフィックス+理解しやすい+プログラムのソースコード)の詳細を学ぶために8分で説明します」を参照してください。

SobelオペレーターとScharrフィルター

ソーベルの計算は、より優れた検出効果を生み出し、ノイズに対するスムーズな抑制効果がありますが、取得されたエッジはより太くなり、誤ったエッジが表示される場合があります。

画像がより複雑になると、ターゲットと背景をしきい値で単純に分離することはできません。現時点では、エッジ検出法または面積拡大法のみを使用してください最も一般的に使用されているエッジ検出法は、ソーベル演算子です。

Sobelオペレーターには、単純な方法、高速処理速度、滑らかで連続的なエッジという利点があります。欠点は、エッジが厚いことです。2値化プロセスのため、取得されたエッジは、しきい値の選択と大きな関係があります。

Sobel()を呼び出すときは、実際にksizeを:: SCHARRに設定してそれを実現するか、Scharrフィルターのみを使用して、Sobel演算子よりも正確にすることができます。したがって、3x3フィルターを選択する場合は、Scharrフィルターが優先されます。速度はSobel()と同じくらい高速です。

原理

ステップ1:xおよびy方向の導出

入力画像がIであるとします。

水平方向の変化:Iと奇数サイズのカーネルのたたみ込み。たとえば、カーネルのサイズが3の場合、Gxの計算結果は次のようになります。

      垂直方向の変化:奇数サイズのカーネルでコンボリューションIたとえば、カーネルのサイズが3の場合、Gyの計算結果は次のようになります。

ステップ2:おおよその勾配を見つける

画像の各点で、GxとGyを組み合わせて、おおよその勾配を求めます。

さらに、代わりに簡単な公開アナウンスを使用することもできます。

Scharr関数はSobelと同じですが、追加のステップがあります。

ステップ1:最初に2つの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));

ステップ2: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);

ステップ3: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);

ステップ4:グラデーションのマージ(概算)

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

シャール関数プロトタイプ

void Scharr( InputArray src,
           OutputArray dst,
           int ddepth,
           int dx,
           int dy, 
           double scale = 1,
           double delta = 0,
           int borderType = BORDER_DEFAULT );
  • パラメーター1: InputArrayタイプのイメージ、通常はcv :: Mat;
  • パラメーター2:タイプOutputArrayのdst、入力画像と同じサイズ。
  • パラメーター3: intタイプddepth、出力画像の深さ 8ビットの入力画像により、結果が切り捨てられます。組み合わせは次のとおりです。

  • パラメーター4: int型dx、x方向の微分次数、1または0;
  • パラメーター5: int型dy、y方向の微分次数、1または0;
  • パラメータ6: doubleタイプのスケール、スケーリング計算の微分値のオプションのスケーリング係数、デフォルト値は1で、スケーリングが実行されないことを示します。
  • パラメーター7:結果にdstに格納する前に、結果にdoubleタイプのdetalおよびdeltaが追加されます。
  • パラメーター8: int型のborderType。通常、注意を払う必要はありません。

色変換機能

void convertScaleAbs(InputArray src,
                   OutputArray dst,
                   double alpha = 1,
                   double beta = 0);
  • パラメーター1: InputArrayタイプのイメージ、通常はcv :: Mat;
  • パラメータ2: OutputArrayタイプのdst、出力画像。
  • パラメーター3:ダブルタイプのアパ。
  • パラメータ4:タイプdoubleの深度。

(補足:実際、これはコントラストと明るさの調整に似ていますが、計算結果が0未満の場合は処理されないため、値が前方に借用され、代わりに白になります)。

 

デモのソースコード

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;
        }
    }
}

エンジニアリングテンプレート:対応するバージョン番号v1.36.0

      対応するバージョン番号v1.36.0

 

オリジナルのブロガーのブログのアドレス:https://blog.csdn.net/qq21497936
オリジナルのブロガーがナビゲーションブログ:https://blog.csdn.net/qq21497936/article/details/102478062を
この記事のブログのアドレス:HTTPS://ブログ.csdn.net / qq21497936 /記事/詳細/ 105425374

元の記事を260件公開しました 賞賛されました411 表示回数520,000回

おすすめ

転載: blog.csdn.net/qq21497936/article/details/105425374