Source code for pyctools.components.io.rawimagefilereader2

#  Pyctools - a picture processing algorithm development kit.
#  http://github.com/jim-easterbrook/pyctools
#  Copyright (C) 2019-20  Pyctools contributors
#
#  This program is free software: you can redistribute it and/or
#  modify it under the terms of the GNU General Public License as
#  published by the Free Software Foundation, either version 3 of the
#  License, or (at your option) any later version.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
#  General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with this program.  If not, see
#  <http://www.gnu.org/licenses/>.

from __future__ import print_function

__all__ = ['RawImageFileReader2']
__docformat__ = 'restructuredtext en'

import os

import numpy
import rawpy

from pyctools.core.config import (
    ConfigBool, ConfigEnum, ConfigFloat, ConfigInt, ConfigPath, ConfigStr)
from pyctools.core.base import Component
from pyctools.core.frame import Frame, Metadata
from pyctools.core.types import pt_float


[docs] class RawImageFileReader2(Component): """Read 'raw' still image file (CR2, NEF, etc.). This component uses the rawpy_ Python package. See :py:class:`~.rawimagefilereader.RawImageFileReader` for a component that uses rawkit. Note that the file is always read in 16-bit linear mode. You will need to convert the image to "gamma corrected" mode before displaying it or saving it to JPEG or similar. See :py:mod:`~pyctools.components.colourspace.gammacorrection` for some useful components. Some options add significantly to the processing time, particularly ``fbdd_noise_reduction`` and some of the ``demosaic_algorithm`` options. ======================== ===== ==== Config ======================== ===== ==== ``path`` str Path name of file to be read. ``demosaic_algorithm`` str Set demosaicing method. Possible values: {}. ``four_color_rgb`` bool Use separate interpolation for 2 green channels. ``dcb_iterations`` int Number of passes of DCB interpolation. ``dcb_enhance`` bool Enhance colours of DCB interpolation. ``fbdd_noise_reduction`` str Enable FBDD noise reduction before demosaicing. Possible values: {}. ``noise_thr`` float Set denoising threshold. Typically 100 to 1000. ``median_filter_passes`` int Number of median filter passes after demosaicing. ``use_camera_wb`` bool Use camera defined white balance. ``use_auto_wb`` bool Automatic white balance. ``user_wb`` str 4 comma separated floats that set the gain of each channel. ``output_color`` str Set colour space. Possible values: {}. ``bright`` float Brightness / white level scaling. ``highlight_mode`` str Set highlight mode. Possible values: {}. ``exp_shift`` float Exposure shift. Darken if < 1.0, lighten if > 1.0. ``red_scale`` float Chromatic aberration correction red scale factor. ``blue_scale`` float Chromatic aberration correction blue scale factor. ``crop`` bool Auto crop image to dimensions in metadata. ======================== ===== ==== .. _rawpy: https://letmaik.github.io/rawpy/ """ highlight_modes = {} for member in rawpy.HighlightMode: highlight_modes[member.name] = member.value for x in range(10): if x not in highlight_modes.values(): highlight_modes[str(x)] = x __doc__ = __doc__.format( ', '.join(["``'" + x.name + "'``" for x in rawpy.DemosaicAlgorithm if x.isSupported]), ', '.join(["``'" + x.name + "'``" for x in rawpy.FBDDNoiseReductionMode]), ', '.join(["``'" + x.name + "'``" for x in rawpy.ColorSpace]), ', '.join(["``'" + x + "'``" for x in highlight_modes])) inputs = [] with_outframe_pool = False def initialise(self): self.config['path'] = ConfigPath() self.config['demosaic_algorithm'] = ConfigEnum( choices=[x.name for x in rawpy.DemosaicAlgorithm if x.isSupported], value='AHD') self.config['four_color_rgb'] = ConfigBool() self.config['dcb_iterations'] = ConfigInt(min_value=0) self.config['dcb_enhance'] = ConfigBool() self.config['fbdd_noise_reduction'] = ConfigEnum( choices=[x.name for x in rawpy.FBDDNoiseReductionMode]) self.config['noise_thr'] = ConfigFloat(value=0, decimals=0) self.config['median_filter_passes'] = ConfigInt(min_value=0) self.config['use_camera_wb'] = ConfigBool(value=True) self.config['use_auto_wb'] = ConfigBool(value=False) self.config['user_wb'] = ConfigStr() self.config['output_color'] = ConfigEnum( choices=[x.name for x in rawpy.ColorSpace], value='sRGB') self.config['bright'] = ConfigFloat(value=1.0, decimals=2) self.config['highlight_mode'] = ConfigEnum( choices=self.highlight_modes.keys(), value='Blend') self.config['exp_shift'] = ConfigFloat(value=1.0, decimals=2, min_value=0.25, max_value=8.0) self.config['red_scale'] = ConfigFloat(value=1.0, decimals=5) self.config['blue_scale'] = ConfigFloat(value=1.0, decimals=5) self.config['crop'] = ConfigBool(value=True) def on_start(self): # read file self.update_config() path = self.config['path'] params = { 'demosaic_algorithm': rawpy.DemosaicAlgorithm[ self.config['demosaic_algorithm']], 'four_color_rgb': self.config['four_color_rgb'], 'dcb_iterations': self.config['dcb_iterations'], 'dcb_enhance': self.config['dcb_enhance'], 'fbdd_noise_reduction': rawpy.FBDDNoiseReductionMode[ self.config['fbdd_noise_reduction']], 'median_filter_passes': self.config['median_filter_passes'], 'use_camera_wb': self.config['use_camera_wb'], 'use_auto_wb': self.config['use_auto_wb'], 'output_color': rawpy.ColorSpace[self.config['output_color']], 'output_bps': 16, 'user_flip': 0, 'no_auto_bright': True, 'bright': self.config['bright'], 'highlight_mode': self.highlight_modes[ self.config['highlight_mode']], 'exp_shift': self.config['exp_shift'], 'gamma': (1.0, 1.0), 'chromatic_aberration': (self.config['red_scale'], self.config['blue_scale']), } if self.config['noise_thr'] != 0: params['noise_thr'] = self.config['noise_thr'] if self.config['user_wb']: params['user_wb'] = eval('(' + self.config['user_wb'] + ')') with rawpy.imread(path) as raw: image = raw.postprocess(**params) if self.config['crop']: w, h = Metadata().from_file(path).image_size() x = (image.shape[1] - w) // 2 y = (image.shape[0] - h) // 2 image = image[y:y+h, x:x+w, :] image = image.astype(pt_float) / pt_float(256.0) out_frame = Frame() # send output frame out_frame.data = image out_frame.type = 'RGB' out_frame.frame_no = 0 out_frame.metadata.from_file(path) out_frame.metadata.set_audit( self, 'data = raw->RGB({})\n'.format(os.path.basename(path)), with_config=self.config) self.send('output', out_frame) # shut down pipeline self.stop()