计算机视觉与计算机图形学的区别
- 图形学做的是如何将现实或者虚拟的场景在计算机上绘制出来,主要有虚拟仿真方向和游戏动漫方向。
- 两个学科有很多相通之处,图像的基础模型是一致的,都是根据计算机的特点设计的。还有一些基本变换也是通用的。
傅里叶变换对图像处理的意义
图像是由一组波组成,在图像处理中,频率域反应了图像在空间域灰度变化剧烈程度,也就是图像灰度的变化速度,也就是图像的梯度大小。那么图像的什么位置的频率比较高呢?显而易见,临界处,因此反应在频率域上是高频分量,图像的噪声大部分情况下是高频部分;图像平缓变化部分则为低频分量。也就是说,傅里叶变换提供另外一个角度来观察图像,可以将图像从灰度分布转化到频率分布上来观察图像的特征。书面一点说就是,傅里叶变换提供了一条从空间域到频率域自由转换的途径。
图像滤波/卷积
图像滤波的作用
- 滤波函数又叫做卷积核、卷积模板;滤波器、滤波模板
- 滤波是处理图像数据的常用基础操作
- 滤波操作可以去除图像中的噪声点,由此增强图像的特征可以根据卷积核的不同把图像滤波分为好多种。如中值滤波,高斯滤波和均值滤波。
滤波/卷积概念
- 卷积可以看成是一种结合了矩阵运算的计算方法
- ?(?)∗?(?)=∫_(−∞)^(+∞)▒?(?)?(?−?)??
卷积结果
图片中圈的红框就是要进行卷积的矩阵,卷积核为中间的矩阵,卷积核的参数和为1,进行卷积就是把图片中的9个值分别乘上对应卷积核的值再求和(3∗1+1∗1+2∗1+0∗0+5∗0+7∗0+1∗−1+8∗−1+2∗−1=−5),依次移动红框,进行同样步骤,便得到最右边4*4的矩阵,这就是卷积的结果。
图像求导
• 连续函数求导
• 使用有限差分表示图像的导数或者偏导数
• 矩阵求导:雅可比矩阵,海森矩阵
前向差分:f(x ) – f(x - 1)
中心差分:f(x + 1) – f(x - 1)
参数解释:
• x是像素在图片中的位置/坐标
• f(x )是与x相对应的图片像素值
边缘检测
图像梯度
- 图像梯度是由图像导数决定的,灰度图像I中亮度值的变化可以描述为x方向、y方向上的导数Ix, Iy。
- 图像导数的计算是通过离散估计得到的,即在x方向,y方向上进行以下的卷积操作: Ix = I * gx; Iy = I * gy;
举例:做一个X方向一阶差分,观察图像的边缘提取情况
Mat src = imread("D:/Android/workspace/lena.jpd",1); //从文件中读图像,图片必须在同一目录下,1为彩色,0为灰色
cvtColor(src, src, COLOR_BGR2GRAY); //函数的作用是将一个图像从一个颜色空间转换到另一个颜色空间
namedWindow("src", WINDOW_AUTOSIZE); //创建一个窗口,窗口大小不可改变
imshow("src", src); //显示src窗口
Mat dImg = Mat(src.rows, src.cols - 2, CV_8UC1);//创建一个和原始图像src高一致,宽减2的一个像素点元素占8位无符号单通道的图片容器
//用于存放对srcX方向求导后的图像,边缘两列不求导,故列数减2
for (int i = 0; i < src.rows; i++) //两层for循环实现对x方向一阶差分边缘检测后的图片相应的像素值复制到dImg
{
for (int j = 1; j < src.cols - 1; j++) //对列循环,从第1列到src.cols-2列
{
dImg.at<uchar>(i, j - 1) = src.at<uchar>(i, j + 1)- src.at<uchar>(i, j - 1);//x方向求导
}
}
namedWindow("dImg", CV_WINDOW_AUTOSIZE);
imshow("dImg", dImg);
waitKey(0); //等待按键
结果:
原图:
检测后效果图:
高斯模糊
高斯模糊,也叫高斯平滑,通常用它来减少图像噪声以及降低细节层次。从数学的角度来看,图像的高斯模糊过程就是图像与正态分布做卷积。由于正态分布又叫作高斯分布,所以这项技术就叫作高斯模糊。可以理解为图像中的每个像素都重新设置像素值为周边相邻像素的平均值。
高斯函数
一维高斯函数形式如下:
有两个参数 μ和σ,期望值μ决定高斯函数的位置,标准差σ 决定高斯函数的胖瘦,σ 越小越瘦,关注的区域越集中
根据一维高斯函数,可以推导二维高斯函数形式如下:
参数解释:
• x, y是卷积参数坐标
• σ是标准差
画出的二维高斯函数如下图所示 :
举例:高斯模糊卷积操作 5 * 5
Mat src = imread("D:/Android/workspace/lena.jpg", 1);
cvtColor(src, src, COLOR_BGR2GRAY);
namedWindow("src", WINDOW_NORMAL);
imshow("src", src);
Mat model = Mat(5, 5, CV_64FC1); //创建一个5*5,一个像素点元素占64位浮点型单通道的高斯模板
double sigma = 80;
for (int i = -2; i <= 2; i++)
{
for (int j = -2; j <= 2; j++)
{
model.at<double>(i + 2, j + 2) =
exp(-(i*i + j * j) / (2 * sigma*sigma)) /
(2 * PI*sigma*sigma); //二维高斯函数,给高斯模板各元素进行赋值
}
}
double gaussSum = 0;
gaussSum = sum(model).val[0]; //高斯模板的所有元素求和
for (int i = 0; i < model.rows; i++)
{
for (int j = 0; j <model.cols; j++)
{
model.at<double>(i, j) = model.at<double>(i, j) / gaussSum; //卷积核的参数和要为1,所以要将高斯模板归1化
}
}
Mat dst = Mat(src.rows - 4, src.cols - 4, CV_8UC1); //左右两列上下两行无法进行卷积运算,故各减4
for (int i = 2; i < src.rows - 2; i++)
{
for (int j=2; j < src.cols - 2; j++)
{
double sum = 0;
for (int m = 0; m < model.rows; m++)
{
for (int n = 0; n < model.cols; n++)
{
sum += (double)src.at<uchar>(i + m - 2, j + n - 2)* model.at<double>(m, n); //与上面卷积结果的原理一样,若有不懂,可看上面的卷积结果分析即可
}
}
dst.at<uchar>(i - 2, j - 2) = (uchar)sum; //将卷积结果依次赋值给新创建的dst矩阵
}
}
namedWindow("dst", WINDOW_AUTOSIZE);
imshow("dst", dst);
waitKey(0);
结果:
原图:
高斯模糊后效果图:
参考链接:https://blog.csdn.net/zxfhahaha/article/details/80139430