Skip to content

Improve thermal camera library with community fixes#2

Open
tdamsma wants to merge 34 commits into
masterfrom
improve-thermal-library
Open

Improve thermal camera library with community fixes#2
tdamsma wants to merge 34 commits into
masterfrom
improve-thermal-library

Conversation

@tdamsma
Copy link
Copy Markdown

@tdamsma tdamsma commented Mar 24, 2026

Summary

Incorporates improvements from the ht301_hacklib community ecosystem into the CEAD fork.

Hot pixel detection + persistent calibration (irpythermal.py)

  • calibrate_raw() now detects both cold AND hot stuck pixels using a symmetric 5% threshold. Previously only cold/dead pixels were detected, leaving hot/stuck pixels uncorrected.
  • New save_calibration(path) / load_calibration(path) methods to persist reference frame and dead pixel mask as .npy files, surviving restarts without re-running shutter calibration.
  • Fix resource leak: find_device() now releases cameras that don't match supported resolutions
  • Replace bare except: with except Exception:

OpenCV int cast fix (utils.py)

  • Cast coordinates to int() in drawTemperature() — OpenCV rejects float coordinates from numpy
    • Source: uncommitted fix found on remote machine (/home/daniel/git/t2s/)

Remove skimage dependency (opencv.py)

  • Replace skimage.exposure.equalize_hist + rescale_intensity with cv2.normalize + cv2.equalizeHist
  • Same visual result, eliminates scikit-image (and its transitive deps) for simpler deployment

Build system (pyproject.toml)

  • Migrate from poetry to uv/PEP 621 format
  • Add missing runtime dependencies

References

Test plan

  • Deploy to Linux machine with T2S+ camera (ssh thijsd@172.16.88.136)
  • Run opencv.py — verify live view with temperature overlay
  • Verify hot pixel detection during calibrate_raw()
  • Test save_calibration / load_calibration round-trip
  • Confirm temperature readings are sane (compare with known reference)

diminDDL and others added 30 commits May 29, 2024 13:53
Added all changes to main
error was
```
cv2.error: OpenCV(4.10.0) 👎 error: (-5:Bad argument) in function 'inRange'
> Overload resolution failed:
> - upperb is not a numpy array, neither a scalar
> - Expected Ptr<cv::UMat> for argument 'upperb'
```
…ix ruff findings

Introduces an "AppState" as an intermediate solution for global variables. This makes
access to global stuff more visible, but should vanish step by step (by
more explicit dependency injection and data modelling)
Make project capable of running inside a virtual environment and format sources
irpythermal.py changes:
- calibrate_raw() now detects both cold AND hot stuck pixels using
  symmetric 5% threshold (previously only detected cold pixels)
  Source: diminDDL/IR-Py-Thermal PR stawel#4
  diminDDL#4

- Add save_calibration() and load_calibration() methods to persist
  reference frame and dead pixel mask as .npy files across restarts
  Source: MCMH2000/OpenHD_HT301_Driver noise_pattern_calibration.npy approach
  https://github.com/MCMH2000/OpenHD_HT301_Driver

- Fix resource leak in find_device(): release cameras that don't match
  supported resolutions instead of leaving them open

- Replace bare except with except Exception
Cast x, y, tx, ty coordinates to int() before passing to cv2.line()
and cv2.putText(). OpenCV requires integer coordinates and fails with
float values from numpy operations.

Source: uncommitted fix found on remote machine /home/daniel/git/t2s/
Replace skimage.exposure.equalize_hist + rescale_intensity with
cv2.normalize + cv2.equalizeHist. Same visual result, eliminates
the scikit-image dependency (and its transitive deps) making
deployment on headless Linux machines simpler.
Convert build system from poetry-core to uv/PEP 621 project format.
Add missing runtime dependencies (av, opencv-python, pyusb, imageio).
Documents where this fork sits in the ht301_hacklib ecosystem,
lists all known forks and their contributions, supported cameras,
temperature calculation details, known calibration issues, and
links to external references (papers, blog posts, teardowns).
tdamsma added 4 commits March 24, 2026 11:24
np.kron upscaling took 32ms/frame (56% of total). cv2.resize with
INTER_NEAREST gives identical pixel-doubled output but is hardware
accelerated. Profiled on T2S+ 256x192 with 4x upscale:
- Before: 17.6 FPS (np.kron 32ms + CLAHE 20ms)
- After: ~25 FPS (cv2.resize <1ms)
calibrate_raw() with dead/hot pixel detection only applies to
camera_raw=True mode (T2S+ v2 where FPGA doesn't process frames).
For v1 units and HT-301, the firmware handles NUC and dead pixel
correction in hardware -- only the shutter command (0x8000) is needed.
Reads from the thermal camera, applies normalize + equalize + colormap
+ CLAHE, and pipes BGR24 frames to /dev/video10 via ffmpeg.

Replaces the duplicate scripts found at:
- /home/daniel/git/t2s/frame_pusher.py (uncommitted)
- /home/daniel/git/pcm/pcm/apps/pcm-capture/app/t2s_virtual.py

Improvements over originals:
- Uses irpythermal instead of ht301_hacklib
- CLI args for device path, orientation, fps
- Proper error handling and cleanup
- Removes unused code (idle_frame, draw_temp, coordinate rotation)
Uses fuser to detect readers on the loopback device every 2s.
Camera stays open and frames are read continuously to keep USB
active, but processing and ffmpeg piping only run when needed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants