opencv four Matの基本操作3(ハイパスフィルター、ローパスフィルター、コントラスト調整)

画像フィルタリングはハイパス フィルタリングとローパス フィルタリングに分けられ、ハイパス フィルタリングはグラフィックスのエッジを検出するために使用され、ローパス フィルタリングは画像のノイズ除去や画像のぼかしに使用されます。ここでの周波数とは変化(隣接する画素値の変化)を指し、ハイパスフィルターは大きな変化(つまり画像のエッジ)の通過を指します(ローパスフィルターは画像のエッジを指します)。小さな変化 (つまり、画像内のグラフィックス) の通過 ハイパス フィルター部分には、ソーベル、シャール、ラプラシアン、キャニーなどの手法が含まれ、ローパス フィルター部分には、平均値フィルター、ボックス フィルター、中央値が含まれます 。フィルタリング、ガウス フィルタリング、およびバイラテラル フィルタリング。コントラスト調整は、画像内の特定の領域のピクセル値を変更して、画像のコントラストを変化させます。このブログ投稿に含まれるコントラスト調整方法には、数値の加算および減算演算、線形変化が含まれます。 、非線形変化、ヒストグラム均等化。

1. ハイパスフィルタリング

ハイパス フィルターには、ソーベル、シャール、ラプラシアン、キャニーなどが含まれます。これらのフィルターの特徴は、画像の高周波部分が通過し、画像の低周波部分がフィルターで除去されることです。プロパティ)、およびこれらのフィルターの値の合計は 0 です。エッジ勾配を計算するとき、ノイズ データの影響を避けるために、一部のローパス フィルターを使用してノイズを除去できます (ガウス フィルターなど)。フィルタリングする場合、結果の値が 255 より大きい (CV_8U の範囲を超える) 可能性があるため、結果のデータ型は通常 16S であり、convertScaleAbs 関数を使用して 16S の範囲を CV_8U に圧縮する必要があります。

1.1 Sobel 演算子と Scharr 演算子

これはノイズへの適用性が高い一次微分演算子であり、最初にガウス フィルタリングを使用して内部でノイズをフィルタリングし、次に一次微分によって画像のエッジを取得します。[コンボリューションカーネルサイズを-1に設定すると、自動的にScharrフィルタアルゴリズムが使用されます] sobel演算子の詳細は下図に示します 左図はx方向の演算子(垂直勾配を求める) 、右図は y 方向の演算子 (水平方向の勾配を求める)

Sobel フィルター演算子を使用するためのコードは次のとおりです。Sobel は水平方向の勾配垂直方向の勾配を計算できることに注意してください。取得される勾配値は負の値になる可能性があるため、取得するには ConvertScaleAbs を使用する必要があります。絶対値最終的なグラデーション結果は、addWeighted 関数を使用して重み付けされ、合計される必要があります

#include<iostream>  
#include <opencv2/core/core.hpp>  
#include <opencv2/highgui/highgui.hpp>  
#include <opencv2/imgproc/imgproc.hpp>
 
using namespace std;
using namespace cv;
 
int scale = 1;
int delta = 0;
int ddepth = CV_16S;
 
int main()
{
    // 读入一张图片  
    Mat image = imread("C:\\Users\\aaa\\Pictures\\car1.png");
    //彩色图像转灰度图像
    cvtColor(image, image, COLOR_BGR2GRAY);
    imshow("原图", image);
     
    Mat grad_x, grad_y;
    Mat abs_grad_x, abs_grad_y;
     
    //求 X方向梯度,竖直边缘
    Sobel(image, grad_x, ddepth, 1, 0, 3, scale, delta, BORDER_DEFAULT);
    //求 Y方向梯度,水平边缘
    Sobel(image, grad_y, ddepth, 0, 1, 3, scale, delta, BORDER_DEFAULT);
    //将中间结果转换到 CV_8U:
    convertScaleAbs(grad_x, abs_grad_x);
    imshow("x", abs_grad_x);
    convertScaleAbs(grad_y, abs_grad_y);
    imshow("y", abs_grad_y);
    //将两个方向的梯度相加来求取近似 
    addWeighted(abs_grad_x, 0.5, abs_grad_y, 0.5, 0, image);
 
    imshow("sobel", image);
 
     
    waitKey(0);
}
 

 コード実行の効果は次のとおりです。 

