C - 解析任意图像文件

时间:2014-02-11 03:31:54

标签: c arrays image binary binaryfiles

对于一个学习示例,我给出了一个要解析的图像文件,格式为:

  • 八个字节表示高度和宽度为32位整数。
  • 文件的其余部分是填充有像素信息的图像数据,由32位信息表示:
    • 红色,绿色,蓝色各8位
    • 透明度信息的8位

我已经创建了一个struct,我可以用二进制文件中的数据成功填充它。

但是我现在的任务是缩小/裁剪图像。我计划采用两个x,y坐标。一个坐标表示图像数据中的起始像素,然后另一个坐标确定结束像素,使其从原始图像中剪切出一个矩形并将其保存到文件中(生成的图像将是2组中的矩形)坐标)。

进行这种裁剪操作的有效方法是什么?我想将每个“像素”放入像素结构中,并且具有2d像素阵列。然而,这似乎使它变得更加复杂。

我在网上搜索过,但是我发现的大多数与图像处理相关的例子都使用了api。

3 个答案:

答案 0 :(得分:0)

最好的方法是拥有一个新结构,将其视为一个对象。从文件加载图像或创建新图像(用零填充)。之后,您可以使用辅助函数来获取像素或将像素放入图像对象中。

在内部,您可以将对象表示为字节数组(unsigned char *)或结构数组,但需要仔细定义它们。现在我要使用字节数组方法。要使结构正常工作,您可能需要小心,例如确保结构的大小与下面的结构相同。使用字节数组,你只需要(y * width + x)* pixel_size作为指向像素的指针,+ 0表示红色,+1表示绿色等。因为它真的听起来像是一个游戏项目或作业忘了制作它很快,只是让它工作,让编译器担心速度。

----为转型----

for (x=0;x<x_new_max;x++)
for (y=0;y<y_new_max;y++) {
   unsigned old_x = transform_x(x); // essentially old_x = x * scale;
   unsigned old_y = transform_y(y); // essentially old_y = y * scale;
   put_pixel(new_image,x,y,get_pixel(old_image,old_x,old_y));
}

或类似的东西,变换函数是关键,x = x * scale,scale将取决于操作函数,你可以在float或fixed中执行变换,如果你在整数数学中都很好。 x比例和y比例可能不同。

缩小图像为new_max_x = old_max_x / 2; new_max_y = old_max_y / 2; x_scale = 0.5; y_scale = 0.5;

玩得开心

答案 1 :(得分:0)

取决于你的图像课程。如果您将像素存储在矩阵中,那么您可以执行以下操作:

for (int i = 0; i <= height*shrink_factor; ++i){
     for (int j = y1; j <= width*shrink_factor; ++j){
        new.pixels[i][j] = old.pixels[i/shrink_factor][j/shrink_factor];
     }
}

对于裁剪:

for (int i = x1; i <= x2; ++i){
    for(int j = y1; j <= y2; ++j){
        new.pixels[i-x1][j-y1] = old.pixels[i][j];
    }
}

答案 2 :(得分:0)

为新图像数据分配一块内存。然后将指针src设置为指向原始图像数据的左上角像素,将另一个dst设置为新图像数据的开头。然后,只需将src的一行(新)行的像素数据从dst复制到src,然后将dst增加原始宽度,将struct image { uint32_t w; /* width in pixels */ uint32_t h; /* height in pixels */ uint32_t *data; /* pixel data */ }; 增加到oimg。每行后的新宽度。

编辑:我快速实现了它 - 这是裁剪操作的关键部分。

我用于图像数据的结构:

nimg

...这是裁剪代码,其中struct imagedata分别指向原始图像和裁剪图像的nimg->w * nimg->h * sizeof(uint32_t)。裁剪后的图片x已分配(大小为y)但尚未初始化。 oimgnimg->wnimg->h中裁剪区域的左上角坐标。已将/* src is offset by y lines, plus x pixels into source image data */ uint32_t *src = oimg->data + y * oimg->w + x; /* dst is at start of new image data */ uint32_t *dst = nimg->data; for (i = 0; i < nimg->h; i++) { /* memcpy() one full new image line (nimg->w * sizeof(uint32_t)) */ memcpy(dst, src, sizeof(uint32_t) * nimg->w); dst += nimg->w; /* increment dst by a full new image line */ src += oimg->w; /* increment src by a full source image line */ } 和{{1}}设置为裁剪图片的宽度和高度(以像素为单位)。

{{1}}

上面的代码假设在一个图像行的末尾和下一个图像行的开头之间没有额外的数据,并且每个图像都有自己的像素数据。一些库将保持“步幅”值以及图像宽度,其保持线之间的偏移;这允许在图像线之间添加额外的填充或未使用的像素,这对于保持对齐或允许由较大图像的一部分组成的图像与它们共享像素数据而不是每个具有单独的副本。