【问题标题】:Convert 12-bit Bayer image to 8-bit RGB using OpenCV使用 OpenCV 将 12 位拜耳图像转换为 8 位 RGB
【发布时间】:2012-05-11 08:13:17
【问题描述】:

我正在尝试使用 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 仍然抛出了一个没有任何有用信息的异常(错误消息是“未知异常”)。

几个月前发布了一个 similar question,但从未得到答复,但由于我的问题更具体地涉及 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);

【问题讨论】:

  • 原来我遗漏了一些东西。我的同事指出我正在混合 C 和 C++ 调用。将最后一行更改为 cv::cvtColor(srcMat, destMat, CV_RGB2BGR);让一切都像魅力一样运作。我仍在研究将 16 位拜耳数据转换为 8 位 RGB 数据的原始问题,所以如果我找到答案,我会发布更新。
  • cvCvtColor 属于旧的 C OpenCV API,但 cv::Mat 是来自 C++ API 的一个类。混合它们不是一个好主意,您最好只使用一个版本的 API。 cv::cvtColor(srcMat, dstMat, COLOR_RGB2BGR) 应该适合你。
  • “绿色过滤器外观”可能意味着您指定了错误的拜耳模式。全部尝试。

标签: image opencv rgb


【解决方案1】:

我能够使用以下代码将我的数据转换为 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,以避免在转换过程中丢失任何颜色信息。

【讨论】:

  • 我做的和这里一样,但我的图像似乎在图像顶部有一个绿色过滤器。不知道为什么
  • @pksorensen:如果您有相关问题,只需在新问题中提出并链接回此问题。这样您就可以添加有关您的特定问题的更多详细信息。
  • 我最终选择了一条不同的路径并使用 Nikon SDK 进行 de-bayer,因为我在尝试使用 libraw 和 opencv 时遇到了一些问题。使用 nikons SDK 给了我更好的结果,并弄清楚了为什么 libraw 无法获得相同的结果,而 opencv 必须等待。还是谢谢。
  • 但是使用 0.0625 否则会“切断低位”(X/16 与位移 X>>4 相同)。所以最好只要求相机发送 8 位图片并保持 CPU 冷却。需要更复杂的压缩方法,例如旧的良好 HDR(慢)或简单曲线(快),以避免在 16(12)位 -> 8 位压缩时丢失 4 位信息。
  • @VitShiryaev 如果我可以让相机以我需要的格式向我发送文件,那就太好了,但在这种情况下,我只能访问文件,而不是相机本身.
【解决方案2】:

Gillfish 的答案在技术上有效,但在转换过程中,它使用的数据结构 (CV_8UC1) 比输入(CV_16UC1)更小,并且丢失了一些颜色信息。

我建议首先解码拜耳编码,但保持每通道 16 位(从 CV_16UC1 到 CV_16UC3),然后再转换为 CV_8UC3。

修改后的 Gillfish 代码(假设相机给出 16 位拜耳编码的图像):

// 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

【讨论】:

  • 我挠了好几个小时,想知道为什么它不起作用,但我意识到我正在处理大端数据,而 opencv 需要小端...
【解决方案3】:

对于任何为此苦苦挣扎的人,上述解决方案仅在您的图像实际上是 16 位时才有效,否则,正如 cmets 已经建议的那样,您应该切断 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);

【讨论】:

    猜你喜欢
    • 2022-01-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-17
    • 2020-05-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多