我試圖計算RGB三色空間與libpng在C,和NumPy在Python中的平均向量,但我得到不同的結果與每個。我非常有信心Python給出this image的[ 127.5 127.5 0. ]
的正確結果。但是,在下面的C塊中,我得到了[ 38.406494 38.433670 38.459641 ]
的荒謬結果。我一直盯着我的代碼數週沒有任何給予,所以我想我會看看別人是否有想法。不同的結果與libpng和numpy的平均向量計算
此外,我已經測試了這個代碼與其他圖像,它給出了類似的荒謬結果。這很好奇,因爲所有三個數字通常匹配前4位左右的數字。我不確定可能是什麼原因造成的。
/* See if our average vector matches that of Python's */
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <png.h>
// For getting the PNG data and header/information back
typedef struct
{
uint32_t width; // width of image
uint32_t height; // height of image
int bit_depth; // bits/pixel component (should be 8 in RGB)
png_bytep datap; // data
} rTuple;
#define PNG_BYTES_TO_CHECK 8
#define CHANNELS 3
int
check_PNG_signature(unsigned char *buffer)
{
unsigned i;
const unsigned char signature[8] = { 0x89, 0x50, 0x4e, 0x47,
0x0d, 0x0a, 0x1a, 0x0a };
for (i = 0; i < PNG_BYTES_TO_CHECK; ++i)
{
if (buffer[i] != signature[i])
{
fprintf(stderr, "** File sig does not match PNG, received ");
for (i = 0; i < PNG_BYTES_TO_CHECK; ++i)
fprintf(stderr, "%.2X ", buffer[i]);
fprintf(stderr, "\n");
abort();
}
}
return 1;
}
rTuple
read_png_file(char *file_name)
{
/* Get PNG data - I've pieced this together by reading `example.c` from
beginning to end */
printf("** Reading data from %s\n", file_name);
png_uint_32 width, height; // holds width and height of image
uint32_t row; // for iteration later
int bit_depth, color_type, interlace_type;
unsigned char *buff = malloc(PNG_BYTES_TO_CHECK * sizeof(char));
memset(buff, 0, PNG_BYTES_TO_CHECK * sizeof(char));
FILE *fp = fopen(file_name, "rb");
if (fp == NULL) abort();
if (fread(buff, 1, PNG_BYTES_TO_CHECK, fp) != PNG_BYTES_TO_CHECK) {
fprintf(stderr, "** Could not read %d bytes\n", PNG_BYTES_TO_CHECK);
abort();
}
check_PNG_signature(buff);
rewind(fp);
// create and initialize the png_struct, which will be destroyed later
png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING
, NULL /* Following 3 mean use stderr & longjump method */
, NULL
, NULL
);
if (!png_ptr) abort();
png_infop info_ptr = png_create_info_struct(png_ptr);
if (!info_ptr) abort();
// following I/O initialization method is required
png_init_io(png_ptr, fp);
png_set_sig_bytes(png_ptr, 0); // libpng has this built in too
// call to png_read_info() gives us all of the information from the
// PNG file before the first IDAT (image data chunk)
png_read_info(png_ptr, info_ptr);
// Get header metadata now
png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
&interlace_type, NULL, NULL);
// Scale 16-bit images to 8-bits as accurately as possible (shouldn't be an
// issue though, since we're working with RGB data)
#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED
png_set_scale_16(png_ptr);
#else
png_set_strip_16(png_ptr);
#endif
png_set_packing(png_ptr);
// PNGs we're working with should have a color_type RGB
if (color_type == PNG_COLOR_TYPE_PALETTE)
png_set_palette_to_rgb(png_ptr);
// Required since we selected the RGB palette
png_read_update_info(png_ptr, info_ptr);
// Allocate memory to _hold_ the image data now (lines 547-)
png_bytep row_pointers[height];
for (row = 0; row < height; ++row)
row_pointers[row] = NULL;
for (row = 0; row < height; ++row)
row_pointers[row] = png_malloc(png_ptr,\
png_get_rowbytes(png_ptr, info_ptr)
);
png_read_image(png_ptr, row_pointers);
png_read_end(png_ptr, info_ptr);
// Now clean up - the image data is in memory
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
fclose(fp);
rTuple t = { width, height, bit_depth, *row_pointers };
return t;
}
int
main(int argc, char *argv[])
{
if (argc != 2) {
printf("** Provide filename\n");
abort();
}
char *fileName = argv[1];
// get data read
rTuple data = read_png_file(fileName);
/* let's try computing the absolute average vector */
uint32_t i, j, k;
double *avV = malloc(CHANNELS * sizeof(double));
memset(avV, 0, sizeof(double) * CHANNELS);
double new_px[CHANNELS];
png_bytep row, px;
for (i = 0; i < data.height; ++i)
{
row = &data.datap[i];
for (j = 0; j < data.width; ++j)
{
px = &(row[j * sizeof(int)]);
for (k = 0; k < CHANNELS; ++k) {
new_px[k] = (double)px[k];
avV[k] += new_px[k];
}
}
}
double size = (double)data.width * (double)data.height;
for (k = 0; k < CHANNELS; ++k) {
avV[k] /= size;
printf("channel %d: %lf\n", k + 1, avV[k]);
}
printf("\n");
return 0;
}
現在與Python我只是一個簡單的上下文管理和計算np.mean(image_data, axis=(0, 1))
,這將產生上述結果我打開一個圖像。
工程很棒。感謝您的所有觀點!這說得通。另外,我前幾天讀到,沒有必要施放'malloc'?在它們之前刪除'(png_bytep *)'仍然會導致編譯成功。 – bjd2385
不客氣!是的,不需要投射'malloc'。我從代碼中刪除了它。感謝您提高答案。 – hmofrad