DepthAI v2 has been superseded by DepthAI v3. You are viewing legacy documentation.
DepthAI Tutorials
DepthAI API References

ON THIS PAGE

  • Demo
  • Setup
  • Source code
  • Pipeline

Thermal Camera

This example demonstrates using a thermal camera to display raw temperature data with a color map and real-time RGB thermal video. It includes mouse interaction to show the temperature at the cursor, combining data processing, visualization, and user interaction for thermal imaging applications.

Demo

Thermal Camera Demo

Setup

Please run the install script to download all required dependencies. Please note that this script must be ran from git context, so you have to download the depthai-python repository first and then run the script
Command Line
1git clone https://github.com/luxonis/depthai-python.git
2cd depthai-python/examples
3python3 install_requirements.py
For additional information, please follow the installation guide.

Source code

Python

Python
GitHub
1#!/usr/bin/env python3
2
3import depthai as dai
4import cv2
5import numpy as np
6
7mouseX, mouseY = 0, 0
8
9
10def onMouse(event, x, y, *args):
11    global mouseX, mouseY
12    mouseX = x
13    mouseY = y
14
15
16device = dai.Device()
17pipeline = dai.Pipeline()
18
19# Thermal camera
20thermalCam = pipeline.create(dai.node.Camera)
21thermalCam.setFps(25) # Limit to 25 to match what the sensor can do, capped even if left at default, but warns.
22width, height = -1, -1
23thermalFound = False
24for features in device.getConnectedCameraFeatures():
25    if dai.CameraSensorType.THERMAL in features.supportedTypes:
26        thermalFound = True
27        thermalCam.setBoardSocket(features.socket)
28        width, height = features.width, features.height
29        break
30if not thermalFound:
31    raise RuntimeError("No thermal camera found!")
32thermalCam.setPreviewSize(width, height)
33
34# Output raw: FP16 temperature data (degrees Celsius)
35xoutRaw = pipeline.create(dai.node.XLinkOut)
36xoutRaw.setStreamName("thermal_raw")
37thermalCam.raw.link(xoutRaw.input)
38
39# Output preview,video, isp: RGB or NV12 or YUV420 thermal image.
40xoutImage = pipeline.create(dai.node.XLinkOut)
41xoutImage.setStreamName("image")
42thermalCam.preview.link(xoutImage.input)
43device.startPipeline(pipeline)
44
45qRaw = device.getOutputQueue("thermal_raw", 2, False)
46qImage = device.getOutputQueue("image", 2, False)
47
48
49RAW_WINDOW_NAME = "temperature"
50IMAGE_WINDOW_NAME = "image"
51# Scale 4x and position one next to another
52cv2.namedWindow(RAW_WINDOW_NAME, cv2.WINDOW_NORMAL)
53cv2.namedWindow(IMAGE_WINDOW_NAME, cv2.WINDOW_NORMAL)
54cv2.moveWindow(RAW_WINDOW_NAME, 0, 0)
55cv2.resizeWindow(RAW_WINDOW_NAME, width * 4, height * 4)
56cv2.moveWindow(IMAGE_WINDOW_NAME, width * 4, 0)
57cv2.resizeWindow(IMAGE_WINDOW_NAME, width * 4, height * 4)
58cv2.setMouseCallback(RAW_WINDOW_NAME, onMouse)
59cv2.setMouseCallback(IMAGE_WINDOW_NAME, onMouse)
60
61while True:
62    inRaw = qRaw.get()
63    inImg = qImage.get()
64
65    # Retrieve one point of fp16 data
66    frame = inRaw.getCvFrame().astype(np.float32)
67    colormappedFrame = cv2.normalize(frame, None, 0, 255, cv2.NORM_MINMAX, cv2.CV_8U)
68    colormappedFrame = cv2.applyColorMap(colormappedFrame, cv2.COLORMAP_MAGMA)
69    if (
70        mouseX < 0
71        or mouseY < 0
72        or mouseX >= frame.shape[1]
73        or mouseY >= frame.shape[0]
74    ):
75        mouseX = max(0, min(mouseX, frame.shape[1] - 1))
76        mouseY = max(0, min(mouseY, frame.shape[0] - 1))
77    textColor = (255, 255, 255)
78    # Draw crosshair
79    cv2.line(
80        colormappedFrame,
81        (mouseX - 10, mouseY),
82        (mouseX + 10, mouseY),
83        textColor,
84        1,
85    )
86    cv2.line(
87        colormappedFrame,
88        (mouseX, mouseY - 10),
89        (mouseX, mouseY + 10),
90        textColor,
91        1,
92    )
93    # Draw deg C
94    text = f"{frame[mouseY, mouseX]:.2f} deg C"
95    putTextLeft = mouseX > colormappedFrame.shape[1] / 2
96    cv2.putText(
97        colormappedFrame,
98        text,
99        (mouseX - 100 if putTextLeft else mouseX + 10, mouseY - 10),
100        cv2.FONT_HERSHEY_SIMPLEX,
101        0.5,
102        textColor,
103        1,
104    )
105    cv2.imshow(RAW_WINDOW_NAME, colormappedFrame)
106
107    cv2.imshow(IMAGE_WINDOW_NAME, inImg.getCvFrame())
108
109    if cv2.waitKey(1) == ord("q"):
110        break

