Этот пример показывает реализацию традиционного конвейера обработки камеры, который визуализирует RGB-изображение из RAW Bayer-массива цветных фильтров (CFA). В примере также показан альтернативный рабочий процесс создания RGB с использованием функций поддержки формата RAW на панели инструментов, таких как rawread, rawinfo, и raw2rgb.
Цифровые однообъективные зеркальные (DSLR) фотоаппараты и многие современные телефонные фотоаппараты могут сохранять данные, собранные с датчика фотоаппарата, непосредственно в файл RAW. Каждый пиксель данных RAW представляет собой количество света, захваченного соответствующим фотодатчиком камеры. Данные зависят от фиксированных характеристик аппаратных средств камеры, таких как чувствительность каждого фотодатчика к определенному диапазону длин волн электромагнитного спектра. Данные также зависят от настроек захвата камеры, таких как время экспозиции, и факторов сцены, таких как источник света.
Это основные этапы обработки в традиционном конвейере обработки камеры:
Импорт содержимого файла RAW
Линеаризация полученного изображения CFA
Масштабирование данных CFA до подходящего диапазона
Применить корректировку баланса белого
Демосаик и поворот
Преобразование изображения CFA в изображение RGB
Можно также применить дополнительные шаги постобработки, такие как обесценение, отсечение подсветки и корректировка контрастности.
Камеры получают изображения и создают файлы RAW. Эти файлы RAW содержат:
Изображение CFA, записанное фотодатчиком камеры
Метаданные, содержащие всю информацию, необходимую для визуализации изображения RGB
Файл RAW может также содержать созданное камерой изображение JPEG для предварительного просмотра или миниатюру JPEG, однако для реализации конвейера камеры необходимы только изображение CFA и метаданные.
Считывание тестового изображения CFA из файла с помощью rawread и отобразить его.
fileName = "colorCheckerTestImage.NEF"; cfaImage = rawread(fileName); whos cfaImage
Name Size Bytes Class Attributes cfaImage 4012x6034 48416816 uint16
imshow(cfaImage,[])
title("Linear CFA Image")
Многие камеры маскируют часть фотодатчика, обычно по краям, чтобы предотвратить захват этими секциями какого-либо света. Это позволяет точно определить черный уровень датчика. Для таких камер количество пикселей в изображении меньше, чем количество пикселей в датчике.
Например, используйте rawinfo для извлечения метаданных из тестового образа CFA. В метаданных обратите внимание, что значение столбца в VisibleImageSize поле меньше, чем в CFAImageSize поле. rawread функция по умолчанию считывает только видимую часть CFA.
fileInfo = rawinfo(fileName); if fileInfo.CFASensorType ~= "Bayer" error( "The input file %s has CFA Image created by a % sensor." + ... "The camera pipeline in this example will work only for a CFA Image created by a Bayer sensor", ... fileName,fileInfo.CFASensorType ); end disp(fileInfo.ImageSizeInfo)
CFAImageSize: [4012 6080]
VisibleImageSize: [4012 6034]
VisibleImageStartLocation: [1 1]
PixelAspectRatio: 1
ImageRotation: 0
RenderedImageSize: [4012 6034]
Многие камеры применяют нелинейное сжатие дальности к захваченным сигналам, прежде чем хранить их в файлах RAW. Для создания линейных данных при подготовке к преобразованию данных CFA необходимо обратить это нелинейное сжатие диапазона. Камеры обычно хранят это сжатие диапазона как таблицу поиска (LUT). Если камера не применяет сжатие диапазона, LUT содержит сопоставление идентификаторов. rawread функция автоматически применяет этот LUT к данным CFA и возвращает значения линеаризованного света.
Постройте график подмножества значений в LinearizationTable поле метаданных тестового изображения.
linTable = fileInfo.ColorInfo.LinearizationTable;
plot((0:length(linTable)-1), fileInfo.ColorInfo.LinearizationTable)
title("Linearization Table")
Метаданные файла RAW включают значение черного уровня, fileInfo.ColorInfo.BlackLevel, и значение белого уровня fileInfo.ColorInfo.WhiteLevel. Диапазон значений пикселей в изображении CFA: [fileInfo.ColorInfo.BlackLevel, fileInfo.ColorInfo.WhiteLevel]. Эти значения можно использовать для масштабирования изображения.
Изображения RAW не имеют истинного черного значения. Даже если затвор закрыт, протекающее через датчики электричество вызывает ненулевое количество фотонов. Камеры используют значение маскированных пикселей для вычисления уровня черного изображения CFA. Различные форматы файлов RAW сообщают об этом черном уровне по-разному. Некоторые форматы файлов определяют уровень черного как одно скалярное значение на канал изображения CFA. Другие форматы, такие как DNG, определяют уровень черного как повторяющуюся область m-by-n, которая начинается в левом верхнем углу видимой части CFA.
Чтобы масштабировать изображение, вычтите уровень черного из изображения CFA. Используйте предоставленные вспомогательные функции для выполнения этих расчетов.
blackLevel = fileInfo.ColorInfo.BlackLevel; disp(blackLevel)
0 0 0 0
if isvector(fileInfo.ColorInfo.BlackLevel) cfaMultiChannel = performPerChannelBlackLevelSub(cfaImage, fileInfo); else cfa = performRegionBlackLevelSub(cfaImage, fileInfo); % Transforms an interleaved CFA into an (M/2-by-N/2-by-4) array, where % each plane corresponds to a specific color channel. % This transformation simplifies pipeline implementation cfaMultiChannel = raw2planar(cfa); end
Чтобы исправить значения данных CFA, меньшие, чем значение черного уровня, установите значение 0.
cfaMultiChannel( cfaMultiChannel < 0 ) = 0;
Метаданные файла RAW часто представляют уровень белого как максимальное значение, допустимое типом данных. Если это значение белого уровня намного выше, чем наибольшее значение в изображении, то при использовании этого значения белого уровня для масштабирования изображение становится темнее, чем должно быть. Чтобы избежать этого, масштабируйте изображение CFA, используя максимальное значение пикселя, найденное в изображении.
cfaMultiChannel = double(cfaMultiChannel); whiteLevel = max(cfaMultiChannel(:)); disp(whiteLevel)
3366
scaledCFAMultiChannel = cfaMultiChannel ./ whiteLevel;
Баланс белого - это процесс удаления нереальных цветных слепков из визуализированного изображения, так что он кажется ближе к тому, как человеческие глаза увидят предмет.
Сначала извлеките значение баланса белого из метаданных.
camWB = fileInfo.ColorInfo.CameraAsTakenWhiteBalance;
Затем масштабируйте множители так, чтобы значения G каналы 1.
gLoc = strfind(fileInfo.CFALayout,"G");
gLoc = gLoc(1);
camWB = camWB/camWB(gLoc);
disp(camWB)1.9336 1.0000 1.0000 1.2656
wbMults = reshape(camWB,[1 1 numel(camWB)]); wbCFAMultiChannel = scaledCFAMultiChannel .* wbMults;
Объединение каналов для создания чередующегося изображения CFA.
cfaWB = planar2raw(wbCFAMultiChannel);
Преобразование чередующегося изображения CFA в 16-битное изображение.
cfaWB = im2uint16(cfaWB);
Преобразуйте изображение CFA, закодированное в Bayer, в изображение с трюэколором путем демосейсинга и поворота. Это изображение находится в линейном пространстве камеры.
camspaceRGB = demosaic(cfaWB,fileInfo.CFALayout);
camspaceRGB = imrotate(camspaceRGB,fileInfo.ImageSizeInfo.ImageRotation);
imshow(camspaceRGB)
title("Rendered Image in Linear Camera Space")
Можно преобразовать изображение CFA в изображение RGB с помощью функций преобразования пространства подключения профиля (PCS) или с помощью матрицы преобразования, возвращенной в метаданных файла RAW.
Преобразование изображения CFA в выходное цветовое пространство Adobe RGB 1998. Это преобразование состоит из следующих шагов:
Преобразование изображения из пространства линейной камеры в пространство соединения профиля, например XYZ.
Преобразуйте изображение из пространства подключения профиля XYZ в цветовое пространство Adobe RGB 1998.
cam2xyz = computeXYZTransformation(fileInfo); xyzImage = imapplymatrix(cam2xyz,im2double(camspaceRGB)); % xyz2rgb function applies Gamma Correction for Adobe RGB 1998 color space adobeRGBImage = xyz2rgb(xyzImage,"ColorSpace","adobe-rgb-1998","OutputType","uint16"); imshow(adobeRGBImage); title("Rendered RGB Image in Adobe RGB 1998 Color Space");

