我很难理解和解析位图图像中存在的信息数据。为了更好地理解,我阅读了以下教程Raster Data.
现在,存在的代码如下,(Greyscale 8bit颜色值)
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
/*-------STRUCTURES---------*/
typedef struct {int rows; int cols; unsigned char* data;} sImage;
/*-------PROTOTYPES---------*/
long getImageInfo(FILE*, long, int);
int main(int argc, char* argv[])
{
FILE *bmpInput, *rasterOutput;
sImage originalImage;
unsigned char someChar;
unsigned char* pChar;
int nColors; /* BMP number of colors */
long fileSize; /* BMP file size */
int vectorSize; /* BMP vector size */
int r, c; /* r = rows, c = cols */
/* initialize pointer */
someChar = '0';
pChar = &someChar;
if(argc < 2)
{
printf("Usage: %s bmpInput.bmp\n", argv[0]);
//end the execution
exit(0);
}
printf("Reading filename %s\n", argv[1]);
/*--------READ INPUT FILE------------*/
bmpInput = fopen(argv[1], "rb");
//fseek(bmpInput, 0L, SEEK_END);
/*--------DECLARE OUTPUT TEXT FILE--------*/
rasterOutput = fopen("data.txt", "w");
/*--------GET BMP DATA---------------*/
originalImage.cols = (int)getImageInfo(bmpInput, 18, 4);
originalImage.rows = (int)getImageInfo(bmpInput, 22, 4);
fileSize = getImageInfo(bmpInput, 2, 4);
nColors = getImageInfo(bmpInput, 46, 4);
vectorSize = fileSize - (14 + 40 + 4*nColors);
/*-------PRINT DATA TO SCREEN-------------*/
printf("Width: %d\n", originalImage.cols);
printf("Height: %d\n", originalImage.rows);
printf("File size: %ld\n", fileSize);
printf("# Colors: %d\n", nColors);
printf("Vector size: %d\n", vectorSize);
/*----START AT BEGINNING OF RASTER DATA-----*/
fseek(bmpInput, (54 + 4*nColors), SEEK_SET);
/*----------READ RASTER DATA----------*/
for(r=0; r<=originalImage.rows - 1; r++)
{
for(c=0; c<=originalImage.cols - 1; c++)
{
/*-----read data and print in (row,column) form----*/
fread(pChar, sizeof(char), 1, bmpInput);
fprintf(rasterOutput, "(%d, %d) = %d\n", r, c, *pChar);
}
}
fclose(bmpInput);
fclose(rasterOutput);
}
/*----------GET IMAGE INFO SUBPROGRAM--------------*/
long getImageInfo(FILE* inputFile, long offset, int numberOfChars)
{
unsigned char *ptrC;
long value = 0L;
unsigned char dummy;
int i;
dummy = '0';
ptrC = &dummy;
fseek(inputFile, offset, SEEK_SET);
for(i=1; i<=numberOfChars; i++)
{
fread(ptrC, sizeof(char), 1, inputFile);
/* calculate value based on adding bytes */
value = (long)(value + (*ptrC)*(pow(256, (i-1))));
}
return(value);
} /* end of getImageInfo */
我不理解: -
我无法理解&#39; GET IMAGE INTOSUBPROGRAM&#39; 部分代码试图获取图像信息,如行,列等没有。为什么这些信息是否存储在4个字节以上,value = (long)(value + (*ptrC)*(pow(256, (i-1))));
指令的用途是什么。
为什么创建了unsigned char dummy ='0'
然后分配了ptrC =&dummy
?
为什么我们只能通过读取1个字节的数据来获取图像中的行数,例如获取特定行和列的灰度值。
为什么我们使用 unsigned char 来存储字节,是不是有其他数据类型或int或long我们可以在这里有效使用?
请帮助我理解这些疑惑(混乱!!?)如果他们听起来很无聊,我会原谅我。
谢谢。
答案 0 :(得分:3)
我会说这个教程在某些方面非常糟糕,你理解它的问题并不总是因为初学者。
我无法理解'GET IMAGE INTOSUBPROGRAM'部分,其中代码试图获取图像信息,如行,列等没有。为什么这些信息存储超过4个字节,值的用途是什么=(长)(值+( ptrC)(pow(256,(i-1))));指令。
存储超过4个字节的原因是允许图像的大小在0到2 ^ 32-1之间。如果我们只使用一个字节,我们只能有0..255的图像和2个字节的0..65535。
奇怪的value = (long)(value + (*ptrC)*(pow(256, (i-1))));
是我以前从未见过的。它用于将字节转换为long,以便它可以用于任何字节序。我们的想法是使用256的幂来将*ptrC
设置为value
,即将第一个字节与1相乘,然后将其与256相乘,接着将其与65536等相乘。
更易读的方法是使用班次,例如value = value + ((long)(*ptrC) << 8*(i-1));
。或者更好的是从最高的一个读取字节到更低的字节并使用value = value << 8 + *ptrC;
。在我的眼中好多了,但是当字节以不同的顺序出现时,并不总是那么简单。
更容易理解的简单重写是
long getImageInfo(FILE* inputFile, long offset, int numberOfChars)
{
unsigned char ptrC;
long value = 0L;
int i;
fseek(inputFile, offset, SEEK_SET);
for(i=0; i<numberOfChars; i++) // Start with zero to make the code simpler
{
fread(&ptrC, 1, 1, inputFile); // sizeof(char) is always 1, no need to use it
value = value + ((long)ptrC << 8*i); // Shifts are a lot simpler to look at and understand what's the meaning
}
return value; // Parentheses would make it look like a function
}
为什么会创建unsigned char dummy ='0'然后分配ptrC =&amp; dummy?
这也毫无意义。他们可以使用unsigned char ptrC
,然后使用&ptrC
代替ptrC
和ptrC
代替*ptrC
。这也表明它只是一个普通的静态变量。
为什么我们不能通过读取1个字节的数据来获取图像中的行数,例如获取特定行和列的灰度值。
如果图像高3475行怎么办?一个字节是不够的。所以它需要更多的字节。阅读方式有点复杂。
为什么我们使用unsigned char来存储字节,是不是有其他数据类型或int或long我们可以在这里有效使用?
无符号字符长度恰好是一个字节。那么为什么我们会使用任何其他类型来存储一个字节呢?
答案 1 :(得分:1)
(4)二进制文件的数据由字节组成,在C中由unsigned char
表示。因为这是一个很长的要输入的词,有时typedef
会被byte
或uchar
提供。一种良好的符合标准的定义字节的方法是使用uint8_t
中的<stdint.h>
。
(3)我不太确定你想要的是什么,但是第一个字节 - 通常是54,但有一些BMP文件 - 构成了一个BMP文件,其中包含有关颜色的信息图像的深度,宽度和高度。字节54之后的字节存储原始数据。我没有测试过yopur代码,但填充可能存在问题,因为必须填充每行的数据以使原始数据大小可以被4整除。
(2)这里定义一个额外的指针没有意义。您也可以直接fread(&dummy, ...)
。
(1)呃。此函数从文件中位置offset
的文件中读取多字节值。该文件由字节组成,但是几个字节可以形成其他数据类型。例如,一个4字节的无符号字由:
uint8_t raw[4];
uint32_t x;
x = raw[0] + raw[1]*256 + raw[2]*256*256 + raw[3]*256*256*256;
在PC上,它使用Little Endian数据。
该示例还显示了pow(256, i)
的来源。在这里使用pow
函数不是一个好主意,因为它意味着与浮点数一起使用。即使乘以256也不是很惯用。通常,我们通过字节移位来构造值,其中乘以2是左移1,因此乘以256是左移8。类似地,上面的加法添加非重叠范围并且通常表示为按位OR,|
:
x = raw[0] | (raw[1]<<8) | (raw[2]<<16) | (raw[3]<<24);
该函数通过重新定位文件指针(并将其保留在新位置)来访问文件。那不是很有效。最好将标题读取为54字节数组并直接访问数组。
代码陈旧而笨拙。看到类似的东西:
for(r=0; r<=originalImage.rows - 1; r++)
已经足够让我不相信它。我相信你可以找到一个从BMP读取灰度图像的更好例子。您甚至可以自己编写,并以BMP格式的Wikipedia article开头。