C 将图像旋转90度的算法?(无额外内存)

C 将图像旋转90度的算法?(无额外内存),c,image-processing,embedded,rotation,C,Image Processing,Embedded,Rotation,在嵌入式C应用程序中,我有一个大图像,我想旋转90度。目前我使用著名的simple来实现这一点。然而,这个算法需要我制作另一个图像副本。我希望避免为副本分配内存,我宁愿在适当的位置旋转它。因为图像不是正方形的,所以这很棘手。有人知道合适的算法吗 编辑以添加澄清,因为人们会问: 我以通常的格式存储图像: // Images are 16 bpp struct Image { int width; int height; uint16_t * data; }; uint16

在嵌入式C应用程序中,我有一个大图像,我想旋转90度。目前我使用著名的simple来实现这一点。然而,这个算法需要我制作另一个图像副本。我希望避免为副本分配内存,我宁愿在适当的位置旋转它。因为图像不是正方形的,所以这很棘手。有人知道合适的算法吗

编辑以添加澄清,因为人们会问:

我以通常的格式存储图像:

// Images are 16 bpp
struct Image {
    int width;
    int height;
    uint16_t * data;
};

uint16_t getPixel(Image *img, int x, int y)
{
    return img->data[y * img->width + x];
}
我希望移动
数据
数组的内容,然后交换
宽度
高度
成员变量。因此,如果我从一个9x20像素的图像开始,然后旋转它,我将得到一个20x9像素的图像。这会改变图像的步幅,这会使算法复杂化。

这可能会有所帮助:


(你可能还需要在换位后做一些镜像,就像rlbond提到的那样)。

这可能太模糊了,也不是你想要的,但我还是要发布

如果您认为图像是2D像素数组,则只需要颠倒顶层或嵌套数组的顺序,这取决于您是否需要水平或垂直翻转?


因此,您可以循环遍历每个像素列(0->columns/2),并交换它们(因此您只需要一个像素的临时内存,而不需要整个图片),或者循环遍历行以进行水平翻转。。这有意义吗?如果没有,将详细说明/编写代码。

如果您以“错误的顺序”从内存中读取图像,则基本上与旋转图像相同。这可能适用于也可能不适用于您正在做的任何事情,但以下是:

image[y][x] /* assuming this is the original orientation */
image[x][original_width - y] /* rotated 90 degrees ccw */
image[original_height - x][y] /* 90 degrees cw */
image[original_height - y][original_width - x] /* 180 degrees */

不确定旋转后将进行什么处理,但可以不使用它,使用另一个函数从原始内存中读取旋转后的像素

uint16_t getPixel90(Image *img, int x, int y) 
{
    return img->data[(img->height - x) * img->width + y];
}

其中,输入参数x和y已将尺寸与原始尺寸进行了交换,这是我对矩阵90度旋转的尝试,这是C中的两步解决方案。
首先将矩阵变换到位,然后交换COL

#define ROWS        5
#define COLS        5

void print_matrix_b(int B[][COLS], int rows, int cols) 
{
    for (int i = 0; i <= rows; i++) {
        for (int j = 0; j <=cols; j++) {
            printf("%d ", B[i][j]);
        }
        printf("\n");
    }
}

void swap_columns(int B[][COLS], int l, int r, int rows)
{
    int tmp;
    for (int i = 0; i <= rows; i++) {
        tmp = B[i][l];
        B[i][l] = B[i][r];
        B[i][r] = tmp;
    }
}


void matrix_2d_rotation(int B[][COLS], int rows, int cols)
{
    int tmp;
    // Transpose the matrix first
    for (int i = 0; i <= rows; i++) {
        for (int j = i; j <=cols; j++) {
            tmp = B[i][j];
            B[i][j] = B[j][i];
            B[j][i] = tmp;
        }
    }
    // Swap the first and last col and continue until
    // the middle.
    for (int i = 0; i < (cols / 2); i++)
        swap_columns(B, i, cols - i, rows);
}



