将BMP转换为2D矩阵弄乱颜色

发布于 2025-02-04 08:16:57 字数 2738 浏览 3 评论 0原文

我正在尝试创建一个2D数组,该数组包含图像中每个像素的RGB值, 我创建了原始图像的副本,以查看图像是否相似,并且我知道输出主要是灰色像素。 (我尝试仅使用标准库)。

这就是我使用

typedef struct { //bmp file values struct
int width;
int height;
} image_t;

typedef struct { //pixel color
unsigned char r;
unsigned char g;
unsigned char b;
} color_t;

主的

int main() {
int i, j;

color_t** matrix;
static image_t image;

if ((LoadSprite(&image, BMP)) != 0) {
    printf_s("Failed to load file: \" %s\"", BMP);
    return -1;
}

matrix = malloc(sizeof(color_t*) * image.height); // allocate memory to image pixel matrix
for (i = 0;i < image.height;i++) {
    matrix[i] = malloc(sizeof(color_t) * image.width);
}

imgtrx(matrix, image, BMP);
CreateBMP(BMPCPY, matrix, image.height, image.width);


return 0;
}

结构。宽度

void imgtrx(color_t** mtrx, image_t image, char* filename) {
int val, t, i = 0, j, k = 0;
FILE* file;

val = fopen_s(&file, filename, "rt");

//fseek(file, 54, SEEK_SET);

fseek(file, 10, SEEK_SET);
fread(&t, 1, 4, file);     //reads the offset and puts it in t
fseek(file, t, SEEK_SET);
int  p, e;

for ( i = 0; i < image.width; i++)
{
    for (j = 0;j < image.height;j++) {
        fread(&mtrx[i][j].r, 8, 1, file);
        fread(&mtrx[i][j].g, 8, 1, file);
        fread(&mtrx[i][j].b, 8, 1, file);
    }
}


fclose(file);

return 0;
}

以下功能将2D数组转换为单个维度并写入BMP副本

void CreateBMP(char* filename, color_t** matrix, int height, int width) 
{
    int i, j;
    int padding, bitmap_size;
    color_t* wrmat;

    wrmat = malloc(sizeof(color_t) * height * width);

    for (i = 0;i < height;i++) {
        for (j = 0;j < width;j++) {
            wrmat[i + j] = matrix[i][j];
        }
    }

    if (((width * 3) % 4) != 0) {
        padding = (width * 3) + 1;
    }
    else
    {
        padding = width * 3;
    }

    bitmap_size = height * padding * 3;

    char tag[] = { 'B', 'M' };
    int header[] = {
        0x3a, 0x00, 0x36,
        0x28,                // Header Size
        width, height,       // Image dimensions in pixels
        0x180001,            // 24 bits/pixel, 1 color plane
        0,                   // BI_RGB no compression
        0,                   // Pixel data size in bytes
        0x002e23, 0x002e23,  // Print resolution
        0, 0,                // No color palette
    };
    header[0] = sizeof(tag) + sizeof(header) + bitmap_size;

    FILE* fp;
    fopen_s(&fp, filename, "w+");
    fwrite(&tag, sizeof(tag), 1, fp);
    fwrite(&header, sizeof(header), 1, fp); //write header to disk
    fwrite(wrmat, bitmap_size * sizeof(char), 1, fp);
    fclose(fp);

    fclose(fp);
    free(wrmat);
}

I'm trying to create a 2d array that contains RGB value for each pixel in the image,
I created a copy of the original image to check out if the images are similar and I got that the output is mostly gray pixels.
(I try to use only standard libraries).

that's the structs I use

typedef struct { //bmp file values struct
int width;
int height;
} image_t;

typedef struct { //pixel color
unsigned char r;
unsigned char g;
unsigned char b;
} color_t;

the main

int main() {
int i, j;

color_t** matrix;
static image_t image;

if ((LoadSprite(&image, BMP)) != 0) {
    printf_s("Failed to load file: \" %s\"", BMP);
    return -1;
}

matrix = malloc(sizeof(color_t*) * image.height); // allocate memory to image pixel matrix
for (i = 0;i < image.height;i++) {
    matrix[i] = malloc(sizeof(color_t) * image.width);
}

imgtrx(matrix, image, BMP);
CreateBMP(BMPCPY, matrix, image.height, image.width);


return 0;
}

the function imgtrx essentially assigns RGB pixel value to the correct location in the matrix according to the image height & width

