* 一、 平移 <https://blog.csdn.net/c2681595858/article/details/82824282#__3>
* 1、思路 <https://blog.csdn.net/c2681595858/article/details/82824282#1_4>
* 2、实现代码 <https://blog.csdn.net/c2681595858/article/details/82824282#2_14>
* 二、缩放 <https://blog.csdn.net/c2681595858/article/details/82824282#_48>
* 1、思路 <https://blog.csdn.net/c2681595858/article/details/82824282#1_49>
* 2、代码实现 <https://blog.csdn.net/c2681595858/article/details/82824282#2_55>
* 三、旋转变换 <https://blog.csdn.net/c2681595858/article/details/82824282#_77>
* 1、思路 <https://blog.csdn.net/c2681595858/article/details/82824282#1_78>

<>一、 平移

<>1、思路

【原图】

【平移后的图像】

<>2、实现代码
(!image.data) { cout << "找不到图片或无法打开图片\n"; return -1; }
namedWindow("image_source", CV_WINDOW_AUTOSIZE); imshow("原图", image);
//--------------------平移变换-------------- int dx = 10, dy = 20; Mat
image_shift(image.rows + dx, image.cols+dy, CV_8UC3);//新建一个大于原图的图像，备用
//一个个像素进行处理 for (int counter1 = 0; counter1 < image.rows; counter1++) { for
(int counter2 = 0; counter2 < image.cols; counter2++) {
//将原坐标进行平移，并将原坐标上的RGB值赋给新坐标 image_shift.at<Vec3b>(counter1+dx, counter2+dy)[0]
= image.at<Vec3b>(counter1, counter2)[0]; image_shift.at<Vec3b>(counter1+dx,
counter2 + dy)[1] = image.at<Vec3b>(counter1, counter2)[1];
image_shift.at<Vec3b>(counter1+dx , counter2+ dy)[2] =
image.at<Vec3b>(counter1, counter2)[2]; } } //imshow("平移", image_shift);
imwrite("1.jpg", image_shift);//将平移后的图像存储为名称为1.jpg的文件 //--------------

<>二、缩放

<>1、思路

*

*

* 上面其实和筛子原理是一样的，只不过计算机中不可能放大一个像素的大小，所以乘以1/2相当于是把筛子缩小，正好对应上画的大小。
* 效果图如下：是缩小效果图

<>2、代码实现
//----------------尺度变换------------------ double mul_num = 0.8;//大于1是放大，小于1是缩小
int row_num = (int)floor(image.rows * mul_num), col_num = (int)floor(image.cols
* mul_num); Mat image_scale(row_num, col_num, CV_8UC3); for (int counter1 = 0;
counter1 < row_num; counter1++) { for (int counter2 = 0; counter2 < col_num;
counter2++) { //将筛孔缩小，对上画的大小 int x = (int)1.0 / mul_num *counter1, y = (int)1.0
/ mul_num *counter2; image_scale.at<Vec3b>(counter1, counter2 )[0] =
image.at<Vec3b>(x, y)[0]; image_scale.at<Vec3b>(counter1, counter2 )[1] =
image.at<Vec3b>(x, y)[1]; image_scale.at<Vec3b>(counter1, counter2 )[2] =
image.at<Vec3b>(x, y)[2]; } } //imshow("尺度变换", image_scale); imwrite("2.jpg",
image_scale);//存储变换后的图像 //----------------尺度变换完成---------------
<>三、旋转变换

<>1、思路

* 如果直接按照仿射矩阵来旋转的话会出问题。因为那个是围绕左上角的原点来旋转的，你一旋转以后，他马上会越界访问，所以会出现问题。下面详细来说：

*

* 将它沿着它的中心旋转，这样就好控制新图像所在的范围了。

* 围绕中心旋转也比较好处理，我们还是回到前面的那个旋转结果啊。

*

