由于工作原因,最近开始研究图像处理相关技术,开始接触OpenCV,主要是为了重构PACS系统中的平移、缩放和旋转三个图像操作的接口函数。opencv作为目前计算机视觉领域的热门开源库,有着稳定且功能强大的优点。下面是刚接触时的一些研究,主要是学习仿射,及一些相关的函数接口的使用,这里整理一下,方便以后查看,若有错误的地方还请谅解,随意评论纠正!
看到很多代码示例都有cv::Mat的字眼,cv是opencv中的一个头文件,我们先简单介绍一下Mat这个类
cv::Mat: 用于分配内存创建对象
采用类的特性,将内存管理和数据信息封装在类的内部,学过c++11的小伙伴应该就很熟悉,这个描述与智能指针很像
主要组成:矩阵头和矩阵数据
拷贝赋值:采用浅拷贝的方式,只复制矩阵头信息,引用矩阵数据
优点:
- 不需要手动申请一块内存;
- 在不需要时不用再手动释放内存;
- 可以通过类的封装,方便的获取到数据的相关信息。
看完它所具有的优点,让人联想到C++11的共享指针,而Mat也是采取引用计数的方法,当引用计数变为0时释放内存。
接下来接下一些接口函数:
Mat imread(const string &filename, int flag = 1)
功能:读取图像
filename:图片路径名
flag:载入标识,指定加载图像的颜色类型,默认值为1,表示三通道的彩色图像
-1:表示按解码得到的方式读入图像
0:表示按单通道方式读入图像,即灰白图像
void imshow(const string &winname, InputArray mat)
功能:显示图像
winname:显示的窗口标题,若无namedWinodw创建窗口则自动创建
mat:需要显示的图像
void nameWindow(const string& winname, int flags = WINDOW_AUTOSIZE)
功能:新建一个显示窗口
Winname:新建的窗口名称
flags :窗口标识
- WINDOW_ANTOSIZE: 窗口自动适用图片大小,且不可手动更改大小
- WINDOW_NORMAL : 可手动修改大小
- WINDOW_OPENGL : 窗口创建时支持OpenGL
Mat getRotationMatrix2D(Point2f center, double angle, double scale)
功能:获取图像绕着某一点的旋转矩阵
center:旋转的中心
angle:旋转的角度
scale:图像的缩放因子
static cv::MatExpr cv::Mat::zeros(int rows, int cols, int type)
功能:设置图像大小类型
rows:行数
cols:列数
type:类型
Mat getAffineTransform( const Point2f* src, const Point2f* dst )
功能:获得根据三点计算的仿射变换矩阵
src:输入图像的三点坐标
dst:输出图像的三点坐标
void warpAffine(InputArray src, OutputArray dst, InputArray M, Size dSize,
int flags = INTER_LINEAR, int borderMode = BORDER_CONSTANT,
const Scalar &borderValue = Scalar())
功能:仿射变换
src:输入图像
dst:输出图像
M:仿射变换矩阵
dSize:输出图像的尺寸
flags :插值算法标识符,默认为INTER_LINEAR
- INTER_NEAREST : 最邻近插值算法
- INTER_LINEAR : 线性插值算法
- INTER_CUBIC : 双立法插值算法
- INTER_AREA : 区域插值算法
- INTER_LANCZOS4 : Lanczos插值(超过8x8邻域的插值)
- INTER_MAX : 用于插值的掩模板
- WARP_FILL_OUTLIERS : 标志位,用于填充目标图像像素值,如果其中的 一些值对应于原图像的异常值,则这 些值复位
- WARP_INVERSE_MAP :标志位,反变换
borderMode :边界像素模式,默认为BORDER_CONSTANT
- BORDER_DEFAULT : 块复制
- BORDER_CONSTANT : 补零
- BORDER_REPLICATE : 边界复制
- BORDER_WRAP : 镜像
borderValue :边界取值,默认为Scalar(),即0
下面来份代码示例(转载自https://www.cnblogs.com/wyuzl/p/7865536.html,里面有详细的代码说明):
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include
#include
using namespace cv;
using namespace std;
/// 全局变量
char* source_window = "Source image";
char* warp_window = "Warp";
char* warp_rotate_window = "Warp + Rotate";
/** @function main */
int main(int argc, char** argv)
{
Point2f srcTri[3];
Point2f dstTri[3];
Mat rot_mat(2, 3, CV_32FC1);
Mat warp_mat(2, 3, CV_32FC1);
Mat src, warp_dst, warp_rotate_dst;
/// 加载源图像
src = imread(argv[1], 1);
/// 设置目标图像的大小和类型与源图像一致
warp_dst = Mat::zeros(src.rows, src.cols, src.type());
/// 设置源图像和目标图像上的三组点以计算仿射变换
srcTri[0] = Point2f(0, 0);
srcTri[1] = Point2f(src.cols - 1, 0);
srcTri[2] = Point2f(0, src.rows - 1);
dstTri[0] = Point2f(src.cols*0.0, src.rows*0.33);
dstTri[1] = Point2f(src.cols*0.85, src.rows*0.25);
dstTri[2] = Point2f(src.cols*0.15, src.rows*0.7);
/// 求得仿射变换
warp_mat = getAffineTransform(srcTri, dstTri);
/// 对源图像应用上面求得的仿射变换
warpAffine(src, warp_dst, warp_mat, warp_dst.size());
/** 对图像扭曲后再旋转 */
/// 计算绕图像中点顺时针旋转50度缩放因子为0.6的旋转矩阵
Point center = Point(warp_dst.cols / 2, warp_dst.rows / 2);
double angle = -50.0;
double scale = 0.6;
/// 通过上面的旋转细节信息求得旋转矩阵
rot_mat = getRotationMatrix2D(center, angle, scale);
/// 旋转已扭曲图像
warpAffine(warp_dst, warp_rotate_dst, rot_mat, warp_dst.size());
/// 显示结果
namedWindow(source_window, CV_WINDOW_AUTOSIZE);
imshow(source_window, src);
namedWindow(warp_window, CV_WINDOW_AUTOSIZE);
imshow(warp_window, warp_dst);
namedWindow(warp_rotate_window, CV_WINDOW_AUTOSIZE);
imshow(warp_rotate_window, warp_rotate_dst);
/// 等待用户按任意按键退出程序
waitKey(0);
return 0;
}