Last active
May 15, 2024 04:33
-
-
Save casebeer/e8ad739edaf11f9ab276b8c5504f7d84 to your computer and use it in GitHub Desktop.
Script to read data from Tooltop T7 a.k.a. Infiray P2 Pro thermal camera using ffmpeg
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# https://www.eevblog.com/forum/thermal-imaging/infiray-and-their-p2-pro-discussion/200/ | |
# https://superuser.com/questions/1009969/how-to-extract-a-frame-out-of-a-video-using-ffmpeg | |
# https://stackoverflow.com/questions/37960828/webcam-streaming-from-mac-using-ffmpeg | |
# | |
# Selected pixel format (yuv420p) is not supported by the input device. | |
#[avfoundation @ 0x7f961cd08b40] Supported pixel formats: | |
#[avfoundation @ 0x7f961cd08b40] uyvy422 | |
#[avfoundation @ 0x7f961cd08b40] yuyv422 | |
#[avfoundation @ 0x7f961cd08b40] nv12 | |
#[avfoundation @ 0x7f961cd08b40] 0rgb | |
#[avfoundation @ 0x7f961cd08b40] bgr0 | |
#-pixel_format 0rgb \ | |
#-pixel_format yuyv422 \ | |
singleframe='-vf \"select=eq(n\\,34)\" -vframes 1' | |
captureMac() { | |
deviceNo="${1:-1}" | |
ffmpeg \ | |
-pixel_format yuyv422 \ | |
-video_size 256x384 \ | |
-f avfoundation -framerate 25 -i "${deviceNo}" \ | |
-vf 'crop=h=(ih/2):y=(ih/2)' \ | |
-pix_fmt yuyv422 \ | |
-f rawvideo - | |
} | |
captureOne() { | |
deviceNo="${1:-1}" | |
outFile="${2:-out.png}" | |
frameNo="${3:-34}" | |
ffmpeg \ | |
-pixel_format yuyv422 -video_size 256x384 \ | |
-f avfoundation -framerate 25 \ | |
-y \ | |
-i "${deviceNo}" \ | |
-vf 'crop=h=(ih/2):y=(ih/2)' \ | |
-pix_fmt yuyv422 \ | |
-vf "select=eq(n\,${frameNo})" -frames:v 1 \ | |
-update 1 \ | |
"${outFile}" | |
} | |
infernoAnnotate() { | |
echo "signalstats, split [main][secondary]; " | |
echo '[main] normalize=smoothing=10, ' | |
echo 'format=pix_fmts=rgb48, ' | |
echo 'pseudocolor=p=inferno, ' | |
echo 'scale=w=2*iw:h=2*ih, ' | |
echo -n 'drawtext=x=3:y=3:borderw=1:bordercolor=white:fontfile=FreeSerif.ttf:text=' | |
echo -n 'MIN\\: %{metadata\\:lavfi.signalstats.YMIN} MAX\\: %{metadata\\:lavfi.signalstats.YMAX} ' | |
echo '[thermal]; ' | |
echo -n '[secondary] drawgraph=' | |
echo -n 'm1=lavfi.signalstats.YMIN:fg1=0xFFFF9040:' | |
echo -n 'm2=lavfi.signalstats.YMAX:fg2=0xFF0000FF:' | |
echo -n 'bg=0x303030:' | |
echo -n 'min=18500:max=24500:' | |
echo -n 'slide=scroll:size=512x64 ' | |
echo '[graph]; ' | |
echo '[thermal][graph] vstack=2 ' | |
} | |
inferno() { | |
# presets | |
# cividis, magma, inferno, highlights, shadows, viridis, plasma | |
echo ' pseudocolor=p=inferno ' | |
} | |
normalize() { | |
echo ' normalize=smoothing=10, format=pix_fmts=rgb48 ' | |
} | |
timestampFilter() { | |
echo -n ' drawtext=fontfile=/assets/static/Inconsolata-Bold.ttf:' | |
echo -n 'shadowx=1:shadowy=1:fontsize=18:fontcolor=white:' | |
echo -n 'x=w-tw-10:y=10:line_spacing=4:' | |
echo 'text=%{localtime\\:%a %Y-%b-%d %T} ' | |
} | |
# WIP | |
tileManual() { | |
i=0 | |
count=0 | |
row=0 | |
while [ "$i" -lt "${#luts[@]}" ]; do | |
echo -n "[${luts[$i]}Out]" | |
let i++ | |
let count++ | |
if [ "$count" -eq 4 ]; then | |
echo " hstack=${count} [row${row}] , " | |
let row++ | |
count=0 | |
fi | |
done | |
if [ "$count" -gt 0 ]; then | |
# TODO; | |
echo " hstack=${count}, pad=w=${count} [row${row}] , " | |
# since we have non-full row, we'll have to pad this out to a full row | |
# width to avoid breaking vstack | |
let row++ | |
count=0 | |
fi | |
i=0 | |
while [ "$i" -lt "$row" ]; do | |
echo -n "[row${i}]" | |
let i++ | |
done | |
echo " vstack=${row} " | |
} | |
pseudocolors() { | |
luts=(magma inferno plasma viridis turbo cividis range1 range2 \ | |
shadows highlights solar nominal preferred total spectral ) | |
unsupportedLuts=(cool heat fiery blues green helix) | |
echo -n "split=${#luts[@]} " | |
for lut in "${luts[@]}" ; do | |
echo -n "[${lut}In]" | |
done | |
echo "," | |
for lut in "${luts[@]}" ; do | |
echo -n "[${lut}In]" | |
echo -n " pseudocolor=p=${lut}, " | |
echo -n "drawtext=x=3:y=3:fontcolor=white:fontsize=18:fontfile=FreeSerif.ttf:text=${lut} " | |
echo "[${lut}Out], " | |
done | |
#tileManual "${luts[@]/%/Out}" | |
#column "${luts[@]/%/Out}" | |
grid "${luts[@]/%/Out}" | |
} | |
grid() { | |
#for lut in "$@" ; do | |
# echo -n "[${lut}Out]" | |
#done | |
# https://stackoverflow.com/questions/20366609/prefix-and-postfix-elements-of-a-bash-array | |
inputs=("${@/#/[}") | |
inputs=("${inputs[@]/%/]}") | |
# tile into grid using xstack | |
#echo " xstack=inputs=${#@}:grid=4x4 " | |
echo -n "${inputs[@]} xstack=inputs=${#inputs[@]}:fill=white:layout=" | |
# xstack 4x4 grid layout, cols then rows | |
#echo -n "0_0|0_h0|0_h0+h1|0_h0+h1+h2|" | |
#echo -n "w0_0|w0_h0|w0_h0+h1|w0_h0+h1+h2|" | |
#echo -n "w0+w4_0|w0+w4_h0|w0+w4_h0+h1|w0+w4_h0+h1+h2|" | |
#echo -n "w0+w4+w8_0|w0+w4+w8_h0|w0+w4+w8_h0+h1|w0+w4+w8_h0+h1+h2 " | |
# xstack 4x4 grid layout, rows then cols | |
echo -n "0_0|w0_0|w0+w1_0|w0+w1+w2_0|" | |
echo -n "0_h0|w0_h0|w0+w1_h0|w0+w1+w2_h0|" | |
echo -n "0_h0+h4|w0_h0+h4|w0+w1_h0+h4|w0+w1+w2_h0+h4|" | |
echo -n "0_h0+h4+h8|w0_h0+h4+h8|w0+w1_h0+h4+h8|w0+w1+w2_h0+h4+h8 " | |
echo | |
} | |
column() { | |
# tile into single tall column | |
inputs=("${@/#/[}") | |
inputs=("${inputs[@]/%/]}") | |
echo "${inputs[@]} vstack=${#inputs[@]} " | |
} | |
processRawData() { | |
ffmpeg \ | |
-pixel_format gray16le -video_size 256x192 \ | |
-y \ | |
-f rawvideo -i - \ | |
-vf " $(normalize) , $(pseudocolors) " \ | |
-f mpegts - | |
} | |
saveframe() { | |
outFile="${1:-out.png}" | |
frameNo="${2:-34}" | |
#-pixel_format gray16le -video_size 256x192 \ | |
#-f rawvideo -i - \ | |
#-vf " $(normalize) , $(pseudocolors), select=eq(n\,${frameNo}) , " \ | |
# | |
ffmpeg \ | |
-y \ | |
-f mpegts -i - \ | |
-vf " select=eq(n\,${frameNo}) , " \ | |
-frames:v 1 -update 1 \ | |
"${outFile}" | |
} | |
rtspSend() { | |
target="${1}" | |
ffmpeg \ | |
-fflags nobuffer -flags low_delay \ | |
-probesize 5M -analyzeduration 2M \ | |
-re \ | |
-f mpegts -i - \ | |
-c:v libx264 -crf 28 -profile:v baseline \ | |
-preset ultrafast \ | |
-x264-params "bframes=0:force-cfr=1:no-mbtree=1:rc-lookahead=0:sync-lookahead=0:keyint=10:min-keyint=5" \ | |
-copyts -an -max_muxing_queue_size 1024 \ | |
-muxpreload 0 -muxdelay 0 \ | |
-f rtsp "$target" | |
} | |
pseudocolors | |
if [ -z "$1" ]; then | |
captureMac | processRawData | saveframe && open out.png | |
else | |
captureMac | processRawData | rtspSend "$1" | |
fi | |
#pseudocolors | |
#saveframe | |
#captureOne && open out.png | |
#capture | ffmpeg -pixel_format yuyv422 -video_size 256x192 -f rawvideo -y -i - -vf "select=eq(n\,34)" -frames:v 1 -update 1 out.png && open out.png | |
#out.png | |
# -i /dev/video4 | |
# -f rawvideo |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment