[libcamera-devel] [PATCH 3/3] utils: raspberrypi: ctt: dng_load_image: Work with DNG files from Picamera2

Laurent Pinchart laurent.pinchart at ideasonboard.com
Mon Jul 11 11:43:59 CEST 2022


On Thu, Jul 07, 2022 at 10:57:01AM +0300, Laurent Pinchart via libcamera-devel wrote:
> On Thu, Jul 07, 2022 at 08:35:39AM +0100, David Plowman wrote:
> > On Wed, 6 Jul 2022 at 19:32, Laurent Pinchart wrote:
> > > On Wed, Jul 06, 2022 at 11:18:36AM +0100, David Plowman via libcamera-devel wrote:
> > > > From: William Vinnicombe <william.vinnicombe at raspberrypi.com>
> > > >
> > > > The exif tags are different between raw files from libcamera-apps and
> > > > from Picamera2, causing issues loading data.
> > > >
> > > > Add code to identify which tags are being used, and then load the
> > > > metadata from the correct tags.
> > > >
> > > > Signed-off-by: William Vinnicombe <william.vinnicombe at raspberrypi.com>
> > > > ---
> > > >  utils/raspberrypi/ctt/ctt_image_load.py | 26 ++++++++++++++++++-------
> > > >  1 file changed, 19 insertions(+), 7 deletions(-)
> > > >
> > > > diff --git a/utils/raspberrypi/ctt/ctt_image_load.py b/utils/raspberrypi/ctt/ctt_image_load.py
> > > > index 934db123..29c17581 100644
> > > > --- a/utils/raspberrypi/ctt/ctt_image_load.py
> > > > +++ b/utils/raspberrypi/ctt/ctt_image_load.py
> > > > @@ -301,17 +301,29 @@ def dng_load_image(Cam, im_str):
> > > >          metadata.read()
> > > >
> > > >          Img.ver = 100  # random value
> > > > -        Img.w = metadata['Exif.SubImage1.ImageWidth'].value
> > > > +        """
> > > > +        libcamera-apps create a separate Exif.Subimage1 for the picture
> > > > +        picamera2 stores everything under Exif.Image
> > >
> > > Is this valid according to the DNG specification ? Or is it that
> > > picamera2 produces TIFF/EP files instead of DNG ? Is there a reason not
> > > to use DNG in all cases ?
> > 
> > Actually DNG and EXIF are all really flavours of TIFF. I would say
> 
> Note that I mentioned TIFF/EP, which is also a different flavour of
> TIFF. Those formats are an utter mess :-)
> 
> > that Picamera2, which uses the PiDNG library, does it properly. In C++
> > we use libtiff which, as far as I can tell, doesn't really support
> > "modern" flavours of DNG-style TIFF. For example, you can't include
> > exposure times in the main image which PiDNG can.
> 
> Where is the "modern" flavour of "DNG-style TIFF" documented ? I'm
> looking at the DNG v1.4.0.0. specification, which states, in the subIFDs
> trees section,
> 
>     DNG recommends the use of SubIFD trees, as described in the TIFF-EP
>     specification. SubIFD chains are not supported.
> 
>     The highest-resolution and quality IFD should use NewSubFileType
>     equal to 0. Reduced resolution (or quality) thumbnails or previews,
>     if any, should use NewSubFileType equal to 1 (for a primary preview)
>     or 10001.H (for an alternate preview).
> 
>     DNG recommends, but does not require, that the first IFD contain a
>     low-resolution thumbnail, as described in the TIFF-EP specification.
> 
> and in the metadata section,
> 
>     Additional metadata may be embedded in DNG in the following ways:
> 
>     • Using TIFF-EP or EXIF metadata tags
>     • Using the IPTC metadata tag (33723)
>     • Using the XMP metadata tag (700)
> 
>     Note that TIFF-EP and EXIF use nearly the same metadata tag set, but
>     TIFF-EP stores the tags in IFD 0, while EXIF store the tags in a
>     separate IFD. Either location is allowed by DNG, but the EXIF
>     location is preferred.
> 
> While the DNG specification seems to allow storing the EXIF tags in
> IFD0, as well as storing the main image there as well, that isn't
> recommended. I'm thus curious to know what you mean by "modern
> flavours".

Following up on this, I now understand this is meant to support DNG
files created by PiDNG ([1]). I've asked them ([2]) why they use IFD0
instead of following the recommendations of the Adobe DNG specification,
waiting for a reply.

[1] https://github.com/schoolpost/PiDNG
[2] https://github.com/schoolpost/PiDNG/issues/65

> > But they are all DNGs, and DarkTable, RawTherapee and dcraw support
> > all of them. Just there are some annoying implementation details...
> > 
> > > > +        this code detects which one is being used, and therefore extracts the correct values
> > > > +        """
> > > > +        try:
> > > > +            Img.w = metadata['Exif.SubImage1.ImageWidth'].value
> > > > +            subimage = "SubImage1"
> > > > +            photo = "Photo"
> > > > +        except KeyError:
> > > > +            Img.w = metadata['Exif.Image.ImageWidth'].value
> > > > +            subimage = "Image"
> > > > +            photo = "Image"
> > > >          Img.pad = 0
> > > > -        Img.h = metadata['Exif.SubImage1.ImageLength'].value
> > > > -        white = metadata['Exif.SubImage1.WhiteLevel'].value
> > > > +        Img.h = metadata[f'Exif.{subimage}.ImageLength'].value
> > > > +        white = metadata[f'Exif.{subimage}.WhiteLevel'].value
> > > >          Img.sigbits = int(white).bit_length()
> > > >          Img.fmt = (Img.sigbits - 4) // 2
> > > > -        Img.exposure = int(metadata['Exif.Photo.ExposureTime'].value*1000000)
> > > > -        Img.againQ8 = metadata['Exif.Photo.ISOSpeedRatings'].value*256/100
> > > > +        Img.exposure = int(metadata[f'Exif.{photo}.ExposureTime'].value*1000000)
> > > > +        Img.againQ8 = metadata[f'Exif.{photo}.ISOSpeedRatings'].value*256/100
> > > >          Img.againQ8_norm = Img.againQ8 / 256
> > > >          Img.camName = metadata['Exif.Image.Model'].value
> > > > -        Img.blacklevel = int(metadata['Exif.SubImage1.BlackLevel'].value[0])
> > > > +        Img.blacklevel = int(metadata[f'Exif.{subimage}.BlackLevel'].value[0])
> > > >          Img.blacklevel_16 = Img.blacklevel << (16 - Img.sigbits)
> > > >          bayer_case = {
> > > >              '0 1 1 2': (0, (0, 1, 2, 3)),
> > > > @@ -319,7 +331,7 @@ def dng_load_image(Cam, im_str):
> > > >              '2 1 1 0': (2, (3, 2, 1, 0)),
> > > >              '1 0 2 1': (3, (1, 0, 3, 2))
> > > >          }
> > > > -        cfa_pattern = metadata['Exif.SubImage1.CFAPattern'].value
> > > > +        cfa_pattern = metadata[f'Exif.{subimage}.CFAPattern'].value
> > > >          Img.pattern = bayer_case[cfa_pattern][0]
> > > >          Img.order = bayer_case[cfa_pattern][1]
> > > >

-- 
Regards,

Laurent Pinchart


More information about the libcamera-devel mailing list