【发布时间】:2014-12-02 10:22:26
【问题描述】:
您好,我正在开发一个将 640x480 位图图像缩小为 320x240 图像的程序。我一直在研究这个问题一段时间,但我发现的所有好例子都是用于增加图像的大小。
(见这里:http://cboard.cprogramming.com/c-programming/154737-help-program-resize-image.html)
我在将该程序中完成的内容转换为我需要完成的内容时遇到了困难。 到目前为止,这是我的代码:
include stdio.h
include stdlib.h
include string.h
include math.h
pragma pack(push, 1)
typedef struct tagBITMAPFILEHEADER
{
unsigned short bfType; //specifies the file type
unsigned int bfSize; //specifies the size in bytes of the bitmap file
unsigned short bfReserved1; //reserved; must be 0
unsigned short bfReserved2; //reserved; must be 0
unsigned int bfOffBits; //species the offset in bytes from the bitmapfileheader to the bitmap bits
} BITMAPFILEHEADER;
pragma pack(pop)
pragma pack(push, 1)
typedef struct tagBITMAPDIBHEADER
{
unsigned int biSize; //specifies the number of bytes required by the struct
int biWidth; //specifies width in pixels
int biHeight; //species height in pixels
unsigned short biPlanes; //specifies the number of color planes, must be 1
unsigned short biBitCount; //specifies the number of bit per pixel
unsigned int biCompression;//spcifies the type of compression
unsigned int biSizeImage; //size of image in bytes
int biXPelsPerMeter; //number of pixels per meter in x axis
int biYPelsPerMeter; //number of pixels per meter in y axis
unsigned int biClrUsed; //number of colors used by th ebitmap
unsigned int biClrImportant; //number of colors that are important
} BITMAPDIBHEADER;
pragma pack(pop)
pragma pack(push, 1)
typedef struct
{
int rgbtBlue;
int rgbtGreen;
int rgbtRed;
}
RGBTRIPLE;
pragma pack(pop)
int main()
{
FILE *input, *output;
BITMAPDIBHEADER inputdibHeader;
BITMAPFILEHEADER inputfileHeader;
BITMAPDIBHEADER outputdibHeader;
BITMAPFILEHEADER outputfileHeader;
int greenValue = 0;
int blueValue = 0;
int redValue = 0;
fopen_s(&output, "test.bmp", "wb");
if (output == NULL){
return NULL;
}
fopen_s(&input, "lolcat.bmp", "rb");
if (input == NULL)
return NULL;
rewind(input); // rewind the file before reading it again
fread(&(inputfileHeader), sizeof(BITMAPFILEHEADER), 1, input);
fread(&(inputdibHeader), sizeof(BITMAPDIBHEADER), 1, input);
rewind(input); // rewind the file before reading it again
fread(&(outputfileHeader), sizeof(BITMAPFILEHEADER), 1, input);
fread(&(outputdibHeader), sizeof(BITMAPDIBHEADER), 1, input);
outputdibHeader.biWidth = inputdibHeader.biWidth *.5;
outputdibHeader.biHeight = inputdibHeader.biHeight *.5;
outputfileHeader.bfSize = outputdibHeader.biWidth * outputdibHeader.biHeight;
outputdibHeader.biSizeImage = inputdibHeader.biSizeImage *.5;
fwrite(&(outputfileHeader), sizeof(BITMAPFILEHEADER), 1, output);
fwrite(&(outputdibHeader), sizeof(BITMAPDIBHEADER), 1, output);
rewind(input);
fseek(input, inputfileHeader.bfOffBits, SEEK_SET);
fseek(output, outputfileHeader.bfOffBits, SEEK_SET);
int oldheight = inputdibHeader.biHeight;
int oldwidth = inputdibHeader.biWidth;
int i;
int timeswriten = 0;
int oldPad = (4 - ((inputdibHeader.biWidth * sizeof(RGBTRIPLE)) % 4)) % 4;
int newPad = (4 - ((outputdibHeader.biWidth * sizeof(RGBTRIPLE)) % 4)) % 4;
// iterate over infile's scanlines
for (int i = 0; i < abs(oldheight); i++)
{
if (i % 2){
// iterate over pixels in scanline
for (int j = 0; j < oldwidth; j++)
{
// temporary storage
RGBTRIPLE triple;
fread(&triple, sizeof(RGBTRIPLE), 1, input);
if (j % 2){
fwrite(&triple, sizeof(RGBTRIPLE), 1, output);
}
// skip over any input padding
fseek(input, oldPad, SEEK_CUR);
}
}
}
fclose(input);
fclose(output);
}
目前,此代码生成有效的位图图像,但创建的图像是原始图像的严重失真版本。我相当确定这是由于我从新图像中省略像素的方式,但我不确定应该采用什么合适的方法。 总的来说,我的问题是谁能帮我解释我应该在哪里以及如何省略像素?
更新
我现在知道我的目标是将 2x2 像素平均为一个像素,但我找不到一个很好的例子来说明如何做到这一点。谁能解释一下这个过程?
更新 2 感谢 PeterT,我知道以下代码似乎是正确的,但我的输出却不是。
RGBTRIPLE *line_a = (RGBTRIPLE*)malloc(inputdibHeader.biWidth * sizeof(RGBTRIPLE)); /* check malloc() */
RGBTRIPLE *line_b = (RGBTRIPLE*)malloc(inputdibHeader.biWidth *sizeof(RGBTRIPLE)); /* check malloc() */
RGBTRIPLE *dest_line = (RGBTRIPLE*)malloc(outputdibHeader.biWidth * sizeof(RGBTRIPLE));
/* move through the target array line by line, consuming two lines from the source
image at a time */
/* also assuming you verified the source image is exactly 2x the size of the dest
malloc() */
for (i = 0; i < outputdibHeader.biHeight; ++i)
{
fread(&(line_a), sizeof(RGBTRIPLE), inputdibHeader.biWidth, input); /* read scanline & advance file pointer, err check in func */
fread(&(line_b), sizeof(RGBTRIPLE), inputdibHeader.biWidth, input);/* read scanline & advance file pointer, err check in func */
for (j = 0; j < outputdibHeader.biWidth; ++j)
{
bilinear_filter(&(dest_line[j]), &(line_a[j * 2]), &(line_a[(j * 2) + 1]), &(line_b[j * 2]), &(line_b[(j * 2) + 1]));
}
fwrite(&(dest_line), sizeof(RGBTRIPLE), outputdibHeader.biWidth, output);
/* or something... point is we're creeping through the files scaline by scanline,
and letting another function handle it to keep this code more intelligble */
}
fclose(input);
fclose(output);
}
void bilinear_filter(RGBTRIPLE *dest, RGBTRIPLE *A, RGBTRIPLE *B, RGBTRIPLE *C, RGBTRIPLE *D)
{
/* assuming 0888 ARGB */
dest->Red = (A->Red + B->Red + C->Red + D->Red) / 4;
dest->Green = (A->Green + B->Green + C->Green + D->Green) / 4;
dest->Blue = (A->Blue + B->Blue + C->Blue + D->Blue) / 4;
}
我认为这个问题可能在于我的标题创建,所以这里是
fread(&(inputHeader), sizeof(TwoHeader), 1, input);
inputfileHeader = inputHeader.fileHeader;
inputdibHeader = inputHeader.dibHeader;
rewind(input); // rewind the file before reading it again
fread(&(outputHeader), sizeof(TwoHeader), 1, input);
outputfileHeader = outputHeader.fileHeader;
outputdibHeader = outputHeader.dibHeader;
outputdibHeader.biWidth = inputdibHeader.biWidth *.5;
outputdibHeader.biHeight = inputdibHeader.biHeight *.5;
//outputfileHeader.bfSize = inputfileHeader.bfSize - (inputdibHeader.biWidth*inputdibHeader.biHeight) + outputdibHeader.biWidth*outputdibHeader.biHeight;
outputfileHeader.bfSize = sizeof(BITMAPFILEHEADER)+sizeof(BITMAPDIBHEADER)+outputdibHeader.biSizeImage;
//outputdibHeader.biSizeImage = inputdibHeader.biSizeImage * .25;
//outputdibHeader.biXPelsPerMeter = inputdibHeader.biXPelsPerMeter * .5;
//outputdibHeader.biYPelsPerMeter = inputdibHeader.biYPelsPerMeter * .5;
//fwrite(&(outputfileHeader), sizeof(BITMAPFILEHEADER), 1, output);
//fwrite(&(outputdibHeader), sizeof(BITMAPDIBHEADER), 1, output);
fwrite(&(outputHeader), sizeof(TwoHeader), 1, output);
rewind(input);
fseek(input, inputfileHeader.bfOffBits, SEEK_SET);
fseek(output, outputfileHeader.bfOffBits, SEEK_SET);
请原谅所有的 cmets 大部分是旧代码或我不确定的代码。
【问题讨论】:
-
可能与您的问题无关(您可能需要更详细地解释),但如果您将图像的宽度和高度都减半,则新的
biSizeImage不会是 1 /2,实际上是 1/2*1/2 = 1/4 大小。主要是,我猜你的 RGB Triplets 应该是unsigned char,而不是int。 -
有相当多的算法具有不同的效率和质量水平。这是一个相当广泛的主题。这可能会让你思考一些事情:stackoverflow.com/questions/6133957/…
-
@RetiredNinja 谢谢这有很大帮助,至少现在我知道要寻找什么了。不幸的是,该页面并没有真正展示任何关于算法在使用中的样子的好例子。我会找一个。如果你碰巧知道一个,你也可以链接。
-
code.google.com/p/nvidia-texture-tools/wiki/MipmapGeneration 有一些关于一些下采样算法/过滤器背后的理论的文章,如果您选择不重新发明轮子,它也是一个很好的库。
标签: c image-resizing bitmapimage