卷积核与图像特征提取

关于卷积

卷积是分析数学中一种重要的运算。卷积是一种线性运算,图像处理中常见的mask运算都是卷积,广泛应用于图像滤波。高斯变换就是用高斯函数对图像进行卷积,卷积操作是图像变换的基础。如果我们称 (f*g) (n)是f、g的卷积:
连续型卷积的公式

离散型卷积的公式

从中我们可以得出

假设现有两个骰子,随机掷骰子点数和为4

那么这样的概率就是f(1)*g(3)+f(2)*g(2)+f(3)*g(1) ,符合:


下面这张图可以很好的帮助理解卷积:

用一个模板和一幅图像进行卷积,对于图像上的一个点,让模板的原点和该点重合,然后模板上的点和图像上对应的点相乘,然后各点的积相加,就得到了该点的卷积值。对图像上的每个点都这样处理。由于大多数模板都是对称的,所以模板不旋转。卷积是一种积分运算,用来求两个曲线重叠区域面积。可以看作加权求和,可以用来消除噪声、特征增强。
把一个点的像素值用它周围的点的像素值的加权平均代替。
卷积是一种线性运算,图像处理中常见的mask运算都是卷积,广泛应用于图像滤波。
卷积关系最重要的一种情况,就是在信号与线性系统或数字信号处理中的卷积定理。利用该定理,可以将时间域或空间域中的卷积运算等价为频率域的相乘运算,从而利用FFT等快速算法,实现有效的计算,节省运算代价。

卷积核
这个核本质上是一个大小固定,由数值参数构成的数组,数组的标定点通常位于数组的中心。数组的大小被称为核支撑。单就技术而言,核支撑实际上仅仅由核数组的非零部分组成。
上图中不停移动的白色块变是卷积核!

opencv的图像卷积函数:cvFilter2D、filter2D()
cvFilter2D() —— opencv中的c语言函数
src:输入图像.
dst:输出图像.
kernel:卷积核, 单通道浮点矩阵. 如果想要应用不同的核于不同的通道,先用 cvSplit 函数分解图像到单个色彩通道上,然后单独处理。
anchor:核的锚点表示一个被滤波的点在核内的位置。 锚点应该处于核内部。缺省值 (-1,-1) 表示锚点在核中心。
函数 cvFilter2D 对图像进行线性滤波,支持 In-place 操作。当核运算部分超出输入图像时,函数从最近邻的图像内部象素差值得到边界外面的象素值。

void cvFilter2D( const CvArr* src, CvArr* dst,
                 const CvMat* kernel,
                 CvPoint anchor = cvPoint(-1,-1));

filter2D() ——— opencv中的c++函数
InputArray src: 输入图像
OutputArray dst: 输出图像,和输入图像具有相同的尺寸和通道数量
int ddepth: 目标图像深度,如果没写将生成与原图像深度相同的图像。原图像和目标图像支持的
当ddepth输入值为-1时,目标图像和原图像深度保持一致
InputArray kernel: 卷积核(或者是相关核), 一个单通道浮点型矩阵。如果想在图像不同的通道使用不同的kernel,可以先使用split()函数将图像通道事先分开
Point anchor: 内核的基准点(anchor),其默认值为(-1,-1)说明位于kernel的中心位置。基准点即kernel中与进行处理的像素点重合的点
double delta: 在储存目标图像前可选的添加到像素的值,默认值为0
int borderType: 像素向外逼近的方法,默认值是BORDER_DEFAULT,即对全部边界进行计算。
该函数使用于任意线性滤波器的图像,支持就地操作。当其中心移动到图像外,函数可以根据指定的边界模式进行插值运算。函数实质上是计算kernel与图像的相关性而不是卷积!

CV_EXPORTS_W void filter2D( InputArray src, OutputArray dst, int ddepth,
                            InputArray kernel, Point anchor=Point(-1,-1),
                            double delta=0, int borderType=BORDER_DEFAULT );

原理
对于图像的每一个像素点,计算它的邻域像素和滤波器矩阵的对应元素的乘积,然后加起来,作为该像素位置的值,这样就完成了滤波过程!

卷积与相关
对图像和滤波矩阵进行逐个元素相乘再求和的操作就相当于将一个二维的函数移动到另一个二维函数的所有位置,这个操作就叫卷积或者相关。卷积和相关的差别是,卷积需要先对滤波矩阵进行180的翻转,但如果矩阵是对称的,那么两者就没有什么差别了。
图像卷积操作的本质是矩阵卷积。某些特殊的卷积核会使图像产生特殊的效果:

图像处理
下面把均把相关性计算看成是卷积运算,从本质上来说其实就是卷积运算,相当于把矩阵旋转了180°所以看成是卷积!