Используйте матрицу преобразования в fileInfo.ColorInfo.CameraTosRGB поле метаданных файла CFA для преобразования изображения из линейного пространства камеры в линейное пространство sRGB.
% This transformation produces a linear sRGB image srgbImageLinear = imapplymatrix(fileInfo.ColorInfo.CameraTosRGB, camspaceRGB,"uint16"); % Apply gamma correction for sRGB colorspace srgbImage = lin2rgb(srgbImageLinear); imshow(srgbImage) title("Rendered RGB Image in sRGB Colorspace")

Как показано в этом примере, для преобразования изображения CFA в изображение sRGB можно использовать общие функции панели инструментов обработки изображений и метаданные файла RAW. Это преобразование также можно выполнить с помощью raw2rgb функция. При использовании raw2rgb функция не обеспечивает такой же гибкости, как использование метаданных, результаты сопоставимы. raw2rgb функция использует libraw 0.20.0 Библиотека обработки файлов RAW. Сравните результат raw2rgb преобразование в преобразование PCS для цветового пространства Adobe RGB 1998 и преобразование метаданных для цветовых пространств sRGB.
adobeRGBReference = raw2rgb(fileName,"ColorSpace","adobe-rgb-1998"); montage({adobeRGBReference, adobeRGBImage},"Size",[1 2]); title("Adobe RGB 1998 Images: Left Image: raw2rgb, Right Image: MATLAB Pipeline")