void imgtrx(color_t** mtrx, image_t image, char* filename) {
int val, t, i = 0, j, k = 0;
FILE* file;

val = fopen_s(&file, filename, "rt");

//fseek(file, 54, SEEK_SET);

fseek(file, 10, SEEK_SET);
fread(&t, 1, 4, file);     //reads the offset and puts it in t
fseek(file, t, SEEK_SET);
int  p, e;

for ( i = 0; i < image.width; i++)
{
    for (j = 0;j < image.height;j++) {
        fread(&mtrx[i][j].r, 8, 1, file);
        fread(&mtrx[i][j].g, 8, 1, file);
        fread(&mtrx[i][j].b, 8, 1, file);
    }
}


fclose(file);

return 0;
}

the following function converts the 2d array to single dimensions and writes a BMP copy

void CreateBMP(char* filename, color_t** matrix, int height, int width) 
{
    int i, j;
    int padding, bitmap_size;
    color_t* wrmat;

    wrmat = malloc(sizeof(color_t) * height * width);

    for (i = 0;i < height;i++) {
        for (j = 0;j < width;j++) {
            wrmat[i + j] = matrix[i][j];
        }
    }

    if (((width * 3) % 4) != 0) {
        padding = (width * 3) + 1;
    }
    else
    {
        padding = width * 3;
    }

    bitmap_size = height * padding * 3;

    char tag[] = { 'B', 'M' };
    int header[] = {
        0x3a, 0x00, 0x36,
        0x28,                // Header Size
        width, height,       // Image dimensions in pixels
        0x180001,            // 24 bits/pixel, 1 color plane
        0,                   // BI_RGB no compression
        0,                   // Pixel data size in bytes
        0x002e23, 0x002e23,  // Print resolution
        0, 0,                // No color palette
    };
    header[0] = sizeof(tag) + sizeof(header) + bitmap_size;

    FILE* fp;
    fopen_s(&fp, filename, "w+");
    fwrite(&tag, sizeof(tag), 1, fp);
    fwrite(&header, sizeof(header), 1, fp); //write header to disk
    fwrite(wrmat, bitmap_size * sizeof(char), 1, fp);
    fclose(fp);

    fclose(fp);
    free(wrmat);
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

稀香 2025-02-11 08:16:57

请注意,BMP文件可以具有不同的像素格式,如Win32和OS/2的Microsoft手册中记录的Bitmapinfoheader家族中所述。

从您的“全灰色”结果中,我怀疑您试图将少于24BPP格式解释为RGB值,或者遇到了阅读文件像素区域的技术问题。

因此,要执行您要尝试的操作,您的代码需要读取Bitmapinfoheader结构的前4个字节,请使用它来确定结构版本,然后在Bitmapinforheader的其余部分中读取以确定像素数组格式和大小/调色板/颜色信息结构的格式位于bitmapinfoheader和实际像素之间。

还要记住,将任何标头字段(包括您已经解析的偏移字段)从Little Endian磁盘格式转换为CPU使用的运行时。
请注意,使用“负高值”来表明反向扫描线顺序非常普遍,因为大多数PC和电视硬件首先是左上像素的左上像素,而正高度BMP文件首先存储左下像素。

bitmapinfoheader结构版本是这些:
2。Bitmapcoreheader(从1980年代开始)
3。bitmapinfoheader(由于Windows 3.00)
4。BITMAPV4HEADER
5。BITMAPV5HEADER(请注意,该文档在链接的颜色配置文件描述中具有错别字)。

要担心的像素格式为:

  • 1BPP(黑色和白色,强制性调色板表示相当于0和1位的RGB),如CGA/EGA/EGA/VGA硬件,每个字节中最重要的位是最左边的(本质上是一个大的endian像素格式)。

  • 4BPP(传统上是标准的CGA颜色,但调色板可以为16个可能的像素代码指定任何其他RGB值)。每个字节中最重要的4位是最左边的像素(本质上是一个大的Endian像素格式)。此格式还用于3BPP EGA硬件像素和2BPP CGA像素,但仅使用16个值中的8或4个。

  • 8BPP(强制性调色板指示每个字节值映射如何到RGB值)。 VGA硬件包括专用芯片(RAMDAC),以显示显示器的完整像素速度进行RGB映射。

  • 16BPP(强制性调色板是3个unit32_t位置板的数组,每个像素与每个像素一起仅恢复存储B,G和R值的位,将这些掩码转换为适当的移位值,作为每个图形的练习程序员)。每个像素是一个小的endian 2个字节值,它具有3个掩码值,以获取蓝色,绿色和红色通道值。最常见的位mask值是5:5:5 15BPP硬件的值,以及5:6:5的硬件,带有1个绿色位。

  • 24BPP(没有调色板或掩码数据)每个像素为蓝色,绿色,红色顺序为3个字节,每个像素的颜色值为255。

  • 32bpp与16BPP相同,仅在4个字节每个像素值。面具描述的常见格式是蓝色,绿色,红色,X和红色,绿色,蓝色,x,其中x可能为0,随机噪声或α通道。还有一些文件使用每个颜色通道超过8位来编码HDR图像。如果您正在编写通用解码器,则至少需要提取每个颜色频道的8个最重要的位,尽管很少需要额外的像素位。

除了所有这些颜色格式之外,标头可能指示多种压缩格式中的任何一种,最值得注意的是Windows 3.x使用的历史性BMP RLE4和BMP RLE8压缩以及使用诸如JPEG之类的常见第三方压缩,但是使用BMP格式由于如今围绕压缩图像的包装非常罕见,因此您可能不必担心,但是,这是向您询问GPU或激光打印机对您进行解压缩JPEG和PNG文件的传统方法在检查其他GDI/GPI API报告是否已安装的驱动程序支持此方面,内存中的JPEG(来自标准JFIF文件)以及内存中的位Mapinfoheader结构到GDI或GPI API。

Note that BMP files can have different pixel formats as detailed in the BITMAPINFOHEADER family of structures documented in the Microsoft manuals for Win32 and OS/2 .

From your "all grey" result, I suspect you are trying to interpret a less than 24bpp format as RGB values, or have run into a technical problem reading the pixel area of the file.

So to do what you are trying to do, your code needs to read the first 4 bytes of the BITMAPINFOHEADER structure, use that to determine the structure version, then read in the rest of the BITMAPINFORHEADER to determine the pixel array format and the size/format of the palette/color information structures that lie between the BITMAPINFOHEADER and the actual pixels.

Also remember to convert any header fields (including the offset field you already parse) from little endian disk format to whatever your runtime CPU uses.
Please note the use of "negative height value" to indicate reversed scanline order is extremely common, as most PC and television hardware stores the top left pixel first, while positive height BMP files store the bottom left pixel first.

The BITMAPINFOHEADER structure versions to worry about are these:
2. BITMAPCOREHEADER (from the 1980s)
3. BITMAPINFOHEADER (Since Windows 3.00)
4. BITMAPV4HEADER
5. BITMAPV5HEADER (Note that the documentation has typos in the linked color profile description).

The pixel formats to worry about are:

  • 1bpp (black and white, with a mandatory palette indicating the RGB equivalent of 0 and 1 bits), as in CGA/EGA/VGA hardware, the most significant bit of each byte is the leftmost (essentially a big endian pixel format).

  • 4bpp (traditionally standard CGA colors, but the palette can specify any other RGB values for the 16 possible pixel codes). The most significant 4 bits of each byte are the leftmost pixel (essentially a big endian pixel format). This format is also used for 3bpp EGA hardware pixels and 2bpp CGA pixels, but using only 8 or 4 of the 16 values.

  • 8bpp (the mandatory palette indicates how each byte value maps to RGB values). VGA hardware included a dedicated chip (the RAMDAC) to do the RGB mapping at the full pixel speed of the monitor.

  • 16bpp (the mandatory palette is an array of 3 unit32_t bitmasks to AND with each pixel to get back only the bits storing the B, G and R values, converting those masks to appropriate shift values is left as an exercise for every graphics programmer). Each pixel is a little endian 2-byte value to be ANDed with the 3 mask values to get the Blue, Green and Red channel values. Most common bitmask values are those for 5:5:5 15bpp hardware and those for 5:6:5 hardware with 1 more green bit.

  • 24bpp (there is no palette or mask data) each pixel is 3 bytes in the order Blue, Green, Red, each giving the color values as a fraction of 255.

  • 32bpp is the same as 16bpp, only with 4 bytes in each pixel value. Common formats described by the mask are Blue,Green,Red,x and Red,Green,Blue,x where x may be 0, random noise or an alpha channel. There are also a few files that use more than 8 bits per color channel to encode HDR images. If you are writing a generic decoder, you need to at least extract the 8 most significant bits of each color channel, though keeping extra pixel bits is rarely necessary.

On top of all these color formats, the HEADER may indicate any of multiple compression formats, most notably the historic BMP RLE4 and BMP RLE8 compressions used by Windows 3.x and the use of common 3rd party compressions such as JPEG, however using BMP format as a wrapper around compressed images is quite rare these days, so you probably don't need to worry, it is however the traditional way to ask the GPU or laser printer to decompress JPEG and PNG files for you, by passing the contents of an in-memory JPEG (from a standard JFIF file) along with an in-memory BITMAPINFOHEADER structure to a GDI or GPI API after checking that other GDI/GPI APIs report that the installed driver supports this.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文