Преобразование 12-битного изображения Байера в 8-битный RGB с использованием OpenCV

Я пытаюсь использовать 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);

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

Я смог преобразовать свои данные в 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 байтах, поэтому мне не нужно было распаковывать данные, чтобы получить данные в 16-битный массив, который поддерживается OpenCV.

Изменить: см. Улучшенный ответ @petr, который преобразуется в RGB перед преобразованием в 8-битный, чтобы избежать потери какой-либо информации о цвете во время преобразования.

Для тех, кто борется с этим, вышеуказанное решение работает только в том случае, если ваше изображение действительно имеет 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);
Другие вопросы по тегам