Through this example, some Canon EOS 5D Mark II CR2 files will be merged together prior to demosaicing in order to create a single radiance image.
Note: The final result exhibits a magenta cast, we haven't investigated the exact origin yet.
The following steps will be taken:
Note: Some steps can be performed using alternative methods or simplified, for instance the DNG conversion can be entirely avoided. Our interest here is to retrieve the camera levels and the Adobe DNG camera colour profiling data.
In [1]:
import logging
import numpy as np
import os
import colour
from colour.plotting import *
from colour_demosaicing import (
demosaicing_CFA_Bayer_DDFAPD,
masks_CFA_Bayer)
from colour_hdri import (
EXAMPLES_RESOURCES_DIRECTORY,
Image,
ImageStack,
camera_space_to_sRGB,
convert_dng_files_to_intermediate_files,
convert_raw_files_to_dng_files,
filter_files,
read_exif_tag,
image_stack_to_radiance_image,
update_exif_tags,
weighting_function_Debevec1997)
from colour_hdri.plotting import plot_radiance_image_strip
logging.basicConfig(level=logging.INFO)
RESOURCES_DIRECTORY = os.path.join(EXAMPLES_RESOURCES_DIRECTORY,
'frobisher_001')
colour.utilities.filter_warnings()
colour.utilities.describe_environment();
In [2]:
colour_style();
In [3]:
# In order to get proper black and white levels from .dng files
# we need to change the dng conversion arguments.
import colour_hdri.process.dng
colour_hdri.process.dng.DNG_CONVERSION_ARGUMENTS = '-e -d "{0}" "{1}"'
RAW_FILES = filter_files(RESOURCES_DIRECTORY, ('CR2',))
DNG_FILES = convert_raw_files_to_dng_files(RAW_FILES, RESOURCES_DIRECTORY)
INTERMEDIATE_FILES = convert_dng_files_to_intermediate_files(
DNG_FILES, RESOURCES_DIRECTORY, demosaicing=False)
update_exif_tags(zip(DNG_FILES, INTERMEDIATE_FILES))
XYZ_TO_CAMERA_SPACE_MATRIX = colour.utilities.as_float_array(
[float(M_c) for M_c in read_exif_tag(
DNG_FILES[-2], 'ColorMatrix2').split()]).reshape((3, 3))
In [4]:
plot_image(colour.cctf_encoding(colour.read_image(
str(INTERMEDIATE_FILES[-2]))[1250:2250, 3000:4000, ...]),
{'text': os.path.basename(INTERMEDIATE_FILES[-2])});
In [5]:
def merge_from_raw_files_with_post_demosaicing(
dng_files,
output_directory,
batch_size=5,
black_level=None,
white_level=None,
white_balance_multipliers=None,
weighting_function=weighting_function_Debevec1997,
CFA_pattern='RGGB'):
paths = []
for dng_files in colour.utilities.batch(dng_files, batch_size):
image_stack = ImageStack()
for dng_file in dng_files:
image = Image(dng_file)
image.read_metadata()
image.path = str(dng_file.replace('dng', 'tiff'))
image.read_data()
image_stack.append(image)
path = os.path.join(
output_directory,
'{0}_{1}_MRFPD.{2}'.format(
os.path.splitext(os.path.basename(image_stack.path[0]))[0],
batch_size,
'exr'))
paths.append(path)
logging.info('Scaling "{0}"...'.format(', '.join(
image_stack.path)))
black_level_e = (0 if
image_stack.black_level[0] is None else
np.max(image_stack.black_level[0]))
white_level_e = (1 if
image_stack.white_level[0] is None else
np.min(image_stack.white_level[0]))
logging.info('\tBlack Level (Exif): {0}'.format(
image_stack.black_level))
logging.info('\tWhite Level (Exif): {0}'.format(
image_stack.white_level))
black_level = black_level if black_level is not None else black_level_e
white_level = white_level if white_level is not None else white_level_e
logging.info('\tBlack Level (Used): {0}'.format(
black_level))
logging.info('\tWhite Level (Used): {0}'.format(
white_level))
# Scaling should be performed on individual planes, for convenience
# and simplicity the maximum of the black level and the minimum of
# the white level are used for all planes.
image_stack.data = (image_stack.data - black_level) * (
1 / (white_level_e - black_level_e))
logging.info('Merging "{0}"...'.format(path))
logging.info('\tImage stack "F Number" (Exif): {0}'.format(
image_stack.f_number))
logging.info('\tImage stack "Exposure Time" (Exif): {0}'.format(
image_stack.exposure_time))
logging.info('\tImage stack "ISO" (Exif): {0}'.format(
image_stack.iso))
image = image_stack_to_radiance_image(image_stack, weighting_function)
image[np.isnan(image)] = 0
logging.info('White Balancing "{0}"...'.format(path))
white_balance_multipliers_e = np.power(
image_stack.white_balance_multipliers[0], -1)
logging.info('\tWhite Balance Multipliers (Exif): {0}'.format(
white_balance_multipliers_e))
white_balance_multipliers = (white_balance_multipliers
if white_balance_multipliers is not None
else white_balance_multipliers_e)
logging.info('\tWhite Balance Multipliers (Used): {0}'.format(
white_balance_multipliers))
# For consistency and comparison ease with
# *Colour - HDRI - Example: Merge from Raw Files* example, the
# white balance multipliers are not normalised here too.
# white_balance_multipliers /= np.max(white_balance_multipliers)
R_m, G_m, B_m = masks_CFA_Bayer(image.shape, CFA_pattern)
image[R_m] *= white_balance_multipliers[0]
image[G_m] *= white_balance_multipliers[1]
image[B_m] *= white_balance_multipliers[2]
logging.info('Demosaicing "{0}"...'.format(path))
image = demosaicing_CFA_Bayer_DDFAPD(image, CFA_pattern)
logging.info('Writing "{0}"...'.format(path))
colour.write_image(image, path)
return paths
PATHS = merge_from_raw_files_with_post_demosaicing(
DNG_FILES, RESOURCES_DIRECTORY)
In [6]:
IMAGE = colour.read_image(PATHS[0])
IMAGE_sRGB = camera_space_to_sRGB(IMAGE, XYZ_TO_CAMERA_SPACE_MATRIX)
colour.write_image(IMAGE_sRGB, PATHS[0].replace('.exr', '_sRGB.exr'))
plot_radiance_image_strip(IMAGE_sRGB);