私がやろうとしているのは、Canon Rebel T5 1200D で撮影した .cr2 RAW ファイルを読み取ることです。LibRaw と OpenCV を使用して画像を読み込んで表示することはできますが、Windows でファイルを開いたときよりも、画像が少し明るすぎて黄色がかっているように見えます。画像自体は投稿の下部にあります。同様の質問がいくつか寄せられています。
LibRaw を使用して CR2 画像を正しくデコードしますか?
OpenCV を使用して 12 ビット Bayer イメージを 8 ビット RGB に変換する
最初にすべてのコードを投稿してから、問題の詳細に入ります。
// Open the CR2 file with LibRaw, unpack, and create image
LibRaw lrProc;
assert( LIBRAW_SUCCESS == lrProc.open_file( "001.cr2" ) );
assert( LIBRAW_SUCCESS == lrProc.unpack() );
assert( LIBRAW_SUCCESS == lrProc.raw2image() );
// Get image dimensions
int width = lrProc.imgdata.sizes.iwidth;
int height = lrProc.imgdata.sizes.iheight;
// Create a buffer of ushorts containing the pixel values of the "BG Bayered" image
std::vector<ushort> vBayerData;
for ( int y = 0; y < height; y++ )
{
for ( int x = 0; x < width; x++ )
{
// Get pixel idx
int idx = y * width + x;
// Each pixel is an array of 4 shorts rgbg
ushort * uRGBG = lrProc.imgdata.image[idx];
// Even rows are RGRGRG..., odd are GBGBGB...
// For even rows, get either red or green, store in vec
if ( y % 2 == 0 )
{
bool red = x % 2 == 0;
vBayerData.push_back( uRGBG[red ? 0 : 1] );
}
// For odd rows, get either blue or green
else
{
bool green = x % 2 == 0;
vBayerData.push_back( uRGBG[green ? 3 : 2] );
}
}
}
// Get rid of libraw image, construct openCV mat
lrProc.recycle();
cv::Mat imgBayer( height, width, CV_16UC1, vBayerData.data() );
// Debayer image, get output
cv::Mat imgDeBayer;
cv::cvtColor( imgBayer, imgDeBayer, CV_BayerBG2RGB );
// The pixel color values were 12 bit, but our data is 16 bit
// transform the range [0, 4095] to [0:65535] (multiply by 16)
imgDeBayer *= 16;
// Display image
cv::namedWindow( "CR2 File", CV_WINDOW_FREERATIO );
cv::imshow( "CR2 File", imgDeBayer );
cv::waitKey();
まず、LibRaw を使用して生の画像ファイルを開いて解凍しました。LibRaw の Web サイト http://www.libraw.org/docs/API-overview-eng.htmlのこの例
各ピクセルが実際の 4 つの ushort 値 [赤、緑 1、青、緑 2] であり、そのピクセルのベイヤー色を表す「画像」が残ることを示します。値を出力すると(次のコードを使用)
// Print the first 4 values of the first 4 rows
for ( int y = 0; y < 4; y++ )
{
for ( int x = 0; x < 4; x++ )
{
int idx = y * width + x;
ushort * uRGBG = lrProc.imgdata.image[idx];
printf( "[%04d, %04d, %04d, %04d] ", uRGBG[0], uRGBG[1], uRGBG[2], uRGBG[3] );
}
printf( "\n" );
}
次の結果が得られます。
[2253, 0000, 0000, 0000] [0000, 2166, 0000, 0000] [2183, 0000, 0000, 0000] [0000, 2195, 0000, 0000]
[0000, 0000, 0000, 2207] [0000, 0000, 2175, 0000] [0000, 0000, 0000, 2099] [0000, 0000, 2122, 0000]
[2246, 0000, 0000, 0000] [0000, 2240, 0000, 0000] [2287, 0000, 0000, 0000] [0000, 2182, 0000, 0000]
[0000, 0000, 0000, 2251] [0000, 0000, 2103, 0000] [0000, 0000, 0000, 2195] [0000, 0000, 2155, 0000]
そのため、偶数行では Red と Green1 ピクセルが交互にゼロ以外の値を持ち、奇数行では Blue と Green2 ピクセルが交互にゼロ以外の値を持ちます。私はそれについて100%ではありませんが、値は12ビットのようです。
OpenCVのcvtColor関数の説明を見ると
http://docs.opencv.org/2.4/modules/imgproc/doc/miscellaneous_transformations.html#cvtcolor
cr2カラーフォーマットのいくつかのこの人の説明と同様に:
http://lclevy.free.fr/cr2/#interpol
「BG」の種類のベイヤー画像を取得したことを示しています (OpenCV ドキュメントで使用されている用語を使用します)。
したがって、その画像を cvtColor に渡すには、展開された生の画像から各ピクセル値を取得し、署名されていない short の連続した画像を作成する必要があります。// ピクセル idx を取得 int idx = y * width + x;
// Each pixel is an array of 4 shorts rgbg
ushort * uRGBG = lrProc.imgdata.image[idx];
// For even rows, get either red or green, store in vec
if ( y % 2 == 0 )
{
bool red = x % 2 == 0;
vBayerData.push_back( uRGBG[red ? 0 : 1] );
}
// For odd rows, get either blue or green
else
{
bool green = x % 2 == 0;
vBayerData.push_back( uRGBG[green ? 3 : 2] );
}
short の連続バッファー (vBayerData) を取得したら、opencv マットを作成し、CV_BayerBG2RGB を使用してデベイヤーします。
ただし、出力したピクセル値を見ると、値がおそらく 12 ビットであることがわかります (完全にはわかりませんが)。したがって、12 ビットの範囲から 16 ビットの範囲に移行する必要があると思います。値を 16 倍することになります。
// Construct bayer image from data
cv::Mat imgBayer( height, width, CV_16UC1, vBayerData.data() );
// Debayer image, get output
cv::Mat imgDeBayer;
cv::cvtColor( imgBayer, imgDeBayer, CV_BayerBG2RGB );
// The pixel color values were 12 bit, but our data is 16 bit
// transform the range [0, 4095] to [0:65535] (multiply by 16)
imgDeBayer *= 16;
ただし、これが私の目に見えるものです(スケーリングについては申し訳ありません、色が重要です):
ここにとても近づいているように感じますが、得られた画像は少し明るすぎて、色が少しずれています。私のカメラの設定は、sRGB 形式を使用して RAW 画像をエクスポートすることになっているため、画像強度に何らかのガンマ補正を適用すると役立つと確信していましたが、正しい画像を取得できないようです。
さまざまなベイヤー行列 (つまり RG)、さまざまなビット深度変換、ビット深度変換を行うときの再配置 (DeBayering の前後) を試しましたが、画像が正しく表示されるようには見えません。
この種の変色を認識する人はいますか?もしそうなら、彼らは私のコードでエラーを見つけるのを手伝ってくれますか?
読んでくれてありがとう、
ジョン
PS ここにはたくさんのテキストがあることは知っていますが、このような投稿に最適な形式が何であるかはわかりませんでした. 私が扱っているすべての情報を提供したかっただけです。
編集: Mark Ransom が以下で提案したように、これはホワイト バランスが正しくないためだと思います。私はデジタル カメラのカラー パイプラインの方向性を指摘されましたが、画像のデコードにはディベイヤー ステップだけではありません。
ウィキペディアの記事から:
典型的なコンポーネントには、イメージ センサー補正 (「デベイリング」またはベイヤー フィルターの適用を含む)、ノイズ リダクション、イメージ スケーリング、ガンマ補正、イメージ エンハンスメント、色空間変換 (RGB、YUV、YCbCr などのフォーマット間)、クロマ サブサンプリング、フレームレート変換、画像圧縮/ビデオ圧縮 (JPEG など)、およびコンピューターのデータ保存/データ転送。