11

我正在尝试使用 OpenCV 2.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);

我以为我跑过了 sourceBuffer 的末尾,因为输入数据是 12 位的,我必须传入 16 位类型,因为 OpenCV 没有 12 位类型。所以我将宽度和高度除以 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);
4

3 回答 3

15

我能够使用以下代码将我的数据转换为 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 位数据是紧密打包的,因此两个 12 位值包含在 3 个字节中。事实证明,每个值都包含在 2 个字节中,因此我无需进行任何解包即可将数据放入 OpenCV 支持的 16 位数组中。

编辑:请参阅@petr 改进的答案,该答案在转换为 8 位之前转换为 RGB,以避免在转换过程中丢失任何颜色信息。

于 2012-05-04T18:34:15.997 回答
10

The Gillfish's answer technically works but during the conversion it uses smaller data structure (CV_8UC1) than the input (which is CV_16UC1) and loses some color information.

I would suggest first to decode the Bayer encoding but stay in 16-bits per channel (from CV_16UC1 to CV_16UC3) and later convert to CV_8UC3.

The modified Gillfish's code (assuming the camera gives image in 16bit Bayer encoding):

// 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
于 2017-07-21T14:27:13.653 回答
0

对于任何为此苦苦挣扎的人,上述解决方案仅在您的图像实际上是 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);
于 2020-03-05T14:28:45.747 回答