OpenCV 학습 기본 이미지 연산 (10 개) : 컨볼 루션 및 컨볼 루션 연산자

회선

컨볼 루션 정의

간단히 말해서 커널은 이미지에 대해 가중치 합산을 수행하며 다음과 같이 표현할 수 있습니다.

H (x, y) = \ sum _ {i = 0} ^ {M_i-1} \ sum _ {j = 0} ^ {M_j-1} I (x + i-a_i, y + j-a_j) K (i, j)

컨볼 루션 커널의 앵커 포인트는 일반적으로 컨볼 루션 커널의 중심점 인 컨볼 루션 커널의 업데이트 출력 지점을 나타냅니다.

컨볼 루션의 단계 크기는 컨볼 루션 커널이 그림에서 한 번 이동하는 거리입니다.

컨볼 루션 경계 문제

컨볼 루션 커널이 이미지 위상 경계로 이동하면 일부 컨볼 루션 커널이 원본 이미지의 경계를 초과하게되는데 이때 작업을 수행 할 수 없으며 원래 이미지의 경계를 확장해야 작업을 수행 할 수 있습니다.

확장 방법

BORDER_DEFAULT : 알려진 가장자리 미러링으로 채우기

BORDER_CONSTANTP : 지정된 픽셀로 가장자리 채우기

BORDER_REPLICATE : 가장 많은 가장자리 픽셀로 가장자리 채우기

BORDER_WRAP : 다른 쪽의 픽셀로 가장자리 채우기

BORDER_ISOLATED : 가장자리를 0으로 채 웁니다.

컨볼 루션 연산자

1 차 연산자

Rebert

Roberts 연산자는 교차 미분 연산자라고도하며 교차 차이를 기반으로하는 기울기 알고리즘으로 국부 차이 계산을 통해 경계선을 감지합니다. 가파르고 노이즈가 적은 이미지를 처리하는 데 자주 사용되며 이미지 가장자리가 +/- 45도에 가까울 때이 알고리즘의 처리 효과가 더 이상적입니다. 단점은 가장자리 위치가 정확하지 않고 추출 된 가장자리 선이 두껍다는 것입니다.

G_x = \ begin {bmatrix} +1 & 0 \\ 0 & -1 \ end {bmatrix}    G_y = \ begin {bmatrix} 0 & +1 \\ -1 & 0 \ end {bmatrix}

Prewitt

Prewitt는 이미지 가장자리 감지를위한 미분 연산자로, 특정 영역에서 픽셀 그레이 값으로 생성 된 차이를 사용하여 가장자리 감지를 수행하는 것이 원칙입니다. Prewitt 연산자는 3 * 3 템플릿을 사용하여 영역의 픽셀 값을 계산하고 Robert 연산자의 템플릿은 2 * 2이므로 Prewitt 연산자의 가장자리 감지 결과는 Robert 연산자보다 가로 및 세로 방향에서 더 분명합니다. , Prewitt 연산자는 더 많은 노이즈와 점진적인 그레이 스케일이있는 이미지를 식별하는 데 적합합니다.

G_x = \ begin {bmatrix} -1 & 0 & 1 \\ -1 & 0 & 1 \\ -1 & 0 & 1 \ end {bmatrix}   G_y = \ begin {bmatrix} -1 & -1 & -1 \\ 0 & 0 & 0 \\ 1 & 1 & 1 \ end {bmatrix}

고전적인 Prewitt 연산자는 새로운 회색 값이 임계 값보다 크거나 같은 모든 픽셀이 에지 포인트라고 믿습니다. 즉, 적절한 임계 값 T를 선택합니다. P (i, j) ≥T이면 (i, j)가 에지 포인트이고 P (i, j)가 에지 이미지입니다. 이 판단은 불합리하며 많은 노이즈 포인트가 큰 회색 값을 가지고 있고 진폭이 작은 에지 포인트의 경우 에지가 대신 손실되기 때문에 에지 포인트의 잘못된 판단을 초래합니다.

  Prewitt 연산자는 노이즈 억제에 영향을줍니다. 노이즈 억제의 원리는 픽셀 평균화를 통하지 만 픽셀 평균화는 이미지의 저역 통과 필터링과 동일하므로 Prewitt 연산자는 에지 위치 지정에 대해 Roberts 연산자만큼 좋지 않습니다.

소벨

