C++ OpenCV4.5 卷积运算和卷积边缘处理(十一)

系列文章目录

C++ OpenCV4.5环境搭建(一)

C++ OpenCV4.5常用API查询手册(二)

C++ OpenCV4.5 图像处理(三)

C++ OpenCV4.5 绘制形状与文字(四)

C++ OpenCV4.5 图像模糊(五)

C++ OpenCV4.5 项目实战一(六)

C++ OpenCV4.5 形态学操作(七)

C++ OpenCV4.5 调整图像亮度的几种方法(八)

C++ OpenCV4.5 图像金字塔和图像阈值(九)

C++ OpenCV4.5 图像的部分处理操作(十)


文章目录

  • 系列文章目录
  • 前言
  • 一、卷积运算
    • 1.卷积概念
    • 2.卷积工作原理
    • 3.常见算子
    • 4.相关API
  • 二、卷积边缘处理
    • 1.卷积边界问题
    • 2.处理边缘
    • 3.相关API


前言

本篇讲解卷积概念、常见算子和卷积边缘处理等


一、卷积运算

1.卷积概念

卷积是图像处理中一个操作,是kernel在图像的每个像素上的操作。

Kernel本质上一个固定大小的矩阵数组,其中心点称为锚点(anchor point)
C++ OpenCV4.5 卷积运算和卷积边缘处理(十一)_第1张图片

2.卷积工作原理

把kernel放到像素数组之上,求锚点周围覆盖的像素乘积之和(包括锚点),用来替换锚点覆盖下像素点值称为卷积处理,从左往右,从上往下,挨个计算每个点的像素值;
假设Kernel是个3×3的矩阵,并且每个点的像素值为1,则卷积运算公式如下:

Sum = 8x1+6x1+6x1+2x1+8x1+6x1+2x1+2x1+8x1
New pixel = sum / (m*n)
C++ OpenCV4.5 卷积运算和卷积边缘处理(十一)_第2张图片

3.常见算子

Robert算子(分别是 X 方向和 Y 方向)
C++ OpenCV4.5 卷积运算和卷积边缘处理(十一)_第3张图片
Sobel算子(分别是 X 方向和 Y 方向)
C++ OpenCV4.5 卷积运算和卷积边缘处理(十一)_第4张图片
拉普拉斯算子
C++ OpenCV4.5 卷积运算和卷积边缘处理(十一)_第5张图片

4.相关API

filter2D方法

