$ exiftool -b -RawThermalImage IMG_*.JPG -w _%f.png
$ convert -version
Version: ImageMagick 6.8.9-1 Q16 x86_64 2014-07-08 http://www.imagemagick.org
$ convert -define png:swap-bytes=on *.png -set filename:fname 'R%t' +adjoin '%[filename:fname].png'
// find max/min RAW value
$ identify -verbose R_*.png | grep -n3 statist | grep min | sort -k 3 | head -n 1
10409- min: 13272 (0.202518)
$ identify -verbose R_*.png | grep -n3 statist | grep max | sort -k 3 | tail -n 1
376- max: 13658 (0.208408)
//stretch level und resize for stacking
convert R_*.png -level 13250,13700 -resize 320x -set filename:fname 'S%t' +adjoin '%[filename:fname].png'
// calc average
$ convert -average SR_*.png stack.png
// mosaic
$ montage SR*.png -tile 6x5 -geometry +2+2 tile_6x5.jpg
//animated gif
$ montage SR*.png -tile 1x1 -geometry +0+0 tile_1x1.gif
//extract RAW
$ exiftool -b -RawThermalImage IR_3115.jpg > IR_3115.tif
//auto-level and resize (without interpolation!) to 8x8 pixel size
$ convert IR_3115.tif -auto-level -filter point -resize 2560x wire6.png
//draw one square with size 8x8
$ convert -size 8x8 xc:none -stroke gray -strokewidth 0 -draw "line 0,0 0,7" -draw "line 0,0 7,0" 1.png
//enlarge to 320x240 squares of size 8x8
$ convert -size 2560x1920 tile:1.png 320x240.png
//overlay grid with image
$ convert wire6.png 320x240.png -compose overlay -composite IR_3115ov.png
//crop a part of 640x480 => 80x60 sensor pixel
$ convert IR_3115ov.png -crop 640x480+800+700 IR_3115ov-crop.png
//extract RAW
$ exiftool -b -RawThermalImage IMG_3353.JPG > wire.png
//change byte order, auto-level and resize (without interpolation) to 8x8 pixel size
$ convert -define png:swap-bytes=on wire.png -auto-level -filter point -resize 640x IMG_3353.png
//draw one square with size 8x8
$ convert -size 8x8 xc:none -stroke gray -strokewidth 0 -draw "line 0,0 0,7" -draw "line 0,0 7,0" 1.png
//enlarge to 80x60 sensor pixel squares
$ convert -size 640x480 tile:1.png 80x60.png
//overlay grid with image
$ convert IMG_3353.png 80x60.png -compose overlay -composite IMG_3353ov.png
$ convert -size 8x8 xc:none -stroke gray -strokewidth 0 -draw "line 0,0 0,7" -draw "line 0,0 7,0" 1.png
$ convert -size 640x480 tile:1.png -transparent white grid.png
$ convert largeimage.png grid.png -flatten overlay.png
inside the Flir One app I found the interesting file SuperResDenoise.plistCode: [Select]<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Date</key>
<date>2014-03-12T22:10:38Z</date>
<key>Deblur_PSD</key>
<dict>
<key>ht1_1x8x8</key>
<array>
--- snip ---
</dict>
<key>Denoise_Parameters</key>
<dict>
<key>dn_dctBlkStepSz</key>
<integer>4</integer>
<key>dn_motionThreshold</key>
<real>0.20000000000000001</real>
<key>dn_smoothing</key>
<integer>50</integer>
</dict>
<key>Description</key>
<string>Flir One Parameters for SuperResolution, Denoise and Deblur.</string>
<key>PSD</key>
<dict>
--- snip ---
<key>Revision_number</key>
<integer>0</integer>
<key>Super_Resolution_Parameters</key>
<dict>
<key>sr_alpha</key>
<real>0.59999999999999998</real>
<key>sr_bestQuality</key>
<true/>
<key>sr_beta</key>
<integer>10</integer>
<key>sr_bilinearUpscale</key>
<false/>
</dict>
</dict>
</plist>
see my posts for details about superresolution:
https://www.eevblog.com/forum/testgear/flir-e4-thermal-imaging-camera-teardown/msg363688/#msg363688
https://www.eevblog.com/forum/testgear/flir-e4-thermal-imaging-camera-teardown/msg363213/#msg363213you can see this effect on the pins of the LQFP64 (pin-distance: 0.5mm)
single image (see left side of chip - pins are different blurred)
stacked image (all pins are sharp)
stacked image (all pins are sharp)
connect with telnet to shell of Flir E40 camera and take a RAW sequence of 90 frames
I used a tripod and moved the cam a little while recording.
...
now stack all png images with free tool Registax http://www.astronomie.be/registax/ and save as 16 bit tif image
Need to find algorithm used there itself while I want implement this with OpenCV support and include to native C/C++ code for Seek Thermal output images enhancements after its calibration frames gradient corrections are made
rset .image.flow.digitalFilter.noiseGen.enabled true/false
rset .image.flow.digitalFilter.noiseGen.level 150 (mK)
Quote.caps.config.image.targetNoise.enabled bool true
.caps.config.image.targetNoise.targetNoiseMk int32 135It could actually be noise reduction or shaping - maybe this is a threshold to decide when to apply noise reduction, i.e. adjust filter until noise is below the target value. "Mk" - mask? Perhaps something like a hysteresis function?
targetNoiseMk is a noise generator in mK (conforming with NETD/ thermal sensity in Flir Datasheets of the selected cam)
Formerly I stacked some noisy images with Registax or AviStax to subtract out the randomly noise and it works great!!
after setting targetNoiseMk to zero, stacking of images don't improve results
here a sample from a Flir E40 (old cam hacked formerly from 160x120 to 320x240)
in service menu I can measuring the noiseCode: [Select]rset .caps.config.image.targetNoise.targetNoiseMk 60 (MilliKelvin)
Temporal noise MilliKelvin Digital Units
Pixel Noise 61.28 12.13
Row Noise 14.84 2.94
Column Noise 13.67 2.71
Spatial noise MilliKelvin Digital Units
Pixel Noise 25.69 5.09
Row Noise 7.08 1.40
Column Noise 7.82 1.55
Uniformity 198.23 39.25
Total noise MilliKelvin Digital Units
Pixel Noise 67.01 13.27
Row Noise 9.71 1.92
Column Noise 10.10 2.00
and now without noise (cam temperature is 25 Grad):Code: [Select]rset .caps.config.image.targetNoise.targetNoiseMk 0 (MilliKelvin)
Temporal noise MilliKelvin Digital Units
Pixel Noise 19.85 3.93
Row Noise 6.39 1.26
Column Noise 8.64 1.71
Spatial noise MilliKelvin Digital Units
Pixel Noise 18.98 3.76
Row Noise 4.70 0.93
Column Noise 5.54 1.10
Uniformity 210.23 41.63
Total noise MilliKelvin Digital Units
Pixel Noise 28.96 5.73
Row Noise 5.76 1.14
Column Noise 7.66 1.52
see the differences (NETD is 0,03 °C @ 25°C)Quotehttp://gs.flir.com/surveillance-products/surveillance-technology/imaging-technotes/IR_Technology_Parameters
Uncooled infrared cameras systems are typically a little noisier, in the range of 30 - 120mK. Noise in an image can be spatial or temporal.
Spatial noise is noise across the image at any given point in time. It is perceived as an unchanging fixed pattern on top of the image.
Temporal noise is noise at any point in the image over time. It is perceived as the static that moves in an image.
NETD is typically the measure of both these noise types.
remarkably Flir dont't disable the noise generator at the top cams of a serie (Flir E4 -> E8 , Flir E30 -> E60)
if you simple delete the SuperResDenoise.plist nothing changes
I think devilmastah can better look inside the code of the flir one app
#
# Generated at 2014-05-27
#
.caps entry
.caps.config entry
.caps.config.name text "app super"
.caps.config.revision text "1.1"
.caps.config.image entry
.caps.config.image.framegrab entry
.caps.config.image.framegrab.fusion entry
.caps.config.image.framegrab.fusion.enabled bool true
.caps.config.image.framegrab.fusion.pip entry
.caps.config.image.framegrab.fusion.pip.enabled bool true
.caps.config.image.framegrab.fusion.hcf entry
.caps.config.image.framegrab.fusion.hcf.enabled bool true
.caps.config.image.services entry
.caps.config.image.services.store entry
.caps.config.image.services.store.enabled bool true
.caps.config.image.services.store.radiometric entry
.caps.config.image.services.store.radiometric.enabled bool true
.caps.config.image.services.store.incompatible entry
.caps.config.image.services.store.incompatible.enabled bool false
.caps.config.image.services.store.incompatible.level int32 0
.caps.config.image.settings entry
.caps.config.image.settings.enabled bool true
.caps.config.image.settings.IRwidth int32 320
.caps.config.image.settings.IRheight int32 240
.caps.config.image.sysimg entry
.caps.config.image.sysimg.alarms entry
.caps.config.image.sysimg.alarms.enabled bool false
.caps.config.image.sysimg.alarms.measfunc entry
.caps.config.image.sysimg.alarms.measfunc.enabled bool false
.caps.config.image.sysimg.alarms.measfunc.maxCount int32 3
.caps.config.image.sysimg.alarms.humidity entry
.caps.config.image.sysimg.alarms.humidity.enabled bool false
.caps.config.image.sysimg.alarms.humidity.maxCount int32 1
.caps.config.image.sysimg.alarms.insulation entry
.caps.config.image.sysimg.alarms.insulation.enabled bool false
.caps.config.image.sysimg.alarms.insulation.maxCount int32 1
.caps.config.image.sysimg.gps entry
.caps.config.image.sysimg.gps.enabled bool true
.caps.config.image.sysimg.irMarkers entry
.caps.config.image.sysimg.irMarkers.enabled bool false
.caps.config.image.sysimg.irMarkers.spot entry
.caps.config.image.sysimg.irMarkers.spot.enabled bool false
.caps.config.image.sysimg.irMarkers.spot.maxCount int32 0
.caps.config.image.sysimg.irMarkers.arrow entry
.caps.config.image.sysimg.irMarkers.arrow.enabled bool true
.caps.config.image.sysimg.irMarkers.arrow.maxCount int32 0
.caps.config.image.sysimg.irMarkers.box entry
.caps.config.image.sysimg.irMarkers.box.enabled bool false
.caps.config.image.sysimg.irMarkers.box.maxCount int32 0
.caps.config.image.sysimg.measureFuncs entry
.caps.config.image.sysimg.measureFuncs.enabled bool true
.caps.config.image.sysimg.measureFuncs.diff entry
.caps.config.image.sysimg.measureFuncs.diff.enabled bool true
.caps.config.image.sysimg.measureFuncs.diff.maxCount int32 1
.caps.config.image.sysimg.measureFuncs.diff.calcMask int32 65526
.caps.config.image.sysimg.measureFuncs.isotherm entry
.caps.config.image.sysimg.measureFuncs.isotherm.enabled bool true
.caps.config.image.sysimg.measureFuncs.isotherm.calcMask int32 20
.caps.config.image.sysimg.measureFuncs.isotherm.dual bool false
.caps.config.image.sysimg.measureFuncs.isotherm.fixScale bool false
.caps.config.image.sysimg.measureFuncs.isotherm.interval bool true
.caps.config.image.sysimg.measureFuncs.isotherm.invInterval bool false
.caps.config.image.sysimg.measureFuncs.isotherm.maxCount int32 1
.caps.config.image.sysimg.measureFuncs.mbox entry
.caps.config.image.sysimg.measureFuncs.mbox.enabled bool true
.caps.config.image.sysimg.measureFuncs.mbox.calcMask int32 1924
.caps.config.image.sysimg.measureFuncs.mbox.maxCount int32 5
.caps.config.image.sysimg.measureFuncs.mcircle entry
.caps.config.image.sysimg.measureFuncs.mcircle.enabled bool true
.caps.config.image.sysimg.measureFuncs.mcircle.calcMask int32 1924
.caps.config.image.sysimg.measureFuncs.mcircle.maxCount int32 5
.caps.config.image.sysimg.measureFuncs.mline entry
.caps.config.image.sysimg.measureFuncs.mline.enabled bool true
.caps.config.image.sysimg.measureFuncs.mline.calcMask int32 1924
.caps.config.image.sysimg.measureFuncs.mline.maxCount int32 1
.caps.config.image.sysimg.measureFuncs.reftemp entry
.caps.config.image.sysimg.measureFuncs.reftemp.enabled bool true
.caps.config.image.sysimg.measureFuncs.reftemp.calcMask int32 1924
.caps.config.image.sysimg.measureFuncs.reftemp.maxCount int32 1
.caps.config.image.sysimg.measureFuncs.script entry
.caps.config.image.sysimg.measureFuncs.script.enabled false
.caps.config.image.sysimg.measureFuncs.script.maxCount int32 0
.caps.config.image.sysimg.measureFuncs.spot entry
.caps.config.image.sysimg.measureFuncs.spot.enabled bool true
.caps.config.image.sysimg.measureFuncs.spot.calcMask int32 514
.caps.config.image.sysimg.measureFuncs.spot.maxCount int32 10
.caps.config.image.sysimg.visualMarkers entry
.caps.config.image.sysimg.visualMarkers.enabled bool false
.caps.config.image.sysimg.visualMarkers.spot entry
.caps.config.image.sysimg.visualMarkers.spot.enabled bool false
.caps.config.image.sysimg.visualMarkers.spot.maxCount int32 0
.caps.config.image.sysimg.visualMarkers.arrow entry
.caps.config.image.sysimg.visualMarkers.arrow.enabled bool false
.caps.config.image.sysimg.visualMarkers.arrow.maxCount int32 0
.caps.config.image.sysimg.visualMarkers.box entry
.caps.config.image.sysimg.visualMarkers.box.enabled bool false
.caps.config.image.sysimg.visualMarkers.box.maxCount int32 0
.caps.config.image.targetNoise entry
.caps.config.image.targetNoise.enabled bool false
.caps.config.image.targetNoise.targetNoiseMk int32 0
.caps.config.image.zoom entry
.caps.config.image.zoom.enabled bool false
.caps.config.image.zoom.maxFactor double 8
.caps.config.system entry
.caps.config.system.focus entry
.caps.config.system.focus.laser entry
.caps.config.system.focus.laser.updateFocus entry
.caps.config.system.focus.laser.updateFocus.enabled bool false
.caps.config.ui entry
.caps.config.ui.fusion entry
.caps.config.ui.fusion.PIP entry
.caps.config.ui.fusion.PIP.enabled bool true
.caps.hw entry
.caps.hw.sdcard entry
.caps.hw.sdcard.enabled bool false
# ID *
# CRC01 b114169e
i'm wondering if perhaps since Flir have been in the thermal buisness so long, they just took big chunks of code they had for say the E4, and ported it for use with the Lepton module and Flir One.
.caps.config.image.settings.IRwidth int32 320
.caps.config.image.settings.IRheight int32 240
mac osx
// verbose: g++ -v
$ g++ *.cpp -o crc01
$ ./crc01
Usage: ./crc01 infile.txt
// count lines
$ wc -l FlashFS/system/calib.rsc
801 FlashFS/system/calib.rsc
//print last line
$ tail -n1 FlashFS/system/calib.rsc
# CRC32 ef8f7e0e
//calc a new crc32 for 801-1=800 lines
$ crc32 <(head -n 800 FlashFS/system/calib.rsc)
ef8f7e0e