enhancement: extract binary data from FLIR radiometric jpg

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

Previous topic - Next topic

Arkana

Hello,
I'm new in this forum.
I came across ExifTool, by my attempt to manipulate radiometric jpg-files from my Flir T-360.
First of all let me thank you all very much. The work you have done here is amazing and profound!

I'm looking for a tool, that manipulates flir-images (post from May 2013) via batch mode.
I want to set a specific settings (scale-temp.min., scale-temp.max, Trefl., Emission, Atmospheric-Temp. and Distance).

I tested the flir.php-skript of Thomas123 and I'm really impressed.
It actually does most of the thigs I'm looking for.
So I wanted to ask, if there are any updates so far? For example a gui + batch-mode would be fantastic!
Is the output actually still radiometric and if not, is there a way to do that?

Something about the backround of this whole issue:
I tested a couple of apps from flir. I actually just know one software what does more or less what I want. This was ThermaCAM QuickView 1.3.
It removes all disturbing elements from the image and also changes the appearance of the color-scale in a certain way (to give some "in-between-values" on the scale is important for a better quality of analyzing these images) You can see the before and after in the attached files.
IR_45707.jpg is the direct camera-output
IR_001_2016.01.28_01.32.jpg is the output after simply opening and saving the image in ThermaCAM QuickView 1.3
There is also the possibility to change the scaling and actually all the parameters including color-pallets.

The big problem with ThermaCAM QuickView is, that it only runs under WindowsXP and it can't do batch-mode. This is particularly a problem, when I need to rescale hundreds of imagines by hand...
Also I'm a Linux-user. I run a virtual machine only for this purpose - this really sucks!!!

So I got some hope, when I started to read this forum and tested some of the suggested skripts. And as I said, the flir.php-skript of thomas123 seems to be the closest to what I'm looking for.
So, is there any chance, that you guys would continue on this track and to build in the end a powerful tool with a nice gui, opensource(!), which will beat the proprietary solutions from flir itself?

There is another link to this issue:
I'm member of the board in the association for applied Thermography in Switzerland ( www.thech.ch ).
Since a long time, we are looking for a way to unify the appearance of Thermal images, no matter which brand the cam is. In this way, the images would be directly comparable.
To solve this problem is for sure a much bigger hack, but you see where I'm going.

I'm very curious about your responses.

Best regards,
Arkana

tomas123

Hi Arkana,

Phil's exiftool forum is not the suitable forum for your question.
I wrote here some additional informations for decoding Flir images:
http://www.eevblog.com/forum/thermal-imaging/flir-e4-thermal-imaging-camera-teardown/msg342072/#msg342072


Quote from: Arkana on February 05, 2016, 07:51:23 AM
I tested the flir.php-skript of Thomas123 and I'm really impressed.
It actually does most of the thigs I'm looking for.
So I wanted to ask, if there are any updates so far? For example a gui + batch-mode would be fantastic!

All my php scripts are only "proof of concepts" for Flir/exiftool/imagemagick workflows.
The php syntax is easy. Therefore everybody can make necessary adjustments for own purpose.

Thomas

Arkana

Hello Thomas,

thanks for the hints! I will check it out the recommended forum.

The php-adjustments would be manageable, but some parts of my request demand some deeper knowledge about the math behind these images as well. Therefore I thought to ask you directly. Actually I would love to discuss some ugrade-ideas with you directly, if you are interested.

But thanks a lot, for all the work, time and sweat you've put so far into this project - it's amazing!

Stefan

edgar_eacg

Greetings, first of all: Congratulations for your great work in this forum.

Following the discussion on this thread
Quote from: tomas123 on April 07, 2013, 12:29:49 PM
(sample 1) Extract Color Table and Raw Image from Flir radiometric JPG and generate a new Image

I'm interested in handling the color palette of some .seq files generated with a SC640 FLIR camera. I use exiftool file.seq -Palette -b > rawData.dat to get the binary data into a .dat file. Indeed as with your sample 1 it's a 672-bytes file. I know that the used color palette is Rainbow (exiftool file.seq -PaletteName and because the camera was configured in this way).
Below is a portion of the generated file rawData.dat

19 7A 9F 19 7A 9F 19 7A A0 19 7A A0 19 7A A0 19 7A A0 19 79 A1 19 79 A1 1A 79 A3 1A 79 A3 1C 77 A5 1C 77 A5 20 74 A5
20 74 A5 27 6F A6 2B 6C A7 ...

