ESF projekt Západočeské univerzity v Plzni reg. č. CZ.02.2.69/0.0/0.0/16 015/0002287

KKY/USVP 5 Thermal Imaging

There are several companies producing thermal cameras. FLIR, Optris, Workswell.

In this lecture, we will work with a camera FLIR T640.

Used library: https://pypi.org/project/flirimageextractor/, https://github.com/nationaldronesau/FlirImageExtractor

Prerequisity: https://exiftool.org/index.html on linux Ubuntu just type sudo apt install exiftool into terminal

In [1]:
%pylab inline
Populating the interactive namespace from numpy and matplotlib
In [2]:
import flirimageextractor
from matplotlib import cm
import matplotlib.pyplot as plt
import numpy as np

How to load an image

In [43]:
flir = flirimageextractor.FlirImageExtractor(palettes=[cm.jet, cm.bwr, cm.gist_ncar])
flir.process_image('./cviceni_5/FLIR0805.jpg')
In [44]:
flir.plot()

Note that the glass behaves like a mirror in the infrared

How to get thermal data

In [45]:
img = flir.get_thermal_np()
In [46]:
plt.figure(1, figsize(10,10))
plt.imshow(img, cmap="gray")
print(type(img[0,0]), np.min(img), np.max(img))
<class 'numpy.float64'> 24.31294485740625 28.775005506518937

How to get metadata

In [7]:
meta = flir.get_metadata('cviceni_5/FLIR0811.jpg')

List of all metadata in the image file

In [8]:
print(meta.keys())
dict_keys(['SourceFile', 'ExifToolVersion', 'FileName', 'Directory', 'FileSize', 'FileModifyDate', 'FileAccessDate', 'FileInodeChangeDate', 'FilePermissions', 'FileType', 'FileTypeExtension', 'MIMEType', 'JFIFVersion', 'ExifByteOrder', 'Make', 'Model', 'Orientation', 'XResolution', 'YResolution', 'ResolutionUnit', 'Software', 'ModifyDate', 'YCbCrPositioning', 'ExposureTime', 'ExifVersion', 'CreateDate', 'ComponentsConfiguration', 'SubjectDistance', 'FocalLength', 'ImageTemperatureMax', 'ImageTemperatureMin', 'FlashpixVersion', 'ColorSpace', 'ExifImageWidth', 'ExifImageHeight', 'DigitalZoomRatio', 'ImageUniqueID', 'Compression', 'ThumbnailOffset', 'ThumbnailLength', 'CreatorSoftware', 'Emissivity', 'ObjectDistance', 'ReflectedApparentTemperature', 'AtmosphericTemperature', 'IRWindowTemperature', 'IRWindowTransmission', 'RelativeHumidity', 'PlanckR1', 'PlanckB', 'PlanckF', 'AtmosphericTransAlpha1', 'AtmosphericTransAlpha2', 'AtmosphericTransBeta1', 'AtmosphericTransBeta2', 'AtmosphericTransX', 'CameraTemperatureRangeMax', 'CameraTemperatureRangeMin', 'CameraTemperatureMaxClip', 'CameraTemperatureMinClip', 'CameraTemperatureMaxWarn', 'CameraTemperatureMinWarn', 'CameraTemperatureMaxSaturated', 'CameraTemperatureMinSaturated', 'CameraModel', 'CameraPartNumber', 'CameraSerialNumber', 'CameraSoftware', 'LensModel', 'LensPartNumber', 'LensSerialNumber', 'FieldOfView', 'FilterModel', 'FilterPartNumber', 'FilterSerialNumber', 'PlanckO', 'PlanckR2', 'RawValueMedian', 'RawValueRange', 'DateTimeOriginal', 'FocusStepCount', 'FocusDistance', 'FrameRate', 'PaletteColors', 'AboveColor', 'BelowColor', 'OverflowColor', 'UnderflowColor', 'Isotherm1Color', 'Isotherm2Color', 'PaletteMethod', 'PaletteStretch', 'PaletteFileName', 'PaletteName', 'Palette', 'RawThermalImageWidth', 'RawThermalImageHeight', 'RawThermalImageType', 'RawThermalImage', 'Real2IR', 'OffsetX', 'OffsetY', 'PiPX1', 'PiPX2', 'PiPY1', 'PiPY2', 'GPSMapDatum', 'EmbeddedImageWidth', 'EmbeddedImageHeight', 'EmbeddedImageType', 'EmbeddedImage', 'ImageWidth', 'ImageHeight', 'EncodingProcess', 'BitsPerSample', 'ColorComponents', 'YCbCrSubSampling', 'ImageSize', 'Megapixels', 'PeakSpectralSensitivity', 'ShutterSpeed', 'ThumbnailImage', 'FocalLength35efl'])
In [9]:
print(meta["Emissivity"])
0.95
In [10]:
print(meta["CameraTemperatureRangeMax"])
150.0 C

How to get a raw thermal data

In [11]:
raw_data = meta.get("RawThermalImage")
In [12]:
print(raw_data)
(Binary data 240492 bytes, use -b option to extract)
In [13]:
import io
import os
import subprocess
from PIL import Image