Sobel オペレーターは画像のエッジを効果的に抽出できますが、画像内の弱いエッジを抽出する場合にはあまり効果的ではありません。したがって、弱いエッジを効果的に抽出するには、ピクセル値間のギャップを大きくする必要があるため、Scharr オペレーターが導入され、その構造は次の図に示されています。

 Scharr オペレーターは Sobel オペレーターの違いを拡張したものであるため、画像のエッジを検出する原理と使用法は 2 つで同じです。Scharr オペレーターのエッジ検出フィルターのサイズは 3×3 であるため、Scharr フィルターとも呼ばれます。フィルタ内の重み係数を増幅することで、画素値の差を大きくすることができます。【OpenCV 4開発徹底解説】Scharr Operator-Knowledgeより引用

1.2 ラプラシアン演算子

  ラプラシアンは画像のエッジ検出に適用できます。OpenCV では、カーネル サイズが 3*3 の場合、次の図に示すように 2 つのカーネル演算子がサポートされます。ラプラシアン演算子は、水平方向と垂直方向の勾配を同時に計算することができ、方向性がないという特徴を持っていますラプラシアン演算子はノイズに敏感な二次微分演算子であるため、ガウス フィルター (ノイズ除去) と併用されることがよくあります。

呼び出しコードは次のようになります。

  Mat image = imread("C:\\Users\\aaa\\Pictures\\car1.png");
    //彩色图像转灰度图像
    cvtColor(image, image, COLOR_BGR2GRAY);
    imshow("原图", image);
     
    Mat grad;
    Laplacian(image, grad, CV_8U);
    convertScaleAbs(grad, grad);
    imshow("Laplacian", grad);
     
    waitKey(0);

コードの結果は次のようになります 

 1.3 キャニー演算子

Cany演算子は 4 つのステップで実装されます:ノイズの除去 = "振幅と方向の計算 = "非最大抑制 = "ヒステリシス閾値、計算時に sobel 演算子を使用して x および y 方向の勾配値を計算します。振幅と方向。具体的な詳細は次のブログに示されています。OpenCV の Canny エッジ検出 (C++ 実装) https://blog.csdn.net/xddwz/article/details/111585648

 上記の3つのフィルタと比較すると、canyの計算処理は複雑であり、計算量が多くなります。その使用コードと実行結果を以下に示します。

   // 读入一张图片  
    Mat image = imread("C:\\Users\\aaa\\Pictures\\car1.png");
    //彩色图像转灰度图像
    cvtColor(image, image, COLOR_BGR2GRAY);
    imshow("原图", image);
     
    Mat grad;
/*
void Canny( InputArray image, OutputArray edges,
                         double threshold1, double threshold2,
                         int apertureSize = 3, bool L2gradient = false )
*/
    Canny(image, grad, 150, 100, 3);
    imshow("grad", grad);
     
    waitKey(0);

2. ローパスフィルタリング

OpenCV で一般的に使用されるローパス フィルターは、平均値フィルター、ボックス フィルター、メディアン フィルター、ガウス フィルター、バイラテラル フィルターで、主に画像内のノイズを除去するために使用されます。

2.1 平均値フィルタリングとボックスフィルタリング

平均値フィルタリングは 、鮮明な画像ノイズを除去し、画像の平滑化、ぼかし、その他の機能を実現するのに役立ちます。理想的な平均値フィルターは、画像内の各ピクセルを、各ピクセルとその周囲のピクセルに対して計算された平均値で置き換えることです。

平均値フィルタリングには、平均値フィルタリングと加重平均値フィルタリングが含まれます。それぞれ次のようになります。

      左側は平均平均フィルタリング、右側は加重平均フィルタリングです。 

 ボックス フィルタリングと平均値フィルタリングの原理は似ており、正規化後のボックス フィルタリングの効果は、同じコンボリューション カーネル サイズの平均値フィルタリングの効果と同じです。OpenCV では、次の図に示すように、ボックス フィルターのカーネル サイズはボックスの行数と列数を指します。

 呼び出しコードは次のようになります。

