一. 数组_二维数组变换_48. 旋转图像

题目描述
给定一个 n × n 的二维矩阵 matrix 表示一个图像。请你将图像顺时针旋转 90 度。

你必须在 原地 旋转图像,这意味着你需要直接修改输入的二维矩阵。请不要 使用另一个矩阵来旋转图像。

示例 1:

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/rotate-image
在这里插入图片描述

输入:matrix = [[1,2,3],[4,5,6],[7,8,9]]
输出:[[7,4,1],[8,5,2],[9,6,3]]

示例 2:
在这里插入图片描述
输入:matrix = [[5,1,9,11],[2,4,8,10],[13,3,6,7],[15,14,12,16]]
输出:[[15,13,2,5],[14,3,4,1],[12,6,8,9],[16,7,10,11]]
示例 3:

输入:matrix = [[1]]
输出:[[1]]
示例 4:

输入:matrix = [[1,2],[3,4]]
输出:[[3,1],[4,2]]

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/rotate-image

在计算机科学中,一个原地算法(in-place algorithm)是一种使用小的,固定数量的额外之空间来转换资料的算法
矩阵转置为对应的行变列[[1,2][3,4]] -> [[1,3],[2,4]],旋转90度[[3, 1],[4, 2]]
这里原来矩阵的第i行,变为了后来的第n-1-i列,原来的第j个元素,变成了现在的第j行
因为原地变化,没有想到解决办法,这里使用了中间变量进行存储
这里面虽然通过了,但是没有按照题目的方法使用了辅助空间
C++ 这里的 = 拷贝是值拷贝,会得到一个新的数组
auto matrix_new = matrix;
这里也是值拷贝
matrix = matrix_new;

void rotate(vector<vector<int>>& matrix) {
    int m = matrix.size();
    vector<vector<int>>  temp(m, vector<int>(m));
    //这里遍历matrix矩阵,将其变换到对应的位置,存储到temp中
    for(int i = 0; i < m; i++) {
        int j1 = m - 1 - i;

        for(int j = 0; j < m; j++) {
            temp[j][j1] = matrix[i][j];
        }
    }
    //将temp的赋值到matrix中
    for(int i = 0; i < m; i++) {
        for(int j = 0; j < m; j++) {
            matrix[i][j] = temp[i][j];
        }
    }
}

这里还有一个思路是,从第一行的第一个元素开始,换到对应的位置,该位置的元素换到下一个位置,直到换回最开始的位置为止
每行从第一个元素开始遍历到倒数第二个元素停止,下一次从第i行第i列元素开始,也是遍历到倒数第二个元素为止,直到所有的元素都遍历一遍停止。
这个我之前一直感觉这只是个思路,根本不可行,说不定还有边角问题没有处理,但是我刚才试了一下,竟然可以通过,我都惊呆了。我的天哪
这里的话,可以分为两种情况,一种是33的矩阵,一种是44的矩阵,这里33的矩阵
(0,0) -> (0,2) -> (2,2) -> (2,0),那么从(0,0)出发的时候,这里经过这四个位置,第一和第二交换
第一和第三交换、第一和第四交换,这里交换三次之后,结果就确定了。
下一个元素(0,1)->(1,2)->(2,1)->(1,0)也是同样的交换三次就可以了,这里的话(0,2)就不需要了,
所以每行的最后一个元素是不需要交换了,这样的话,就是将最外层进行完整的替换了。
而中间的(1,1)就不需要替换了。4
4的去除最外面一层,剩下的是22的矩阵,这个矩阵可以直接遍历三次
直接得到转置后的结果。
思路:
1.首先定义left=0,right=n-2,row = 0;
2.这里首先遍历row行的left到right的所有元素进行一一的交替
3.当前层结束之后,left++,right–,row++,这样进行下一层的遍历【无论最后一层是2
2还是1*1都不会出错】
4.如果当前从(0,0) -> (0,2) -> (2,2) -> (2,0),直到重新到(0,0)停止,把初始位置作为一个存储临时变量的地方,一个一个的交替

void rotate(vector<vector<int>>& matrix) {
    int m = matrix.size();
    int left = 0, right = m - 2; //这里定义左边界和右边界
    int row = 0;

    while(left <= right) {
        //找到当前层的初始位置
        for(int j = left; j <= right; j++) {
            int i1 = j;
            int j1 = m - 1 - row;

            //下一个位置没回到初始位置,就继续迭代
            while(i1 != row || j1 != j) {
                swap(matrix[row][j], matrix[i1][j1]);
                int temp = i1;
                i1 = j1;
                j1 = m - 1 - temp;
            }
        }

        //缩小外边界
        left++;
        right--;
        row++;
    }
}

