web-dev-qa-db-ja.com

OpenCVを使用して12ビットのベイヤー画像を8ビットのRGBに変換する

OpenCV2.3.1を使用して12ビットのベイヤー画像を8ビットのRGB画像に変換しようとしています。これは、cvCvtColor関数を使用するとかなり簡単なはずですが、次のコードで呼び出すと、関数は例外をスローします。

int cvType = CV_MAKETYPE(CV_16U, 1);
cv::Mat bayerSource(height, width, cvType, sourceBuffer);
cv::Mat rgbDest(height, width, CV_8UC3);
cvCvtColor(&bayerSource, &rgbDest, CV_BayerBG2RGB);

入力データが12ビットであるため、sourceBufferの終わりを超えて実行していると思いました。また、OpenCVには12ビット型がないため、16ビット型を渡す必要がありました。そのため、幅と高さを2で割りましたが、cvCvtColorは、有用な情報が含まれていない例外をスローしました(エラーメッセージは「不明な例外」でした)。

数ヶ月前に投稿された 同様の質問 は回答されませんでしたが、私の質問は12ビットのベイヤーデータをより具体的に扱っているので、新しい質問に値するほど明確であると思いました。

前もって感謝します。

編集:cvCvtColor関数を8ビットデータで動作させることさえできないので、何かが足りないに違いありません:

cv::Mat srcMat(100, 100, CV_8UC3);
const cv::Scalar val(255,0,0);
srcMat.setTo(val);
cv::Mat destMat(100, 100, CV_8UC3);
cvCvtColor(&srcMat, &destMat, CV_RGB2BGR);
11
Gillfish

Gillfishの答えは技術的には機能しますが、変換中に入力(CV_16UC1)よりも小さいデータ構造(CV_8UC1)を使用し、一部の色情報を失います。

最初にBayerエンコーディングをデコードすることをお勧めしますが、チャネルあたり16ビット(CV_16UC1からCV_16UC3)のままにして、後でCV_8UC3に変換します。

変更されたGillfishのコード(カメラが16ビットのBayerエンコーディングで画像を提供すると仮定):

// Copy the data into an OpenCV Mat structure
cv::Mat mat16uc1_bayer(height, width, CV_16UC1, inputBuffer);

// Decode the Bayer data to RGB but keep using 16 bits per channel
cv::Mat mat16uc3_rgb(width, height, CV_16UC3);
cv::cvtColor(mat16uc1_bayer, mat16uc3_rgb, cv::COLOR_BayerGR2RGB);

// Convert the 16-bit per channel RGB image to 8-bit per channel
cv::Mat mat8uc3_rgb(width, height, CV_8UC3);
mat16uc3_rgb.convertTo(mat8uc3_rgb, CV_8UC3, 1.0/256); //this could be perhaps done more effectively by cropping bits
6
Petr

次のコードを使用して、データを8ビットRGBに変換できました。

// Copy the data into an OpenCV Mat structure
cv::Mat bayer16BitMat(height, width, CV_16UC1, inputBuffer);

// Convert the Bayer data from 16-bit to to 8-bit
cv::Mat bayer8BitMat = bayer16BitMat.clone();
// The 3rd parameter here scales the data by 1/16 so that it fits in 8 bits.
// Without it, convertTo() just seems to chop off the high order bits.
bayer8BitMat.convertTo(bayer8BitMat, CV_8UC1, 0.0625);

// Convert the Bayer data to 8-bit RGB
cv::Mat rgb8BitMat(height, width, CV_8UC3);
cv::cvtColor(bayer8Bit, rgb8BitMat, CV_BayerGR2RGB);

カメラから取得した12ビットデータが密集していると誤解していたため、2つの12ビット値が3バイトに含まれていました。各値は2バイトに含まれていることが判明したため、OpenCVでサポートされている16ビット配列にデータを取得するために解凍を行う必要はありませんでした。

編集:変換中に色情報が失われないように、8ビットに変換する前にRGBに変換する@petrの改善された回答を参照してください。

14
Gillfish

これに苦労している人にとって、上記の解決策は、画像が実際に16ビットである場合にのみ機能します。コメントですでに示唆されているように、最下位4ビットを切り落とす必要があります。私はこれでそれを達成しました。あまりきれいではありませんが、機能します。

unsigned short * image_12bit = (unsigned short*)data;
char out[rows * cols];

for(int i = 0; i < rows * cols; i++) {
  out[i] = (char)((double)(255 * image_12bit[i]) / (double)(1 << 12));
}

cv::Mat bayer_image(rows, cols, CV_8UC1, (void*)out);
cv::cvtColor(bayer_image, *res, cv::COLOR_BayerGR2BGR);
0
Simone Zandara