#include <iostream>
#include <opencv2\opencv.hpp>

using namespace cv;
using namespace std;

int main()
{
	//---------------------------用于方框滤波的图像--------------------
	Mat img = imread("C:\\Users\\aaa\\Pictures\\timg.jpg",0);
	resize(img, img, { 500,300 });

	//将CV_8U类型转换成CV_32F类型,避免计算后的数据过大
	Mat equalImg_32F;
	img.convertTo(equalImg_32F, CV_32F, 1.0 / 255);
	Mat resultNorm, result, equalImg_32FSqr;
	//--------------------------方框滤波boxFilter----------------------
	boxFilter(img, resultNorm, -1, Size(3, 3), Point(-1, -1), true);  // 进行归一化,则为均值滤波
	boxFilter(img, result, -1, Size(3, 3), Point(-1, -1), false);     // 不进行归一化
	//----------------------方框滤波sqrBoxFilter()---------------------
	//对每个像素数值的平方求和/求均值
	sqrBoxFilter(equalImg_32F, equalImg_32FSqr, -1, Size(3, 3), Point(-1, -1), true, BORDER_CONSTANT);
	//-------------------------显示处理结果----------------------------
	imshow("原始图像", img);
	imshow("归一化", resultNorm);
	imshow("不归一化", result);
	imshow("平方和求均值", equalImg_32FSqr);
	waitKey(0);
	return 0;
}

コード実行の効果は次のとおりです 

 2.2 メディアンフィルタリング 

特定の条件下では、メディアン フィルターは、ボックス フィルターや平均フィルターなどの一般的な線形フィルターによって引き起こされる画像の詳細のぼやけを克服でき、パルス干渉や画像スキャン ノイズを除去するのに非常に効果的で、エッジ情報を保護するためにも一般的に使用されます。エッジを保持する機能は、エッジのブラーを望まない場合に役立ち、非常に古典的なスムージング ノイズ処理方法です。以下の内容は以下を参照しました:Opencv の画像フィルタリング: 5. メディアン フィルタリング (cv2.medianBlur)_Justth. の blog-CSDN blog_opencvメディアン フィルタリングの前に導入された平均フィルタリング、ボックス フィルタリング、ガウス フィルタリングはすべて線形フィルタリング手法です。線形フィルタリングの結果はすべてのピクセル値の線形結合であるため、ノイズを含むピクセルも考慮され、ノイズは除去されず、よりソフトな形で存在します。このとき、非線形フィルタリングを使用した方が効果が高い場合があります。メディアン フィルタリングは上記のフィルタリング方法とは異なり、フィルタリング結果は加重平均によって計算されなくなります。現在のピクセルのピクセル値を、近傍のすべてのピクセル値の中央値に置き換えます。5.1 原理の紹介 メディアン フィルターは、現在のピクセルとその周囲のピクセル (奇数ピクセルの合計) のピクセル値を取得し、これらのピクセル値を並べ替えて、中央の位置のピクセル値をそのピクセル値として使用します。現在のピクセル。次の瞬間のために.. https://blog.csdn.net/qq_49478668/article/details/123485382

 メディアン フィルターは、現在のピクセルとその周囲のピクセル (合計で奇数のピクセルがあります) のピクセル値を取得し、これらのピクセル値を並べ替えて、中央の位置のピクセル値を現在のピクセルのピクセル値として使用します。次の行列の場合:

 その近傍を 3×3 のサイズに設定し、その 3×3 近傍内のピクセルのピクセル値を (昇順と降順の両方で) 並べ替えます。昇順で並べ替えた後のシーケンス値は次のようになります: [66, 78,90,91,93,94,95,97,101]。このシーケンスでは、中心位置 (中心点または中点とも呼ばれます) の値は「93」であるため、元のピクセル値 78 をこの値で現在の点の新しいピクセル値として置き換えます。メディアン フィルタリングの効果は次のとおりです。

 呼び出しコードは次のようになります。

#include <iostream>
#include <opencv2\opencv.hpp>

using namespace cv;
using namespace std;

