1. 程式人生 > >C/C++ 影象二進位制儲存與讀取

C/C++ 影象二進位制儲存與讀取

在深度學習時,製作樣本資料集時,需要產生和讀取一些二進位制影象的資料集,如MNISTCIFAR-10等都提供了適合C語言的二進位制版本。

以CIFAR-10的資料集為例,官網上有兩段關鍵的介紹:

二進位制版本資料集格式為(影象大小為32x32):

<1 x label><3072 x pixel>
...
<1 x label><3072 x pixel>

In other words, the first byte is the label of the first image, which is a number in the range 0-9. The next 3072 bytes are the values of the pixels of the image. The first 1024 bytes are the red channel values, the next 1024 the green, and the final 1024 the blue. The values are stored in row-major order, so the first 32 bytes are the red channel values of the first row of the image.

由此,繪製一個簡圖:

memory

根據影象大小32x32 = 1024,不難知道,每個顏色值儲存為1 byte,因此,對於單個影象的二進位制儲存與讀取(先不管RGB顏色儲存順序),找了一張32x32的彩色lena影象,如下實現:

#include <iostream>
#include <stdio.h>
#include <stdlib.h>

#include "cv.h"
#include "highgui.h"

using namespace cv;
using namespace std;

void main()
{
    FILE *fpw = fopen( "E:\\patch.bin"
, "wb" ); if ( fpw == NULL ) { cout << "Open error!" << endl; fclose(fpw); return; } Mat image = imread("E:\\lena32.jpg"); if ( !image.data || image.channels() != 3 ) { cout << "Image read failed or image channels isn't equal to 3."
<< endl; return; } // write image to binary format file int labelw = 1; int rows = image.rows; int cols = image.cols; fwrite( &labelw, sizeof(char), 1, fpw ); char* dp = (char*)image.data; for ( int i=0; i<rows*cols; i++ ) { fwrite( &dp[i*3], sizeof(char), 1, fpw ); fwrite( &dp[i*3+1], sizeof(char), 1, fpw ); fwrite( &dp[i*3+2], sizeof(char), 1, fpw ); } fclose(fpw); // read image from binary format file FILE *fpr = fopen( "E:\\patch.bin", "rb" ); if ( fpr == NULL ) { cout << "Open error!" << endl; fclose(fpr); return; } int labelr(0); fread( &labelr, sizeof(char), 1, fpr ); cout << "label: " << labelr << endl; Mat image2( rows, cols, CV_8UC3, Scalar::all(0) ); char* pData = (char*)image2.data; for ( int i=0; i<rows*cols; i++ ) { fread( &pData[i*3], sizeof(char), 1, fpr ); fread( &pData[i*3+1], sizeof(char), 1, fpr ); fread( &pData[i*3+2], sizeof(char), 1, fpr ); } fclose(fpr); imshow("1", image2); waitKey(0); }

執行結果如下:

results

再看圖片屬性:

attribute

與官網上的大小3073一致,那麼這麼存取應該沒問題。

嚴格按照官網的RGB通道分別儲存,略作修改就可以實現:

/*  for ( int i=0; i<rows*cols; i++ )
    {
        fwrite(&dp[i*3],   sizeof(char), 1, fpw);
        fwrite(&dp[i*3+1], sizeof(char), 1, fpw);
        fwrite(&dp[i*3+2], sizeof(char), 1, fpw);
    }
*/

    for ( int i=0; i<rows*cols; i++ )
        fwrite(&dp[i*3+2],   sizeof(char), 1, fpw); // R

    for ( int i=0; i<rows*cols; i++ )
        fwrite(&dp[i*3+1],   sizeof(char), 1, fpw); // G

    for ( int i=0; i<rows*cols; i++ )
        fwrite(&dp[i*3],   sizeof(char), 1, fpw);  // B

儲存和讀取多張圖片方法類似,這裡就不做介紹。