* 具体实现代码如下： //----------------旋转变换------------------ double angle = 135.0 *
3.1415926 / 180.0;//把角度化成弧度 int dis = ceil(sqrt(pow(image.rows, 2) +
pow(image.cols, 2)));//新图像的长宽应该是原图像的对角线长度 Mat image_nrota(dis, dis, CV_8UC3);
for (int counter1 = 0; counter1 < image.rows; counter1++) { for (int counter2 =
0; counter2 < image.cols; counter2++) { //计算应该平移的距离 float cenX =
image_nrota.rows/2 - ((image.rows / 2) * cos(angle) - (image.cols/2) *
sin(angle)), cenY = image_nrota.cols/2 - ((image.rows / 2) * sin(angle) +
(image.cols / 2) * cos(angle)); //按照仿射矩阵计算后进行平移 int x = counter1 * cos(angle) -
counter2 * sin(angle) + cenX, y = counter1 * sin(angle) + counter2 * cos(angle)
+ cenY; image_nrota.at<Vec3b>(x, y)[0] = image.at<Vec3b>(counter1,
counter2)[0]; image_nrota.at<Vec3b>(x, y)[1] = image.at<Vec3b>(counter1,
counter2)[1]; image_nrota.at<Vec3b>(x, y)[2] = image.at<Vec3b>(counter1,
counter2)[2]; } } //imshow("旋转", image_nrota); imwrite("3.jpg", image_nrota);
//-----------旋转变换完成---------------
* 后面还有偏移变换，就不在赘述原理了，比较简单，直接上完整代码。
【change.h】
#pragma once #include <opencv2/core/core.hpp> #include
<opencv2/highgui/highgui.hpp> #include <iostream> #include <cmath> #include
<Windows.h> using namespace std; using namespace cv; //对图像进行平移操作 void shift(Mat
&image, int dx, int dy) { Mat image_shift(image.rows + dx, image.cols + dy,
CV_8UC3);//新建一个大于原图的图像，备用 //一个个像素进行处理 for (int counter1 = 0; counter1 <
image.rows; counter1++) { for (int counter2 = 0; counter2 < image.cols;
counter2++) { //将原坐标进行平移，并将原坐标上的RGB值赋给新坐标 image_shift.at<Vec3b>(counter1 + dx,
counter2 + dy)[0] = image.at<Vec3b>(counter1, counter2)[0];
image_shift.at<Vec3b>(counter1 + dx, counter2 + dy)[1] =
image.at<Vec3b>(counter1, counter2)[1]; image_shift.at<Vec3b>(counter1 + dx,
counter2 + dy)[2] = image.at<Vec3b>(counter1, counter2)[2]; } } //imshow("平移",
image_shift); imwrite("1.jpg", image_shift);//将平移后的图像存储为名称为1.jpg的文件 } //进行尺度变换
void scale(Mat &image, double mul_num) { int row_num = (int)floor(image.rows *
mul_num), col_num = (int)floor(image.cols * mul_num); Mat image_scale(row_num,
col_num, CV_8UC3); for (int counter1 = 0; counter1 < row_num; counter1++) { for
(int counter2 = 0; counter2 < col_num; counter2++) { //将筛孔缩小，对上画的大小 int x =
(int)1.0 / mul_num * counter1, y = (int)1.0 / mul_num * counter2;
image_scale.at<Vec3b>(counter1, counter2)[0] = image.at<Vec3b>(x, y)[0];
image_scale.at<Vec3b>(counter1, counter2)[1] = image.at<Vec3b>(x, y)[1];
image_scale.at<Vec3b>(counter1, counter2)[2] = image.at<Vec3b>(x, y)[2]; } }
//imshow("尺度变换", image_scale); imwrite("2.jpg", image_scale);//存储变换后的图像 }
//进行旋转 void rotation(Mat &image, double angle_in) { double angle = angle_in *
3.1415926 / 180.0;//把角度化成弧度 int dis = ceil(sqrt(pow(image.rows, 2) +
pow(image.cols, 2)));//新图像的长宽应该是原图像的对角线长度 Mat image_nrota(dis, dis, CV_8UC3);
for (int counter1 = 0; counter1 < image.rows; counter1++) { for (int counter2 =
0; counter2 < image.cols; counter2++) { //计算应该平移的距离 float cenX =
image_nrota.rows / 2 - ((image.rows / 2) * cos(angle) - (image.cols / 2) *
sin(angle)), cenY = image_nrota.cols / 2 - ((image.rows / 2) * sin(angle) +
(image.cols / 2) * cos(angle)); //按照仿射矩阵计算后进行平移 int x = counter1 * cos(angle) -
counter2 * sin(angle) + cenX, y = counter1 * sin(angle) + counter2 * cos(angle)
+ cenY; image_nrota.at<Vec3b>(x, y)[0] = image.at<Vec3b>(counter1,
counter2)[0]; image_nrota.at<Vec3b>(x, y)[1] = image.at<Vec3b>(counter1,
counter2)[1]; image_nrota.at<Vec3b>(x, y)[2] = image.at<Vec3b>(counter1,
counter2)[2]; } } //imshow("旋转", image_nrota); imwrite("3.jpg", image_nrota); }
//垂直偏移变换 void voffset(Mat &image, double sv) { Mat image_voffset(sv*image.rows
+ image.cols, image.cols, CV_8UC3); for (int counter1 = 0; counter1 <
image.rows; counter1++) { for (int counter2 = 0; counter2 < image.cols;
counter2++) { int x = counter1 * sv + counter2; image_voffset.at<Vec3b>(x,
counter2)[0] = image.at<Vec3b>(counter1, counter2)[0];
image_voffset.at<Vec3b>(x, counter2)[1] = image.at<Vec3b>(counter1,
counter2)[1]; image_voffset.at<Vec3b>(x, counter2)[2] =
image.at<Vec3b>(counter1, counter2)[2]; } } //imshow("垂直偏移", image_voffset);
imwrite("4.jpg", image_voffset); } //水平偏移变换 void hoffset(Mat &image, double sh)
{ Mat image_hoffset(image.rows, sh*image.rows + image.cols, CV_8UC3); for (int
counter1 = 0; counter1 < image.rows; counter1++) { for (int counter2 = 0;
counter2 < image.cols; counter2++) { int y = counter1 * sh + counter2;
image_hoffset.at<Vec3b>(counter1, y)[0] = image.at<Vec3b>(counter1,
counter2)[0]; image_hoffset.at<Vec3b>(counter1, y)[1] =
image.at<Vec3b>(counter1, counter2)[1]; image_hoffset.at<Vec3b>(counter1, y)[2]
= image.at<Vec3b>(counter1, counter2)[2]; } } //imshow("水平偏移", image_hoffset);
imwrite("5.jpg", image_hoffset); }
【main.cpp】
#include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp>
#include <iostream> #include <cmath> #include <Windows.h> #include "change.h"
using namespace std; using namespace cv; int main() { //读原图 Mat image; image =