int main()
{
	Mat img = imread("C:\\Users\\aaa\\Pictures\\timg.jpg",0);
	resize(img, img, { 500,300 });
	Mat grayResult;
	medianBlur(img, grayResult , 3);
	imshow("原始图像", img);
	imshow("中值滤波", grayResult);
	waitKey(0);
	return 0;
}

コード操作の効果は次のとおりです。 

 2.3 ガウスフィルタリング 

ガウス フィルタリングは画像のバランス、画像のぼかし、または画像のノイズ除去に使用されます。重み付きフィルタリングの実装です。ガウス フィルタリングの演算子はガウス分布関数から計算されます (中央のフィルタリングが最も重要で、外側のフィルタリングが 2 番目です)ガウス分布には、標準偏差と分散という 2 つのパラメータがあります。ガウス フィルタリングの演算子は次のとおりです。各位置に異なる重みを割り当てます。中央の重みが最も大きく、エッジが 2 番目で、すべての重みの合計は 1 になります。

ガウス フィルタリングを使用した場合のコードと効果は次のとおりです。 

    Mat img = imread("C:\\Users\\aaa\\Pictures\\timg.jpg",0);
	resize(img, img, { 500,300 });
	Mat out;
	GaussianBlur(img, out, cv::Size(5, 5), 3, 3);
	imshow("原始图像", img);
	imshow("out", out);
	waitKey(0);

2.4 双方向フィルタリング

バイラテラル フィルタ (バイラテラル フィルタ) は非線形フィルタリング手法であり、バイラテラル フィルタの利点はエッジ保存ができることです。一般に、ガウス フィルタリングはノイズ低減に使用され、明らかにエッジがぼやけてしまい、高周波の細部に対する保護効果は明ら​​かではありませんが、バイラテラル フィルタリングを使用すると、ガウス フィルタリングのノイズ低減効果を達成でき、ノイズを十分に維持できます。エッジ (両側性のため、このフィルターにはガウス フィルターよりも 1 つ多いガウス分散 sigma-d があります)。内容は以下から参照しています: OpenCV Study Notes (7) Median and Bi Lateral Filtering - Short Book

双方向フィルタリングを使用した場合のコードと効果は次のとおりです。 

Mat img = imread("C:\\Users\\aaa\\Pictures\\timg.jpg",0);
	resize(img, img, { 500,300 });
	Mat out;
	/*
	bilateralFilter( InputArray src, OutputArray dst, int d,
                                   double sigmaColor, double sigmaSpace,
                                   int borderType = BORDER_DEFAULT )
	*/
	bilateralFilter(img, out, 25, 25 * 2, 25 / 2);
	imshow("原始图像", img);
	imshow("out", out);
	waitKey(0);

3. コントラスト調整

コントラスト調整とは、画像内の特定の領域のピクセル値を変更することで画像のコントラストを変更することです。コントラスト強調は明るい部分をより明るく、暗い部分をより暗くすること、コントラスト強調の低減は、明るい部分をより暗く、暗い部分をより明るくすることです。具体的なコントラスト調整方法としては、数値加算減算(コントラストを強くすることはできず、画像全体を明るくしたり暗くしたりすることしかできない)、線形変化(画素値を一次関数y=ax+bで変化させる)などがあります。 、a>1の場合、コントラストの強化、a<1の場合コントラストを弱める)、非線形変更(対数変更、グラマ変更、カスタム変更関数)、ヒストグラム等化などの手段。

3.1 数値の足し算と引き算

画像の明るさはマットの加減算で調整できます(コントラストは調整できません) 加算結果が255を超える場合は255、減算結果が0未満の場合は0となります。

テストコードは以下の通りです

#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include<opencv2/core/core.hpp>
#include<iostream>
 
using namespace std;
using namespace cv;
int main()
{
	Mat srcImage;
	srcImage = imread("C:/Users/aaa/Pictures/b.jpg", 0);
	resize(srcImage, srcImage,{},0.5,0.5);
	imshow("img", srcImage);
	Mat img_bl,img_an;
	//
	img_an = srcImage - 50;//减=》变暗
	img_bl = srcImage + 50;//加=》变亮
	imshow("img-50", img_an);
	imshow("img+50", img_bl);
	waitKey(0);
	return 0;
}

 コード実行の効果は次のとおりです 

