C位图:旋转和缩放

Posted

技术标签:

【中文标题】C位图:旋转和缩放【英文标题】:C bitmap: rotation and zoom 【发布时间】:2016-04-18 06:49:38 【问题描述】:

我最近正在为一个在学校遇到问题的朋友检查 C。因为我只学过 java 和 C#,虽然这很容易。但目前坚持这一点。

我有一个项目正在读取一个小的 bmp (512x512) 图像。我设法改变了它的一些颜色并让它旋转(水平和垂直)。虽然我坚持 -90° 旋转。

1.旋转 (512x512)

目前我有这段代码(getPixel 和 setPixel 都是我自己的函数):

typedef struct _bitmap 
    char file_path[PATH_MAX+1];
    char magic_number[3];
    unsigned int size;
    unsigned char application[5];
    unsigned int start_offset;
    unsigned int bitmapHeaderSize;
    unsigned int width;
    unsigned int height;
    unsigned short int depth;
    unsigned  char* header;
    PIXEL* raster;
 BITMAP;

void rotate(BITMAP* bmp) 
    int i;
    int j;
    PIXEL* originalPixel;
    BITMAP* originalBmp;

    deepCopyBitmap(bmp, originalBmp);

    for(j=1; j <= bmp->height; j++) 
        for(i=1; i <= bmp->width; i++) 
            originalPixel=getPixel(originalBmp->raster, bmp->width, bmp->height, j, i);
            setPixel(bmp->raster, bmp->width, bmp->height, (bmp->width + 1 - i), j, originalPixel);
        
                      


void deepCopyBitmap(BITMAP* bmp, BITMAP* copy) 
    *copy = *bmp;
    if (copy->raster) 
        copy->raster = malloc(copy->height * sizeof(*copy->raster));
        for (int i = 0; i < copy->height; i++) 
            copy->raster[i] = malloc(copy->width * sizeof(*copy->raster[i]));
            memcpy(copy->raster[i], bmp->raster[i], copy->width * sizeof(*copy->raster[i]));
        
    


indirection requires pointer operand ('PIXEL' (aka 'struct _pixel') invalid)
            copy->raster[i] = malloc(copy->width * sizeof(*copy->raster[i]));
                                                          ^~~~~~~~~~~~~~~~
indirection requires pointer operand ('PIXEL' (aka 'struct _pixel') invalid)
            memcpy(copy->raster[i], bmp->raster[i], copy->width * sizeof(*copy->raster[i]));
                                                                         ^~~~~~~~~~~~~~~~
expanded from macro 'memcpy' __builtin___memcpy_chk (dest, src, len, __darwin_obsz0 (dest))

这正确地旋转了图像的第一个对角线部分,但第二个部分完全错误(第一个对角线部分的两倍)。

我认为问题在于,在左右交换像素时,我开始交换已经交换的像素。所以我尝试将我的 bmp 复制到一个原始位图 (originalBmp) 和一个旋转 (rotatedBmp) 上。虽然我认为它只是复制参考。 有人知道我如何创建重复的 bmp 吗?

As example(对不起烟道img):我想要垂直线(左)转-90度,所以它变成水平线(右)。虽然左对角线部分是正确的。但是对角线的右侧部分不正确地复制了左侧对角线的一部分。我认为是因为它交换了 bmp 文件中已经交换的像素。

2。旋转 (512x1024)

如果高度或宽度是另一个的两倍会怎样?有人知道如何开始吗?

3.缩放 (200%)

有人知道怎么做吗?获取位图的中心像素,并在图像的开头使它们两次,还是有更好/更清洁的解决方案?

1 2 3 4 5 6 7 8     3 3 4 4 5 5 6 6
2 2 3 4 5 6 7 8     3 3 4 4 5 5 6 6
3 3 3 4 5 6 7 8     4 4 4 4 5 5 6 6
4 4 4 4 5 6 7 8     4 4 4 4 5 5 6 6
5 5 5 5 5 6 7 8     5 5 5 5 5 5 6 6
6 6 6 6 6 6 7 8     5 5 5 5 5 5 6 6
7 7 7 7 7 7 7 8     6 6 6 6 6 6 6 6
8 8 8 8 8 8 8 8     6 6 6 6 6 6 6 6

【问题讨论】:

