【发布时间】:2019-09-29 05:08:25
【问题描述】:
我正在努力像素化由存储在 二进制 (P6) PPM 文件中的 RGB 值组成的图像。 图像像素化步骤如下:
- 读入二进制数据并存储在一维数组中
- 遍历存储在此数组中的数据,单元格大小为“c”(行 x 列)。用户可以更改此变量“c”,但对于此程序,它当前设置为
int c = 4;,这意味着它迭代块尺寸为4 x 4的像素数据 - 现在找到每个大小为“c”的单元格中的平均颜色值
- 将每个平均颜色值输出到新的输出 PPM 文件
每个二进制 PPM 文件都以以下格式的标题开头,由“幻数”组成,后跟宽度、高度,最后是最大颜色值 255。标题 cmets 被忽略。 以下标题示例显示了 P6 格式的 PPM 图像(因此是 二进制 文件),宽度为 16,高度为 16,最大颜色值为 255:
P6
16
16
255
我在哪里挣扎:
- 我不确定如何找到每个单元格的平均 RGB 值,然后将其输出到新的数据流。通过将该单元格中的总颜色除以循环迭代次数来线性读取数据(即不将其读入数组(或缓冲区))时,我想出了一种方法,但事实证明这是不正确的。
- 嵌套的 for 循环是否以改变输出图像方向的方式排序,例如它是旋转 180 度等吗?我正在努力通过读取原始二进制数据来确定这一点。
我的尝试:
#define _CRT_SECURE_NO_WARNINGS //preprocessor requirement
#include <stdio.h> //library for I/O functions
#include <stdlib.h> //library for general functions
#define magic_size 10 //macro for PPM character found within header
typedef struct {
int t_r, t_g, t_b; //Struct to hold RGB pixel data
} Pixel;
int main()
{
char magic_number[magic_size]; //variable for PPM format
int width = 0, height = 0, max_col = 0; //imagine dimensions
int c = 4; //mosaic parameter
/* INPUT FILE HANDLING */
FILE *inputFile;
inputFile = fopen("Sheffield512x512.ppm", "r");
//input file error handling
if (inputFile == NULL)
{
printf(stderr, "ERROR: file cannot be opened");
getchar(); //prevent cmd premature closure
exit(1); //exit program cleanly
}
/* OUTPUT FILE HANDLING */
FILE *outputFile;
outputFile = fopen("mosaic.ppm", "w");
//output file error handling
if (outputFile == NULL)
{
printf(stderr, "ERROR: cannot write to file");
getchar(); //prevent cmd premature closure
exit(1); //exit program cleanly
}
// Scan the header (these variables are used later on)
fscanf(inputFile, "%s\n%d\n%d\n%d", &magic_number, &width, &height, &max_col);
// Error handling. Program only supports binary files (i.e. of P6 format)
if (magic_number[1] != '6')
{
printf("Only Binary images supported!\n");
getchar(); //prevent cmd premature closure
return;
}
// Raw 1 dimensional store of pixel data
Pixel *data = malloc(width*height * sizeof(Pixel));
//2D index to access pixel data
Pixel **pixels = malloc(height * sizeof(Pixel*));
// Read the binary file data
size_t r = fread(data, width*height, sizeof(unsigned char), inputFile);
// Build a 1-dimensional index for the binary data
for (unsigned int i = 0; i < height; ++i)
{
pixels[i] = data + (i * width);
}
// Close the input file
fclose(inputFile);
/* BEGIN PIXELATION PROCESS */
// Print the OUTPUT file header
fprintf(outputFile, "%s\n%d\n%d\n%d", magic_number, width, height, max_col);
//loop condition variables
int cw_x = ceil((double)(width / (float)c));
int cw_y = ceil((double)(height / (float)c));
//iterate through 2d array in cells of size c
for (int c_x = 0; c_x < cw_x; c_x += 1)
{
for (int c_y = 0; c_y < cw_y; c_y += 1)
{
//iterate within the cells
for (int _x = 0; _x < c; _x++)
{
int x = c_x * c + _x;
//bounds checking
if (x < width)
{
for (int _y = 0; _y < c; _y++)
{
int y = c_y * c + _y;
//bounds checking
if (y < height)
{
//write data to the output FILE stream
fwrite(data, width*height, sizeof(unsigned char), outputFile);
}
}
}
}
}
}
//close the output file
fclose(outputFile);
return 0;
}
【问题讨论】:
-
请注意,
fread(data, width*height, sizeof(unsigned char), ..)的阅读量不够,因为您必须阅读 RGB 值,即Pixels。 -
请注意,
sizeof(Pixel)可能超过 RGB,因为编译器可以填充结构。在声明Pixel之前,使用#pragma pack (push n)和n文件/格式中整数的大小,然后使用#pragma pop。 -
您不要使用
pixels。删除它。 -
fwrite(data, width*height, ..当然总是会写入图像的第一个字节。 -
只是为了好玩...stackoverflow.com/a/47153407/2836621
标签: c image-processing binary ppm pixelate