Я пытаюсь прочитать RAW-файл .cr2 на моем Canon Rebel T5 1200D. Я могу загрузить и отобразить изображение, используя LibRaw и OpenCV, но изображение кажется слишком ярким и немного более желтым, чем при открытии файла в Windows. Сами изображения находятся внизу поста. Было задано несколько похожих вопросов:
Использование LibRaw для правильного декодирования изображения CR2?
Преобразование 12-битного изображения Байера в 8-битный RGB с использованием OpenCV
Сначала я опубликую весь свой код, а затем подробно расскажу о проблеме.
// 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
http://www.libraw.org/docs/API-overview-eng.html
указывает, что у меня останется «изображение», где каждый пиксель — это фактические 4-кратные значения [Red, Green1, Blue, Green2], представляющие байрированный цвет в этом пикселе. Когда я распечатываю значения (используя следующий код)
// 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 имеют альтернативно нулевые значения. Значения кажутся 12-битными, хотя я не на 100% в этом.
Глядя на описание функции OpenCV cvtColor
http://docs.opencv.org/2.4/modules/imgproc/doc/miscellaneous_transformations.html#cvtcolor
А также описание этого человека некоторых цветовых форматов cr2:
http://lclevy.free.fr/cr2/#interpol
Указывает на то, что у меня есть изображение Bayered разновидности «BG» (согласно терминологии, используемой в документах OpenCV.)
Итак, чтобы передать это изображение в cvtColor, мне нужно взять значение каждого пикселя из распакованного необработанного изображения и создать непрерывное изображение неподписанных шорт.
// Получить пиксельный идентификатор
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] );
}
Как только у меня есть непрерывный буфер шортов (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;
После всего этого вот изображение, с которым я остался:
Однако вот что видят мои глаза (извините за масштабирование, цвет имеет значение):
Я чувствую себя так близко, но изображение, которое я получаю, слишком яркое и немного не в цвете. Настройки на моей камере — экспорт изображений в формате RAW с использованием формата sRGB, поэтому я был уверен, что применение гамма-коррекции к интенсивности изображения поможет, но я не могу вывести правильное изображение.
Я пробовал разные матрицы Байера (то есть RG), разные преобразования глубины в битах, реорганизацию, когда я делаю преобразование глубины в битах (до и после дебейринга), но ни одна из них, кажется, не заставляет изображение выглядеть правильно.
Кто-нибудь признает этот вид обесцвечивания? И если да, могут ли они помочь мне найти ошибку в моем коде?
Спасибо за чтение,
Джон
P.S. Я знаю, что здесь много текста, я не был уверен, какой формат для такого поста был лучшим. Я просто хотел предоставить всю информацию, с которой я работаю.
РЕДАКТИРОВАТЬ:
Как предложил Марк Рэнсом ниже, я думаю, это связано с неправильным балансом белого. Я был направлен в сторону цифровая камера цветной конвейер, и декодирование изображения — это гораздо больше, чем просто шаг дебайера.
Из статьи в Википедии:
Типичные компоненты включают исправления датчика изображения (включая
«распад» или применение фильтра Байера), шумоподавление, изображение
масштабирование, гамма-коррекция, улучшение изображения, преобразование цветового пространства
(между форматами, такими как RGB, YUV или YCbCr), подвыбор цветности,
преобразование частоты кадров, сжатие изображений / сжатие видео (например,
JPEG) и компьютерное хранение данных / передача данных.
Задача ещё не решена.
Других решений пока нет …