OpenCV图像特征提取与检测C++(四)仿射变换、积分图计算

仿射变换(Affine Transformation或 Affine Map),又称仿射映射,是指在几何中,一个向量空间进行一次线性变换并接上一个平移,变换为另一个向量空间的过程。它保持了二维图形的“平直性”(即:直线经过变换之后依然是直线)和“平行性”(即:二维图形之间的相对位置关系保持不变,平行线依然是平行线,且直线上点的位置顺序不变)。
一个任意的仿射变换都能表示为乘以一个矩阵(线性变换)接着再加上一个向量(平移)的形式。
三种常见的变换形式:

  • 旋转,rotation (线性变换)
  • 平移,translation(向量加)
  • 缩放,scale(线性变换)

仿射变换针对的是平面上的物体位姿变化,如水平/垂直方向位移、旋转、缩小/放大,常见的应用有ORC字符识别。投影变换针对的是三维空间中的位置变化,受限于物体依然是平面的,也称为二维投影变换,常见的应用有车牌识别。
使用OpenCV函数warpAffine 来实现一些简单的重映射。
使用OpenCV函数getRotationMatrix2D 来获得旋转矩阵。

warpAffine函数

void warpAffine(InputArray src,//输入图像,即源图像,填Mat类的对象即可
OutputArray dst, //函数调用后的运算结果存在这里,需和源图片有一样的尺寸和类型
InputArray M, //2×3的变换矩阵
Size dsize, //表示输出图像的尺寸
int flags=INTER_LINEAR,//插值方法的标识符。此参数有默认值INTER_LINEAR(线性插值),可选的插值方式如下:
//INTER_NEAREST - 最近邻插值
//INTER_LINEAR - 线性插值(默认值)
//INTER_AREA - 区域插值
//INTER_CUBIC –三次样条插值
//INTER_LANCZOS4 -Lanczos插值
//CV_WARP_FILL_OUTLIERS - 填充所有输出图像的象素。如果部分象素落在输入图像的边界外,那么它们的值设定为 fillval.
//CV_WARP_INVERSE_MAP –表示M为输出图像到输入图像的反变换,即 。因此可以直接用来做象素插值。否则, warpAffine函数从M矩阵得到反变换
intborderMode=BORDER_CONSTANT, //边界像素模式,默认值为BORDER_CONSTANT。
const Scalar& borderValue=Scalar())//在恒定的边界情况下取的值,默认值为Scalar(),即0

getRotationMatrix2D

Mat getRotationMatrix2D(Point2fcenter, //表示源图像的旋转中心
double angle, //旋转角度。角度为正值表示向逆时针旋转(坐标原点是左上角)
double scale)//缩放系数

代码:

#include <opencv2/opencv.hpp>
#include <opencv2/xfeatures2d.hpp>
#include<iostream>
#include<math.h>
#include <string> 
#include<fstream> 
using namespace cv;
using namespace std;
using namespace cv::xfeatures2d;

int main()
{
    //定义两组点,代表两个三角形
    Point2f srcTriangle[3];
    Point2f dstTriangle[3];
    //定义一些Mat变量
    Mat rotMat(2, 3, CV_32FC1);
    Mat warpMat(2, 3, CV_32FC1);
    Mat src, dst_warp, dst_warp_rotate;

    src = imread("C:/Users/Administrator/Desktop/pic/5.jpg");
    dst_warp = Mat::zeros(src.rows, src.cols, src.type());

    //设置源图像和目标图像上的三组点以计算仿射变换
    srcTriangle[0] = Point2f(0, 0);
    srcTriangle[1] = Point2f(static_cast<float>(src.cols - 1), 0);
    srcTriangle[2] = Point2f(0, static_cast<float>(src.rows - 1));

    dstTriangle[0] = Point2f(static_cast<float>(src.cols*0.0), static_cast<float>(src.rows*0.33));
    dstTriangle[1] = Point2f(static_cast<float>(src.cols*0.65), static_cast<float>(src.rows*0.35));
    dstTriangle[2] = Point2f(static_cast<float>(src.cols*0.15), static_cast<float>(src.rows*0.6));

    //仿射变换
    warpMat = getAffineTransform(srcTriangle, dstTriangle);
    warpAffine(src, dst_warp, warpMat, dst_warp.size());

    //对图像进行缩放后再旋转
    // 计算绕图像中点顺时针旋转50度缩放因子为0.6的旋转矩阵
    Point center = Point(dst_warp.cols / 2, dst_warp.rows / 2);
    double angle = -30.0;
    double scale = 0.8;
    // 通过上面的旋转细节信息求得旋转矩阵
    rotMat = getRotationMatrix2D(center, angle, scale);
    // 旋转已缩放后的图像
    warpAffine(dst_warp, dst_warp_rotate, rotMat, dst_warp.size());
    imshow("src", src);
    imshow("dst1", dst_warp);
    imshow("dst", dst_warp_rotate);

    waitKey(0);
}

结果:
这里写图片描述

积分图计算
积分图:将图像中任意一点的像素值变成其左上角所有像素值的总和(包含其自身像素值)得出的图像就叫积分图通过积分图像,可以加快计算速度。
API:

void integral( // 积分图计算
    InputArray src, // 输入图像,灰度图
    OutputArray sum, // 求和,输出的尺寸比原图行列都要加1 , 不想行列变化的,自己实现积分图算法
    OutputArray sqsum, // 求和的平方,输出的尺寸比原图行列都要加1
    OutputArray tilted, // 旋转45°的积分图
    int sdepth = -1, 
    int sqdepth = -1 
);

代码:

#include <opencv2/opencv.hpp>
#include <opencv2/xfeatures2d.hpp>
#include<iostream>
#include<math.h>
#include <string> 
#include<fstream> 
using namespace cv;
using namespace std;
using namespace cv::xfeatures2d;

int main() {
    Mat src = imread("C:/Users/Administrator/Desktop/pic/1.jpg",0);
    imshow("input", src);
    Mat dst1 = Mat::zeros(src.rows + 1, src.cols + 1, CV_32FC1);
    Mat dst2 = Mat::zeros(src.rows + 1, src.cols + 1, CV_64FC1);
    integral(src, dst1, dst2);
    Mat res1, res2;
    normalize(dst1, res1, 0, 255, NORM_MINMAX,CV_8UC1);
    imshow("dst1", dst1);
    normalize(dst2, res2, 0, 255, NORM_MINMAX,CV_8UC1);
    imshow("dst2", dst2);

    waitKey(0);
}

结果:这里写图片描述

猜你喜欢

转载自blog.csdn.net/qq_26907755/article/details/81744282