ExifTool Forum

General => Metadata => Topic started by: alfazaz on February 10, 2014, 01:03:15 PM

Title: Decoding FLIR information
Post by: alfazaz on February 10, 2014, 01:03:15 PM
Hello !

I don't know if I post my question to the right place... but I need some help and with a little chance.... ;-)

I have a FLIR i7 and I need to import directly some informations in my python script for thermal photos. Now, I get these informations calling

exiftool -FLIR:PlanckR1 -FLIR:PlanckR2 -FLIR:PlanckB -FLIR:PlanckO -FLIR:PlanckF -FLIR:RawValueMedian -FLIR:RawValueRange -FLIR:ReflectedApparentTemperature -FLIR:Emissivity -s3 -q nomphoto

and I also get raw thermal data importing raw.png created with

exiftool -b -RawThermalImage nomphoto | convert - gray:- | convert -depth 16 -endian msb -size 140x140 gray:- raw.png

but I would like to have no call to exiftool to have a standalone program for my students.

Do you know how can I do ? I looked into FLIR.pm of exiftool without success. I don't know at what adresses to look to get informations (position etc...).

Thanks in advance !

Sorry if I'm really in a wrong place, and also for my english (I'm french... ;-) )

Title: Re: Decoding FLIR information
Post by: Phil Harvey on February 10, 2014, 07:58:44 PM
I don't think I can be any help here.  FLIR.pm is the best documentation I know for the format of FLIR metadata.

- Phil
Title: Re: Decoding FLIR information
Post by: alfazaz on February 11, 2014, 02:53:53 AM
Thanks for the answer.

When I look into FLIR.pm, I can see, for example at line 297 :
0x58 => { Name => 'PlanckR1', %float8g }, #1

With exiftool -v5, I get (for the same PlanckR1) :
| | PlanckR1 = 12767.2041015625
  | | - Tag 0x0058 (4 bytes, float[1]):
  | |     4f44: d1 7c 47 46   

I understand that 0x58 is not the absolute address for bytes for PlanckR1 value. It's relative ? How can I get an absolute address ? What about 4f44 I see with exiftool ?

I'm newbie for binary decoding and I think I miss the way to get absolute positions (they change from one file to another). I just need to get the right byte position for PlanckR1 (I think I can get the other informations after...).

Thanks if you can help me and, even if you can't, thanks for exiftool !
Title: Re: Decoding FLIR information
Post by: Phil Harvey on February 11, 2014, 07:35:47 AM
First you need to parse the JPEG file structure to find the FLIR APP1 segment, then see the ProcessFLIR subroutine in FLIR.pm for how to parse this data.  The comments in the code give details about the structure.

- Phil

P.S. I will be splitting this thread into a separate topic and moving it into the Metadata board.
Title: Re: Decoding FLIR information
Post by: alfazaz on February 11, 2014, 08:36:18 AM
Ok. I will give it a try...

Long life to exiftool ! ;-)
Title: Re: Decoding FLIR information
Post by: tomas123 on February 11, 2014, 10:03:51 AM
as simple entry point you can look in the comments of my first post
https://exiftool.org/forum/index.php/topic,4898.msg23497.html#msg23497

here I used awk for parsing the FLIR APP1 segment and the sub segment "0x01 => { Name => 'RawData',..."

Title: Re: Decoding FLIR information
Post by: tomas123 on February 11, 2014, 10:11:51 AM
use this document for understanding the fff format
Title: Re: Decoding FLIR information
Post by: alfazaz on February 11, 2014, 05:01:16 PM
Thank you very much !
Title: Re: Decoding FLIR information
Post by: alfazaz on February 13, 2014, 04:58:13 AM
Success !!!!

My problem is solved with your help. Here is my pythonic way to extract a numpy array with temperatures of a photo from the FLIR i7 (hope this helps !) :


import numpy as np
from math import pi
from PIL import Image
import io
import struct

####################################################
# Extraction function of temperature and date
# of a jpg FLIR i7 thermal photo
#
# Input :
#   * nomphoto : Pathname to the FLIR i7 jpg
#
# Output :
#   * Timage : 140x140 array of temperatures (in kelvin)
#   * Date : UNIX seconds date of the jpg
#
# Inspired from https://exiftool.org/forum/index.php?action=post;topic=5602.0;last_msg=27325
# and relatives
#
####################################################

def FextraireT(nomphoto):
    infile = open(nomphoto,'rb')
    try:
        buff = infile.read()
    finally:
        infile.close

    def Fdecode(buffer,index,s):
        # Decode with s type of buffer at index
        return struct.unpack(s,buffer[index:index+struct.calcsize(s)])[0]
       
    # APP1 FFF extract
    offsetAPP1=buff.find(b'\xFF\xE1',68)
    lengthAPP1=Fdecode(buff,offsetAPP1+2,'>H')
    APP1=buff[offsetAPP1+12:offsetAPP1+lengthAPP1+2]
    recordoffset=Fdecode(APP1,int('0x18',16),'>i')
    recordnum=Fdecode(APP1,int('0x1c',16),'>i')
    FRD=APP1[recordoffset:recordnum*int('0x20',16)]
    # RawData (subdirectory)
    posdebut=Fdecode(FRD,int('0x000',16)+int('0x0c',16),'>i')
    poslongueur=Fdecode(FRD,int('0x000',16)+int('0x10',16),'>i')
    RawData=APP1[posdebut:posdebut+poslongueur]
    # PNG image
    posinit=int('0x0020',16)
    PNGimage=RawData[posinit:-11]
    # It's tricky : needs to swap bytes
    imagebrute=Image.open(io.BytesIO(PNGimage))
    rawimg = np.array(imagebrute,dtype='int16')
    rawimg.byteswap(True)
    # Bytes swapped !
    # CameraInfo (subdirectory)
    posdebut=Fdecode(FRD,int('0x020',16)+int('0x0c',16),'>i')
    poslongueur=Fdecode(FRD,int('0x020',16)+int('0x10',16),'>i')
    CameraInfo=APP1[posdebut:posdebut+poslongueur]
    # Emissivity E
    E=Fdecode(CameraInfo,int('0x0020',16),'<f')
    # Tra
    Tra=Fdecode(CameraInfo,int('0x0028',16),'<f')
    # PlanckR1
    R1=Fdecode(CameraInfo,int('0x0058',16),'<f')
    # PlanckB
    B=Fdecode(CameraInfo,int('0x005c',16),'<f')
    # PlanckF
    F=Fdecode(CameraInfo,int('0x0060',16),'<f')
    # PlanckO
    O=Fdecode(CameraInfo,int('0x0308',16),'<i')
    # PlanckR2
    R2=Fdecode(CameraInfo,int('0x030c',16),'<f')
    # date (UNIX)
    Date=Fdecode(CameraInfo,int('0x0384',16),'<i')
    # Temperature array
    RAWrefl=R1/(R2*(np.exp(B/Tra)-F))-O
    Timage=(B/np.log(R1/(R2*((rawimg-(1-E)*RAWrefl)/E+O))+F))
    return Timage, Date

##############
# Example

[Timage,Date]=FextraireT('Photos/IR_0307.jpg')