int _tmain(int argc, _TCHAR* argv[])
{
    int B[ROWS][COLS] = { 
                  {1, 2, 3, 4, 5}, 
                      {6, 7, 8, 9, 10},
                          {11, 12, 13, 14, 15},
                          {16, 17, 18, 19, 20},
                          {21, 22, 23, 24, 25}
                        };

    matrix_2d_rotation(B, ROWS - 1, COLS - 1);

    print_matrix_b(B, ROWS - 1, COLS -1);
    return 0;
}
#定义第5行
#定义COLS 5
无效打印矩阵(整数b[][COLS],整数行,整数列)
{

对于(int i=0;i这类似于2D矩阵的旋转。下面是我的算法,将2D矩阵旋转90度。它也适用于M X N。对给定矩阵进行转置,然后将第一列与最后一列交换,第二列与最后第二列交换,依此类推。您也可以使用行而不是列

import java.io.*;
import java.util.*;

public class MatrixRotationTest
{
public static void main(String arg[])throws Exception
{
    BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    System.out.println("Enter the matrix rows:");
    int r = Integer.parseInt(br.readLine());
    System.out.println("Enter the matrix columns:");
    int c = Integer.parseInt(br.readLine());
    int[][] matrix = new int[r*c][r*c];
    for(int i=0;i<r;i++)
    {
        System.out.println("Enter row "+(i+1));
        for(int j=0;j<c;j++)
        {
            matrix[i][j] = Integer.parseInt(br.readLine());
        }
    }
    matrix = reverseMatrixColumns(transformMatrix(matrix),r,c);
    System.out.println("Rotated Matrix");
    for(int i=0;i<c;i++)
    {
        for(int j=0;j<r;j++)
        {
            System.out.print(matrix[i][j]+" ");
        }
        System.out.println();
    }
}

    //Transform the given matrix
public static int[][] transformMatrix(int[][] matrix)throws Exception
{
    for(int i=0;i<matrix.length;i++)
    {
        for(int j=i;j<matrix[0].length;j++)
        {
            int temp = matrix[i][j];
            matrix[i][j] = matrix [j][i];
            matrix[j][i] = temp;
        }
    }
}

    //Swap columns
public static int[][] reverseMatrixColumns(int[][] matrix,int r,int c)
{
    int i=0,j=r-1;
    while(i!=r/2)
    {
        for(int l=0;l<c;l++)
        {
            int temp = matrix[l][i];
            matrix[l][i] = matrix[l][j];
            matrix[l][j] = temp;
        }
        i++;
        j--;
    }
    return matrix;
}
}
import java.io.*;
导入java.util.*;
公共类矩阵旋转测试
{
公共静态void main(字符串arg[])引发异常
{
BufferedReader br=新的BufferedReader(新的InputStreamReader(System.in));
System.out.println(“输入矩阵行:”);
int r=Integer.parseInt(br.readLine());
System.out.println(“输入矩阵列:”);
int c=Integer.parseInt(br.readLine());
int[][]矩阵=新的int[r*c][r*c];

对于(inti=0;i来说,真正的答案是:不,你不能不分配一些内存

或者您必须使用递归,这将在处理大型图像时失败

但是,有些方法需要的内存比图像本身少

例如,您可以获取点A(x从0到宽度,y从0到高度),计算其新位置,B,在将其替换为A之前将B复制到其新位置(C),等等

但是,该方法需要跟踪已经移动的字节(使用旋转图像中每像素一位的位图)


请参阅wikipedia的文章,它清楚地证明了这不能用于非方形图像:这里是链接:

这里是java中的一个简单方法

    public static void rotateMatrix(int[][] a) {                                                                            
    int m =0;
    for(int i=0; i<a.length; ++i) {
        for(int j=m; j<a[0].length; ++j) {
            int tmp = a[i][j];
            a[i][j] = a[j][i];
            a[j][i] = tmp;
        }
        m++;
    }

    for(int i=0; i<a.length; ++i) {
        int end = a.length-1;
        for(int j=0; j<a[0].length; j++) {
            if(j>=end)
                break;
            int tmp = a[i][j];
            a[i][j] = a[i][end];
            a[i][end] = tmp;
            end--;
        }
    }
}
publicstaticvoidrotatematrix(int[][]a){
int m=0;

对于(inti=0;i这个问题花了我相当长的时间,但是如果你有正确的方法,它是非常简单的

注意,这仅适用于方形矩阵。矩形需要使用其他算法(转置和翻转)。如果要就地执行,可能需要临时调整数组大小

简化问题 考虑以下矩阵:

 1  2  3  4
 5  6  7  8
 9 10 11 12
13 14 15 16
旋转90度,只看角落(数字1、4、16和13)。如果你在视觉上有问题,请自己写一张便利贴

现在,让我们考虑下面的一个:

1 - - 2
- - - -
- - - -
4 - - 3
将其旋转90度,注意数字是如何以循环方式旋转的:2变为1,3变为2,4变为3,1变为4

旋转角 要旋转角点,必须根据第一个角点定义所有角点:

  • 第一个拐角是
    (i,j)
  • 第二个拐角是
    (尺寸-j,i)
  • 第三个角是
    (尺寸-i,尺寸-j)
  • 第四个角落将是
    (j,尺寸-i)
注意数组是基于0的,因此
大小也需要基于0。(意思是,您需要减去1)

既然您已经理解了旋转角的概念,我们将把“旋转角”的概念扩展到“旋转象限”。同样的原理也适用

代码 如果被覆盖,您需要确保没有数字。也就是说,您需要同时旋转4个数字

#include <algorithm>
#include <numeric>
#include <vector>

using std::iota;
using std::swap;
using std::vector;

// Rotates 4 numbers.
// e.g: 1, 2, 3, 4 becomes 4, 1, 2, 3
// int& means numbers are passed by reference, not copy.
void rotate4(int &a, int &b, int &c, int &d)
{
   swap(a, b);
   swap(b, c);
   swap(c, d);
}

void rotateMatrix(vector<vector<int>>& m) {
    int n = m.size();

    // NOTE: i and j from 0 to n/2 is a quadrant
    for (int i = 0; i < n/2; i++) {
    // NOTE : here + 1 is added to make it work when n is odd
    for (int j = 0; j < (n + 1)/2; j++) {
        int r_i = (n - 1) - i;
        int r_j = (n - 1) - j;

        rotate4(
             m   [i]   [j],
             m [r_j]   [i],
             m [r_i] [r_j],
             m   [j] [r_i]
        );
    }
    }
}

void fillMatrix(vector<vector<int>>& m) {
    int offset = 0;

    for (auto &i : m) {
        iota(i.begin(), i.end(), offset);
        offset += i.size();
    }
}

// Usage:
const int size = 8;
vector<vector<int>> matrix (size, vector<int>(size));
fillMatrix(matrix);
rotateMatrix(matrix);
#包括
#包括
#包括
使用std::iota;
使用std::swap;
使用std::vector;
//旋转4个数字。
//例如:1,2,3,4变成了4,1,2,3
//int&表示数字通过引用传递,而不是复制。
无效旋转4(内部和a、内部和b、内部和c、内部和d)
{
掉期(a、b);
互换(b,c);
互换(c,d);
}
空心旋转矩阵(矢量和m){
int n=m.size();
//注:从0到n/2的i和j是一个象限
对于(int i=0;i#include <algorithm>
#include <iostream>
#include <iterator>

using std::copy;
using std::cout;
using std::ostream;
using std::ostream_iterator;
using std::vector;

ostream& operator<<(ostream& os, vector<vector<int>>& m) {
    for (auto const &i : m) {
        copy(i.begin(), i.end(), ostream_iterator<int>(os, " "));
        os << "\n";
    }

    return os;
}

// Usage
cout << matrix;