Skip to content

Instantly share code, notes, and snippets.

@casebeer
Last active May 15, 2024 04:33
Show Gist options
  • Save casebeer/e8ad739edaf11f9ab276b8c5504f7d84 to your computer and use it in GitHub Desktop.
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
#!/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