Sobel 연산자는 가우시안 평활화와 미분 유도를 결합한 에지 감지를위한 이산 미분 연산자입니다. 이 연산자는 이미지 밝기의 대략적인 값을 계산하는 데 사용됩니다. 이미지 가장자리의 밝기에 따라 해당 영역에서 특정 수를 초과하는 특정 지점이 가장자리로 기록됩니다. Sobel 연산자는 Prewitt 연산자를 기반으로 가중치 개념을 추가합니다. 인접 지점 사이의 거리가 현재 픽셀에 다른 영향을 미치는 것으로 믿어집니다. 픽셀이 가까울수록 현재 픽셀의 영향이 커져 이미지를 구현할 수 있습니다. 가장자리 윤곽을 선명하게하고 강조 표시합니다.

Sobel 연산자의 가장자리 위치는 더 정확하며 노이즈가 많고 회색조가 점진적인 이미지에 자주 사용됩니다.

G_x = \ begin {bmatrix} -1 & 0 & 1 \\ -2 & 0 & 2 \\ -1 & 0 & 1 \ end {bmatrix}   G_y = \ begin {bmatrix} -1 & -2 & -1 \\ 0 & 0 & 0 \\ 1 & 2 & 1 \ end {bmatrix}

Sobel 연산자는 픽셀 포인트 상하 좌우 인접 포인트의 그레이 스케일 가중치 차이를 기반으로 에지를 감지하여 에지에서 극한값에 도달합니다. 노이즈에 스무딩 효과가 있으며보다 정확한 에지 방향 정보를 제공합니다. Sobel 연산자는 가우스 평활화 및 미분 유도 (미분)를 결합하기 때문에 결과적으로 더 많은 노이즈 저항이 발생합니다. 정확도 요구 사항이 그다지 높지 않은 경우 Sobel 연산자가 더 일반적으로 사용되는 에지 감지 방법입니다.

이미지의 각 픽셀에 대한 수평 및 수직 그라디언트의 대략적인 값을 다음 공식과 결합하여 그라디언트의 크기를 계산할 수 있습니다.

G = \ sqrt {G_x ^ 2 + Gy ^ 2}

그러나 실제 엔지니어링에서는 계산을 단순화하기 위해 위의 공식이 다음 공식으로 대체되는 경우가 많습니다.

G = \ 왼쪽 |  G_x \ 오른쪽 |  + \ 왼쪽 |  G_y \ right |

등방성 소벨 算 子

  소벨 연산자의 또 다른 형태는 가중 평균 연산자 인 (등방성 소벨) 연산자입니다. 가중치는 0 점과 중앙 저장소 사이의 거리에 반비례합니다. 모서리가 다른 방향으로 감지되면 기울기 진폭이 동일하며 일반적으로 등방성 소벨이라고합니다. (등방성 소벨) 연산자. 또한 두 개의 템플릿이 있습니다. 하나는 수평 가장자리를 감지하고 다른 하나는 수직 평면 가장자리를 감지합니다. 일반 Sobel 연산자와 비교하여 등방성 Sobel 연산자는 더 정확한 위치 가중치 계수를 가지며, 다른 방향의 에지를 탐지 할 때 기울기의 크기는 동일합니다.

G_x = \ begin {bmatrix} -1 & 0 & 1 \\-\ sqrt {2} & 0 & \ sqrt {2} \\ -1 & 0 & 1 \ end {bmatrix}   G_y = \ begin {bmatrix} -1 &-\ sqrt {2} & -1 \\ 0 & 0 & 0 \\ 1 & \ sqrt {2} & 1 \ end {bmatrix}

Scharr 연산자

