【图像处理知识复习】07图像的旋转matlab,C++实现

本文介绍了一种基于行列号变换的图像旋转算法,通过MATLAB和C++两种语言实现了图像的旋转功能。该算法首先计算旋转后的行列号,然后填充到新画布上形成旋转后的图像。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

先给出效果,直观感受下(会有空洞问题,紧跟的后面文章会解决):


算法:分别用两个矩阵保存行、列号值,据公式(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 已触发了一个断点。点击继续,可以出旋转结果。不知如何处理这个断点问题,记录下来。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Mr.Q

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值