前提
opencv-pythonで①Png画像を読み込み、②ピクセル出力した結果および③保存したPng画像と、
C++ とlibpngで①Png画像を読み込み、④ピクセル出力した結果および⑤保存したPng画像では、
②と④はすべて同じ結果になりますが、③と⑤をバイナリで比較するとヘッダーは同じでしたが、IDATのデータ部分が異なる結果になりました。
環境:
python 3.10
opencv-python 4.6.0.66
C++17
libpng 1.6.37
Png画像:
ビットの深さ 32
実現したいこと
上記③と⑤を同じ結果にしたい。
opencvもlibpngを使用しているため、同じ結果になると思いましたが、
Pngの圧縮などの知識があまりなく、なぜ異なるのかがわかっていません。
該当のソースコード
③
python
1cvimg = cv2.imread("./temp/sample.png", -1) 2cv2.imwrite("./temp/cv.png", cvimg, [cv2.IMWRITE_PNG_COMPRESSION, 6])
opencv内のlibpng使用箇所
C++
1bool PngEncoder::write( const Mat& img, const std::vector<int>& params ) 2{ 3 png_structp png_ptr = png_create_write_struct( PNG_LIBPNG_VER_STRING, 0, 0, 0 ); 4 png_infop info_ptr = 0; 5 FILE * volatile f = 0; 6 int y, width = img.cols, height = img.rows; 7 int depth = img.depth(), channels = img.channels(); 8 volatile bool result = false; 9 AutoBuffer<uchar*> buffer; 10 11 if( depth != CV_8U && depth != CV_16U ) 12 return false; 13 14 if( png_ptr ) 15 { 16 info_ptr = png_create_info_struct( png_ptr ); 17 18 if( info_ptr ) 19 { 20 if( setjmp( png_jmpbuf ( png_ptr ) ) == 0 ) 21 { 22 if( m_buf ) 23 { 24 png_set_write_fn(png_ptr, this, 25 (png_rw_ptr)writeDataToBuf, (png_flush_ptr)flushBuf); 26 } 27 else 28 { 29 f = fopen( m_filename.c_str(), "wb" ); 30 if( f ) 31 png_init_io( png_ptr, (png_FILE_p)f ); 32 } 33 34 int compression_level = -1; // Invalid value to allow setting 0-9 as valid 35 int compression_strategy = IMWRITE_PNG_STRATEGY_RLE; // Default strategy 36 bool isBilevel = false; 37 38 for( size_t i = 0; i < params.size(); i += 2 ) 39 { 40 if( params[i] == IMWRITE_PNG_COMPRESSION ) 41 { 42 compression_strategy = IMWRITE_PNG_STRATEGY_DEFAULT; // Default strategy 43 compression_level = params[i+1]; 44 compression_level = MIN(MAX(compression_level, 0), Z_BEST_COMPRESSION); 45 } 46 if( params[i] == IMWRITE_PNG_STRATEGY ) 47 { 48 compression_strategy = params[i+1]; 49 compression_strategy = MIN(MAX(compression_strategy, 0), Z_FIXED); 50 } 51 if( params[i] == IMWRITE_PNG_BILEVEL ) 52 { 53 isBilevel = params[i+1] != 0; 54 } 55 } 56 57 if( m_buf || f ) 58 { 59 if( compression_level >= 0 ) 60 { 61 png_set_compression_level( png_ptr, compression_level ); 62 } 63 else 64 { 65 // tune parameters for speed 66 // (see http://wiki.linuxquestions.org/wiki/Libpng) 67 png_set_filter(png_ptr, PNG_FILTER_TYPE_BASE, PNG_FILTER_SUB); 68 png_set_compression_level(png_ptr, Z_BEST_SPEED); 69 } 70 png_set_compression_strategy(png_ptr, compression_strategy); 71 72 png_set_IHDR( png_ptr, info_ptr, width, height, depth == CV_8U ? isBilevel?1:8 : 16, 73 channels == 1 ? PNG_COLOR_TYPE_GRAY : 74 channels == 3 ? PNG_COLOR_TYPE_RGB : PNG_COLOR_TYPE_RGBA, 75 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, 76 PNG_FILTER_TYPE_DEFAULT ); 77 78 png_write_info( png_ptr, info_ptr ); 79 80 if (isBilevel) 81 png_set_packing(png_ptr); 82 83 png_set_bgr( png_ptr ); 84 if( !isBigEndian() ) 85 png_set_swap( png_ptr ); 86 87 buffer.allocate(height); 88 for( y = 0; y < height; y++ ) 89 buffer[y] = img.data + y*img.step; 90 91 png_write_image( png_ptr, buffer.data() ); 92 png_write_end( png_ptr, info_ptr ); 93 94 result = true; 95 } 96 } 97 } 98 }
⑤ 読み込み省略してます。
C++
1void test(png_bytepp image, 2 int width, 3 int height, 4 int bitDpth, 5 int colorType, 6 int interlaceType) 7{ 8 png_structp png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); 9 png_infop info = png_create_info_struct(png); 10 11 if ((info == NULL) || (setjmp(png_jmpbuf(png)) != 0)) { 12 png_destroy_write_struct(&png, NULL); 13 return; 14 } 15 FILE* f = fopen("cpp.png", "wb"); 16 png_init_io(png, (png_FILE_p)f); 17 18 png_set_compression_level(png, 6); 19 png_set_IHDR(png, info,width, height, bitDpth, colorType, 0,PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); 20 21 png_write_info(png, info); 22 png_write_image(png, image); 23 png_write_end(png, info); 24 25 png_destroy_write_struct(&png, &info); 26 fclose(f); 27}
③と⑤バイナリ比較抜粋
回答3件
あなたの回答
tips
プレビュー