DepthAI
  • DepthAI Components
    • AprilTags
    • Benchmark
    • Camera
    • Calibration
    • DetectionNetwork
    • Events
    • FeatureTracker
    • Gate
    • HostNodes
    • ImageAlign
    • ImageManip
    • IMU
    • Misc
    • Model Zoo
    • NeuralDepth
    • NeuralNetwork
    • ObjectTracker
    • RecordReplay
    • RGBD
    • Script
    • SpatialDetectionNetwork
    • SpatialLocationCalculator
    • StereoDepth
    • Sync
    • VideoEncoder
    • Visualizer
    • Warp
    • RVC2-specific
  • Advanced Tutorials
  • API Reference
  • Tools
Software Stack

ON THIS PAGE

  • Demo
  • Pipeline
  • Source code

Thermal Crosshair

Supported on:RVC2
The example uses DepthAI to process and display thermal camera data, showing a colorized temperature map and raw thermal image side-by-side, with a mouse-controlled crosshair displaying real-time temperature readings in degrees Celsius.This example requires the DepthAI v3 API, see installation instructions.

Demo

Thermal Camera Demo

Pipeline

Source code

Python

Python
GitHub
1import depthai as dai
2import cv2
3import numpy as np
4
5mouseX, mouseY = 0, 0
6
7
8def onMouse(event, x, y, *args):
9    global mouseX, mouseY
10    mouseX = x
11    mouseY = y
12
13
14# Thermal camera
15
16with dai.Pipeline(True) as pipeline:
17    thermal = pipeline.create(dai.node.Thermal)
18    # Output raw: FP16 temperature data (degrees Celsius)
19    qTemperature = thermal.temperature.createOutputQueue()
20    # Output color: YUV422i image data
21    qColor = thermal.color.createOutputQueue()
22    pipeline.start()
23    MAGMA_WINDOW_NAME = "Colorized Temperature"
24    IMAGE_WINDOW_NAME = "Thermal image"
25    # Scale 4x and position one next to another
26    cv2.namedWindow(MAGMA_WINDOW_NAME, cv2.WINDOW_NORMAL)
27    cv2.namedWindow(IMAGE_WINDOW_NAME, cv2.WINDOW_NORMAL)
28    initialRescaleAndPositionDone = False
29
30    while True:
31        inTemperature = qTemperature.get()
32        inColor = qColor.get()
33
34        thermalData = (
35            inTemperature.getData()
36            .view(dtype=np.float16)
37            .reshape((inTemperature.getHeight(), inTemperature.getWidth()))
38            .astype(np.float32)
39        )
40        normalizedThermalData = cv2.normalize(thermalData, None, 0, 1, cv2.NORM_MINMAX)
41        normalizedThermalData = (normalizedThermalData * 255).astype(np.uint8)
42        colormappedFrame = cv2.applyColorMap(normalizedThermalData, cv2.COLORMAP_MAGMA)
43        if not initialRescaleAndPositionDone:
44            cv2.moveWindow(MAGMA_WINDOW_NAME, 0, 0)
45            width, height = colormappedFrame.shape[1], colormappedFrame.shape[0]
46            cv2.resizeWindow(MAGMA_WINDOW_NAME, width * 4, height * 4)
47            cv2.moveWindow(IMAGE_WINDOW_NAME, width * 4, 0)
48            cv2.resizeWindow(IMAGE_WINDOW_NAME, width * 4, height * 4)
49            cv2.setMouseCallback(MAGMA_WINDOW_NAME, onMouse)
50            cv2.setMouseCallback(IMAGE_WINDOW_NAME, onMouse)
51            initialRescaleAndPositionDone = True
52        colormappedFrame = cv2.applyColorMap(colormappedFrame, cv2.COLORMAP_MAGMA)
53        if (
54            mouseX < 0
55            or mouseY < 0
56            or mouseX >= thermalData.shape[1]
57            or mouseY >= thermalData.shape[0]
58        ):
59            mouseX = max(0, min(mouseX, thermalData.shape[1] - 1))
60            mouseY = max(0, min(mouseY, thermalData.shape[0] - 1))
61        textColor = (255, 255, 255)
62        # Draw crosshair
63        cv2.line(
64            colormappedFrame,
65            (mouseX - 10, mouseY),
66            (mouseX + 10, mouseY),
67            textColor,
68            1,
69        )
70        cv2.line(
71            colormappedFrame,
72            (mouseX, mouseY - 10),
73            (mouseX, mouseY + 10),
74            textColor,
75            1,
76        )
77        # Draw deg C
78        text = f"{thermalData[mouseY, mouseX]:.2f} deg C"
79        putTextLeft = mouseX > colormappedFrame.shape[1] / 2
80        cv2.putText(
81            colormappedFrame,
82            text,
83            (mouseX - 100 if putTextLeft else mouseX + 10, mouseY - 10),
84            cv2.FONT_HERSHEY_SIMPLEX,
85            0.5,
86            textColor,
87            1,
88        )
89
90        cv2.imshow(MAGMA_WINDOW_NAME, colormappedFrame)
91        cv2.imshow(IMAGE_WINDOW_NAME, inColor.getCvFrame())
92
93        if cv2.waitKey(1) == ord("q"):
94            break