Then according to your comment
QuoteSize is here 224x1 Pixel (=672/3)
I assume that each 3-byte group represents one pixel of this pallete (241x1) with one byte as one color channel. Thus, for example, (19 7A 9F) should be the color of the first pixel but how can I interpret these values? How can I get the RGB values for each pixel of this palette?

Thanks in advance.


tomas123

I don't understand your question.
In your link above the color table format is explained.
The colorspace is a interchanged YCbCr.

Do you know my newer post here?
http://www.eevblog.com/forum/thermal-imaging/flir-e4-thermal-imaging-camera-teardown/msg352778/#msg352778

Quoteafter understanding the BT.601 offset, I found a simple solution:

The colors are right, but the brightness is limited (16..238?).
With 16 Bit convert (Q16) we can simple stretch the brightness from 16*256=4096 to 238*256=60928

check your IM colorspace (switch between RGB or sRGB )
$ exiftool -b -Palette FLIR0074.jpg | convert -size 224X1 -depth 8 RGB:- -separate -swap 1,2 -set colorspace YCbCr -combine -colorspace sRGB -level 4096,60928 -resize 448x30! iron16.png
perfect:


compare with a screenshot from FlirTools GUI

edgar_eacg

Ok. Got it. I finally got the color palette I need. I lost the detail about interchanging CrCb
One last thing. Could you please give me some guidelines on the algorithm used to convert one pixel's temperature to color using the color palette?
Assuming I already have the pixel temperatures from the raw data,

I took a view on this thread looking for this process and you provide the flir.php file.

Quote from: tomas123 on May 14, 2013, 04:03:02 PM

flir.php
#!/usr/bin/php
<?php
//------------- set necessary paramters -------------------------------------

if (strtoupper(substr(PHP_OS03)) === 'WIN') {
    
//WINDOWS user: set path to tools
    
$convert='"C:\Program Files\ImageMagick-6.8.5-Q16\convert.exe"';
    
$exiftool='"C:\Program Files\exiftool\exiftool.exe"';
    
//set font variable as needed (Mac/Win) for color scale
    
$font='-font c:\windows\Fonts\arialbd.ttf';

} else {
    
//Unix/Mac: set path to tools here 
    
$convert='/opt/ImageMagick/bin/convert';
    
$exiftool='/usr/bin/exiftool';
    
//set font variable as needed (Mac/Win) for color scale
    
$font='-font /Library/Fonts/Arial\ Bold.ttf';
}

//color scale
$font_color='white';
$frame_color='black';

//extract embedded palette to
$embpal='palette.png';

//--------------------------------------------------------------------------

$shortopts  "";
$shortopts .= "i:";  // Required value
$shortopts .= "o:";  
$shortopts .= "h";  

$longopts  = array(
    
"resize:",     // Required value
    
"rmin:",     
    
"rmax:",    
    
"pal:",
    
"tref:",
    
"emis:",
    
"pip::",       // opt. value
    
"clut",        // No value
    
"scale",      
    
"help",       
);
$options getopt($shortopts$longopts);
#var_dump($options);

function help()
{
global 
$argv;
echo <<<EOT

usage: 
$argv[0] [options] -i ir_file.jpg -o outputimage

Settings:
-i ir_file.jpg      flir radiometric image
-o output.jpg       save  8 Bit image jpg
-o output.png       save 16 Bit image png

Options Summary:
--resize val        scale sensor size with "convert -resize val" (val i.e. 600x or 100%, default is 200%)
--tref temp         overwrite embedded Reflected Apparent Temperature (degree Celsius) 
--emis val          overwrite embedded Emissivity (val i.e. 0.95)
--rmin raw_min      set min RAW value instead embedded value (set scale min temp)
--rmax raw_ma       set max RAW value instead embedded value (set scale max temp)
--pal iron.png      use own palette (instead of embedded palette.png)
--clut              disable "Color LookUp Table" and color scale (save a grayscale image)
--scale             disable color scale on the right edge
--pip[=AxB]         input image is a flir PiP radiometric image
                    overlay embedded "real image" with "ir image"
                    [optional] crop ir image to size AxB (i.e. --pip=90x90 )
--help              print this help
  
# source: 
# [1] https://exiftool.org/forum/index.php/topic,4898.0.html

EOT;
}