Scharr 연산자와 Sobel 연산자의 차이점은 스무딩 부분에 있습니다. 여기서 사용되는 스무딩 연산자는 중앙 인 1 / 4 * [1, 2, 1]에 비해 1/16 * [3, 10, 3]입니다. 요소의 가중치는 더 무겁습니다. 이것은 더 무작위적인 신호 인 이미지에 상대적 일 수 있으며 도메인은 관련이 없습니다. 따라서 인접 평활화는 상대적으로 작은 표준 편차를 갖는 가우스 함수를 사용해야하며 더 얇고 더 큽니다. 주형.

  Sobel 연산자는 상대적으로 작은 커널을 계산하기 때문에 근사 미분의 정확도가 상대적으로 낮습니다. 예를 들어 3 * 3 Sobel 연산자의 경우 기울기 각도가 수평 또는 수직 방향에 가까우면 부정확성이 더 분명해집니다. . Scharr 연산자는 Sobel 연산자만큼 빠르지 만 특히 코어가 더 작은 시나리오의 경우 정확도가 더 높으므로 Scharr 연산자를 사용하는 경우 이미지 가장자리 추출을 달성하기 위해 3 * 3 필터를 사용하는 것이 좋습니다.

  • Sobel 연산자는 가장자리를 추출하는 필터 연산자의 한 형태입니다. X 및 Y 방향 각각은 템플릿을 사용하며 두 템플릿이 결합되어 그라디언트 연산자를 형성합니다. X 방향 템플릿은 수직 가장자리에 가장 큰 영향을 미치고 Y 방향 템플릿은 수평 가장자리에 가장 큰 영향을 미칩니다.

  • Robert 연산자는 Gradient 연산자의 일종으로 교차 점검을 통해 Gradient를 표현하는 연산자로 Local Difference 연산자를 이용하여 Edge를 찾는 연산자로 가파르고 노이즈가 적은 영상에 가장 좋은 효과를줍니다.

  • prewitt 연산자는 노이즈를 억제하는 효과가있는 가중 평균 연산자이지만 픽셀 평균은 이미지의 동일한 필터링과 동일하므로 prewitt 연산자는 가장자리를 배치 할 때 robert 연산자만큼 좋지 않습니다.

2 차 연산자

라플라스

라플라시안 연산자는 n 차원 유클리드 공간에서 2 차 미분 연산자로 이미지 향상 및 가장자리 추출 분야에서 자주 사용됩니다. 주변의 픽셀을 그레이 차이로 계산하는데, 기본 프로세스는 이미지의 중앙 픽셀의 그레이 값과 그 주변의 다른 픽셀의 그레이 값을 결정하는 것입니다. 중앙 픽셀의 그레이 값이 높을수록 중앙 픽셀의 그레이 값이 증가합니다. 이미지 선명 화 작업을 달성하기 위해 중앙 픽셀의 그레이 레벨을 줄입니다. 알고리즘 구현 프로세스에서 Laplacian 연산자는 이웃 중앙 픽셀의 4 개 또는 8 개 방향의 기울기를 계산 한 다음 기울기를 추가하여 중앙 픽셀의 그레이 레벨과 이웃에있는 다른 픽셀의 그레이 레벨 간의 관계를 결정하고 마지막으로 그라디언트 연산을 통해 결정합니다. 결과적으로 픽셀 그레이 스케일이 조정됩니다.

G_4 = \ begin {bmatrix} 0 & 1 & 0 \\ 1 & -4 & 1 \\ 0 & 1 & 0 \ end {bmatrix}   G_8 = \ begin {bmatrix} 1 & 1 & 1 \\ 1 & -8 & 1 \\ 1 & 1 & 1 \ end {bmatrix}

Laplacian 연산자의 기본 프로세스는 이미지의 중앙 픽셀의 회색 값과 주변 다른 픽셀의 회색 값을 결정하는 것입니다. 중앙 픽셀의 회색이 높으면 중앙 픽셀의 회색이 증가하고 그렇지 않으면 중앙 픽셀의 회색이 감소합니다. 이미지 선명 화 작업을 실현합니다. 알고리즘 구현 프로세스에서 Laplacian 연산자는 이웃 중앙 픽셀의 4 개 또는 8 개 방향의 기울기를 계산 한 다음 기울기를 추가하여 중앙 픽셀의 그레이 레벨과 이웃에있는 다른 픽셀의 그레이 레벨 간의 관계를 결정하고 마지막으로 그라디언트 연산을 통해 결정합니다. 결과적으로 픽셀 그레이 스케일이 조정됩니다.

         라플라스 연산자는 회전 불변이있는 등방성 연산자, 2 차 미분 연산자입니다. 주변 픽셀의 그레이 스케일 차이를 고려하지 않고 가장자리의 위치 만 신경 쓸 때 더 적합합니다. 분리 된 픽셀에 대한 Laplace 연산자의 반응은 가장자리 또는 선에 대한 반응보다 강하므로 노이즈가없는 이미지에만 적합합니다. 노이즈가있는 경우 Laplacian 연산자를 사용하여 에지를 감지하기 전에 저역 통과 필터링이 필요합니다. 따라서 일반적인 분할 알고리즘은 Laplacian 연산자와 평활 연산자를 결합하여 새 템플릿을 생성합니다.

