仿射变换综合示例
视频讲解如下:
当前系列所有demo下载地址:
https://github.com/GaoRenBao/OpenCv4-Demo
不同编程语言对应的OpenCv版本以及开发环境信息如下:
语言 | OpenCv版本 | IDE |
C# | OpenCvSharp4.4.8.0.20230708 | Visual Studio 2022 |
C++ | OpenCv-4.5.5-vc14_vc15 | Visual Studio 2022 |
Python | OpenCv-Python (4.6.0.66) | PyCharm Community Edition 2022.1.3 |
本章节给大家讲讲如何实现仿射变换。当前代码主体还是使用毛星云的demo,C#和Python都是在C++版本的基础上转换过来的,三个版本的效果基本一致。
首先我们需要准备一张测试图片:
三组代码运行效果都是一样的,我这里就不一一展示了,最终运行效果如下:
C#版本代码如下:
C#版本需要安装“OpenCvSharp4”、“OpenCvSharp4.runtime.win”两个库才行。不然会报错。
如果需要使用“ BitmapConverter.ToBitmap”操作,则需要追加安装“OpenCvSharp4.Extensions”库。
/*
OpenCv版本 OpenCvSharp4.4.8.0.20230708
内容:仿射变换综合示例
博客:/Course?id=2768964000187
作者:高仁宝
时间:2023.11
*/
using OpenCvSharp;
using System.Collections.Generic;
namespace demo
{
internal class Program
{
public static string WINDOW_NAME1 = "【原始图窗口】";//为窗口标题定义的宏
public static string WINDOW_NAME2 = "【经过Warp后的图像】";//为窗口标题定义的宏
public static string WINDOW_NAME3 = "【经过Warp和Rotate后的图像】";//为窗口标题定义的宏
static void Main(string[] args)
{
//【1】参数准备
//定义两组点,代表两个三角形
List<Point2f> srcTriangle = new List<Point2f>();
List<Point2f> dstTriangle = new List<Point2f>();
//定义一些Mat变量
Mat rotMat = new Mat(2, 3, MatType.CV_32FC1);
Mat warpMat = new Mat(2, 3, MatType.CV_32FC1);
Mat dstImage_warp_rotate = new Mat();
//【2】加载源图像并作一些初始化
Mat srcImage = Cv2.ImRead("../../../images/tree.jpg");
// 设置目标图像的大小和类型与源图像一致
Mat dstImage_warp = new Mat(srcImage.Size(), srcImage.Type());
//【3】设置源图像和目标图像上的三组点以计算仿射变换
srcTriangle.Add(new Point2f(0, 0));
srcTriangle.Add(new Point2f(srcImage.Cols - 1, 0));
srcTriangle.Add(new Point2f(0, srcImage.Rows - 1));
dstTriangle.Add(new Point2f((float)(srcImage.Cols * 0.0), (float)(srcImage.Rows * 0.33)));
dstTriangle.Add(new Point2f((float)(srcImage.Cols * 0.65), (float)(srcImage.Rows * 0.35)));
dstTriangle.Add(new Point2f((float)(srcImage.Cols * 0.15), (float)(srcImage.Rows * 0.6)));
//【4】求得仿射变换
warpMat = Cv2.GetAffineTransform(srcTriangle, dstTriangle);
//【5】对源图像应用刚刚求得的仿射变换
Cv2.WarpAffine(srcImage, dstImage_warp, warpMat, dstImage_warp.Size());
//【6】对图像进行缩放后再旋转
// 计算绕图像中点顺时针旋转50度缩放因子为0.6的旋转矩阵
Point center = new Point(dstImage_warp.Cols / 2, dstImage_warp.Rows / 2);
double angle = -50.0;
double scale = 0.6;
// 通过上面的旋转细节信息求得旋转矩阵
rotMat = Cv2.GetRotationMatrix2D(center, angle, scale);
// 旋转已缩放后的图像
Cv2.WarpAffine(dstImage_warp, dstImage_warp_rotate, rotMat, dstImage_warp.Size());
//【7】显示结果
Cv2.ImShow(WINDOW_NAME1, srcImage);
Cv2.ImShow(WINDOW_NAME2, dstImage_warp);
Cv2.ImShow(WINDOW_NAME3, dstImage_warp_rotate);
// 等待用户按任意按键退出程序
Cv2.WaitKey(0);
}
}
}
C++演示代码如下:
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
using namespace cv;
using namespace std;
#define WINDOW_NAME1 "【原始图窗口】" //为窗口标题定义的宏
#define WINDOW_NAME2 "【经过Warp后的图像】" //为窗口标题定义的宏
#define WINDOW_NAME3 "【经过Warp和Rotate后的图像】" //为窗口标题定义的宏
int main()
{
//【1】参数准备
//定义两组点,代表两个三角形
Point2f srcTriangle[3];
Point2f dstTriangle[3];
//定义一些Mat变量
Mat rotMat(2, 3, CV_32FC1);
Mat warpMat(2, 3, CV_32FC1);
Mat srcImage, dstImage_warp, dstImage_warp_rotate;
//【2】加载源图像并作一些初始化
srcImage = imread("../images/tree.jpg");
if (!srcImage.data) { printf("读取图片错误,请确定目录下是否有imread函数指定的图片存在~! \n"); return false; }
// 设置目标图像的大小和类型与源图像一致
dstImage_warp = Mat::zeros(srcImage.rows, srcImage.cols, srcImage.type());
//【3】设置源图像和目标图像上的三组点以计算仿射变换
srcTriangle[0] = Point2f(0, 0);
srcTriangle[1] = Point2f(static_cast<float>(srcImage.cols - 1), 0);
srcTriangle[2] = Point2f(0, static_cast<float>(srcImage.rows - 1));
dstTriangle[0] = Point2f(static_cast<float>(srcImage.cols * 0.0), static_cast<float>(srcImage.rows * 0.33));
dstTriangle[1] = Point2f(static_cast<float>(srcImage.cols * 0.65), static_cast<float>(srcImage.rows * 0.35));
dstTriangle[2] = Point2f(static_cast<float>(srcImage.cols * 0.15), static_cast<float>(srcImage.rows * 0.6));
//【4】求得仿射变换
warpMat = getAffineTransform(srcTriangle, dstTriangle);
//【5】对源图像应用刚刚求得的仿射变换
warpAffine(srcImage, dstImage_warp, warpMat, dstImage_warp.size());
//【6】对图像进行缩放后再旋转
// 计算绕图像中点顺时针旋转50度缩放因子为0.6的旋转矩阵
Point center = Point(dstImage_warp.cols / 2, dstImage_warp.rows / 2);
double angle = -50.0;
double scale = 0.6;
// 通过上面的旋转细节信息求得旋转矩阵
rotMat = getRotationMatrix2D(center, angle, scale);
// 旋转已缩放后的图像
warpAffine(dstImage_warp, dstImage_warp_rotate, rotMat, dstImage_warp.size());
resize(srcImage, srcImage, Size(srcImage.cols * 0.7, srcImage.rows * 0.7), (0, 0), (0, 0), 3);
resize(dstImage_warp, dstImage_warp, Size(dstImage_warp.cols * 0.7, dstImage_warp.rows * 0.7), (0, 0), (0, 0), 3);
resize(dstImage_warp_rotate, dstImage_warp_rotate, Size(dstImage_warp_rotate.cols * 0.7, dstImage_warp_rotate.rows * 0.7), (0, 0), (0, 0), 3);
//【7】显示结果
imshow(WINDOW_NAME1, srcImage);
imshow(WINDOW_NAME2, dstImage_warp);
imshow(WINDOW_NAME3, dstImage_warp_rotate);
// 等待用户按任意按键退出程序
waitKey(0);
return 0;
}
Python演示代码如下:
import cv2
import numpy as np
#【1】载入原始图
srcImage = cv2.imread("../images/tree.jpg")
cv2.imshow("srcImage", srcImage)
#【2】设置目标图像的大小和类型与源图像一致
dstImage_warp = np.ones(srcImage.shape,srcImage.dtype)
#【3】设置源图像和目标图像上的三组点以计算仿射变换
srcTriangle = np.float32([
[0,0],
[srcImage.shape[1] - 1,0],
[0,srcImage.shape[0] - 1]
])
dstTriangle = np.float32([
[srcImage.shape[1] * 0.0,srcImage.shape[0] * 0.33],
[srcImage.shape[1] * 0.65,srcImage.shape[0] * 0.35],
[srcImage.shape[1] * 0.15,srcImage.shape[0] * 0.6]
])
#【4】求得仿射变换
warpMat = cv2.getAffineTransform(srcTriangle,dstTriangle)
#【5】对源图像应用刚刚求得的仿射变换
dstImage_warp = cv2.warpAffine(srcImage,warpMat,(srcImage.shape[1],srcImage.shape[0]))
#【6】对图像进行缩放后再旋转
# 计算绕图像中点顺时针旋转50度缩放因子为0.6的旋转矩阵
center = (dstImage_warp.shape[1] / 2, dstImage_warp.shape[0] / 2)
angle = -50.0
scale = 0.6
# 通过上面的旋转细节信息求得旋转矩阵
rotMat = cv2.getRotationMatrix2D(center, angle, scale)
# 旋转已缩放后的图像
dstImage_warp_rotate = cv2.warpAffine(dstImage_warp, rotMat, (dstImage_warp.shape[1],dstImage_warp.shape[0]))
#【7】显示效果图
cv2.imshow('dstImage_warp',dstImage_warp)
cv2.imshow('dstImage_warp_rotate',dstImage_warp_rotate)
cv2.waitKey(0)
cv2.destroyAllWindows()