边缘检测卷积核

图像锐化卷积核

 

 

 

 


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

using namespace cv;
using namespace std;

int main(int argc, char *argv[]) {	
	Mat src = imread("C:\\Users\\Tim\\Desktop\\Image\\book.png");

	namedWindow("src_window", CV_WINDOW_AUTOSIZE);
	imshow("src_window", src);

	Mat dst = Mat::zeros(src.size(), src.type());

	//定义卷积核

	//边缘检测
	//Mat C = (Mat_<double>(3, 3) << -1, -2, -1, 0, 0, 0, 1, 2, 1); // Sobel算子 横向边缘检测
	//Mat C = (Mat_<double>(3, 3) << -1,  0, 1, -2, 0, 2, -1, 0, 1); // Sobel算子 纵向边缘检测
	//Mat C = (Mat_<double>(3, 3) << -1, -1, -1, 0, 0, 0, 1, 1, 1); // Prewitt算子 横向边缘检测
	//Mat C = (Mat_<double>(3, 3) << -1, 0, 1, -1, 0, 1, -1, 0, 1); // Prewitt算子 纵向边缘检测
	//Mat C = (Mat_<double>(3, 3) << -1, -1, -1, -1, 8, -1, -1, -1, -1); // Laplacian算子 边缘检测

	//图像锐化
	//Mat C = (Mat_<double>(3, 3) << -1, -1, -1, -1, 9, -1, -1, -1, -1);
	//Mat C = (Mat_<double>(3, 3) << 1, 1, 1, 1, -7, 1, 1, 1, 1);//更加强调边缘的锐化

	//浮雕
	//Mat C = (Mat_<double>(3, 3) << -6, -3, 0, -3, 1, 3, 0, 3, 6);
	filter2D(src, dst, src.depth(), C, Point(-1, -1));

	namedWindow("dst_window", CV_WINDOW_AUTOSIZE);
	imshow("dst_window", dst);

	moveWindow("src_window", 1, 1);
	moveWindow("dst_window", 1, 1);
	waitKey(0);
	return 0;
}
#include <iostream>
#include <opencv2\opencv.hpp>

using namespace cv;
using namespace std;

int main(int argc, char *argv[]){

	//Mat src = imread("C:\\Users\\Tim\\Desktop\\Image\\a.jpg");
	Mat src = imread("C:\\Users\\Tim\\Desktop\\test.png");
	if (src.empty()){
		cout << "load image filed..." << endl;
		return -1;
	}

	namedWindow("src_window", CV_WINDOW_AUTOSIZE);
	imshow("src_window", src);

	namedWindow("dst_window", CV_WINDOW_AUTOSIZE);
	Mat dst;
	//3*3均值滤波模糊
	blur(src, dst, Size(3, 3), Point(-1, -1));
	//GaussianBlur(src, dst, Size(3, 3), 11, 11);//高斯滤波
	imshow("dst_window", dst);
	waitKey(0);
	return 0;
}

 

\

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

using namespace cv;
using namespace std;

int main(int argc, char **argv)
{

	Mat src = imread("C:\\Users\\Tim\\Desktop\\Image\\notbeautify1.png");
	//Mat src = imread("C:\\Users\\Tim\\Desktop\\Image\\AI.png");

	Mat dst;
	if (src.empty())
	{
		cout << "load image filed..." << endl;
		return -1;
	}

	namedWindow("src_window", CV_WINDOW_AUTOSIZE);
	imshow("src_window", src);


	//中值滤波去掉椒盐噪声
	//medianBlur(src, dst, 3);

	//双边滤波
	bilateralFilter(src, dst, 15, 100, 3);
	namedWindow("medianBlur_dst", CV_WINDOW_AUTOSIZE);
	imshow("medianBlur_dst", dst);


	Mat gblur;
	GaussianBlur(src, gblur, Size(15, 15), 3, 3);
	namedWindow("HelloWorld",CV_WINDOW_AUTOSIZE);
	namedWindow("bglur_dst", CV_WINDOW_AUTOSIZE);
	imshow("bglur_dst", gblur);

	//通过掩模提升对比度
	Mat retImg;
	Mat kernal = (Mat_<int>(3, 3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);
	filter2D(dst, retImg, dst.depth(), kernal, Point(-1, -1), 0);

	namedWindow("retImg", CV_WINDOW_AUTOSIZE);
	imshow("retImg", retImg);

	waitKey(0);
	return 0;
}

--------------------- 
作者:TimGitChat 
来源:CSDN 
原文:https://blog.csdn.net/m0_38032942/article/details/82230059 
版权声明:本文为博主原创文章,转载请附上博文链接!

猜你喜欢

转载自blog.csdn.net/viafcccy/article/details/88809178