3.2 線形操作

y=ax+b の一次関数マッピングを通じてピクセル値を変更します。a>1 はコントラストを強化し、a<1 はコントラストを低減します。

テストコードは以下の通りです

#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include<opencv2/core/core.hpp>
#include<iostream>
 
using namespace std;
using namespace cv;
int main()
{
	Mat srcImage;
	srcImage = imread("C:/Users/aaa/Pictures/b.jpg", 0);
	resize(srcImage, srcImage,{},0.5,0.5);
	imshow("img", srcImage);
	Mat img_bl,img_an;
	//
	img_an = srcImage*0.8 + 10;//a<1=》变暗
	img_bl = srcImage*1.5 - 30;//a>1=》变亮
	imshow("img*0.6 + 10", img_an);
	imshow("img*1.2 - 30", img_bl);
	waitKey(0);
	return 0;
}

コード実行の効果は次のとおりです 

3.3 非線形変換

opencv での一般的な非線形変換は、対数変換 (凸状関数、y=x 関数イメージの上) とガンマ変換 (ガンマ値の変化に応じて y=x 関数イメージの下または上になる可能性があります) です。非線形関数をカスタマイズして画像の明るさを調整します。

対数変化、ガンマのコードを以下に示します。対数変化を行う場合、対数変化に対応する値の範囲は0~255ですが、対数変化後の出力値の範囲は255を超えるため、ノーマライズ機能を使用して値の範囲を0~255に圧縮する必要があることに注意してください。 。Floot型マットの場合、opencvで理解できる範囲は[0,1]で、1を超えた部分は白となるため、 CV_32FをCV_8Uに変換する(または正規化関数を使用して値の範囲を[0に圧縮する)必要があります。 ,1])

#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include<opencv2/core/core.hpp>
#include<iostream>
 
using namespace std;
using namespace cv;
 
int main()
{
	Mat srcImage;
	srcImage = imread("C:/Users/aaa/Pictures/b.jpg", 0);
	resize(srcImage, srcImage,{},0.5,0.5);
	imshow("img", srcImage);
	
	//log变化、对数变化,使图像变亮
	Mat img_log;
	srcImage.convertTo(srcImage, CV_32F);
	log(srcImage, img_log);//log变化后图像值会出现小数,log函数的输出范围超出0~255
	normalize(img_log, img_log, 0, 255, NORM_MINMAX);//将log函数的输出压缩到0~255内
	img_log.convertTo(img_log, CV_8U);//因为图像是CV_32F,且值域超出0~1
 
	//gamma变化
	Mat g2_05=gamma_mat(srcImage, 2, 0.5);
	Mat g1_13 = gamma_mat(srcImage, 2, 1.3);
	imshow("img_log", img_log);
	imshow("g2_05", g2_05);
	imshow("g1_13", g1_13);
	waitKey(0);
	return 0;
}

gamma_mat 関数の実装は次のとおりです. ガンマ関数の変更は 0 ~ 1 の値の範囲を対象としているため、mat のピクセル値 (値の範囲は 0 ~ 255) を正規化する必要があることに注意してください。  (つまり、CV_8U から CV_64F を 255 で割ります)演算結果も 0 ~ 1 の間にないため、正規化 (または 255 に正規化) する必要があります。

Mat gamma_mat(Mat src,float c, float gamma) {
	//伽马变换
	Mat gamma_image;  //归一化图像
	src.convertTo(src, CV_64F);
	src = src / 255;
	int height = src.rows;
	int width = src.cols;
	gamma_image.create(src.size(), CV_64F);
	for (int i = 0; i < height; i++)
	{
		for (int j = 0; j < width; j++)
		{
			gamma_image.at<double>(i, j) = c*pow(src.at<double>(i, j), gamma);
 
		};
	};
    //方式一  归一化
    normalize(gamma_image, gamma_image, 0, 1, NORM_MINMAX);
    //方式二  归255 转CV_8U
	//normalize(gamma_image, gamma_image, 0, 255, NORM_MINMAX);
	//gamma_image.convertTo(gamma_image, CV_8U);
    //方式三  归255 转CV_8U
	//gamma_image.convertTo(gamma_image, CV_8U, 255, 0);
	return gamma_image;
}