这里正方形旋转,因此每次正好有四个点被替换,替换之后的结果就是我们的结果
这里,r,c->c,n-r-1->n-r-1,n-c-1->n-c-1,r->r,c,那么最后有回到原来的位置了。
所以我们要确定从哪些初始位置开始变化,我上面的那种方法也可以,n为偶数,n^2/4=每次变化的个数,这里可以设置为(0,n/2)和(0,n/2)
这里的话,奇数个的话,(n^2 - 1) / 4,所以这里可以设置为(0,n/2)和(0, (n + 1) /2)

void rotate(vector<vector<int>>& matrix) {
    int m = matrix.size();
    int r_len = m / 2, c_len = (m + 1) / 2;   //这里原本我是要分偶数和奇数不同的情况,但是像官方这样写也很好。

    for(int i = 0; i < r_len; i++) {
        for(int j = 0; j < c_len; j++) {
            //这里设置i,j是初始下标,可以用上面的while循环找到所以替换的位置,因为每次只有四个位置,所以也可以直接用四行代码替换
            //下面这种代码是适合环的情况下,向后移动,那么拿出一个位置的值,其他的补上,最后那个还没有被赋值用temp填充
            int temp = matrix[m - i - 1][m - j - 1];
            matrix[m - i - 1][m - j - 1] = matrix[j][m - i - 1];
            matrix[j][m - i - 1] = matrix[i][j];
            matrix[i][j] = matrix[m - j - 1][i];
            matrix[m - j - 1][i] = temp;
        }
    }
}

这里另一种思路是,水平翻转,在对角线翻转,就能得到旋转90的结果
a[i][j] , a[n-i-1][j] => a[n-i-1][j] , a[j][n-i-1]

void rotate(vector<vector<int>>& matrix) {
    int m = matrix.size();

    //水平翻转
    for(int i = 0; i < m / 2; i++) {
        for(int j = 0; j < m; j++) {
            swap(matrix[i][j], matrix[m - i - 1][j]);
        }
    }

    //对角线翻转
    for(int i = 0; i < m; i++) {
        for(int j = i + 1; j < m; j++) {
            swap(matrix[i][j], matrix[j][i]);
        }
    }
}
int main() {
    vector<vector<int>>  matrix(4, vector<int>(4));
    matrix[0][0] = 1;
    matrix[0][1] = 2;
    matrix[0][2] = 3;
    matrix[0][3] = 4;
    matrix[1][0] = 4;
    matrix[1][1] = 5;
    matrix[1][2] = 6;
    matrix[1][3] = 8;
    matrix[2][0] = 9;
    matrix[2][1] = 10;
    matrix[2][2] = 11;
    matrix[2][3] = 12;
    matrix[3][0] = 13;
    matrix[3][1] = 14;
    matrix[3][2] = 15;
    matrix[3][3] = 16;
    rotate(matrix);
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
根据提供的引用内容,本设计采用OV5640摄像头作为输入,输出HDMI,分辨率为1024x768@60Hz。图像缓存至DDR做旋转变换旋转角度由口命令控制。因此,实现图像旋转需要以下步骤: 1. 从OV5640摄像头获取图像数据,并将其存储到DDR中。 2. 从DDR中读取图像数据,并进行旋转变换。 3. 将旋转后的图像数据输出到HDMI。 在Verilog中实现图像旋转,需要使用图像处理算法,例如旋转矩阵算法旋转矩阵算法是一种常用的图像处理技术,其基本理就是指图像以某一点为中心旋转一定的角度,形成一幅新的图像的过程。当然这个点通常就是图像的中心。图像旋转图像几何变换的一种,旋转前后的图像的像素的 RGB 都是没有改变的,改变的只是每一个像素的所在位置,这个就是旋转的本质。 以下是一个Verilog实现图像旋转的例子: ```verilog module image_rotation ( input clk, input rst, input [7:0] angle, input [31:0] in_data, output reg [31:0] out_data ); reg [31:0] buffer [0:1023][0:767]; reg [31:0] temp; reg [7:0] x, y; reg [31:0] sin_val, cos_val; reg [31:0] x_new, y_new; reg [31:0] x_center = 320; reg [31:0] y_center = 240; always @(posedge clk) begin if (rst) begin x <= 0; y <= 0; out_data <= 0; end else begin // 读取输入数据 temp <= in_data; buffer[x][y] <= temp; // 计算旋转后的坐标 sin_val <= $sin(angle); cos_val <= $cos(angle); x_new <= (x - x_center) * cos_val - (y - y_center) * sin_val + x_center; y_new <= (x - x_center) * sin_val + (y - y_center) * cos_val + y_center; // 输出旋转后的像素值 out_data <= buffer[x_new][y_new]; // 更新坐标 if (x == 1023) begin x <= 0; y <= y + 1; end else begin x <= x + 1; end end end endmodule ``` 该Verilog模块实现了一个简单的图像旋转功能,输入数据为一个像素点的RGB值和旋转角度,输出数据为旋转后的像素点的RGB值。具体实现过程为:首先将输入数据存储到一个二维数组中,然后根据旋转角度计算旋转后的坐标,最后输出旋转后的像素值。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值