C++

1/*
2    Thermal camera example.
3    Streams temperature and thermal image from thermal sensor and displays them.
4*/
5#include <algorithm>
6#include <cstdio>
7
8#include "depthai/depthai.hpp"
9
10volatile int mouseX, mouseY = 0;
11void mouseCallback(int event, int x, int y, int flags, void* userdata) {
12    mouseX = x;
13    mouseY = y;
14}
15
16const cv::Scalar WHITE(255, 255, 255);
17
18int main() {
19    dai::Device d;
20    dai::Pipeline pipeline;
21    auto thermal = pipeline.create<dai::node::Camera>();
22    // Find the sensor width, height.
23    int width, height;
24    bool thermal_found = false;
25    for(auto& features : d.getConnectedCameraFeatures()) {
26        if(std::find_if(features.supportedTypes.begin(),
27                        features.supportedTypes.end(),
28                        [](const dai::CameraSensorType& type) { return type == dai::CameraSensorType::THERMAL; })
29           != features.supportedTypes.end()) {
30            thermal->setBoardSocket(features.socket);  // Thermal will always be on CAM_E
31            width = features.width;
32            height = features.height;
33            thermal_found = true;
34        }
35    }
36    if(!thermal_found) {
37        throw std::runtime_error("Thermal camera not found!");
38    }
39    thermal->setPreviewSize(width, height);
40    auto xlink = pipeline.create<dai::node::XLinkOut>();
41    auto xlinkRaw = pipeline.create<dai::node::XLinkOut>();
42    // Output preview,video, isp: RGB or NV12 or YUV420 thermal image.
43    thermal->preview.link(xlink->input);
44    // Output raw: FP16 temperature data (degrees Celsius)
45    thermal->raw.link(xlinkRaw->input);
46
47    xlinkRaw->setStreamName("thermal_raw");
48    xlink->setStreamName("thermal");
49    d.startPipeline(pipeline);
50    auto q = d.getOutputQueue("thermal", 2, false);
51    auto qRaw = d.getOutputQueue("thermal_raw", 2, false);
52
53    const char* tempWindow = "temperature";
54    const char* imageWindow = "image";
55    cv::namedWindow(tempWindow, cv::WINDOW_NORMAL);
56    cv::setMouseCallback(tempWindow, mouseCallback);
57    cv::namedWindow(imageWindow, cv::WINDOW_NORMAL);
58    cv::setMouseCallback(imageWindow, mouseCallback);
59    // Scale 4x and position one next to another
60    cv::moveWindow(tempWindow, 0, 0);
61    cv::resizeWindow(tempWindow, width * 4, height * 4);
62    cv::moveWindow(imageWindow, width * 4, 0);
63    cv::resizeWindow(imageWindow, width * 4, height * 4);
64    while(true) {
65        auto temp = qRaw->tryGet<dai::ImgFrame>();
66        if(temp) {
67            auto frame = temp->getCvFrame();
68            // Retrieve one point of fp16 data
69            cv::Mat frameFp32(temp->getHeight(), temp->getWidth(), CV_32F);
70            frame.convertTo(frameFp32, CV_32F);
71            cv::Mat normalized;
72            cv::normalize(frameFp32, normalized, 0, 255, cv::NORM_MINMAX, CV_8UC1);
73            cv::Mat colormapped(temp->getHeight(), temp->getWidth(), CV_8UC3);
74            cv::applyColorMap(normalized, colormapped, cv::COLORMAP_MAGMA);
75            if(mouseX < 0 || mouseY < 0 || mouseX >= colormapped.cols || mouseY >= colormapped.rows) {
76                mouseX = std::max(0, std::min(static_cast<int>(mouseX), colormapped.cols - 1));
77                mouseY = std::max(0, std::min(static_cast<int>(mouseY), colormapped.rows - 1));
78            }
79            double min, max;
80            cv::minMaxLoc(frameFp32, &min, &max);
81            auto textColor = WHITE;
82            // Draw crosshair
83            cv::line(colormapped, cv::Point(mouseX - 10, mouseY), cv::Point(mouseX + 10, mouseY), textColor, 1);
84            cv::line(colormapped, cv::Point(mouseX, mouseY - 10), cv::Point(mouseX, mouseY + 10), textColor, 1);
85            // Draw deg C
86            char text[32];
87            snprintf(text, sizeof(text), "%.1f deg C", frameFp32.at<float>(mouseY, mouseX));
88            bool putTextLeft = mouseX > colormapped.cols / 2;
89            cv::putText(colormapped, text, cv::Point(putTextLeft ? mouseX - 100 : mouseX + 10, mouseY - 10), cv::FONT_HERSHEY_SIMPLEX, 0.5, textColor, 1);
90            cv::imshow(tempWindow, colormapped);
91        }
92        auto image = q->tryGet<dai::ImgFrame>();
93        if(image) {
94            cv::imshow(imageWindow, image->getCvFrame());
95        }
96        int key = cv::waitKey(1);
97        if(key == 'q') {
98            break;
99        }
100    }
101
102    return 0;
103}

Pipeline

Need assistance?

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