LOG (가우스의 라플라시안)

LOG 연산자는 먼저 이미지에 대해 가우스 필터링을 수행 한 다음 라플라시안 2 차 도함수를 찾은 다음, 필터링 된 결과의 영점 교차를 감지하여 2 차 도함수의 pot zero point를 기반으로 이미지의 경계를 감지합니다. 이미지 또는 개체의 가장자리를 얻으려면.

  LOG 연산자는 노이즈 억제 및 에지 감지의 두 방향을 포괄적으로 고려하고 가우스 스무딩 필터와 라플라시안 샤프닝 필터를 결합하여 먼저 노이즈를 완화 한 다음 에지 감지를 수행하므로 효과가 더 좋습니다. . 이 연산자는 시각 생리학의 수학적 모델과 유사하므로 이미지 처리 분야에서 널리 사용되었습니다. 그것은 강한 간섭 방지 능력, 높은 경계 위치 정확도, 좋은 가장자리 연속성의 특성을 가지고 있으며 약한 대비로 경계를 효과적으로 추출 할 수 있습니다.

API 소개

가장자리 채우기

copyMakeBorder(src,dst,top,bottom,left,right,borderType,color)
// src 原图   dst 目标图
// top,bottom,left,right 上下左右填充宽度
//borderType 填充类型 
//color 当使用BORDERTPYPE_CONSTANTP时,才用

Sobel (Scharr) 연산자

Sobel(  //Scharr相同
InputArray Src,   //输入图像
QutputArray dst,  //输出图像
int depth,        //输出位深度 设为"-1"会自适应 选择合适的
int dx,    //x方向,几阶导数
int dy,    //y方向,几阶导数      
int ksize,        //kernel大小,必须是奇数
double scale = 1, //输出是否缩放,即乘因子
double delta = 0, //输出是否加偏差,即加因子
int borderType = BORDER_DEFAULT  //
)

라플라시안 算 子

Laplacian( 
src_gray,     //src_gray: 输入图像
dst,          //dst: 输出图像
ddepth,       //ddepth: 输出图像的深度因为输入图像的深度是 CV_8U ,这里我们必须定义 ddepth = CV_16S 以避免外溢。
kernel_size,  //kernel_size: 内部调用的 Sobel算子的内核大小,此例中设置为3。
scale, 
delta, 
BORDER_DEFAULT 
);

코드 연습

가장자리 보충

#include <iostream>
#include <math.h>
#include <opencv2/opencv.hpp>

using namespace cv;
using namespace std;

int main(int argc, char* argv[])
{
	//src = imread("src.jpg");
	Mat src = imread("cat.png"),dst;
	if (!src.data)
	{
		cout << "cannot open image" << endl;
		return -1;
	}
	namedWindow("input image", WINDOW_AUTOSIZE);
	imshow("input image", src);
	Mat d1, d2, d3, d4,d5,d6,d7,d8;
	int top = (int)(0.10 * src.rows);
	int bottom = (int)(0.10 * src.rows);
	int left = (int)(0.10 * src.cols);
	int right = (int)(0.10 * src.cols);

	copyMakeBorder(src, d1, top, bottom, left, right, BORDER_CONSTANT, Scalar(255, 255, 255));
	copyMakeBorder(src, d2, top, bottom, left, right, BORDER_DEFAULT);
	copyMakeBorder(src, d3, top, bottom, left, right, BORDER_REFLECT);
	copyMakeBorder(src, d4, top, bottom, left, right, BORDER_REPLICATE);
	copyMakeBorder(src, d5, top, bottom, left, right, BORDER_WRAP);
	copyMakeBorder(src, d6, top, bottom, left, right, BORDER_ISOLATED);
	copyMakeBorder(src, d7, top, bottom, left, right, BORDER_REFLECT101);

	imshow("BORDER_CONSTANT", d1);
	imshow("BORDER_DEFAULT", d2);
	imshow("BORDER_REFLECT", d3);
	imshow("BORDER_REPLICATE", d4);
	imshow("BORDER_WRAP", d5);
	imshow("BORDER_ISOLATED", d6);
	imshow("BORDER_REFLECT101", d7);

	waitKey(0);
	return 0;
}