filter2D(

  • Mat src, // 输入图像
  • Mat dst, // 模糊图像
  • int depth, // 图像深度32/8
  • Mat kernel, // 卷积核/模板
  • Point anchor, // 锚点位置
  • double delta // 计算出来的像素+delta )

其中 kernel是可以自定义的卷积核

C++ OpenCV4.5 卷积运算和卷积边缘处理(十一)_第6张图片

代码如下(示例):

#include 
#include 

using namespace std;
using namespace cv;

int g_iCount = 6;
char g_szOutputWnd[] = "输出图像";

void CallbackDemo(int pos, void* userdata)
{
	Mat srcImg = *((Mat*)userdata);
	Mat dstImg;

	switch (pos % g_iCount)
	{
	case 0:
	{
		// Robert X 方向
		Mat kernelX = (Mat_<int>(2, 2) << 1, 0, 0, -1);
		filter2D(srcImg, dstImg, -1, kernelX, Point(-1,-1), 0.0);
		break;
	}
	case 1:
	{
		// Robert Y 方向
		Mat kernelY = (Mat_<int>(2, 2) << 0, 1, -1, 0);
		filter2D(srcImg, dstImg, -1, kernelY);
		break;
	}
	case 2:
	{
		// Sobel X 方向
		Mat kernelX = (Mat_<int>(3, 3) << -1, 0, 1, -2, 0, 2, -1, 0, 1);
		filter2D(srcImg, dstImg, -1, kernelX);
		break;
	}
	case 3:
	{
		// Sobel Y 方向
		Mat kernelY = (Mat_<int>(3, 3) << -1, -2, -1, 0, 0, 0, 1, 2, 1);
		filter2D(srcImg, dstImg, -1, kernelY);
		break;
	}
	case 4:
	{
		// 拉普拉斯算子
		Mat kernel = (Mat_<int>(3, 3) << 0, -1, 0, -1, 4, -1, 0, -1, 0);
		filter2D(srcImg, dstImg, -1, kernel);
		break;
	}
	case 5:
	{
		// 自定义卷积模糊
		int iKSize = 3;		// 大于1的奇数
		Mat kernel = Mat::ones(Size(iKSize, iKSize), CV_32F) / (float)(iKSize * iKSize);
		filter2D(srcImg, dstImg, -1, kernel);
	}
	default:
		return;
	}

	imshow(g_szOutputWnd, dstImg);
}

int main(void)
{
	Mat srcImg;
	srcImg = imread("E:\\1.png");
	if (srcImg.empty())
	{
		cout << "load image fail..." << endl;
		return -1;
	}
	imshow("输入图像", srcImg);

	int iValue = 0;
	namedWindow(g_szOutputWnd);
	createTrackbar("算子", g_szOutputWnd, &iValue, g_iCount, (TrackbarCallback)CallbackDemo, (void*)&srcImg);
	
	CallbackDemo(iValue, (void*)&srcImg);

	waitKey(0);

	return 0;
}

二、卷积边缘处理

1.卷积边界问题

图像卷积的时候边界像素,不能被卷积操作,原因在于边界像素没有完全跟kernel重叠,所以当3x3滤波时候有1个像素的边缘没有被处理,5x5滤波的时候有2个像素的边缘没有被处理;

2.处理边缘

在卷积开始之前增加边缘像素,填充的像素值为0或者RGB黑色,比如3x3在
四周各填充1个像素的边缘,这样就确保图像的边缘被处理,在卷积处理之
后再去掉这些边缘。openCV中默认的处理方法是: BORDER_DEFAULT,此外
常用的还有如下几种:

  • BORDER_CONSTANT – 填充边缘用指定像素值
  • BORDER_REPLICATE – 填充边缘像素用已知的边缘像素值。
  • BORDER_WRAP – 用另外一边的像素来补偿填充

3.相关API

给图像添加边缘

copyMakeBorder(

  • Mat src, // 输入图像
  • Mat dst, // 添加边缘图像
  • int top, // 边缘长度,一般上下左右都取相同值,
  • int bottom,
  • int left,
  • int right,
  • int borderType // 边缘类型
  • Scalar value )

代码如下(示例):

#include 
#include 

using namespace std;
using namespace cv;

int g_iCount = 4;
char g_szOutputWnd[] = "输出图像";

void CallbackDemo(int pos, void* userdata)
{
	Mat srcImg = *((Mat*)userdata);
	Mat dstImg;

	int iTop = (int)(0.05 * srcImg.rows);
	int iBottom = (int)(0.05 * srcImg.rows);
	int iLeft = (int)(0.05 * srcImg.cols);
	int iRight = (int)(0.05 * srcImg.cols);
	int iBorderType = BORDER_DEFAULT;

	switch (pos % g_iCount)
	{
	case 0:
	{
		// 填充边缘用指定像素值
		iBorderType = BORDER_CONSTANT;
		break;
	}
	case 1:
	{
		// 填充边缘像素用已知的边缘像素值
		iBorderType = BORDER_REPLICATE;
		break;
	}
	case 2:
	{
		// 用另外一边的像素来补偿填充
		iBorderType = BORDER_WRAP;
		break;
	}
	default:
		// 默认-推荐
		iBorderType = BORDER_DEFAULT;
		break;
	}

	// 随机颜色
	Scalar color = Scalar(0, 255, 0);

	// color只有在iBorderType为BORDER_CONSTANT时才有效
	copyMakeBorder(srcImg, dstImg, iTop, iBottom, iLeft, iRight, iBorderType, color);

	/******************************高斯模糊边缘处理******************************/
	//GaussianBlur(srcImg, dstImg, Size(3, 3), 0, 0, iBorderType);

	imshow(g_szOutputWnd, dstImg);
}

int main(void)
{
	Mat srcImg;
	srcImg = imread("E:\\11.png");
	if (srcImg.empty())
	{
		cout << "load image fail..." << endl;
		return -1;
	}
	imshow("输入图像", srcImg);

	int iValue = 0;
	namedWindow(g_szOutputWnd);
	createTrackbar("处理边缘", g_szOutputWnd, &iValue, g_iCount, (TrackbarCallback)CallbackDemo, (void*)&srcImg);
	
	CallbackDemo(iValue, (void*)&srcImg);

	waitKey(0);

	return 0;
}

你可能感兴趣的:(OpenCV4.5学习记录,opencv,c++)