前言:
笔者目前在校本科大二,有志于进行计算机视觉、计算机图形学方向的研究,准备系统性地、扎实的学习一遍OpenCV的内容,故记录学习笔记,同时,由于笔者同时学习数据结构、机器学习等知识,会尽量根据自己的理解,指出OpenCV的应用,并在加上自己理解的前提下进行叙述。
若有不当之处,希望各位批评、指正。
本篇学习内容:
1.重映射
2.仿射变换
3.直方图均衡化
1.重映射
摘自《OpenCV3编程入门》:
重映射,就是把一幅图像中某位置的像素放置到另一个图片指定位置的过程。为了完成映射过程,需要获得一些插值为非整数像素的坐标,因为源图像与目标图像的像素坐标不是一一对应的。
用remap()进行重映射:
void cv::remap (
InputArray src, //输入图像
OutputArray dst, //输出图像
InputArray map1,
InputArray map2,
int interpolation, //插值方式
int borderMode = BORDER_CONSTANT, //边界模式
const Scalar & borderValue = Scalar() //边界值
)
remap()的公式如下:
对部分参数进行进一步介绍:
map1,map2: 有两种方式来输入这两个参数。
第一种方式是让map1表示src的x坐标的映射后的指定位置,map2表示src的y坐标的映射后的指定位置。
第二种方式是让map1表示src的(x,y)坐标的映射后的指定位置,这种情况下,map2可以输入一个空Mat类。
下面用一个例子来展示这两种方式:
Mat img = imread("E:/program/image/1.jpg");
//方式一
Mat map_x, map_y, dst;
dst.create(img.size(), img.type());
map_x.create(img.size(), CV_32F);
map_y.create(img.size(), CV_32F);
for (int i = 0; i < img.rows; i++) {
for (int j = 0; j < img.cols; j++) {
map_x.at<float>(i, j) = img.cols - j;
map_y.at<float>(i, j) = i;
}
}
//方式二
Mat map_xy, y, dst2;
map_xy.create(img.size(), CV_32FC2);
dst2.create(img.size(), img.type());
for (int i = 0; i < img.rows; i++) {
for (int j = 0; j < img.cols; j++) {
map_xy.at<Vec2f>(i, j)[0] = img.cols - j;
map_xy.at<Vec2f>(i, j)[1] = i;
}
}
remap(img, dst, map_x, map_y, INTER_NEAREST);
remap(img, dst2, map_xy, y, INTER_NEAREST);
imshow("img", img);
imshow("dst", dst);
imshow("dst2", dst2);
waitKey();
2.仿射变换
相信在高中数学中,大家就对仿射变换不陌生。线性代数中用矩阵变换的角度来进一步进行仿射变换的定义。在线性代数中,仿射变换可以理解为一个向量空间到另一个向量空间的映射(以矩阵相乘的形式),而保持一些性质不变。在对二维图像的处理中,我们可以把它再简化一下,即:对(x,y)左乘一个2×2的矩阵,再在右边加上一个2×1的常数(a,b)。这个2×2的矩阵和1×2的常数合起来是一个2×3的矩阵,这通常被称之为仿射变换矩阵M。
公式如下:(这即是warpAffine()的公式)
用warpAffine()进行仿射变换:
void cv::warpAffine (
InputArray src, //输入图像
OutputArray dst, //输出图像
InputArray M, //放射变换矩阵
Size dsize, //输出图像的大小 size
int flags = INTER_LINEAR, //标识符,插值方法和逆变换选项
int borderMode = BORDER_CONSTANT, //边界模式
const Scalar & borderValue = Scalar() //边界值
)
对部分参数进行进一步介绍:
flags: 这是插值方式和逆变换选项的组合标识符。比如说,可以设置一个插值方式,再设置WARP_INVERSE_MAP表明M是一个逆变换。
用getRotationMatrix2D()进行计算二维旋转变换矩阵:
Mat cv::getRotationMatrix2D (
Point2f center, //旋转中心
double angle, //旋转角度
double scale //缩放系数
)
注意:getRotationMatrix2D()只是用于获取一个旋转矩阵,这个矩阵是要输入到warpAffine()里面的。
用getAffineTransform()计算仿射变换矩阵:
Mat cv::getAffineTransform (
const Point2f src[],
const Point2f dst[]
)
输入的src[]和dst[]是2个三角形的顶点。
下面用一个例子来展示这三个函数:
Mat img = imread("E:/program/image/1.jpg");
Mat dst;
Mat M;
Point2f srcp[3];
Point2f dstp[3];
srcp[0] = Point2f(0, 0);
srcp[1] = Point2f(100, 100);
srcp[2] = Point2f(100, 0);
dstp[0] = Point2f(10, 10);
dstp[1] = Point2f(50, 80);
dstp[2] = Point2f(10, 50);
M = getAffineTransform(srcp, dstp);
Mat rotate;
rotate = getRotationMatrix2D(Point(100, 100), 30.0, 1.2);
warpAffine(img, dst, M, img.size());
warpAffine(dst, dst, rotate, img.size());
imshow("img", img);
imshow("dst", dst);
waitKey();
3.直方图均衡化
直方图均衡化就是用一定的算法使直方图大致平和的方法。
再具体一些,直方图均衡化就是通过拉伸像素强度分布范围来增强对比度的一种方法。
用equalizeHist()来进行直方图均衡化:
void cv::equalizeHist (
InputArray src,
OutputArray dst
)
注意:输入图像只能是8位单通道图像。
一个小例子:
Mat img = imread("E:/program/image/1.jpg");
Mat src;
cvtColor(img, src, COLOR_BGR2GRAY);
Mat dst;
equalizeHist(src, dst);
imshow("src", src);
imshow("dst", dst);
waitKey();
参考文献:
- OpenCV官方文档:https://docs.opencv.org/4.x/
- 《OpenCV3编程入门》毛星云、冷雪飞等编著