最近在学习OpenCV中的图像变换方面的知识,想就前面的学习进行个简单的总结。图像的变换就是将一幅图像转变成图像数据的另外一种表现形式。图像的变换有很多内容,主要涉及到图像的卷积滤波、扭曲、拉伸、霍夫变换、离散傅里叶变换等等。在这篇博文中,我们将先从图像的卷积开始讨论。
(1)卷积
关于卷积的数学理论,我们在信号与系统或者是积分变换的教材中已经多次提到,对于一维卷积通俗的来说,实际的过程就是f(x)先做一个Y轴的反转,然后再沿X轴平移t就是f(t-x),然后再把g(x)拿来,两者乘积的值再积分.想象一下如果g(x)或者f(x)是个单位的阶越函数。那么就是f(t-x)与g(x)相交部分的面积。而对于图像,我们可以定义图像为I(x,y),核为G(i,j),参考点位于相应核的(ai,aj)坐标上,则卷积H(x,y)定义如下:
一个特殊的卷积所实现的功能是由其卷积核的形式决定的。这个核的本质是一个大小固定、由数值参数构成的数组,数组的参考点通常位于数组的中心。数组的大小称为核支撑。
在OpenCV中,有函数cvFilter2D()来完成这样的操作。下面对这个函数做个简单的介绍。
void cvFilter2D(
const CvArr* src,
CvArr* dst,//源图像src和目标图像dst大小应该相同
const CvMat* kernel,//卷积核,单通道浮点矩阵
CvPoint anchor=cvPoint(-1,-1)//设置参考点为核的中心
)
(2)卷积边界
在刚才的介绍上,我们注意到一个问题,就是在函数cvFilter2D()函数中提及到源图像src和目标图像dst大小应该相同,但是也会出现大小不同的情况,那么OpenCV是怎么处理这种情况的呢?在默认的情况下,在卷积之前,OpenCV通过复制源图像src的边界创建了虚拟像素,这样以便于目标图像dst边界的像素可以被填充。但同时在OpenCV中也有函数cvCopyMakeBorder()函数,它可以将特定的图像轻微变大,然后以各种方式自动填充图像边界。下面简介下这个函数。
void cvCopyMakeBorder(
const CvArr* src,
CvArr* dst,
CvPoint offset,
int bordertype,
CvScalar value=cvScalarAll(0)
)
当调用OpenCV库函数中的卷积功能时,cvCopyMakeBorder()函数就会被自动调用,所以不用重复编辑这个函数。
(3)程序实例
#include<opencv2/opencv.hpp>
#include<iostream>
int main( )
{
IplImage* src, *dst;
float k[9] = { 1.0, -2.0, 1.0, 4.0,
-2.0, -1.0, 4.0, -2.0, 2.0 }; //核
CvMat km = cvMat(3, 3, CV_32FC1, k); //构造单通道浮点矩阵,将图像IplImage结构转换为图像数组
src = cvLoadImage("lena.JPG",CV_LOAD_IMAGE_UNCHANGED);
dst = cvCreateImage(cvGetSize(src), IPL_DEPTH_8U, 3);
cvNamedWindow("src", 0);
cvShowImage("src", src);
cvNamedWindow("Filtering", 0);
cvFilter2D(src, dst, &km, cvPoint(-1, -1)); //设参考点为核的中心
cvShowImage("Filtering", dst);
cvWaitKey(0);
cvReleaseImage(&src);
cvReleaseImage(&dst);
return 0;
}
最后的运行结果如图: