使用libpng和numpy进行平均向量计算的结果不同

时间:2017-01-02 03:42:47

标签: c python-3.x numpy libpng

我试图用C中的libpng和Python中的NumPy计算RGB三刺激空间中的平均向量,但我得到的结果各不相同。我非常有信心Python使用[ 127.5 127.5 0. ] [ 38.406494 38.433670 38.459641 ]给出了正确的结果。但是,使用以下C块,我得到了/* 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; } 的荒谬结果。几个星期以来,我一直盯着我的代码而没有给予任何帮助,所以我想我能看出其他人是否有想法。

此外,我已经使用其他图片测试了此代码,并且它提供了类似的荒谬结果。这很奇怪,因为所有三个数字通常都匹配前4个左右的数字。我不确定是什么导致了这一点。

np.mean(image_data, axis=(0, 1))

现在使用Python我只需使用简单的上下文管理器打开图像并计算var shuffle = function (items) { var item, randomIndex; for(var i = 0; i < items.length; i++){ randomIndex= (Math.random() * items.length) | 0; item = items[i]; items[i] = items[randomIndex]; items[randomIndex] = item; } } describe('Suite', function() { it("should a", function () { console.log("execute a"); }); it("should b", function () { console.log("execute b"); }); it("should c", function () { console.log("execute c"); }); shuffle(this.children); // shuffle the 'it' blocks }); ,这会产生上面的结果。

1 个答案:

答案 0 :(得分:1)

基本上,你有一些错误(libpng方面和指针算术),我试图通过比较你的代码Github gist来找到它们。以下是我为制作与Python NumPy相同的图像均值所做的更改列表。

  1. rTuple结构中,您需要使用png_bytep datappng_byte更改为png_bytep *datap;类型的指针。
  2. read_png_file中,使用png_set_filler在读取图像后添加填充字节。有关详细信息,请参阅here

    if(color_type == PNG_COLOR_TYPE_RGB  ||
       color_type == PNG_COLOR_TYPE_GRAY ||
       color_type == PNG_COLOR_TYPE_PALETTE)
    png_set_filler(png_ptr, 0xFF, PNG_FILLER_AFTER);
    
  3. read_png_file中,在使用row_pointers

  4. 分配png_read_update_info(png_ptr, info_ptr);之前更新更改
  5. 再次,在read_png_file中,使用以下方法更改为图像像素设置内存的方式:

    png_bytep *row_pointers = (png_bytep*)malloc(sizeof(png_bytep) * height);
    for(row = 0; row < height; row++)
    {
        row_pointers[row] = malloc(png_get_rowbytes(png_ptr,info_ptr));
    }
    
  6. main中,将row = &data.datap[i];更改为row = data.datap[i];,以便在此处访问指针。

  7. 我不想用与问题几乎相同的代码填充答案,因此如果您只想复制并粘贴答案,这就是指向complete code的链接。