3.4 ヒストグラムの等化

ヒストグラム イコライゼーションを使用すると、画像のコントラストを強化できます。詳細な概念については、次のリンクを参照してください:
OpenCV ヒストグラム イコライゼーション_Yang Jian のブログ-CSDN ブログ_opencv ヒストグラム イコライゼーションの記事ディレクトリ ヒストグラム イコライゼーションの概要 画像のヒストグラムとは何ですか? ヒストグラム イコライゼーションとは何かをよりわかりやすく説明します。ヒストグラム等化はどのように実装されますか? ヒストグラム イコライゼーションの役割 ヒストグラム イコライゼーションの手順 関連する APIequalizeHist コード例 ヒストグラム イコライゼーションの概要 画像のヒストグラムとは? 画像ヒストグラムとは、グレー スケール範囲内の画像全体のピクセル値 (0 ~ 255) を指します。発生頻度は画像ヒストグラム-ヒストグラムと呼ばれます。ヒストグラムは画像のグレー レベルの分布を反映しています。画像の統計的特徴です。簡単に言うと、ヒストグラムは画像内のピクセルの強度分布をグラフで表現したもので、各強度値が持つピクセルの数を数えます。たとえば、下の図では、左側の図は grey_1671465600 https://blog.csdn.net/weixin_45525272/article/details/122663041

グレースケール ヒストグラム イコライゼーションは、 equalizeHist(in_mat,out_mat) を直接呼び出すことができます。具体的な呼び出しケースは次のとおりです。 

#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include<opencv2/core/core.hpp>
#include<iostream>
 
using namespace std;
using namespace cv;
 
int main()
{
	Mat srcImage;
	srcImage = imread("C:/Users/aaa/Pictures/a.jpg", 0);
	resize(srcImage, srcImage,{},0.5,0.5);
	imshow("原始图", srcImage);
	Mat new_img;
	equalizeHist(srcImage, new_img);
	imshow("经过直方图均衡化后的图", new_img);
	waitKey(0);
	return 0;
}

コード実行の効果は次のとおりです 

カラー イメージのヒストグラム イコライゼーションは、特に bgr イメージの場合、各チャネルを直接イコライズすることはできません。この種の bgr 画像の場合、まず色空間を BGR から HSV に変換し、次に画像を 3 つのマット (分配オブジェクト H、S、V の 3 チャネル) に分割し、そのマットのマット上でヒストグラム等化を実行する必要があります。 Vチャンネル。最後に、H、S、V の 3 チャンネルのシングル チャンネル マットを 3 チャンネルのマットにマージし、hsv 色空間のマットを bgr のマットに変換します。具体的な操作は以下の通り

#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include<opencv2/core/core.hpp>
#include<iostream>
 
using namespace std;
using namespace cv;
Mat brgEqualizeHist(Mat bgr) {
	Mat hsvImg, dstImage;
	cvtColor(bgr, hsvImg, COLOR_BGR2HSV);
	//定义一个channels储存分离后的通道
	vector<Mat> channels;
	//H,S,V三个通道
	Mat h, s, v;
	//分离图像
	split(hsvImg, channels);
 
	h = channels.at(0);
	s = channels.at(1);
	v = channels.at(2);
	//对V通道就行直方图均衡化,使图像的亮度变得均衡
	equalizeHist(v, v);
 
	//将直方图均衡化的通道合并起来
	merge(channels, hsvImg);
	cvtColor(hsvImg, dstImage, COLOR_HSV2BGR);
	return dstImage;
}
int main()
{
	Mat srcImage;
	srcImage = imread("C:/Users/aaa/Pictures/a.jpg", 1);
	resize(srcImage, srcImage,{},0.5,0.5);
	imshow("原始图", srcImage);
	Mat new_bgr = brgEqualizeHist(srcImage);
	imshow("经过直方图均衡化后的图", new_bgr);
	waitKey(0);
	return 0;
}

 コード実行の効果は次のとおりです

おすすめ

転載: blog.csdn.net/m0_74259636/article/details/128587670