if (isset(
$options['help']) || isset($options['h']))
{
 
help();
};

if (isset(
$options['i']))
{
    
$flirimg="\"".$options['i']."\"";
    if (isset(
$options['o']))
    {
        
$destimg="\"".$options['o']."\"";    
    } else {
      print 
'Error: No output file specified! "-o filename"'."\n";
      exit(
1);
    }
} else {     
    
help();
    exit(
1);
};

if (isset(
$options['pal']))
{
    
$pal="\"".$options['pal']."\"";  
} else {
    
$pal=$embpal;
}

if (isset(
$options['resize']))
{
    
$resize='-resize '.$options['resize'];    
} else {
    
// default
    
$resize="-resize 200%";
}

//get Exif values (syntax for Unix and Windows)
eval('$exif='.shell_exec($exiftool.' -php -flir:all -q '.$flirimg));
//var_dump($exif);

if (isset($options['tref']))
{
    
$Temp_ref=$options['tref'];  
} else {
    
$tmp=explode(" ",$exif[0]['ReflectedApparentTemperature']);
    
$Temp_ref $tmp[0];
}
if (isset(
$options['emis']))
{
    
$Emissivity=$options['emis'];  
} else {
    
$Emissivity=$exif[0]['Emissivity'];
}
print(
"\nReflected Apparent Temperature: ".$Temp_ref." degree Celsius\nEmissivity: ".$Emissivity."\n");

// save Flir values for Plancks Law for better reading in short variables
$R1=$exif[0]['PlanckR1'];
$R2=$exif[0]['PlanckR2'];
$B$exif[0]['PlanckB'];
$O$exif[0]['PlanckO'];
$F$exif[0]['PlanckF'];

print(
'Plancks values: '.$R1.' '.$R2.' '.$B.' '.$O.' '.$F."\n\n");

// get displayed temp range in RAW values
$RAWmax=$exif[0]['RawValueMedian']+$exif[0]['RawValueRange']/2;
$RAWmin=$RAWmax-$exif[0]['RawValueRange'];

print(
'RAW Temp Range from sensor : '.exec($convert.' raw.png -format "%[min] %[max]" info:')."\n");
printf("RAW Temp Range FLIR setting: %d %d\n",$RAWmin,$RAWmax);

//overwrite with settings
if (isset($options['rmin'])) $RAWmin=$options['rmin'];
if (isset(
$options['rmax'])) $RAWmax=$options['rmax'];

printf("RAW Temp Range select      : %d %d\n",$RAWmin,$RAWmax);

// calc amount of radiance of reflected objects ( Emissivity < 1 )
$RAWrefl=$R1/($R2*(exp($B/($Temp_ref+273.15))-$F))-$O;
printf("RAW reflected: %d\n",$RAWrefl); 

// get displayed object temp max/min and convert to "%.1f" for printing
$RAWmaxobj=($RAWmax-(1-$Emissivity)*$RAWrefl)/$Emissivity;
$RAWminobj=($RAWmin-(1-$Emissivity)*$RAWrefl)/$Emissivity;
$Temp_min=sprintf("%.1f"$B/log($R1/($R2*($RAWminobj+$O))+$F)-273.15);
$Temp_max=sprintf("%.1f"$B/log($R1/($R2*($RAWmaxobj+$O))+$F)-273.15);

// extract color table, swap Cb Cr and expand video pal color table from [16,235] to [0,255]
// best results: Windows -colorspace sRGB | MAC -colorspace RGB
exec($exiftool.' '.$flirimg.' -b -Palette | '.$convert.' -size "'.$exif[0]['PaletteColors'].'X1" -depth 8 YCbCr:- -separate -swap 1,2 -set colorspace YCbCr -combine -colorspace RGB -auto-level '.$embpal);

// draw color scale
exec($convert." -size 30x256 gradient: $pal -clut -mattecolor ".$frame_color.' -frame 5x5 -set colorspace rgb gradient.png');

// if your imagemagick have no freetype library remove the next line
exec($convert." gradient.png -background ".$frame_color." ".$font." -fill ".$font_color." -pointsize 15 label:\"$Temp_max C\" +swap -gravity Center -append  label:\"$Temp_min\" -append gradient.png");

