先给出效果,直观感受下(会有空洞问题,紧跟的后面文章会解决):
算法:分别用两个矩阵保存行、列号值,据公式(I = icost-jsint; J = isint+jcost。旋转角度t给定。),旋转行列号,新画布,填充。
1. matlab实现:
%题目:图像的旋转
%公式;I = icost-jsint; J = isint+jcost。旋转角度t给定。
f = imread('D:\Code\Image\classic.jpg');
f = rgb2gray(f);
figure,imshow(f);
[row,col] = size(f);
A = zeros(row,col);%保存的是行号
B = zeros(row,col);%保存的是列号
%1, 旋转后的行、列号
for i=1:row
for j=1:col
A(i,j) = round( i*cosd(30)-j*sind(30) );%旋转后的行号矩阵
end
end
for i=1:row
for j=1:col
B(i,j) = round( i*sind(30)+j*cosd(30) );%旋转后的列号矩阵
end
end
%2, 使行列号值为正整数,加上某个值即可,因为所有的像素都加了相同的值,所以不会破坏相对空间位置
Min_A = min(min(A));
Min_B = min(min(B));
if Min_A <= 0
add_value = 1 - Min_A; % Min_A + add_value = 1,使得最小值为1;
A = A + add_value;
end
if Min_B <= 0
add_value = 1 - Min_B;
B = B + add_value;
end
%3,定义新的画布,并遍历旧画布,填充到新画布中
maxi = max(max(A)); %最大行号
maxj = max(max(B)); %最大列号
G = zeros(maxi,maxj);%扩大后的画布,保存的值为灰度值
for i=1:row
for j=1:col
G(A(i,j),B(i,j)) = f(i,j);%像素值填充
end
end
figure,
imshow(uint8(G));%显示旋转后图像
2. C++实现:
#include <opencv2/opencv.hpp>
#include <iostream>
#include <fstream> //方便查看mat像素值,这个头文件是必须要有的
using namespace cv;
using namespace std;
#define Pi 3.1415926
int main()
{
Mat img = imread("D:/Code/Image/classic.jpg", 0);
imshow("原图", img);
int rows = img.rows, cols = img.cols;
printf("rows = %d cols = %d \n", rows, cols);
Mat row_mat = Mat::zeros(img.size(), CV_64F); //定义成CV_32FC1,用不了minMaxLoc,不知为何
Mat col_mat = Mat::zeros(img.size(), CV_64F);
//Mat row_mat = img.clone(), col_mat = img.clone();
ofstream fout("D:\\data.txt"); //创建一个data.txt的文件
double radian = 30 * Pi / 180;
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
row_mat.at<double>(i, j) = round(i * cos(radian) - j * sin(radian)); // 旋转后的行号矩阵
col_mat.at<double>(i, j) = round(i * sin(radian) + j * cos(radian)); // 旋转后的列号矩阵
fout << "rows= " << row_mat.at<double>(i, j) << " " << "cols= " << col_mat.at<double>(i, j) << endl; //将变量的值写入文件,方便查看
//printf("rows = %f cols = %f \n", row_mat.at<double>(i, j), col_mat.at<double>(i, j));
}
}
fout.close();
// 使行列值为正数
// 找到最小值
double minv_row = 0.0, maxv_row = 0.0, minv_col = 0.0, maxv_col = 0.0;
cv::minMaxLoc(row_mat, &minv_row, &maxv_row);
//minMaxIdx(row_mat, min_row, max_row);
printf("min_row = %f max_row = %f \n", minv_row, maxv_row);
ofstream fout2("D:\\row.txt");
if (minv_row <= 0)
{
double add_value = 1 - minv_row; // min_A + add_value == 1,使得最小值为1
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
row_mat.at<double>(i, j) = row_mat.at<double>(i, j) + add_value;
fout2 << "rows= " << row_mat.at<double>(i, j) << endl;
}
}
}
fout2.close();
ofstream fout3("D:\\col.txt");
if (minv_col <= 0)
{
double add_value = 1 - minv_col; // min_A + add_value == 1,使得最小值为1
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
col_mat.at<double>(i, j) = col_mat.at<double>(i, j) + add_value;
fout3 << "cols= " << col_mat.at<double>(i, j) << endl;
}
}
}
fout3.close();
cv::minMaxLoc(row_mat, &minv_row, &maxv_row);
cv::minMaxLoc(col_mat, &minv_col, &maxv_col);
Mat newImage = Mat::zeros(maxv_row, maxv_col, img.type());
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
newImage.at<uchar>(row_mat.at<double>(i, j), col_mat.at<double>(i, j)) = img.at<uchar>(i, j);
//printf("rows = %f cols = %f , pixelV = %d\n", row_mat.at<double>(i, j), col_mat.at<double>(i, j), newImage.at<uchar>(row_mat.at<double>(i, j), newImage.at<uchar>(row_mat.at<double>(i, j), col_mat.at<double>(i, j))));
}
}
imshow("效果图", newImage);
waitKey(0);
return 0;
}
运行时,出现ConsoleApplication1.exe 已触发了一个断点。点击继续,可以出旋转结果。不知如何处理这个断点问题,记录下来。