記事がオリジナルの記事である場合、許可なく複製することはできません。
元のブロガーのブログアドレス:https : //blog.csdn.net/qq21497936
オリジナルのブロガーのブログナビゲーション:https : //blog.csdn.net/qq21497936/article/details / 102478062
この記事のブログアドレス:https : //blog.csdn.net/qq21497936/article/details/105425374
読者、知識は無限大、人材は乏しい、需要を変える、専門家を見つける、または自分で勉強する
ディレクトリ
Scharr関数はSobelと同じですが、追加のステップがあります。
ステップ1:最初に2つのcv :: Matキャッシュを作成する
エンジニアリングテンプレート:対応するバージョン番号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