srgbReference = raw2rgb(fileName,"ColorSpace","srgb"); montage({srgbReference, srgbImage}); title("sRGB Images: Left Image: raw2rgb, Right Image: MATLAB Pipeline");

performPerChannelBlackLevelSub функция выполняет вычитание черного уровня при задании черного уровня в качестве скалярного значения для каждого канала.
function cfa = performPerChannelBlackLevelSub(cfa, fileInfo) % Transforms an interleaved CFA into an (M/2-by-N/2-by-4) array, where % each plane corresponds to a specific color channel. % This transformation simplifies pipeline implementation cfa = raw2planar(cfa); blackLevel = fileInfo.ColorInfo.BlackLevel; blackLevel = reshape(blackLevel,[1 1 numel(blackLevel)]); cfa = cfa - blackLevel; end
performRegionBlackLevelSub функция выполняет вычитание черного уровня при задании его в области m-by-n.
function cfa = performRegionBlackLevelSub(cfa,fileInfo) % The m-by-n black-level must be repeated periodically across the entire image repeatDims = fileInfo.ImageSizeInfo.VisibleImageSize ./ size(fileInfo.ColorInfo.BlackLevel); blackLevel = repmat(fileInfo.ColorInfo.BlackLevel, repeatDims); cfa = cfa - blackLevel; end
computeXYZTransformation функция масштабирует матрицу метаданных, которая определяет преобразование между линейным пространством камеры и пространством соединения профиля XYZ. Масштабирование этой матрицы позволяет избежать сильного розового цвета в тонированном изображении.
function cam2xyz = computeXYZTransformation(fileInfo) % The CameraToXYZ matrix imposes an RGB order i.e % [X, Y, Z]' = fileInfo.ColorInfo.CameraToXYZ .* [R, G, B]'. % However, the order of values for white balance mutlipliers are as per % fileInfo.CFALayout. Hence, we have to reorder the multipliers to % ensure we are scaling the correct row of the CameraToXYZ matrix. wbIdx = strfind(fileInfo.CFALayout,"R"); gidx = strfind(fileInfo.CFALayout,"G"); wbIdx(2) = gidx(1); wbIdx(3) = strfind(fileInfo.CFALayout,"B"); wbCoeffs = fileInfo.ColorInfo.D65WhiteBalance(wbIdx); cam2xyz = fileInfo.ColorInfo.CameraToXYZ ./ wbCoeffs; end