Этот пример показывает реализацию традиционного конвейера обработки фотоаппарата, который отображает изображение RGB из изображения массива цветных фильтров RAW Bayer-pattern (CFA). В примере также показан альтернативный рабочий процесс создания RGB с использованием функций поддержки формата RAW файла в тулбоксе, таких как rawread
, rawinfo
, и raw2rgb
.
Цифровые однообъективные рефлекторные (DSLR) камеры, а также многие современные телефонные камеры могут сохранять данные, собранные с датчика камеры, непосредственно в файл RAW. Каждый пиксель данных RAW является количеством света, захваченным соответствующим фотосенсором камеры. Данные зависят от фиксированных характеристик оборудования камеры, таких как чувствительность каждого фотосенсора к конкретной области значений длин волн электромагнитного спектра. Данные также зависят от настроек захвата камеры, таких как время экспозиции, и факторов сцены, таких как источник света.
Это основные шаги обработки в традиционном конвейере обработки камер:
Импортируйте содержимое файла RAW
Линеаризация полученного изображения CFA
Масштабируйте данные CFA в соответствующую область значений
Применить регулировку белого баланса
Демосаика и вращение
Преобразуйте изображение CFA в изображение RGB
Можно также применить дополнительные шаги постобработки, такие как шумоподавление, подсветка усечения и регулировка контрастности.
Камеры получают изображения и создают файлы. Эти 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
поле. The 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 содержит тождества отображения. The 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. Различные форматы файлов сообщают об этом черном уровне по-разному. Некоторые форматы файлов задают черный уровень как одно скалярное значение на канал изображения CFA. Другие форматы, такие как DNG, задают черный уровень как повторяющуюся область m на 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;
Метаданные необработанного файла часто представляют белый уровень как максимальное значение, допустимое типом данных. Если это значение белого уровня намного выше, чем самое высокое значение в изображении, использование этого значения белого уровня для масштабирования приводит к тому, что изображение темнее, чем должно быть. Чтобы избежать этого, масштабируйте изображение 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 в изображение труколора путем демозафикации и вращения его. Это изображение находится в линейном пространстве камеры.
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")
Как показывает этот пример, можно использовать общие функции тулбокса обработки изображений и метаданные RAW файла для преобразования изображения CFA в изображение sRGB. Это преобразование можно также выполнить с помощью raw2rgb
функция. При использовании raw2rgb
функция не обеспечивает такой же гибкости, как использование метаданных, результаты сопоставимы. The raw2rgb
функция использует libraw 0.20.0
Библиотека обработки необработанных файлов. Сравните результат 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");
The 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
The performRegionBlackLevelSub
функция выполняет вычитание черного уровня, когда вы задаете его по области m на 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
The 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