연산자 추출 가장자리

#include <iostream>
#include <math.h>
#include <opencv2/opencv.hpp>

using namespace cv;
using namespace std;

int main(int argc, char* argv[])
{
	//src = imread("src.jpg");
	Mat src = imread("src.jpg"),gray_src;
	if (!src.data)
	{
		cout << "cannot open image" << endl;
		return -1;
	}
	namedWindow("input image", WINDOW_AUTOSIZE);
	imshow("input image", src);
	GaussianBlur(src, src, Size(3, 3), 0, 0);
	cvtColor(src,src,COLOR_BGR2GRAY);

	//Robert算子
	//X
	Mat dst_rx, dst_ry;
	Mat kernel_x1 = (Mat_<int>(2, 2) << 1, 0, 0, -1);
	filter2D(src, dst_rx, -1, kernel_x1, Point(-1, -1), 0.0);
	
	//Y
	Mat kernel_y1 = (Mat_<int>(2, 2) << 0 ,1, -1, 0);
	filter2D(src, dst_ry, -1, kernel_y1, Point(-1, -1), 0.0);

	//拼接两个方向的梯度
	Mat xygrad = Mat(src.size(), src.type());
	int width = xygrad.cols;
	int height = xygrad.rows;
	for (int row = 0; row < height; row++)
	{
		for (int col = 0; col < width; col++)
		{
			int xg = dst_rx.at<uchar>(row, col);
			int yg = dst_ry.at<uchar>(row, col);
			int xy = xg + yg;
			xygrad.at<uchar>(row, col) = saturate_cast<uchar>(xy);
		}
	}
	imshow("Rebort", xygrad);


	// prewitt算子
	Mat dst_sx, dst_sy;
	//X
	Mat kernel_x2 = (Mat_<int>(3, 3) << -1, 0, 1, -1, 0, 1, -1, 0, 1);
	filter2D(src, dst_sx, -1, kernel_x2, Point(-1, -1), 0.0);
	
	//Y
	Mat kernel_y2 = (Mat_<int>(3, 3) << -1, -2, -1, 0, 0, 0, 1, 2, 1);
	filter2D(src, dst_sy, -1, kernel_y2, Point(-1, -1), 0.0);
	
	for (int row = 0; row < height; row++)
	{
		for (int col = 0; col < width; col++)
		{
			int xg = dst_sx.at<uchar>(row, col);
			int yg = dst_sy.at<uchar>(row, col);
			int xy = xg + yg;
			xygrad.at<uchar>(row, col) = saturate_cast<uchar>(xy);
		}
	}
	imshow("Prewitt", xygrad);

	//Sobel 算子
	Sobel(src, dst_rx, CV_16S, 1, 0, 3);
	convertScaleAbs(dst_rx, dst_rx);
	Sobel(src, dst_ry, CV_16S, 0, 1, 3);
	convertScaleAbs(dst_ry, dst_ry);
	for (int row = 0; row < height; row++)
	{
		for (int col = 0; col < width; col++)
		{
			int xg = dst_rx.at<uchar>(row, col);
			int yg = dst_ry.at<uchar>(row, col);
			int xy = xg + yg;
			xygrad.at<uchar>(row, col) = saturate_cast<uchar>(xy);
		}
	}
	imshow("Sobel", xygrad);

	//Scharr 算子
	Scharr(src, dst_rx, CV_16S, 1, 0);
	convertScaleAbs(dst_rx, dst_rx);
	Scharr(src, dst_ry, CV_16S, 0, 1);
	convertScaleAbs(dst_ry, dst_ry);
	for (int row = 0; row < height; row++)
	{
		for (int col = 0; col < width; col++)
		{
			int xg = dst_rx.at<uchar>(row, col);
			int yg = dst_ry.at<uchar>(row, col);
			int xy = xg + yg;
			xygrad.at<uchar>(row, col) = saturate_cast<uchar>(xy);
		}
	}
	imshow("Scharr", xygrad);

	//Laplacian 算子
	Mat edge_image;
	Laplacian(src, edge_image, CV_16S, 3);
	convertScaleAbs(edge_image, edge_image);
	imshow("Laplacian", edge_image);
	

	waitKey(0);
	return 0;
}

 

추천

출처blog.csdn.net/fan1102958151/article/details/107343870