放大 200% == 在两个方向上每个像素加倍,所以每个像素都变成四个。如果您希望结果更大或只是裁剪部分,则取决于实施。不是矩形,又要看具体实现了。 我不知道setPixelgetPixel 函数,但我似乎很奇怪索引(ij)从1 开始。这是故意的吗?在 C 语言中,您通常会从 0 开始。 您是否使用调试器运行代码,逐步检查所有相关变量? "... 只学过 java 和 C#,虽然会很容易" 显然不是... ;-) C 那时更“低级” Java 或 C#。您想了解数组、指针及其关系,以及使用malloc()/calloc()free() 进行动态内存管理。 【参考方案1】:

从您的代码看来,originalBmpbmp 似乎都是指向某些 BMP 类型的指针。因此,当您执行originalBmp=bmp; 时,您只会得到两个指向同一个 BMP 的指针,即它们对相同的数据进行操作。

我假设你有类似的东西

struct BMP

   // ....
;

如果是这种情况,您可以像这样复制:

struct BMP originalBmp = *bmp;

使用originalBmp 时,您必须使用. 表示法,例如originalBmp.raster

编辑另一种方法

您可以直接在原始 bmp 上进行旋转,而不是制作原始 bmp 的副本。每次轮换将涉及 4 个位置。您可以先将 4 个位置复制到临时变量中,然后将它们写入最终位置。

对于一个简单的矩阵,它可能是这样的:

#include <stdio.h>

#define WIDTH 4

// display function
void d(int t[WIDTH][WIDTH])

    int i, j;
    for (i=0; i<WIDTH;i++)
    
        for (j=0; j<WIDTH; j++)
        
            printf("%d ", t[i][j]);
        
        printf("\n");
    


int main(void) 
    int org[WIDTH][WIDTH];
    int i, j;

    // Just initialize the matrix
    for (i=0; i<WIDTH;i++)
    
        for (j=0; j<WIDTH; j++)
        
            org[i][j] = 10 + i*5 + j;
        
    

    printf("Original\n");
    d(org);

    // Rotate the matrix
    for (j=0; j < (WIDTH/2); j++)
    
        for (i=0; i < ((WIDTH+1)/2); i++)
        
            int t1 = org[j][i];
            int t2 = org[i][WIDTH-1-j];
            int t3 = org[WIDTH-1-j][WIDTH-1-i];
            int t4 = org[WIDTH-1-i][j];

            org[j][i] = t2;
            org[i][WIDTH-1-j] = t3;
            org[WIDTH-1-j][WIDTH-1-i] = t4;
            org[WIDTH-1-i][j] = t1;
        
    
    printf("Rotated\n");
    d(org);
    return 0;

这将输出:

Original
10 11 12 13 
15 16 17 18 
20 21 22 23 
25 26 27 28 
Rotated
13 18 23 28 
12 17 22 27 
11 16 21 26 
10 15 20 25 

改成#define WIDTH 5会输出:

Original
10 11 12 13 14 
15 16 17 18 19 
20 21 22 23 24 
25 26 27 28 29 
30 31 32 33 34 
Rotated
14 19 24 29 34 
13 18 23 28 33 
12 17 22 27 32 
11 16 21 26 31 
10 15 20 25 30 

【讨论】:

我已经更新了我的代码示例。尝试了您的解决方案,并提供了有关该功能的更多详细信息。虽然结果还是一样,但我不认为它“复制”了 originalBmp/rotatedBmp 中的数据。 @PeterVanGorp - 您可能应该展示BITMAP 的外观。如果它使用动态分配,则需要进行深度复制。 我已经添加了 BITMAP @PeterVanGorp - BITMAP 有一个指针,即PIXEL* raster; 我猜这是保存 512x512 像素的地方。由于它有一个指针,因此您必须进行深度复制。也就是说,你需要为一个新的PIXEL分配空间,然后将PIXEL从一个BITMAP复制到另一个。 @PeterVanGorp - 查看替代方法的更新答案

以上是关于C位图:旋转和缩放的主要内容,如果未能解决你的问题,请参考以下文章

Android,围绕自我中心旋转位图而不缩放它

使用 JNI 和 NDK 旋转位图

AS3 图像在内部旋转/缩放以适合精灵

在目标 c 中翻转缩放和旋转的 uiview

Android-用单指手势旋转图像

从相机/图库加载图像位图时会旋转 [Android 9]