if (
$exif[0]['RawThermalImageType'] != "TIFF")
{
  
//16 bit PNG: change byte order
   
$size=$exif[0]['RawThermalImageWidth']."x".$exif[0]['RawThermalImageHeight'];
   
exec($exiftool." -b -RawThermalImage $flirimg | ".$convert." - gray:- | ".$convert." -depth 16 -endian msb -size ".$size." gray:- raw.png");   
}else{
   
exec($exiftool." -b -RawThermalImage $flirimg | ".$convert." - raw.png");      
}

// convert every RAW-16-Bit Pixel with Planck's Law to a Temperature Grayscale value and append temp scale
$Smax=$B/log($R1/($R2*($RAWmax+$O))+$F);
$Smin=$B/log($R1/($R2*($RAWmin+$O))+$F);
$Sdelta=$Smax-$Smin;
exec($convert." raw.png -fx \"($B/ln($R1/($R2*(65535*u+$O))+$F)-$Smin)/$Sdelta\" ir.png");

if ( !isset(
$options['pip']) )
{    
    if ( !isset(
$options['clut']) )
    {
        if ( !isset(
$options['scale']) )
            {
            
// with color scale
            
exec($convert." ir.png ".$resize.$pal -clut -background ".$frame_color." -flatten +matte gradient.png -gravity East +append $destimg");
        }else{
            
exec($convert." ir.png ".$resize.$pal -clut ".$destimg);
        }
    }else{
        
// only gray picture
            
exec($convert." ir.png ".$resize." ".$destimg);
    }    
}else{
//make PiP
    //read embedded image
    
exec($exiftool." -b -EmbeddedImage $flirimg | ".$convert." - -set colorspace YCbCr -colorspace RGB embedded.png");
    
$geometrie=$exif[0]['OffsetX'].$exif[0]['OffsetY'];
    if ( 
is_string($options['pip']) )
    {
        
$crop="-gravity Center -crop ".$options['pip']."+0+0";
    }  
    
$resize=100*$exif[0]['EmbeddedImageWidth']/$exif[0]['Real2IR']/$exif[0]['RawThermalImageWidth'];
    
$resize="-resize ".$resize.'%';
    
exec($convert." ir.png $crop +repage ".$resize.$pal -clut embedded.png +swap -gravity Center -geometry $geometrie -compose over -composite -background ".$frame_color." -flatten +matte gradient.png -gravity East +append ".$destimg);
}

print(
"wrote $destimg with Temp-Range: $Temp_min / $Temp_max degree Celsius\n");

?>


But when I checked the source code I realized that the algorithm is wrapped in the use of convert.exe through the command line exec.
I'm interested in the mapping algorithm from temperatures to color (using the color Palette) so that I could conceive an inverse algorithm for mapping from color to pixel temperature.

Thanks

tomas123

This is not a exiftool question.
Please use this forum for your questions:
http://www.eevblog.com/forum/thermal-imaging/

There are many ImageMagick samples and software tools (like Thermovision_JoeC) for converting Flir images with the knowledge of exiftools reverse engineering.

casonar

Hi,

Sorry to resurrect this post, but it seemed the best fit considering what I was

I have an image here from a FLIR T420. ExifTool says that it's a PNG for the RawThermalImage and I can extract it. The problem is that the image is very distorted and I'm not sure what to do with it. I want to be able to translate the raw thermal image information to temperature values. I can do this with a raw TIFF, but the PNG seems to be much different.

I have tried the flir.php conversion script and it gives me the same information.

I have attached the image as well as what I receive when I extract the "RawThermalImage" from ExifTool.

Thanks for your thoughts.

tomas123

simply swap the byte order in your 16 bit png:

http://www.eevblog.com/forum/thermal-imaging/flir-e4-thermal-imaging-camera-teardown/msg348398/#msg348398

Quote// swap byte order (here you have trouble)
convert t1.png pgm:- | convert -endian lsb pgm:- t2.png
or
convert t1.png gray:- | convert -depth 16 -endian msb -size 320x240 gray:- t2.png
or since IM 6.8.8 with switch png:swap-bytes
convert -define png:swap-bytes=on t1.png t2.png

your image
$ convert -define png:swap-bytes=on FLIR0055.jpg.png  -auto-level swap.png

casonar

Ah, that's great! I've been searching and trying to figure this out for a couple of days now.

Should ExifTool do the byte swapping (or at least have an explanation that this could/should be necessary)?

Phil Harvey

Quote from: casonar on June 09, 2017, 12:39:14 PM
Should ExifTool do the byte swapping (or at least have an explanation that this could/should be necessary)?

This would stray into the realm of image editing, which I try to avoid doing with 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 ($).

siddhantmodi

#161
Hello,

Thanks a lot Phil and Tomas for all the work you guys have done!

I've gone through this thread extensively and have understood most of what I need to be doing to get temperature information out of my FLIR camera images. I have a FLIR Vue Pro R (640 x 512) that I am using for some ground testing, with the idea being that this camera will eventually be mounted on a drone. Using exiftool and the raw2temp.sh script, as well as the atmosphere.xls spreadsheet, I have been able to successfully calculate pixel temperatures and found that they match the data I get from FLIR Tools.

Simultaneously, I have been trying to do the same for a friend, who has a DJI Zenmuse XTR camera mounted on his DJI drone. The camera is a FLIR camera and I believe it is also a Vue Pro R (640 x 512) but has been rebranded a bit. He took some images and passed them onto me for analysis. FLIR Tools is able to decode those images and give me a csv file with temperatures. The problem arises when I try to use exiftool + atmosphere.xls. The results I get from this method do not match the output from FLIR Tools. I have checked all the parameters I am entering to the calculation spreadsheet multiple times and all seems to be correct so I am a bit lost at the moment.

I am unable to attach files to this post due to some error, so the DJI image, as well as the output from FLIR Tools, and the spreadsheet for calculations can all be found on this link. I hope that someone will be able to assist me! Please let me know if there are any questions that you may have for me.

https://www.dropbox.com/sh/e7fc6vv9wh6nby4/AABSQICe6LArWakWgRvQ0QYda?dl=0

Thank you for all your help and time.

Kind regards,
Sid

Phil Harvey

Hi Sid,

Have you tried posting this question here?:  http://www.eevblog.com/forum/thermal-imaging/

- 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 ($).

edgar_eacg

Hello.

First of all, Congratulations for your great application!!
I've been working with a Flir T630sc camera and exiftool works great. I'm specially interested in the way you decode the Date Time Original TAG directly from the binary jpg file. In the attached file the timestamp is 2017:09:15 10:58:36.162-06:00. Using the -H option with the exiftool command I get the  0x0384 address tag for the date time but I have no data in this address. In the following thread you mention that the address is 0x038c but is the same issue. I thought that the address was camera model dependant but I've tried a P640 model and the exiftool app retrieves it correct.

Quote from: Phil Harvey on April 12, 2013, 07:27:54 AM
OK, I am now able to decode the time zone from the FFF information (it was located at offset 0x38c in the CameraInfo):

> exiftool ~/Desktop/{fpf,jpg}/*1* -datetimeoriginal -G1
======== /Users/phil/Desktop/fpf/Ir_2517_dst-1.fpf
[FLIR]          Date/Time Original              : 2013:04:12 09:24:01.131
======== /Users/phil/Desktop/fpf/Ir_2519_dst+0.fpf
[FLIR]          Date/Time Original              : 2013:04:12 09:24:44.292
======== /Users/phil/Desktop/fpf/Ir_2521_dst+1.fpf
[FLIR]          Date/Time Original              : 2013:04:12 09:25:14.279
======== /Users/phil/Desktop/jpg/IR_2517_DST-1.jpg
[ExifIFD]       Date/Time Original              : 2013:04:12 09:24:01
[FLIR]          Date/Time Original              : 2013:04:12 09:24:01.131-01:00
======== /Users/phil/Desktop/jpg/IR_2519_DST+0.jpg
[ExifIFD]       Date/Time Original              : 2013:04:12 09:24:44
[FLIR]          Date/Time Original              : 2013:04:12 09:24:44.292+00:00
======== /Users/phil/Desktop/jpg/IR_2521_DST+1.jpg
[ExifIFD]       Date/Time Original              : 2013:04:12 09:25:14
[FLIR]          Date/Time Original              : 2013:04:12 09:25:14.279+01:00
    6 image files read


And the times in all of my samples are now consistent.  Thanks!

- Phil

Please, could you give me some guidelines on how to locate the date time address tag and how do you decode it?

Phil Harvey

See here for the decoding of the FLIR DateTimeOriginal.  The address is 0x0384 in the CameraInfo (type 0x20) record.  You must parse the FLIR metadata to locate this record.  Further down in the source code you will find the ProcessFLIR procedure which shows you how to do 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 ($).