我正在努力像素化由存储在 binary (P6)PPM文件中的RGB值组成的图像。 像素化图像的步骤如下:
int c = 4;
,这意味着它将以4 x 4
的块尺寸遍历像素数据。每个二进制PPM文件均以以下格式的标头开头,包括“魔术数字”,然后是宽度,高度,最后是最大颜色值255。标头注释将被忽略。以下标头示例显示了格式为P6(因此为 binary 文件),宽度为16,高度为16和最大颜色值为255的PPM图像:
P6
16
16
255
我在哪里挣扎:
我的尝试
#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;
}
答案 0 :(得分:2)
在评论中,我给了您一些有关代码错误的反馈。您可以自己修复这些问题。使用调试器来测试/检查所有这些准备步骤。例如,读取文件并立即将其写入(并显示图像),这样您就可以确定读取没问题。
您的主要问题是循环。
从本质上讲,您有一个一维数组,该数组由scanline-after-scanline组成,每条扫描线均包含像素。与BMP格式相反,您的格式似乎未使用填充字节在字边界上对齐扫描线。这样会更容易。
一个像素由三个颜色值R,G和B组成,我假设每个颜色值都是一个字节(无符号字符)。然后,内存分配和读取变为:
unsigned char *data = malloc(width*height*3);
r = fread(data, width*height*3, 1, inputFile);
该循环现在以4的增量遍历所有行,并以4的增量遍历每个像素。因此,它一次处理一个正方形,计算平均值并将其写出:
c= 4;
for (y=0; y<height; y += c)
{
for (x=0; x<width; x += c)
{
unsigned int avgR=0, avgG=0, avgB= 0;
for (dy=0; dy<c && y+dy<height; dy++)
{
for (dx=0; dx<c && x+dx<width; dx++)
{
avgR += data[ y*width*3 // line in image
+ x*3 // pixel on line
+ dy*width*3 // line of square
+ dx*3 // R pixel in line of square
];
avgG += data[ y*width*3 // line in image
+ x*3 // pixel on line
+ dy*width*3 // line of square
+ dx*3 + 1 // G pixel in line of square
];
avgB += data[ y*width*3 // line in image
+ x*3 // pixel on line
+ dy*width*3 // line of square
+ dx*3 + 2 // B pixel in line of square
];
}
}
unsigned char avgRb= avgR/(dx*dy);
unsigned char avgGb= avgG/(dx*dy);
unsigned char avgBb= avgB/(dx*dy);
fwrite(&avgR,1,1,outputFile);
fwrite(&avgG,1,1,outputFile);
fwrite(&avgB,1,1,outputFile);
}
}
这可以使用指针算法进行优化,但这显示了所需的循环基础。
注意:
..&& y+dy<height
在最后一个正方形不适合高度时测试边框情况。宽度相同。
因此,平均值是通过除以(dx*dy)
而得出的。
免责声明
我无法测试它,因此该算法是一种心理构造。