thermal_img_bytes = subprocess.check_output(["exiftool", "-RawThermalImage", "-b", 'cviceni_5/FLIR0811.jpg'])
In [14]:
print(thermal_img_bytes)
9d\x03\xd2\x1c\xd3\xfb\x9c\x95\x8b\xcaVZb\x17\xc0\xb8E\x99,`\x021\xf3\x00\xa2\xe8.S=\xb6,\'\x92\x0b\x01\x8c\xd04\x98\x9als\x01g\[email protected]\xba\xe9\x87\x89\x01\xa5\xf8\xec\xa7p\xe0\x9d\\$\xef\x04x\xf0\xf2\x8e\xbc\x99\x97\x9b\xbb\x80\x92+\xe7z\xf8\xe7N`[\xe6\xd2\x9ac\x00\xb5\xca\x8b\xe2\xb9-J\xb2p\x14\x99\xca\x8a\x08\xcdp_\xed\x9ds\x07\xc5oL\xd1\x0f\xec1\xe5\xbf\xb9k\xc1\x8f\xec9l\x9f\xb6\xca\xf0\xa1\x9d\xa3\x93\x02\x1fM\x81\x94^\xc2Dc\xb8S\xa5 \x83\xef$\x0720\xec\xee\xea\xc3\xd4\xc9\x8do\xf4\x1cE\x99\xbe\xa2\xca\x05\x85"\xd4Q$\x1b\xee\x0b\xffA\x94\xeb\xe8\x83:\xcb\x93\x16%z)\xfc\xe8S\x88B\x03%6\n\xb2\xfe\x07X\xe7\xd8\x88\xebh\x0f\x8a\xb9\x1fy\xebE\x1eS\x1b\x9fiIr\x84(\xee\xdf4\xcb\xd1\x02\x8c\xf1\x0b&\xfa\x92\x0eWh\xa1~\xe7\x95\x02\xdb\xa0a^!\x99\x97\xd4i\x85{\xd9\x1f\xe6Iq\x9c\xcf4\xd6\xa4Y\xf2\xb5}\xa2\xeb\x9f\xea\xbeBe\x13a\xe3\xa1cE\x96\xaep\x06\xfd\xd5S!\x9b\\\xb5\xe35P\x85\x1f~`L\xdc\xb7Y\x1bbHy\xa4\x9d$\xde\xa1k\x1f\xe3\xd0nh\x0f\x13\xce\x85P\xd6#\xab\xb0\xa4\x1f\x1e\xdaZ\xddZ(\x1dB"\n\xd3\xc1&\xba\xcf\xed\xa2\x86\x84Gw\x82\xc3U\xe3\xab\x89\xbc\xd2\x15\x0c\x1fU\x1a\xef\x94B\xbdX\xacQC\xb1P\xe3E\xe3x\xc5\xbfq\xae#\xed\x93\x11\xf22\xda\x867u)\x1b\x19\xd3\x97\x90\x92&\xa4\xd0\xae3\xa4\x91` \xcb9\xf4\x84m\xcb\t\xf9u\x17GH\x9c\x06\xe9-{\xe3\x9b\x9f\x0bh\x02}\xc1\x98>T\x8a\xbe\x87\x075!\xdb\x99z\x85!s\x13\xc5\t;=\xb3\xbbu^\xb1\x8d0\xfcd\xd4R-%V\x0bq\x94\xe3A\x9d\x0c\\p`|+M\x96\x86\xdb\xc3C\x1cJ\xc1N\xca\xe6\xf8\x00\xe8X\xc6l\x1dQ\xf8\x03\xd6[\x93\xb8\xfaQ \xf7\x13\xc48|\xae\x04>\xb6\x8d\x04p\n\x0b\x12\x19\xb0P\xd9\xa8e\xbdB[\xa1\xd4(\xdc\x00o`\xab\x9d\x1e\xdc\x16\xa5\xc0\xb4\x93;\x17\x1c\x83\xb0 Lu\x01A+Z\xd1B\x18\xaa\x1f\xd7N.\x19\xe5\x98\x9c\x94\x95\x0b\xef\x05/f\x934\xb8\x06\x99MW\xac9\xfe\xd6\xc5\xb7\xad\xfe\xc2.\x81<u\xfa\xb1]-\xfc\xd8\x8e\xde\xbe\xac\xe7\xee\x0b\xd3\x06\xc6\xf1\xcc>\x95\x93\xc7\x02\xb9<`\xfa\xe5\xc1W\x8f\xbf\xcc9\x0e\x8e\xfc\\\x98\xcf\xf1H*\xd3\xfd\xce\xbb\xb5\x03\x90\xd6V\xdfX\x8f\x8d9\x9b\xef\xae(8\xb2\x80\xea\xa7\xcd\x08\xa0\x92\xdctA\xbb\x9c\x9eN}\xf2k\xaa\x98\xe3\xb0U\xd0\xcfR\x92\x86\x96~\x05\x01U\xac\xd4\x90&$O6\xc9\x918\x87\x17\xab\xe4,h\xa2\xc6\xc1\x1b\xd9{g\x8dC\x8fQ\xc6\x89\xa3\xc6t\xcc_\x08\xd2\x82\x03BRIX\xc2\xa2\xbd\x16\xd5\xbbD\xc0=a\xc3e\x02\xf6\xb6\x01\x97\xdb\xb8X\x87\x1b<\xaaA=\x0cD\xa0\xd1"\xdb[\xd3\xf6K_Z\x9a\xb2\x91G\x9b\x10\x8c3\\\xec2\xc8\xb8\xabt0Ao>\x03\x0b\x90\x06\x15\x05\x04|\xe8\x83g\x16\xa0M!\xc1l\xe7\x08\x13P\x89*\x89\xb5\xc7\x83\x00~\xf5\x9a}\x99\x0f\x8f \x07\x8c\xc5\xfb=\x0b\x7f\x90.`k\xef\x1d\xcf\xf0\xcc\x17\x96i\xb5\xce\x08,\x91Uwtg\x8d\x14\x16\xb2\x01\x1e\n\xbb\x10\x01\xf7\xb0C\xe6l x(\x11X\x89\xae\xb4\xc6\xa3\xc5!\x9al\x0b\x0b.\x947\x02\x9c\x17\xfd\xd7C\x98\xa2\t\xdeaD3M\xb7\xb3\xfao_.\x0e\xe3\xa8\x18b\x94\xd2"\x8d\xf9\xd1\x07o\xf9\xa5\x88\xe11W;\xb3;|\xad\xa5;\'\xc0)\xd1T\x7f(\xea\xe7\x8b"\xe6\'\xd7\'\xa5_C1\x02\xd7\'d\xcd\x19\x01\xd5~\xea\xd7\\\x9b\xa6|F7a\xc3>G\x97\x1f3\x8a\xe3\x00&\xe8\x01\x91\x01\x8f\xea\xab*\xe1p\x89\xcc\xad\x85\x8b\xe3\xed\xf3>X*H1\x01\xe3\xb6\xed\x91\x9a\x0f\xd5\x06\x08c\x04\x00fH\x01D\xbc\x95k\x89\xa5-\x881_\xaagT\x94\x0e\x07+g(\xb8\xabI\xae\xa0}\xd9<\x0cR\x80\x05DA[\xe8\x04g#e&\x94{\xd1\x01\xaa\xaaVzKr:`\x1a\xa0\xa0r\xea\xd7\xca\x93a^\xbf\x07"xT\xea\xcf\xec\xc8+\xb7\x1e\xe8\x8a\x1d\thM\xc5k\xea\xfd\xd1m\x8fA#\x9b8\xd2V\xa0\xc2\t\x183/g\xf7\x9288\x80\xf6\xf8t\xeb\x9a\xa9\xa6j\x04\x15\x7fQ0M\xa6[2\xe1\x8c\x1di\xc2\xa6\x06a\x11\x87\x12\x07\x9d\x14V\x8c\xa3\xc20\xc5b\xbd\x02\x9bv\x82\x12[\x04(th\xc7\x0f\xdd\xa0\xc2\x96\xfe\xda\x1e\xd4\xe4\x0cu|\x94\xc4\x02\xb3ZD;\xf6g{X\x82\x1aa\xf1h\xc9"\xec\x9a\x14\xf1\xbcn\xeb\xe5\xa5\xa7\x9f>k%`\xe1B-Ib\x9a\x82\x84\xa6pd\xc2\x89\xb0`)\x86\xfe\xf5\[email protected]\xc33L\xa7\x1d\xb2H\xe9]5N\x0b\xea)\x12A\x8d0\xe4,\xdd\x1c\x01\x19O\xb7\xaa"8\x80\xf2,\x14r\xd2%[5+)\xa84g\xb0\xbae\xcd\xbcE"\xc1\xae`KF\xa3\t\x05\xb8\xf3}\x7fC\xcc6\xb4/\xd0\xecQ\xef7\xcfw\x9c\xf7\x98\xcf\xfde\x9f\xf5\xde\xa7;\xcf\xf4\x89\xcf#p\x93\xef\xc5\xc9\x0c+\x02\x16\xee\xf2\xa3\xab\xdd\x16\x04\xb3\xfc\xad\x1a\x8e\xb6\xe8\\OA\x8d\xdd\x84\xa7\xf4\xae7$eSaQ;\xd6\xc2#\x0b\xb1\x9a\xa3\x8a\x1b\x92HJ\xa5\x8d(H\xbb\xe9\x9c\xc5\xa5~|y\xc7\x87\xc4\x95V5\xef\xdb\xfb0\xc7/\xc35?o4\xb8k\x96z\xf7\xe6\x8ea+\xa9\x93\xc7\xfe`8\xba\x7f\xbf\xee\xff\xc5W{=\xac\x07\xcf\xa21\xabD\x8c\xb4\xd0\xe0)\xb01\x8f\xbc.e2\x0c2\x12\xa0\x12Lp\xe9\xd1\x9c\xdc\xc0+h&\xaeu=0$\x1aAME\x05\x16\x95&\x08R\x80j\nhq\x91{\x11\x81\xc1\x8d\xd0\x19jfL\xfb\xc8\xcbT>w=L)o\xda\x96\x13k\t\xa4\\\x174SQ\xd9O\x0fc\x1c\xce\\\x99\xbc\xa1\xaf\x943\xa0O^\xf6\xf6\x1d\xe6\x06\x944\x038\xd5$8\xed\x13y\xf5=\x0c\x8e\x8f\xa6q\xda\xb8A\x1b\x84\xd4t\xe7=\x15\xfa\xa3\xdb\x07\xf8\xf1\xd3\xdb7Eyr\x13\xe1\xf3~M\xcch\xb2G\xe1\xd3\xe5\x1dk\xf5\xc4~\x04\xb7\xe7]?\x1e7~%)\x90$\xfb\x91y\xb9\xad\xcfU\x16\xdcJ\xf8\xab\xce\x02*`\xf7\xc0\xd5\xf4\x13$\xed\x80\xc7=\x8d\xb2\x0f\x0b\xb16\xda%\xb6\xa89\xd3U\xdd[k\xaf\xa0\xe9\xd7\x19R\xd6\xaf\xd0GK*\xb9\x83z\x19\xde\x18\xdc\x87\xdd\xc1\x98U\x05I\xa1\x95S\x0b"\xb4\x07\x8c\xd5W\x05\xa3j\xcfx\xc8]\xf0\x96D\xa1,\xb4\xe4\x9eFM\x0f\xa0\xcf\xd5\x8c\x13\x82k\xe1\xac_c\xc3\x10\x0epr\xdf5\xf4Y\xb8\x80G\xee\xac\x86\xf1\xe5\xf5x\xeaoI\xa0\x04\xadJ\xae\x15t\xd1#\x9c\x94\xd2\xa1\xf5\xb2\xab\xad\x87V|\xeb[\xa8\xf3\x17\xbf!\xb0\x10I\x1e\xe7IC\x93R`\xe1A\xc0\x84\'\x9a\xd1\xc6\x88t+\x08y-Ho\x95\xeb\xe6\xc2\x9f;Z\xfd\xb8\xc8c\xca\xd9\x8d\x84\xea/\x8b\x1dV\xf4\x85\xc1#\xec\xfb\xe4\xb9\x8dUc\xf8\xc6\xd5\xb5\xb0Y\xf8\x93$\n\xf7\xc7\x93\xf7\xf8\xb7\r&\x92\x02I\x85\xa4\xae\x01\xd0%m\x1e\xf2\xd0\x00.\xab\xae\x05:\xdf\xe7\xa2\xb5\xa8PY\x85\x0b\x89-+\xb0R\x1a\xd1\x8a\xc6p[\x1c\x08!\xf8\xd2\xda\x84\x96\x0f\xe1\xba*?\xf4\xee\xe3\x15o\xa8\xb0B>\xb1\xc7\xd2^\xbd\r\xee\xdd^\xc0WP9\x9d>\xbcO\xd7/B\xdf%\x10\xdazv-\x1e;\xfd\x0b\xb7\xc2aR#\xae\xc0\xad\x11S\xf9\x80t\xa1J\x85\xd2q\x8a\x95\x05\xc5n\xe2UK\x95\xbb\x85\x1dl\x03\xaf\xebAT\x86\n\xc8\x01\xaf~\xea\xa5W\[email protected]\xf1\xfdMD\xbb\x02g=\xc1\xa1\xc9\x99\xffF\xf6\xd7\xf9x4\xa9I\xa45\xde1<\t8 \x82\x13\xa3:\x8a\xa7\x14\x82\xe7j\x01*b\n\xd7\x8a8\xb4\xd5\x1fj\xe0\xfc\x14\x0f\n\x85p-\x93\x8d\xfcANH\xc1\xbf\xb6\x1c*\r\x15\x02LB\x83\x94\xd5\x99#HZ\xc5\xe4\xe2\x8fL\x02\xe1G\xab\xa7/\xaf\xdb3\xca\xde\xb1c\x1f\xdb\xd1w\x0e\\\x96\[email protected]\x9f\xe1\x19\xd0U\xbeGF]\x10\xb7\xfa\x82w\xd7\xaeZMe\xa5\xb4U !\xf9\xc1m\x9ad7 \xb35AK \x17vH\xa8\x8f\xcf\xd7\xbbA\xf6\x8e\xd3\xc9\xe7tF\xb2\x00Tp\xc1\x8d\xb6U\xb3Y\xd7d\x82\x86h9\x99\xa2\xa8\xcaKwt\x8d\x8a~Y\x8d5\xd5\xc0\xd6\xe9\xb4\x01g\xe1\xd5Y\xb2\xe1"\xd8\xd3 \xbdr\x0f\xbd\xe92\xf9\xd9\x80%\xb2o\xadH\xaeg\xae\x90N\x8e\xa0!\xbc8ki\xbewV\xfb\xac\x0b\x1a\x9f+8\x03[\x02\x80\r0\x87\xec\xc6\xadN1\x96\xa7\xe5\x14\xaa \x1e\xbe\xa4\xee\xea#HB\xd1j,\\I\xe3\xb9\xe8m[[\x82I\xb2uaQ\xbap\xb6\x95A\xad\xb3\xb4\xd1\xa1\xca\x11\x9ea\x0c\xbeCZ|V\xfd\xe0\x97\x14\xc2\x19\\\x98b\xd3\xda1^\xfa{~\xf3\x0b\x17\xc7\xb2\x1am-\x14\x8d\x13(\xf0D\xe8\x1b\x0b|\x92\xa50cE:4C(^\xbb\x94\xe0\xf9\x85n\x89\xbb}7\xf4YQ\xbf\xf5\x1c\x17\x1c\x93\x1b~LSm+\x812u\x17\xb9Z\x15\xe7\xdb\xaaM^Qjl\x19Bj\x89g\xba\xa2\x0b\xe1\xf3X\x1c\x08\xa5-B\xb0\xb7\xd9e>\x84[\xf8l\xdbQ>G;4\xa6\r\x94\x0b\xd5B<\xdc\xa9.=[i_J\xb0\xa7\xbeX\xd7gA\xa1\xdbX&\xf0\x93\xe2\xfc\xcc\x1e\x83%M?\xbd\xa3(-fq.\xac\xb9\x94\r8\x80\[email protected]\x961\xcb\xbbX\xf5\xbeR58[\xba\xc4L+\x17Z\x00\x16Ss`\xfd\xaa\x15\x99\x06\x93M\x9d\nn\x0c\xddb(\xf5\x88\xfa\xd1\xd4\xa6\x91\xe4#\xa0\x04\x98\xce\x16\xd6\x08_\x08\x12\x12\x8c\xa2\x153i\xcfi],g\n/b:\xc6|\xc1Z\x16#\xb5Q\xf44\xae\xbf\xb5\x0eF*\x96re\xe7I\x06H\xc6AO\x1f}\xfd\x1c\xfa\xe1R\xda\xe1\xae*\xd7\x97\x98[\xd9\xbbs\x13\xdbGw\xd7\xc7\x87/\xff\xfe\xbe\x1b\xf8#\x0b\xfe7NoX\xb03-\x05\x1f\xdc\x00\xbc*\x8f\xb4\x1f\x1b\r\xda\x04\x1d\x92\xb3\x82\x90-E1\x7f\xa1\xa8J\x07\'Z\xb42IR\xd7\xf1s$\xd2;\x9b\xa3\xb3\x9d\xd7y\xb7\x01\xdd\xb5\xe7\xa5\xd1]z\x05\xb9.\xe6$\x0f\x90\xc2AkR\xc6\xe6\x92\xe4 \xbd\xa0\x89V\xaeMb\xba\xc5\xa3\x1fc\xfa\xcb\x85][5A\x11\xce\xb4\xf1\xde9{\xff\xaaM\xca\xe9\xfa\xb4Ji\x8ac\xdcV\xf2\n\x0e\x9c\xdd/\xadW1\xe1\xe2\xb0X\x1cq\xc9#\xbc\xb1\x92\xd1I\xc1\x89\xb8,\xccq.\xef\xe8\x19%\x9c\x17\x869\x19\x8c\xe1\x8fV\xd9\xb1\xe5\x056\xc6\x8d{u\xd8\xdf\xbe\xce\xc7\xaf=I\xc6\x0e\x85\xc6B4\xad\xa0\x0cy\xecb\x042D\x83\x04\xf4\xadE\x1c\xc0=\'\xf4\x12\x04\x9d\x9b\xf3\xee\x96:m\x85\x984\xaa\x16u\xe9f\xc8\x9b\xe5H^\x08B\x1dNP\xb5\x91\xe4Xp)8\xf5\xbd\xd0\xb3\xe46~\xc0\x13Y\xdc\x7f\xa4\x9d\x12\x00\x174DW\xd3\xf7v\x07\x18m\xdfg2z<W\xea\xc9cI \xd4\xe4M\xfa\xb8`\xd9\xe3N\xbbT\xc6\x0b\xee_\xaa\xe6\x0b\xf8\x14\x03h\xa8\xb0OSFT\x12\x84V\xe8\xb1e\x06%\xf2\xdc\\8c1\xe7\x9d\x83{\xa92:\xf1\xa1T o\[email protected]\xbc\xf2\x82tv\xb0f\xbe\xfb}\xf7\x80\x83\xbbv\xb3\'\x8e\xef\x98<zt\xcd\x17f\x9f\xd9\x1d\xcf\xd2\x9a/ s\xc3\xae\xd1\x87\xa8#\xfb\x18\x16\x8c\x08\xcb\x1d5E\x08Cb-\xd6\x0c\x0f\x84]\x1c)\xfcQ\xe8\xbdk\x1bt\x98\x94\xc1\x19\x94\xc8\xde\x1bN\x1d\x94\xe1\x050\x13b\xec\x19\xc9\xb8\xd8\xcbq\x8cqP\x00\x1e\x8ex+\xe0P\xf0\xe1\xf2\xfa\xd6\x1a=\xbd\x81\x06\x17\xbe\x97\xbe\xc7=\x19\xbd|\x8a\xa6|\xc5\xe5\x9e\xbf\xe6\xc15\xdc\xcbQ\xc0\xebr\x02^\xbd\xd2\x82\xe3\x0c\xd9HBKm\x83\x1c\xcdE\xb50\x82\x06\x07n"XX\x16\xe4\xfd\x02\xf9#\x0b|\xf7\x9e~\xfa\xf2s\xd3\xca/O\x17\xad\x9b\x1a\x8f\x89\xd4\xa5\x8a\xfd.\x88\xa0\x8b#\xf2\n4\x9c\xf6\x99\xeb=#\xc0\[email protected]\xb4\xc1\xa16\x02\xa7\x05\x06t,\xeb\xfb\xafOU\xbd\tG\xdb\x8cHf\xea\xf4\xfc\x85E\xf1\xe5\x87\xbb\n\xeb \x0b\xa0V\x11{\x8f6\xcdj+\xa3:\x9b\x9b\xa3\xed\x9cv\xa8\xd2d\xd6\x80\x9a,]\xd2\x84\x05\xc7X\x06\xac!\x84\x93Hz\xce\xa1\xae\xe5a\x0b\xce\xe7\xbdq\x0e\xaaZpW\x9c\x1e\xf6t\xd6\x91f\x08\xa5M\xce\x19-cB6\xab\xb4Z\xad\xae\x86\xc1\xa3\x8f\xa9\xa3\xc9Z\x0f\xf7h\x15\xd0\n_H\xae\xb6\xb0\xea\x15\x82\xfcGS\x1a8\x82\'\xfe\xc9\x15\xca\xb5\xdb\xa7\xa9A\x8dsL\xf2\xc8\x0bC4\x97\x0cp\xaa\r$;S?\x92A\xc4c\xab [\x84\x10\xbc\x8d\xd4yA)k\xd3<9\xf8\x0c\xbd\x08\xa8\xc60\xf1m\x95.\x89\xf1KV\x8f\x06(\x1c\xa9\xe2i\x07JY\x04O\xc6\'\xc3\x8dM\xab\xd1\xefBW\x9aM\x12\xde\xc9b\xf6\x88$\x85\x11]Xb\x1d|5=\x16\xa2\xdd\[email protected]=-\x7f\xa0\xe7\x1d/&\xbf\xf6\xf0\x8b/\xf6e}\xd4\xda\xe5\xa7j\xc3\xb5\x17;\x98KH\x9dP\xdc\xbd\xbf\xb0\xa3?\x14\x90B\xd5\xc9sJ\x80\xb6\xeb\x99i\xd1\xe0\x9e$\xb0Z\xcf2\x1c\x1a\x0f_\\\xfb\x15o^\xb1E\xa8V\xca/+E\xde\xed\x81\xa8\x80\x05\xbc\x14\x90B\x0f\xd6\nPL(\x9ca\xb5\xda\x8e\x9a32\xd5\x80X\xa1N\xbfT\xc2\x81\nhX?\xea-\xc0F\x0b\x1dJ\x07=\xef\xb8QkAeM\xed\x8dJ\xc5D\xa30 s\xd4X\x9d\xc1\xb3s\xad0Q\rCS\x9f\x9a\xc3\x0bg\xe0B\xb6\xc2\x18\xf3\x9b\x98k\x9d\xa2\xb5\xe1\xd4\xce\x08\xd9\xa4t\xac5K\xc6\xd4\xaeM\x9b8\xf7\x8bZ\x1aI\xde\\\x1f\xb0\xe5\xe0[t\x0b\xd6Q\[email protected]\xcf\xed)\x80\xbe\x0c\xe976\xd2\x8d\xe5\xab\xa7\xb7\x17P\xb0\xc2-\xd0\x93\xef\xf6\x9d\x97\xef=D!\xae\x85P\\;\'m\xc4\x1fi\xcb\xe0\xb8\xf3\xe0\x08A\xdb\x88\x02\xe9+w\x0cTHo\\<\x01\x0e\x17xz\x0f\x8b<\xef+\xa3i\x92~\xf5\xc8YH{hU\x9e\xa4\x0fS\r\x95~S\xe9\xec\x93\x84dG\xdd\x0c\xc2\xf1\xd6\xac\xd2\r{B\x13\[email protected]\xd48\xb0er\x9e[K\x1e9.\xf4\xb1c\xd6\xcb%r\x83\xac\x99}\xb8\xde1)\xc7\xb3\x17\xfaFA\tO\xf1P%\xee\xbc\xb1\x0f\xdb\x18\xbf\xa9\x90\xab\xbf6YE\x83\xf6\xda\x01{l\xc659\xc2#\xdaV0\xb5\xa5W\xf2\xb5\xd5\xd7-\x88\xf9\r\xdb\x1eaH\x8b.YI7\xb8\xc3Y\xa9\x03\x06Y\x99~\xb9s\xf3,\xb8\x13>\x93S\x1d\xc4\xe3\xd8\xec\x90\x07\x0f8Q\tm\xfc\xadp\xc57-\x0b\x16P\xdb8U\x7f,v\xd8;\x0epHsMN\x0fn[&a\x17\x98%%\xffz\xc1\xae\xb8\xdd\xb5\x84g\xe3\xe2V\x88\xb1\x05\xed\x89\xf1\xd0\xd8\xb8s\xe7\x0c?\xc2m\xde\x02_\xe8\xa9\xc8L\x98qe\x06\xd0\x88\xee\xe3\xc0o#\xa2\x83\x1fg-P\x98\x8b\xa0JK&\xbd\x9e\xef\xc4.d\xa3)\t\xd9\x0c\xc7\xbc\xa1\x11\xf0m\xc2\xfc\xd0\xbc\x08\x05\x8f0.\x0c\x9a\x1fI\xecW\xb4m\x87\xa3\xd5>\x94\x9f==\xbao\xe9~q\xf5\xbb\'\x1c]6\xcb\xfa\xe0z.\x92\xb8\xa9\x98r\xad\x93h\x1cp\xcb\x94\x00\x07\x0c\x1c\xe7\x98GS0\x018\x95\\\x02\x16j\x0f\x06\xa0\x84B\x8e!+\xe1EayA\x15\xc8`M -~\x1b\xb5j\x89\xf8\x84\xa7\xf2\xe0^\x85\xc9\xc5\xc1\x8b\xcb_\x01p\xfd\x14\xa8)\xc0\xb9&\x0eZ\xf8D\xa5\xdc\n/(\x06\xad\x0c\nx\xb2\x14\xa7\xcd\xf9s\x9e}\xb8\xb6U\xf5\x1e\xc0\xd3\xbf\xecL\xe9M\xdaQ)\x94\x92\xed\xc8\x9e\xb8\xc3\x1b\x1a\xde\xf7\xdf_2\x1cP\x96\x85L\xb4\\\xe6\xf8\xe9\xd3\xf7\x9f>~\xf9\xba\xf33\x03\x95\xcb\x00\x1e\xf2\xdaR\xaf\xed\x02%\x87\x9e!S\x85I\xbf}\xc1\x8b\rB\xa84yU\xbb\xe1\xc4CL\x85\xce*\xb8\xea\x05\x1bg\xee\xbf\xda\x14\x10\n\x15\xf6\xc1\xcb\xd1\xa4W\x7f\x16\xc2I\xa5\x8d\x1f\x12\xb0IV`\tZ.\r9F\xe3\xb4\x07\xbe\xd5\x02;x}\xcf}\xb2USy\xf2\[email protected]\x90\x05\xe6qgr\xee1a\xce\xb3n\t\xb4:\xbdc\x90G\x0bl\x93F\xa3\xcb\xd9\xaa#\xb4\xc3mr\x08M\xb9\x9bc>\xc5[\\\xe3.\x1e\xe9\x80\xe3\x92\x96\xab\x84*!M5\xca\xda*T\xb2[%\xf6<c\xa9[\x15#\xf8\x94(\xba\xcb\xc1\xb3\x85\xa5\x16\xe3\xf2\x10n\x9aN\xc2\x13\xcax\x85%\xc8\xc0U\xf8(\x04\xf0\x94$\xd3\xabPs\r?\xfb\x84w<\xa7yc\x08gFc\xf3t\x9d\xff\x99\xe7\x84v\xf6\xd5?l\x1a\x89\xc7\xf2\x8c\xa3\x07z\xd2!\x8bf\x19A!\x9f}\xeee\xf4\x91pA\xe4Z5I{&\x9c\xa4\xbb\xfb:\xe57\xbd|b\xbf\xb8E\xa3I\xae>i\x9c\xadZrr\x13aA\x99\x15K\x1c\xf4\x87/\\\xb1\x1a=\xc7\xb3x\xc3\x03\xacp\xd2\n\xf9\x85:\xd5\xb05=\xbdX\x8c6\xd1-A<\xb1\xe5#\xad\xdd\xa3\xd2\xae\x12Vn\xd5\\0\xc7?\x8f\xb9mS~_\xfb\xf9\xe2f_\x8f\x8c\x1e\xf4\xafL\xad\x06\x00\x00\t\xd7IDAT\x1b\xc3\xf7\xf4\xb8\x04\xf9\xe1\xf5\xb9a{\xb1\xcc\xccX\xe0\xc8\x91\x08F$\xa2ZF<\xae\xacq\x99\x96\xb3)Y\xe8\xc3\x88\xc2U\xcd\xe2\xda\xa9\xe1\t\xc7\x1c\x89\xc3h\x16"\[email protected]\xc1\x1cB- \x1e\xee\x98"\xd5\x12\xd87*z\xad\xc3\x08\\\x01\xd6\xb4\xa4\x96xc\x0c\x10\x90\xc1M\x01\x05\xebjC\x99\x9b\xb2A\xd1\x08\xb8\x01\xa5\x024%\xe4\xc6\xe5\xc8\x1c\xed\x00\x0bP\xd2\x82\\.\xf0\xfb\xcc}3{\x10"\x03\x18\xdejKk>\x93Y\x7f\x9c\xf9\x112\[email protected]\x0e?\x7f\xf9\xbb\xa7w\x8d\x9f\x7f\xb1*\xf0\xa33\x8dI\xe5\xa3\x83\xd6G6\xbd\xb51\xf7\xe1\xfd\xa2L\xaagv\x96$O\xee\xd7\xff\xc7&\xf1G\xf7\xf7\x89\xab\xd9MH\x98\xbc\xab\xbc\xc6\x90\'\xbdp\xcf\n\x16\x82\x0b;\xe0Qp\x16JWs\xee\t\xd1x\xcf\xd6\xc9\x1f\xbf=\xee\x02\x15Z*\xe8\xf4)M\x93\x0cJ\xd8\xa8\x00G\xb7\x82\x1e\xca\xb4\x0e\xa2\x81\x9c\xe4\xb9\x91\xf1aD\x88\xb9w\xed\x84"|\xa2\xc4Jh\x1c\xceAz\xced$<\xaa\x8ba\xa9\x97\xf6\xd9\x00\xf7\xdad\xe5h$\xbbc\x9c/7\xc4\xa7\xd1PM3\xed\x02\xf4\x17\xaeT\xe6\xda\xfb\xb2OW.\xdb\x9d\xe0>\x1d\x0fVRss&\xf7:p\xa0\xb8U*\xb8o\x01\x1a\xf1\x88Ba\xc9\x7f8<P\xceGp\xe2X\x12W\x15A\x8a\x80d\xba]\x98\xc8\x8f\xf8\x12\xdb\xe1\xe8\xe0\x9c6I=J/\xef\xe0\xbc\xbe_?\xfc\x1b\xc9Y\xc7\xb4\xd3\x8fT<\x89\x84q\xe7\x0c\x0b\xa7\x89,\xef\x08\x0bt\xfd\xd7\'\xd7P\xb3\xa6\xbf\xde{\x94=\x19\xec/\xb0\xff7\xfd\x93\t:LK\xc9\xc5[T\xa9\xf4\xa5\x02s\x9e\x84\xf0O\xef$(\xba\x845\x9a\xb4\xa3\xa3T+\xb8\xd3+\xady\xdd3\xcd\xd3\x97\x9b\x12\x1d\r\x01\xc2u\xb1\xc5T\x9f\xe5\xc9\xad$\xb0\x97$\x1d\x92\xbe\x1b\xe2\xec\x9cX\xcd\xb7\x9d\x17\x0f\xefr\xa3]\x14\xb0\xc9\xbf\xde?\xba\x1f\xdb\x93\x99>8\xffxx\xbb2n\x00\x00q9PS\xdb\xaa#\xe4\x89\xa1\xca\xc8\xb9\xe5!\xca%\xa8\xe1M\xbaZ\xc6L\x01/\xcc9S\rc\x10\xaa(O\x04G2K+&\x14\x93\xb1v\xea\xe5\xb3T~P\xeeJ.\xd52\x11\x8e\x88\xec\x95\x9a\xb8\x8b\xac\x81k\xc0\xf2\xac\xafB"\xa5\x96q9OY\xa8\xb0$\xe0f\xf2\x00D>\x9f\xf5\xf7\xa3\x15\xb3\xd1\x07S\x08\xbc%\x81\xc0\xcb\xf8\xa8\xfb_\rR\x88`,\xbd\xd3\x82O\x9d\xd7\xae\x10\x1e\xffZ\xddw\xfe\xe8\x82\xdf\xe5\xf4\xff\xee\xba\x9d\xda\xe8\xb9e!\xc1\xcd\x14\x96\xac}\x8b\x16\'\xb2\x15\xc9\xba\x9d\x10\xa9p\xf7\xd0K\xb2\n5\xc0AJ\x15ckM\xf8/t\xe0BK\xbc\x83#\x8dj\x1d\xc4l[\xc2\xdd+v\xad\xcf\x7f\xf9V\xaa)\xb3\xa2\xae-j\x021\x8ei\xc2\x84\xce{ \xf2\xba%ar\x83W)\rW\x05-v\xd3\xce\x0b*\xb8\x80\xf0\x80b\xfa\x82\xa5*\xf4\xc3\x89q\x84\x82\x97\xbe\xb4\x8d#\xce\x03\x87(\x16J\xb2\x90\xf6x\xb5\x835\x17w\xc4\xcbX\xfah\x97\xdb\x86\x01a\x87\xcb\xb7P\x0f\xcb\x05\n\x81\x0c\xaf\xb6zX1t\x81J\xf2\x83bA\x90[\nUj\x08#Ye\xc6\xbdw=3\toy\x8757\xb6\xef\xc7hd\t=m\xd1%!w\x96\x10,v\xe0\x11U\x1e\xc1f4dj\xea\xafzx\xdc\xed;\x87\xf78\x83\x05(:\xc4\x17\xf4G\xd5\x11/\xfd\xf5v\x94\xed\xbdO\xf70\xdd\xfb\xb0j\xb4<\x1b\x1fP\xc5Z.\x13\xdd\xb3\xbd\x84\x8a\x08Z\xa1\x89\x83O\xbe\t\x13\xce8\x97L\xe9l\x8dv.M\xa3l4\x92\xf1\xf7;\x87\x0c\xfc\xa7Y\xc8\xc0\x1f\x1a\xf0u\xd7\xf4\xdcU\xdc5\xd8q\xfa\xc4\x05\x84\'\x85\xb4\xaa5\xdd\xba*\xa1^U\x0eX-\xf5^\x84\xf1xa\xf8\xabHx\xecZh<\xb1\xf0\xf6\xc2\x16\x9c\xee^\x9d\xe7[\x19?\xb2\xb6O\xef>\xfc\xf7\xed\xef\x076\x07\xfb\xd8\x02\xe1\xfb\xc6\xc1\x96\x99\x18\x9a\xf0B\x16\xc7*\x0c!W8\x000\xef\x0f8\x1f\xa0R\x80\xaa\xbd\x08\xc2\x85\x12`\xff\xc6\xcc\xbdW\x86\xebc\x92L\xa9\xd6\x12\n^-\\\x120g\xa0\xd6\x00\xdc\x8eA\xcb\xad\xad\xca\x04Z\xbc\x1cm\xc0IO\xa61Q\x11`\x04\xaa\x80"\x8b\x81\x8f\x17\x90\xa90)\xd4\xea\x845,G\xc8\x07*\xe0\x13<Pk\xaaB\x9e\xc0\xa1\xad M\xaa\x1cR5\xe5UU\xc4\xd18D\xa1M\x86L\xda\xc6\xb6\x0e\xc2\xd4M\x82\xdb6R.\xbc\xeb\xf4\x8b\xa7\x0f^\xbe\xe9\xf4\xf7\xce\xbft\xfa\xd2\xd1\xee*1\xc3\x0bS\xcc\xee\xfa1\x8bT\t\x08G\x00u\xffF\xc2\xb7\xba\xd4\x94AK\xb5{\xceR\x98\xcf\x91\xb8l-\x9b\xaa\xd1\\\x81G\xde4\xd25\xb0l\xbf\x9a\xa3\xfa\xd3\x04\xbe-k\xb0&\x07(4\xe1\x89>\xe8\xb7P dV\x83\x9b\xb4\x93\x10\x10\x05a\xf5\x80q\x0f\xab\xfa\x1f\xdd\xb0\xd4\xa4\xc9\xe4\x8c&\x84I\xba\xa5\'}\[email protected]\xc3O}\xd3\xca\x9a]\xb9\xc8f\xb5\xa5_\x0eFK\xbe\xb8S\xed\x9c5B\x19M8\xcf\xb9,a\xe0\x8a\xa5\xe0)\x9b\x90B\x8b0\xe0/\xeb\n<\x90\x95\x14U\x8a\xa4\x97\xeaC\xd6\xa3\xd3\xba5\xc1;6.\x0b\xdbx\xc1\x13,b\x90W \x11\xc2Q\[email protected]\xc3\x16\xbd\x91\xcaB\x90#\xb4)Q\x1d\xc1\xabqI\xe4\x82\x02\x17\xa7\xfb\x83?\x17(\xd0\n\xfb\x8e:G\x96<\xa7\xdeUR\xd6\x96%4KV8D3K\xb0)9\n.\x07\xd6k\xb96\xdb\x00\xf3\xe2\xb6\x90\xe0\x91\xbd\x8dA+n"D\x07\xa50(1\xd0FI\x95=\xd3X\xa5\x88\x80\xe5\x85?a\xc9\x96#\xba\xe1Q\x87\xd5*j\xc2\x8f\x11\xd0\xb0\xee\x877\xe9\xc7\x83\x84y\x83\x98$t\x9a\xcbX\xd9F\x81V\xb3/9<\x92\xa4\xedI\xecg[Y\xe9\x1e\xc6lqr\xf7\xd5C+2\xda\xf6\xf2\xe2\xee\xca\x7fl\xa5\x87/N\x7f\xd5(\xb2\xe4m2\r\x81A\xb2\x82\xbc\xecKm\x04&|*\xc3&\x95k\x8b1\xec`\xd3Ym\xb4\xc6\x9c\xf5>FJI]S\x8b\xe5#@\xd5\x0e\\\xa853\x038X:\'\xbfy\xbc\xb5q\xb4I\xe8\x9d\xb8R\xd5\x1ew\xea\x11A\xd8\xde&\xc1\x95;\x18?W!\x85+R\x8d\xa0=y\x00F\x0b\x94\x8e\x12\x1c\xef\xb7\x16\xcbIQ8\xab\n\n\xcc\x85\x0e\x9c\x18\x9b\xc4n\xdd\x91e\xc8M3\xd1\xf5\xc9Y\xbd\n\x19\x8c\x0f\xd0td\x05\xef\xcbNo\xbf>\x1b\x86I\xbaR\x8b\x17\x179\xd8\x81\xb6pwh\x88\xeb\xe1\xce\[email protected]\xdf{\xe5\xba\x1b\xfaiF\x1a\x10228\x87B\x8d\x16\x84\x054\xf1\x05\xb0\xc2\xaa\x9ck\x04\x13L\xfc\xd1\x88\xb1\xfc\xe0\xba\x04U=\xc0.t\xcaM\xcd\x12\xd2\x86V\xfa&\x93^\xf2<D\xe0%\x174\xba\nK\xbbP\x01#\x90\x04\x9c\xb89\xc61F\xdc\xd3k?q\x92\xc3\xa8\x15\xea!D6.\[email protected]\xa9\xc0\xe21\xea\x80oL\xb4\xfc\xe8\x93\x0e\xac\\\x0b\x1a\xe1E\xab\x10 \xd5\x93\x04}\xc9\xc6y\xb6\xd5\xbb\x17\xf7\x87)\xe8\xb2XC^\x0f\x04\xbdg\xce\x93}h\x96\x86\xb9e\xd2\xc1\xc0\x1d;?\x0e\xb7\x11\x03\x87q&\xfdf\x03vJ#\xce\xee\x1bn\xb6\xe5%\xc4\xb0\xfa~\x16\x82\xecU\xbb\xc7\x9e\xbc+\xd5\x1b\xdb\xb2t\xe7\x06\xa4_\x9eGc\x02{\x96\x8e\xe7k\xcf\x9dC\x836\xf9O\x81Qr\xc2;\xcd\x84Ha\xc2\xc8\xfah\x89\xf3\x97\x8b\x82%\xc4mP\xda\xe8\x90V4p\x04\x05\x85F\x98\xd4\x83\xbd\xfd\xe2\xb0\xe0\xc6\xce\xa4\xa4W#\xe8\xe7\x1dT6\x171\x16\xdd\xa6q\x7f\xe9\x13N\xe8F\xe0\xcb\xdb=\xb2\xcax\xb8\xa5\xf7<\x8e\x96\xf9\xb1\xa0\x8d{\x08\xc2\xd3\xd3\xbb\xd8W\xdd\xa8=\x8b\xf8\x0f\xb5$\xf8\xd8zA\xe6\x077\x8aD\xf3\xf1\xbd\xb7;\xf9c+\'\x1e\xd9\xf5_\xafy\x1c\xe7\[email protected]\xb8\x05\xa1(\x06\x11\x83\x83Iu\x94\xba\x84cP_\xc2:\x1e<)Q\xe4\xee\x1a#@Xl\x0en\x15\xb4\xa0\x84Q/\xefZ\xe1\xa9\n\xc8\x8d3"\x05\t\xa9F\xa2PN\x83\x9f\x03`\xfa\x1b+\xa8k\'\xf7\xcb\x0f\x9c\xdb\xea\x96\xb2\xdf\x08e c\xc6\xddQ\xd1\x04<p(\x17\xde2\x11\xc9\x98H\xff\xaa\x10\xdcd\xb8\x8c\x8a\x0f\x9f\x1d\xe7xLl\x7f\x18\xa5\xd3\x99\x173YS\xc5\x9bi<m\x90\xcdb\xc1\x8d\xe5\xa2w]\xbe\xe0\xfc\x19k\xf1\xab\xdb\x13\xf8G\xce\xf7]\xf9\xc6\xa5\xd4"\x93\x91\xb9\x877\xe9\xef\x17H\\6`\\ \xb1\x10\xef\x8b\x94L\x7f\x8d+\x1d\xd0,\x10q`\x12\x82\x1e\r\x80\x90\xb1q\x85\x8eU\xc2{\xaf\xdf\x8e\xea!\x98\xc1\xeb\xc8\xa6Y\x9e\x1c\xb9\xd2\x11rP\x10\x08\x8c\x93.i\x8a\xb4\xc6-1\xe0T\xbb\xc2\x84\x00E\x13\x8ey\[email protected]\x1f/\x7f{\x18A)\x14\xe2\xf0vh\x9e\xe5}N\x83-X\x14^\x8da\xf1\xc51\xad\xebs\x04\x02\x92\xc3\x05\x0e:\x7f\x8bKv\xc3[\xc9\x1b\xe8}n\x84\xe3X\x96%\xdf\xffW\xd3\x1d\xe3 \x0c\xc3P\x18\xce\xceM8=\xd7a\xe2\x00lH\x88\x81\x01\xfc\xe5W\x96Vj\x9c\xd8~v\x1c\xd7\xaeT\x94\x1d\x810\xed\xed\xa0J\xa6\xe2\x01z\xbcTh\xdb\x88t\xe4\x1f,\xa8\xc1c\xd4<\xd2x\x95\xab#l}~"K\xb6\x06.S\xbb\xda\xa0\xd0\xc6\x98\x0e\xac\xbc|\xa8\xa6{\x89\x12\x0e\xfb\xafm\x13\x04\xcb\xab\xc8g\xe7\xa1O\x07W(\x14\xf2\xcc`Wa=\x8c \xcc\x17\xe2-|\x9a\x0bM\xe3\xe9p\x10\xea3k!\xaf\xb0\xd8\x8e\xcd\xaa{\xc2\x96\x88~\xf9\xa6g4q\xe5\xe9x\x1dK\xd2QiG\\ \x13T\xe3\xc6J\xb4\x83\t^e\xb6\[email protected]\x8b\xaf\xf07\x99]\xbb\xb4& Y\x0b\x8c\xf8\xebZ\xf8\x18\xfd=\xc1\x0c\xad\x9e\xb4\xfbAF\xe1\xe4\xb9\xf9\\\xe6\xd8\x92\x9b>\xa6\xe2\xe7\xc8z\xad\xeb\xba\xcf\n\x9fu\x9b\xe7\xdf\xdf\x1f\x84\xfc\xd5\xbb\xa4\xb0\xd1q\x00\x00\x00\x00IEND\xaeB`\x82'
In [15]:
thermal_img_stream = io.BytesIO(thermal_img_bytes)
thermal_img_stream.seek(0)

thermal_img = Image.open(thermal_img_stream)
thermal_np = np.array(thermal_img)
In [16]:
plt.figure(1, figsize(10,10))
plt.imshow(thermal_np, cmap="gray")
print(type(thermal_np[0,0]), np.min(thermal_np), np.max(thermal_np))
<class 'numpy.int32'> 56 65339

How to transform RAW values into temperature

In [17]:
args = [
                "exiftool",
                "-Emissivity",
                "-SubjectDistance",
                "-AtmosphericTemperature",
                "-ReflectedApparentTemperature",
                "-IRWindowTemperature",
                "-IRWindowTransmission",
                "-RelativeHumidity",
                "-PlanckR1",
                "-PlanckB",
                "-PlanckF",
                "-PlanckO",
                "-PlanckR2",
                "-j",
                "-",
            ]
In [ ]:
def raw2temp(
        raw,
        E=1,
        OD=1,
        RTemp=20,
        ATemp=20,
        IRWTemp=20,
        IRT=1,
        RH=50,
        PR1=21106.77,
        PB=1501,
        PF=1,
        PO=-7340,
        PR2=0.012545258,
    ):
        """
        convert raw values from the flir sensor to temperatures in C
        # this calculation has been ported to python from
        # https://github.com/gtatters/Thermimage/blob/master/R/raw2temp.R
        # a detailed explanation of what is going on here can be found there
        """

        # constants
        ATA1 = 0.006569
        ATA2 = 0.01262
        ATB1 = -0.002276
        ATB2 = -0.00667
        ATX = 1.9

        # transmission through window (calibrated)
        emiss_wind = 1 - IRT
        refl_wind = 0

        # transmission through the air
        h2o = (RH / 100) * exp(
            1.5587
            + 0.06939 * (ATemp)
            - 0.00027816 * (ATemp) ** 2
            + 0.00000068455 * (ATemp) ** 3
        )
        tau1 = ATX * exp(-sqrt(OD / 2) * (ATA1 + ATB1 * sqrt(h2o))) + (1 - ATX) * exp(
            -sqrt(OD / 2) * (ATA2 + ATB2 * sqrt(h2o))
        )
        tau2 = ATX * exp(-sqrt(OD / 2) * (ATA1 + ATB1 * sqrt(h2o))) + (1 - ATX) * exp(
            -sqrt(OD / 2) * (ATA2 + ATB2 * sqrt(h2o))
        )

        # radiance from the environment
        raw_refl1 = PR1 / (PR2 * (exp(PB / (RTemp + 273.15)) - PF)) - PO
        raw_refl1_attn = (1 - E) / E * raw_refl1
        raw_atm1 = PR1 / (PR2 * (exp(PB / (ATemp + 273.15)) - PF)) - PO
        raw_atm1_attn = (1 - tau1) / E / tau1 * raw_atm1
        raw_wind = PR1 / (PR2 * (exp(PB / (IRWTemp + 273.15)) - PF)) - PO
        raw_wind_attn = emiss_wind / E / tau1 / IRT * raw_wind
        raw_refl2 = PR1 / (PR2 * (exp(PB / (RTemp + 273.15)) - PF)) - PO
        raw_refl2_attn = refl_wind / E / tau1 / IRT * raw_refl2
        raw_atm2 = PR1 / (PR2 * (exp(PB / (ATemp + 273.15)) - PF)) - PO
        raw_atm2_attn = (1 - tau2) / E / tau1 / IRT / tau2 * raw_atm2

        raw_obj = (
            raw / E / tau1 / IRT / tau2
            - raw_atm1_attn
            - raw_atm2_attn
            - raw_wind_attn
            - raw_refl1_attn
            - raw_refl2_attn
        )

        # temperature from radiance
        temp_celcius = PB / np.log(PR1 / (PR2 * (raw_obj + PO)) + PF) - 273.15
        return temp_celcius