C++

1#include <iostream>
2#include <opencv2/opencv.hpp>
3
4#include "depthai/depthai.hpp"
5
6volatile int mouseX = 0, mouseY = 0;
7
8void onMouse(int event, int x, int y, int flags, void* userdata) {
9    mouseX = x;
10    mouseY = y;
11}
12
13int main() {
14    // Create pipeline
15    dai::Pipeline pipeline(true);
16
17    // Create nodes
18    auto thermal = pipeline.create<dai::node::Thermal>();
19    // Output raw: FP16 temperature data (degrees Celsius)
20    auto qTemperature = thermal->temperature.createOutputQueue();
21    // Output color: YUV422i image data
22    auto qColor = thermal->color.createOutputQueue();
23
24    // Start pipeline
25    pipeline.start();
26
27    const char* MAGMA_WINDOW_NAME = "Colorized Temperature";
28    const char* IMAGE_WINDOW_NAME = "Thermal image";
29
30    // Scale 4x and position one next to another
31    cv::namedWindow(MAGMA_WINDOW_NAME, cv::WINDOW_NORMAL);
32    cv::namedWindow(IMAGE_WINDOW_NAME, cv::WINDOW_NORMAL);
33    bool initialRescaleAndPositionDone = false;
34
35    while(true) {
36        auto inTemperature = qTemperature->get<dai::ImgFrame>();
37        auto inColor = qColor->get<dai::ImgFrame>();
38
39        // temperature data is float16: convert it to float32
40        cv::Mat thermalData(inTemperature->getHeight(), inTemperature->getWidth(), CV_32F);
41        inTemperature->getCvFrame().convertTo(thermalData, CV_32F);
42
43        // Normalize thermal data
44        cv::Mat normalizedThermalData;
45        cv::normalize(thermalData, normalizedThermalData, 0, 1, cv::NORM_MINMAX);
46        normalizedThermalData.convertTo(normalizedThermalData, CV_8U, 255.0);
47
48        // Apply color map
49        cv::Mat colormappedFrame;
50        cv::applyColorMap(normalizedThermalData, colormappedFrame, cv::COLORMAP_MAGMA);
51
52        if(!initialRescaleAndPositionDone) {
53            cv::moveWindow(MAGMA_WINDOW_NAME, 0, 0);
54            int width = colormappedFrame.cols;
55            int height = colormappedFrame.rows;
56            cv::resizeWindow(MAGMA_WINDOW_NAME, width * 4, height * 4);
57            cv::moveWindow(IMAGE_WINDOW_NAME, width * 4, 0);
58            cv::resizeWindow(IMAGE_WINDOW_NAME, width * 4, height * 4);
59            cv::setMouseCallback(MAGMA_WINDOW_NAME, onMouse);
60            cv::setMouseCallback(IMAGE_WINDOW_NAME, onMouse);
61            initialRescaleAndPositionDone = true;
62        }
63
64        // Clamp mouse coordinates
65        mouseX = std::max(0, std::min(static_cast<int>(mouseX), thermalData.cols - 1));
66        mouseY = std::max(0, std::min(static_cast<int>(mouseY), thermalData.rows - 1));
67
68        // Draw crosshair
69        cv::Scalar textColor(255, 255, 255);
70        cv::line(colormappedFrame, cv::Point(mouseX - 10, mouseY), cv::Point(mouseX + 10, mouseY), textColor, 1);
71        cv::line(colormappedFrame, cv::Point(mouseX, mouseY - 10), cv::Point(mouseX, mouseY + 10), textColor, 1);
72
73        // Draw temperature text
74        std::string text = std::to_string(thermalData.at<float>(mouseY, mouseX)) + " deg C";
75        bool putTextLeft = mouseX > colormappedFrame.cols / 2;
76        cv::putText(colormappedFrame, text, cv::Point(mouseX - (putTextLeft ? 100 : -10), mouseY - 10), cv::FONT_HERSHEY_SIMPLEX, 0.5, textColor, 1);
77
78        cv::imshow(MAGMA_WINDOW_NAME, colormappedFrame);
79        cv::imshow(IMAGE_WINDOW_NAME, inColor->getCvFrame());
80
81        if(cv::waitKey(1) == 'q') {
82            break;
83        }
84    }
85
86    return 0;
87}

Need assistance?

Head over to Discussion Forum for technical support or any other questions you might have.