简体   繁体   English

C-解析任意图像文件

[英]C - Parsing arbitrary image file

For a learning example, I'm given an image file to parse that is in this format: 对于一个学习示例,我给了一个图像文件以这种格式进行解析:

  • Eight bytes denote the height and width as 32 bit ints. 八个字节将高度和宽度表示为32位整数。
  • The rest of the file is image data filled with pixel information, which are represented by 32 bits of information: 文件的其余部分是填充有像素信息的图像数据,由32位信息表示:
    • 8 bits each for Red,Green,Blue 红色,绿色,蓝色各8位
    • 8 bits for transparency information 8位透明度信息

I have created a struct, and I can successfully fill it with the data from the binary file. 我已经创建了一个结构,并且可以成功地用二进制文件中的数据填充它。

However I have now been tasked with shrinking/cropping the image. 但是,我现在的任务是缩小/裁剪图像。 I plan on taking two x,y coordinates. 我计划取两个x,y坐标。 One coordinate to represent the start pixel within the image data, and then another to determine the end pixel such that it will cut a rectangle from the original image and save it into a file (The resulting image will be the rectangle within the 2 sets of coordinates). 一个坐标表示图像数据中的开始像素,然后另一个坐标确定结束像素,以便它将从原始图像中切割出一个矩形并将其保存到文件中(结果图像将是2组中的矩形)。坐标)。

What would be an efficient way to do this cropping operation? 什么是进行此种植操作的有效方法? I was thinking of putting each "pixel" into a pixel struct, and having a 2d array of pixels. 我正在考虑将每个“像素”放入一个像素结构中,并具有一个二维像素数组。 However this seems to make it more complicated than may be necessary. 但是,这似乎使它变得比必要的更为复杂。

I've searched online, but most examples that relate to image processing, that I found, utilize api's. 我已经在网上搜索过,但是发现的大多数与图像处理有关的示例都使用了api。

The best thing is to have a new struct, think of it as a object. 最好的事情是拥有一个新的结构,将其视为一个对象。 Either load the image from a file or create a new image (filled with zeroes). 从文件加载图像或创建新图像(用零填充)。 After that you can use use helper functions which get a pixel or put a pixel to/from an image object. 之后,您可以使用使用帮助器功能来获取像素或向/从图像对象放置像素。

Internally you can represent the object as a byte array (unsigned char *) or an array of structs, but they need to be defined carefully. 在内部,您可以将对象表示为字节数组(无符号char *)或结构数组,但是需要仔细定义它们。 For now I'd go with the byte array method. 现在,我将使用字节数组方法。 For a struct to work right you MIGHT need to be careful, eg ensure that the size of the struct is the same as what's underneath. 为了使结构正常工作,您可能需要小心,例如,确保结构的大小与下面的大小相同。 With the byte array you'll simply have (y*width+x)*pixel_size as the pointer to the pixel, and +0 for red, +1 for green etc. Since it really sounds like a play project or assignment forget about making it fast, just get it to work and let the compiler worry about the speed. 使用字节数组,您只需将(y * width + x)* pixel_size用作像素的指针,将+0表示红色,将+1表示绿色,等等。由于这听起来像是一个播放项目或工作分配,因此不必它运行起来很快,只需使其运行即可,让编译器担心速度。

---- for the transformation ---- ----进行改造----

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));
}

or something similar, the transform function is the key, x=x*scale, scale will depend on the manipulation function, you can perform the transform in float or fixed, if you're good even in integer math. 或类似的东西,转换函数是关键,x = x * scale,比例将取决于操作函数,即使您在整数数学方面也不错,则可以以float或fixed进行转换。 the x scale and y scale might differ. x比例尺和y比例尺可能不同。

To shrink image be half new_max_x = old_max_x/2; 将图片缩小一半new_max_x = old_max_x / 2; new_max_y=old_max_y/2; new_max_y = old_max_y / 2; x_scale=0.5; x_scale = 0.5; y_scale=0.5; y_scale = 0.5;

have fun 玩得开心

It's up to how you have your image class. 这取决于您如何设置图像类。 If you have the pixels stored in a Matrix, then you could do something like: 如果您将像素存储在矩阵中,则可以执行以下操作:

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 the cropping: 对于裁剪:

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

Allocate a block of memory for the new image data. 为新的图像数据分配一个内存块。 Then set a pointer src to point at the top left pixel of the original image data, and another dst to the start of the new image data. 然后将指针src设置为指向原始图像数据的左上像素,另一个dst指向新图像数据的开始。 Then just copy one (new) line's worth of pixel data from src to dst for each line of the new image, incrementing src by the original width and dst by the new width after each line. 然后,只需为新图像的每一行将一条(新)行的像素数据从src复制到dst在每行之后将src原始宽度,将dst新宽度。

EDIT: I did an quick implementation of it -- here's the key part of the cropping operation. 编辑:我做了一个快速的实现-这是裁剪操作的关键部分。

The struct I'm using for the image data: 我用于图像数据的结构:

struct image {
  uint32_t    w;      /* width in pixels */
  uint32_t    h;      /* height in pixels */
  uint32_t    *data;  /* pixel data */
};

...And here's the cropping code, where oimg and nimg are pointers to struct image 's for the original image and cropped image respectively. ...这是裁剪代码,其中oimgnimg是分别指向原始图像和裁剪图像的struct image的指针。 The cropped image's data is allocated (size is nimg->w * nimg->h * sizeof(uint32_t) ) but not initialized. 已分配裁剪图像的data (大小为nimg->w * nimg->h * sizeof(uint32_t) ),但未初始化。 x and y are the top-left coords of the cropped area in oimg . xyoimg裁剪区域的左上角坐标。 nimg->w and nimg->h have been set to the width and height, in pixels, of the cropped image. nimg->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 */
}

The above code assumes that there is no extra data between the end of one image line and the start of the next, and that each image has its own pixel data. 上面的代码假定在一个图像行的末尾与下一个图像行的末尾之间没有多余的数据,并且每个图像都有自己的像素数据。 Some libraries will keep a "stride" value as well as the image width, which holds the offset between lines; 一些库将保留“跨步”值以及图像宽度,该值保留行之间的偏移量。 this allows for extra padding or unused pixels between image lines, useful for maintaining alignment or to allow images that consist of a part of a larger image with which they share pixel data rather than each having a separate copy. 这允许在图像线之间添加额外的填充或未使用的像素,这对于保持对齐或允许包含较大图像的一部分的图像可以共享像素数据,而不是每个图像都有单独的副本是有用的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM