enhancement: extract binary data from FLIR radiometric jpg

Started by tomas123, March 20, 2013, 12:49:46 PM

Previous topic - Next topic

Phil Harvey

I haven't had any luck with the FLIR software.  I have FLIR Tools v1.01 installed on my Mac, and had already downloaded FLIR ResearchIR v3.4 so I installed it on my old PC (the installation took over an hour!), but in neither software can I find any options to save FPF-format images.  Are you saying that the FLIR Tools should be able to write FPF images?  I can't find this option anywhere.

- Phil
...where DIR is the name of a directory/folder containing the images.  On Mac/Linux/PowerShell, use single quotes (') instead of double quotes (") around arguments containing a dollar sign ($).

tomas123

sorry for your lost time

Quote from: tomas123 on April 11, 2013, 12:52:43 PM
I loaded my file IR_1546.jpg from B40 to ThermaCAM Researcher Pro 2.10 (trial) and saved it without some manipulation as Ir_1546.fpf

you found the old document Thermacam Researcher 2001 with defination of old flir fild format fpf.

So I installed the Thermacam Researcher and found there the function to save jpg as fpf.
http://www.flir.com/cs/emea/en/view/?id=42404

The flir fpf is a exotic old file format. It's not worth to write some code for it. It's a good Rosetta Stone.
We should focus on the flir radiometric jpg. There are thousands of cams and user.

With Flir Tools you can play around the nice color palettes  ;) and read Flir fff-Files (rename to jpg as workaround).

The  Thermacam Resarcher  is not the FLIR ResearchIR...

Phil Harvey

Thanks for explaining.  I'll download the old Thermacam software when I can get on a faster connection.  I just wanted to run the software to see if I could locate the only 2 pieces of information from the FPF that we aren't yet decoding from the FFF:  The external trigger count, and the frame sequence count.

I have already added support for FPF files just because it was the easiest way for me to compare the samples you sent, so I might as well leave this in the official release (which I was hoping to release tomorrow).

- Phil
...where DIR is the name of a directory/folder containing the images.  On Mac/Linux/PowerShell, use single quotes (') instead of double quotes (") around arguments containing a dollar sign ($).

tomas123

it may be that external trigger count and the frame sequence count never coded in radiometric jpg

Flir has a special file formats for picture sequence of radiometric pictures ( *.seq)
This is a movie stream as sequence of blocks.
Every block start with a regular FFF header and contains four(!) raw 16 bit pictures in a single Tag 0x0001.
Here make  frame sequence count sense.

tomas123

only for informationen

as attachment a short movie stream of 14 frames with 30 frames/sec (0,467 sec) in flir stream format *.seq

the best thing - exiftool read this format:
$ exiftool -ver
9.26
$ exiftool Flir_Movie.seq -flir:all -H -G
[APP1]          0x0001 Raw Thermal Image Width         : 320
[APP1]          0x0002 Raw Thermal Image Height        : 240
[APP1]          0x0010 Raw Thermal Image Type          : TIFF
[APP1]          0x0010 Raw Thermal Image               : (Binary data 153804 bytes, use -b option to extract)
[APP1]          0x0020 Emissivity                      : 0.95
[APP1]          0x0024 Object Distance                 : 2.00 m
[APP1]          0x0028 Reflected Apparent Temperature  : 20.0 C
[APP1]          0x002c Atmospheric Temperature         : 15.0 C
[APP1]          0x0030 IR Window Temperature           : 19.0 C
[APP1]          0x0034 IR Window Transmission          : 1.00
[APP1]          0x003c Relative Humidity               : 50.0 %
[APP1]          0x0090 Camera Temperature Range Max    : 120.0 C
[APP1]          0x0094 Camera Temperature Range Min    : -20.0 C
[APP1]          0x00d4 Camera Model                    : FLIR E40
[APP1]          0x00f4 Camera Part Number              : 49001-2001
[APP1]          0x0104 Camera Serial Number            : 49033333
[APP1]          0x0114 Camera Software                 : 20.0.0
[APP1]          0x0170 Lens Model                      : FOL18
[APP1]          0x0190 Lens Part Number                :
[APP1]          0x01a0 Lens Serial Number              :
[APP1]          0x01ec Filter Model                    :
[APP1]          0x01fc Filter Part Number              :
[APP1]          0x021c Filter Serial Number            :
[APP1]          0x0384 Date/Time Original              : 2013:04:14 12:55:57.433+01:00
[APP1]          0x0000 Palette Colors                  : 224
[APP1]          0x0006 Above Color                     : 16 128 128
[APP1]          0x0009 Below Color                     : 16 128 128
[APP1]          0x000c Overflow Color                  : 16 128 128
[APP1]          0x000f Underflow Color                 : 16 128 128
[APP1]          0x0012 Isotherm 1 Color                : 16 128 128
[APP1]          0x0015 Isotherm 2 Color                : 16 128 128
[APP1]          0x001a Palette Method                  : 0
[APP1]          0x001b Palette Stretch                 : 1
[APP1]          0x0050 Palette Name                    : Gray
[APP1]          0x0070 Palette                         : (Binary data 672 bytes, use -b option to extract)


I saved with Flir Tools+ a single frames from movie in radiometric jpg format, but I can't found a frame sequence counter...

Phil Harvey

Hi Tomas,

Thanks.  I'll take a look at this tomorrow when I'm on a faster internet connection.

- Phil
...where DIR is the name of a directory/folder containing the images.  On Mac/Linux/PowerShell, use single quotes (') instead of double quotes (") around arguments containing a dollar sign ($).

tomas123

Quote from: tomas123 on April 12, 2013, 02:25:31 PM
Every block start with a regular FFF header and contains four(!) raw 16 bit pictures in a single Tag 0x0001.
this is wrong, *seq is a following sequence of normal *.fff files
Flir  scaled up my sensor size from 160x120 to 320x240 in movie sequence (quadruple size)

$ exiftool Flir_Movie.seq
ExifTool Version Number         : 9.26
Raw Thermal Image Width         : 320
Raw Thermal Image Height        : 240
Raw Thermal Image Type          : TIFF
Raw Thermal Image               : (Binary data 153804 bytes, use -b option to extract)

$ exiftool Flir_Movie.seq -b -RawThermalImage > seq.tif

$ identify seq.tif
seq.tif TIFF 320x240 320x240+0+0 16-bit Grayscale DirectClass 154KB 0.000u 0:00.000


Phil Harvey

*snif*  I'm heartbroken that you used identify instead of ExifTool:

exiftool Flir_Movie.seq -b -RawThermalImage | exiftool -

;)

- Phil
...where DIR is the name of a directory/folder containing the images.  On Mac/Linux/PowerShell, use single quotes (') instead of double quotes (") around arguments containing a dollar sign ($).

tomas123

#53
sorry for my ignorance and delayed feedback

Quote from: Phil Harvey on April 07, 2013, 04:00:45 PM
You say that only FLIR software can calculate the temperatures, isn't the formula given in "the measurement formula" reference you gave?
I worked hard on decoding the Flir variables for calculating pixel temperature

here is a explanation of Flir Raw value (Page 8)
http://www.workswell.cz/manuals/flir/hardware/A3xx_and_A6xx_models/AXXX_Control_Image_Interfaces.pdf
"RAW"=16 bit un-compressed IR image linear in signal with ancillary calibration data

I found a nice hint in this Flir documents:
http://flir.custhelp.com/ci/fattach/get/1667/
on page 2 they say, that the response of "A/D Counts" are linear to Radiance with a offset.

The Radiance formula you find in Planck's Law
http://en.wikipedia.org/wiki/Planck%27s_law

e^(h*c/(k*λ*T)−1 = (2*h*c^2/λ^5)/I
Planck's Constant h = 6.626068x10-34 joule sec 
Boltzman's Constant k =1.38066x10-23 joule deg-1
Speed of light in vacuum c =2.997925x10+8 m/s
T = object temperature in Kelvins
λ = wavelength in m
I = radiance in Joules/m^3/sec/steradian
e Euler Number

solve it to Temperature formula
T= B / ln(R/I +1)
with ln => Natural logarithm
by substitute with
R = 2*h*c^2/λ^5 
B = h*c/(k*λ)

as explained above is Radiance "I" linear to  Flir A/D Counts "S"
we can write
I = R2*(S+O)
with
S = 16 Bit A/D Counts
R2 = constant factor
O = offset

and with R = R1/R2
T= B / ln(R/I +1)
goes to
T = B / ln(R1/(R2(S+O))+1)

on page 14 in this FLIR document, I found a confirmation for this formulation:
Quotehttp://www.workswell.cz/manuals/flir/hardware/Ax5_models/ICD_GenICam_ICD_FLIR_Ax5_Camera_PC.pdf
Temperature (in Kelvin) = B / log(R / (S - O) + F)
S is the 14-bit digital signal value.
log(x) is the base-e logarithm of the x parameter.
R Planck R constant
B Value range 1300 - 1600.
F Value range 0.5 - 2
O (offset) constant

please note, that Flir replaced the constant 1 in Planck's Law with F (range 0.5 - 2)

now lets find this values in Flir FFF-sequence
here are the offsets (LensFieldOfViewDegree is bycatch)

exiftool FLIR.pm
# FLIR camera record (ref PH)
%Image::ExifTool::FLIR::CameraInfo = (
...
    0x58 => { Name => 'PlanckR1',     Format => 'float', PrintConv => 'sprintf("%f",$val)' },
    0x5C => { Name => 'PlanckB',     Format => 'float', PrintConv => 'sprintf("%f",$val)' },
    0x60 => { Name => 'PlanckF',     Format => 'float', PrintConv => 'sprintf("%f",$val)' },
    0x1b4 => { Name => 'LensFieldOfViewDegree',     Format => 'float', PrintConv => 'sprintf("%.1f",$val)' },
    0x308 => { Name => 'PlanckO',     Format => 'int16s', PrintConv => 'sprintf("%i",$val)' },
    0x30C => { Name => 'PlanckR2',     Format => 'float', PrintConv => 'sprintf("%.8f",$val)' },

please note Offset is a signed word and Flir substituted R = R1/R2

with this Exiftool patch I get:
$exiftool -flir:all IR_2530.jpg | grep Planck
Planck R1                       : 16030.829102
Planck B                        : 1406.699951
Planck F                        : 1.250000
Planck O                        : -7800
Planck R2                       : 0.09530587



Now we must consider the Emissivity with "Reflected Apparent Temperature"
here comes FLIR with the "the measurement formula" into play

S_obj = Radiance of object
S_refl = Radiance of reflected objects
S_mes = measured Radiance (total radiance)
Em = Emissivity of object

S_mes = Em*S_obj + (1-Em)*S_refl
can be written as
S_obj = (S_mes - (1-Em)*S_refl)/Em
and
T_obj = B/ln(R1/(R2(S_obj+O))+1)
thats all

I ignore the Emission of atmosphera. The influence is low by short distance. The calculation effort is high (distance, humidity).
Our calculated temperature is 100% identical with Flir temperature if you set the object distance to zero and let external optics transmission by 1.0!!

for testing I wrote a short shell script raw2tmp.sh

#!/bin/bash
echo "usage $0 flir.jpg PixelArea"
echo "see imagemagick crop for PixelArea, sample 1x1+0+0"

# get Flir values
Flir=$(exiftool -Flir:all "$1")
Type=$(echo "$Flir" | grep "Raw Thermal Image Type" | cut -d: -f2)
if [ "$Type" != " TIFF" ]
    then
        echo "only for RawThermalImage=TIFF"
        exit 1
fi

R1=$(echo "$Flir" | grep "Planck R1" | cut -d: -f2)
R2=$(echo "$Flir" | grep "Planck R2" | cut -d: -f2)
B=$(echo "$Flir" | grep "Planck B" | cut -d: -f2)
O=$(echo "$Flir" | grep "Planck O" | cut -d: -f2)
F=$(echo "$Flir" | grep "Planck F" | cut -d: -f2)

# get RAW Sensor value
RAW=$(exiftool -b -RawThermalImage "$1" 2>/dev/zero | convert - -crop $2 -colorspace gray -format "%[mean]" info: )

# calc spectral range of used Flir camera
echo -n "spectral range [micrometer]: "
echo "scale=2;14387.6515/$B"| bc -l

# calc Temperature of PixelArea with Emissivity = 1.0
degree=$(echo "scale = 8;$B/l($R1/($R2*($RAW+$O))+$F)-273.15" | bc -l )
echo "$RAW RAW => $degree degree Celsius at Emissivity=1.0"

# calc Temperature of PixelArea with saved Emissivity
Emissivity=$(echo "$Flir" | grep "Emissivity" | cut -d: -f2)
Refl_Temp=$(echo "$Flir" | grep "Reflected Apparent Temperature" | sed 's/[^0-9.-]*//g')

RAWrefl=$(echo "scale = 8;$R1/($R2*(e($B/($Refl_Temp+273.15))-$F))-$O" | bc -l )
RAWobj=$(echo "scale = 8;($RAW-(1-$Emissivity)*$RAWrefl)/$Emissivity" | bc -l )
echo $Emissivity $Refl_Temp $RAW $RAWrefl $RAWobj
degree=$(echo "scale = 8;$B/l($R1/($R2*($RAWobj+$O))+$F)-273.15" | bc -l )
echo "$RAWobj RAW => $degree °C at Emissivity=$Emissivity and $Refl_Temp °C reflected temp."


usage ./raw2tmp.sh flir.jpg PixelArea
see imagemagick crop for PixelArea, sample 1x1+0+0

here a sample with a area of 1x1 Pixel and the first pixel on top right (x,y => 0,0)
$ ./raw2tmp.sh IR_1546.jpg  1x1+0+0
spectral range [micrometer]: 10.30
12626 RAW => -9.51770751 degree Celsius at Emissivity=1.0
12373.04334215 RAW => -11.39208744 °C at Emissivity= 0.95 and 20.0 °C reflected temp.


With this values I also calculated the spectral range of camera
it's simple
B = h*c/(k*λ) goes to
λ[μm]=14387.6515/Planck_B
There are two sort of cams on market SW and LW cameras.
see Short Wave and Long Wave
http://en.wikipedia.org/wiki/Infrared

sample of spectral range with Flir E40:
calculated from Exif: 10.30 μm (Peak)
datasheet: 7.5–13 μm (Range)




script works only for Tiff Images
if you use "Raw Thermal Image Type"=PNG you must change upper/lower byte
$ convert cat1.png gray:- | convert -depth 16 -endian msb -size 120x120 gray:- -auto-level cat2.png


PH Edit: Fixed typo in a formula

tomas123

here a sample for the quality of approximation

use shell script from previous post

here are the first 6 Pixel of first line with Emissivity = 0.7
$ for i in $(seq 0 5); do ./raw2tmp.sh IR_2521_em_0.7.jpg  1x1+$i+0 | grep reflected; done
17169.92339290 RAW => 18.60727574 °C at Emissivity= 0.70 and 30.0 °C reflected temp.
17187.06625004 RAW => 18.69889653 °C at Emissivity= 0.70 and 30.0 °C reflected temp.
17207.06625004 RAW => 18.80568329 °C at Emissivity= 0.70 and 30.0 °C reflected temp.
17195.63767861 RAW => 18.74467600 °C at Emissivity= 0.70 and 30.0 °C reflected temp.
17199.92339290 RAW => 18.76755800 °C at Emissivity= 0.70 and 30.0 °C reflected temp.
17187.06625004 RAW => 18.69889653 °C at Emissivity= 0.70 and 30.0 °C reflected temp.


as attachment the exported temperature csv matrix from Flir Tools
$ head -n 1 IR_2521_em_0.7.csv | tr ";" "\n" | head -n 6
18,607
18,699
18,806
18,745
18,768
18,699







and the first 6 Pixel of same picture with Emissivity=1.0

$ for i in $(seq 0 5); do ./raw2tmp.sh IR_2521_em_1.0.jpg  1x1+$i+0 | grep reflected; done
17845.00000000 RAW => 22.15501195 °C at Emissivity= 1.00 and 21.0 °C reflected temp.
17857.00000000 RAW => 22.21699384 °C at Emissivity= 1.00 and 21.0 °C reflected temp.
17871.00000000 RAW => 22.28925951 °C at Emissivity= 1.00 and 21.0 °C reflected temp.
17863.00000000 RAW => 22.24797078 °C at Emissivity= 1.00 and 21.0 °C reflected temp.
17866.00000000 RAW => 22.26345606 °C at Emissivity= 1.00 and 21.0 °C reflected temp.
17857.00000000 RAW => 22.21699384 °C at Emissivity= 1.00 and 21.0 °C reflected temp.


and the temperature csv matrix from Flir Tools
$ head -n 1 IR_2521_em_1.0.csv | tr ";" "\n" | head -n 6
22,155
22,217
22,289
22,248
22,263
22,217


you can see, its identical  :)
I was too lazy to use printf in shell script

Phil Harvey

Thank you very much for sharing your hard work here!  I'm sure this will be extremely useful to anyone else who wants to use the FLIR raw image data.

- Phil
...where DIR is the name of a directory/folder containing the images.  On Mac/Linux/PowerShell, use single quotes (') instead of double quotes (") around arguments containing a dollar sign ($).

tomas123

I don't need the Raw temperature values for my work.
I only use the possibility to make nice panoramas from raw images...

After you've found so many FLIR tags I also wanted to be a cool tag hunter  8)

Phil Harvey

Well, you certainly are a very cool tag hunter!!  I'll add your new tags, but I want to think about this for a while and study your notes before I decide on final names for them.  These were certainly too involved for me to decode by myself.  Thanks again for all your work on this!

- Phil
...where DIR is the name of a directory/folder containing the images.  On Mac/Linux/PowerShell, use single quotes (') instead of double quotes (") around arguments containing a dollar sign ($).

tomas123

Quote from: Phil Harvey on April 18, 2013, 07:42:01 PM
but I want to think about this for a while and study your notes before I decide on final names for them

I also thought hard about names.
I found two FLIR documents for the FLIR AX5 camera with register names for Planck's Law

Page 14 Measurement registers
http://www.workswell.cz/manuals/flir/hardware/Ax5_models/ICD_GenICam_ICD_FLIR_Ax5_Camera_PC.pdf
QuoteTemperature (in Kelvin) = B / log(R / (S - O) + F), where

S is the 14-bit digital signal
value.
log(x) is the base-e logarithm of the x parameter.
R   Integer   RW   Gets and sets the Planck R constant. This
value is used when converting from signal value to temperature.
B   Float   RW   Gets or sets Planck B constant. This value is
used when converting from signal value to temperature. Value range 1300 - 1600.
F   Float   RW   Gets or sets Planck F constant. This value is
used when converting from signal value to temperature. Value range 0.5 - 2.
O   Float   RW   Gets and sets Planck O (offset) constant. This
value is used when converting from signal value to temperature.

and Page 3
http://www.workswell.cz/manuals/flir/hardware/Ax5_models/Notice_to_customer_FLIR_Ax5%20I_O_synchronization_and_measurement.pdf
QuoteThe FLIR AX5 camera provides registers that can be used to convert object signal values to temperature.

For each measurement range (or gain mode) there is a set of register values that is used for this conversion.
Register name Type
R Integer
B Float
F Float
O Float
Please note that these registers will be automatically updated when switching between high gain mode and low gain mode.
The formula for calculating temperature is:
T (in Kelvin) = B / log(R/(S – O) + F)

In Flir FFF Format the register R is segemted in two registers.
I named they with  R1 and R2, because R1/R2= Flir_Register_R

The FOV "Field Of View" is the name in every Flir camera datasheet. There you find also the name "Spectral range"


Phil Harvey

Thanks for the explanation.  Your Planck names make sense now, and I'm leaning towards FieldOfView for the other tag.

- Phil
...where DIR is the name of a directory/folder containing the images.  On Mac/Linux/PowerShell, use single quotes (') instead of double quotes (") around arguments containing a dollar sign ($).