К содержимому
  1. Главная
  2. Документация
  3. Камеры для Raspberry Pi
  4. Arducam ToF Camera SDK для Raspberry Pi

Arducam ToF Camera SDK для Raspberry Pi

Документация Arducam · перевод arducam-russia.ru

SDK для разработчиков ToF-камеры Arducam

Что такое SDK

SDK (комплект средств разработки) — набор инструментов для разработки ПО в одном устанавливаемом пакете. В него входят компилятор, отладчик, а иногда и программный фреймворк — всё это упрощает создание приложений. Обычно SDK привязан к конкретному сочетанию аппаратной платформы и операционной системы.

Программный стек ToF-камеры Arducam

Arducam ToF SDK — динамическая библиотека на C++. В ней три класса: Camera, Frame и Sensor. Camera управляет захватом и обработкой изображения с камеры, Frame — памятью, в которой хранятся данные камеры, а Sensor — это конкретная реализация обращения к камере. Он вызывается как объект-член класса Camera, и обычно пользователь с ним напрямую не работает.

Структура программного стека ToF-камеры Arducam

Работа с SDK ToF-камеры Arducam

Установка SDK

SDK устанавливается вместе с драйвером камеры и нужными зависимостями, когда вы выполните шаги ниже. Это те же команды, что в шагах 1–3 основной инструкции по установке.

Шаг 1. Скачайте репозиторий

git clone https://github.com/ArduCAM/Arducam_tof_camera.git

Шаг 2. Перейдите в каталог Arducam_tof_camera

cd Arducam_tof_camera

Шаг 3. Установите драйвер, зависимости, SDK и OpenCV

./Install_dependencies.sh

Когда появится запрос на перезагрузку, введите y. Raspberry Pi перезагрузится автоматически.

Запуск примеров

Примеры на C

Порядок работы с SDK

  1. Создайте экземпляр камеры.
  2. Запустите камеру.
  3. Запросите кадр.
  4. Получите данные кадра.
  5. Освободите память кадра.
  6. Остановите камеру.

Пример

#include "ArduCamDepthCamera.h"
#include <stdlib.h>
#include <stdio.h>

void getPreview(uint8_t *preview_ptr, float *phase_image_ptr, float *amplitude_image_ptr)
{
    unsigned long int len = 240 * 180;
    for (unsigned long int i = 0; i < len; i++)
    {
        uint8_t amplitude = *(amplitude_image_ptr + i) > 30 ? 254 : 0;
        float phase = ((1 - (*(phase_image_ptr + i) / 2)) * 255);
        uint8_t depth = phase > 255 ? 255 : phase;
        *(preview_ptr + i) = depth & amplitude;
    }
}

int main()
{
    ArducamDepthCamera tof = createArducamDepthCamera();
    FrameBuffer frame;
    if (init(tof,CSI,DEPTH_TYPE,0))
        exit(-1);
    if (start(tof))
        exit(-1);
    uint8_t *preview_ptr = malloc(180*240*sizeof(uint8_t)) ;
    float* depth_ptr = 0;
    int16_t *raw_ptr = 0;
    float *amplitude_ptr = 0;
    FrameFormat format;
    if ((frame = requestFrame(tof,200)) != 0x00){
        format = getFormat(frame,DEPTH_FRAME);
    }
    for (;;)
    {
        if ((frame = requestFrame(tof,200)) != 0x00)
        {
            depth_ptr = (float*)getDepthData(frame);
            printf("Center distance:%.2f.\n",depth_ptr[21600]);
            amplitude_ptr = (float*)getAmplitudeData(frame);
            getPreview(preview_ptr,depth_ptr,amplitude_ptr);
            releaseFrame(tof,frame);  
        }
    }

    if (stop(tof))
        exit(-1);
    return 0;
}

Содержимое CMakeList.txt

cmake_minimum_required(VERSION 3.4)
SET(CMAKE_BUILD_TYPE "Debug")
SET(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -O0 -Wall -g2 -ggdb")  
project(example_tof)
include_directories(BEFORE /usr/include/c  /usr/include/cpp)
add_executable( example_tof your_filename.c )
target_link_libraries( example_tof ArducamDepthCamera_c pthread)

Сборка и запуск

mkdir build && cd build
cmake ..
make

Результат

Результат работы примера на C: расстояние до центра кадра

Примеры на C++

Порядок работы с SDK

  1. Создайте экземпляр камеры.
  2. Инициализируйте экземпляр камеры.
  3. Запустите камеру.
  4. Запросите кадр.
  5. Получите данные кадра.
  6. Освободите память кадра.
  7. Остановите камеру.

Пример

#include "ArduCamTOFCamera.hpp"
#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>
#include <chrono>
#include <iostream>

// MAX_DISTANCE value modifiable  is 2 or 4
#define MAX_DISTANCE 4

void display_fps(void)
{
    static int count = 0;
    ++count;
    static std::chrono::high_resolution_clock::time_point time_beg = std::chrono::high_resolution_clock::now();
    std::chrono::high_resolution_clock::time_point time_end = std::chrono::high_resolution_clock::now();
    std::chrono::duration<double, std::ratio<1, 1>> duration_s = time_end - time_beg;
    if (duration_s.count() >= 1)
    {
        std::cout << "fps:" << count << std::endl;
        count = 0;
        time_beg = time_end;
    }
}

void getPreview(uint8_t *preview_ptr, float *phase_image_ptr, float *amplitude_image_ptr)
{
    auto len = 240 * 180;
    for (auto i = 0; i < len; i++)
    {
        uint8_t mask = *(amplitude_image_ptr + i) > 30 ? 254 : 0;
        float depth = ((1 - (*(phase_image_ptr + i) / MAX_DISTANCE)) * 255);
        uint8_t pixel = depth > 255 ? 255 : depth;
        *(preview_ptr + i) = pixel & mask;
    }
}
cv::Rect seletRect(0, 0, 0, 0);
cv::Rect followRect(0, 0, 0, 0);
void onMouse(int event, int x, int y, int flags, void *param)
{
    if (x < 4 || x > 251 || y < 4 || y > 251)
        return;
    switch (event)
    {
    case cv::EVENT_LBUTTONDOWN:

        break;

    case cv::EVENT_LBUTTONUP:
        seletRect.x = x - 4 ? x - 4 : 0;
        seletRect.y = y - 4 ? y - 4 : 0;
        seletRect.width = 8;
        seletRect.height = 8;
        break;
    default:
        followRect.x = x - 4 ? x - 4 : 0;
        followRect.y = y - 4 ? y - 4 : 0;
        followRect.width = 8;
        followRect.height = 8;
        break;
    }
}

int main()
{
    ArduCam::ArduCamTOFCamera tof;
    ArduCam::FrameBuffer *frame;
    if (tof.init(ArduCam::CSI,ArduCam::DEPTH_TYPE)){
        std::cerr<<"initialization failed"<<std::endl;
        exit(-1);
    }

    if (tof.start()){
        std::cerr<<"Failed to start camera"<<std::endl;
        exit(-1);
    }
    //  Modify the range also to modify the MAX_DISTANCE
    tof.setControl(ArduCam::RANGE,MAX_DISTANCE);
    ArduCam::CameraInfo tofFormat = tof.getCameraInfo();

    float *depth_ptr;
    float *amplitude_ptr;
    uint8_t *preview_ptr = new uint8_t[tofFormat.height * tofFormat.width];
    cv::namedWindow("preview", cv::WINDOW_AUTOSIZE);
    cv::setMouseCallback("preview", onMouse);

    for (;;)
    {
        frame = tof.requestFrame(200);
        if (frame != nullptr)
        {
            depth_ptr = (float *)frame->getData(ArduCam::DEPTH_FRAME);
            amplitude_ptr = (float *)frame->getData(ArduCam::AMPLITUDE_FRAME);
            getPreview(preview_ptr, depth_ptr, amplitude_ptr);

            cv::Mat result_frame(tofFormat.height, tofFormat.width, CV_8U, preview_ptr);
            cv::Mat depth_frame(tofFormat.height, tofFormat.width, CV_32F, depth_ptr);
            cv::Mat amplitude_frame(tofFormat.height, tofFormat.width, CV_32F, amplitude_ptr);

            cv::applyColorMap(result_frame, result_frame, cv::COLORMAP_JET);
            amplitude_frame.convertTo(amplitude_frame, CV_8U,255.0/1024,0);
            cv::imshow("amplitude", amplitude_frame);
            cv::rectangle(result_frame, seletRect, cv::Scalar(0, 0, 0), 2);
            cv::rectangle(result_frame, followRect, cv::Scalar(255, 255, 255), 1);

            std::cout << "select Rect distance: " << cv::mean(depth_frame(seletRect)).val[0] << std::endl;

            cv::imshow("preview", result_frame);

            if (cv::waitKey(1) == 27)
                break;
            display_fps();
        }
        tof.releaseFrame(frame);
    }

    if (tof.stop())
        exit(-1);
    return 0;
}

Содержимое CMakeList.txt

cmake_minimum_required(VERSION 3.4)
SET(CMAKE_BUILD_TYPE "Debug")
SET(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -O0 -Wall -g2 -ggdb")  
project(example_tof)
include_directories(BEFORE /usr/include/c  /usr/include/cpp)
find_package( OpenCV REQUIRED )
include_directories( ${OpenCV_INCLUDE_DIRS} )
add_executable(example_tof your_filename.cpp )
target_link_libraries( example_tof ArducamDepthCamera ${OpenCV_LIBS} )

Сборка и запуск

mkdir build && cd build
cmake ..
make 

Результат

Результат работы примера на C++: карта глубины и амплитуда

Пример на Python

Порядок работы с SDK

  1. Создайте экземпляр камеры.
  2. Инициализируйте экземпляр камеры.
  3. Запустите камеру.
  4. Запросите кадр.
  5. Получите данные кадра.
  6. Освободите память кадра.
  7. Остановите камеру.

Пример

import sys
import cv2
import numpy as np
import ArduCamDepthCamera as ac

dir(ac)
def process_frame(depth_buf: np.ndarray, amplitude_buf: np.ndarray) -> np.ndarray:

    depth_buf = np.nan_to_num(depth_buf)

    amplitude_buf[amplitude_buf<=30] = 0
    amplitude_buf[amplitude_buf>30] = 255

    depth_buf = (1 - (depth_buf/2)) * 255
    depth_buf = np.clip(depth_buf, 0, 255)
    result_frame = depth_buf.astype(np.uint8)  & amplitude_buf.astype(np.uint8)
    return result_frame 

selectRect_x1 = 0
selectRect_y1 = 0
selectRect_x2 = 0
selectRect_y2 = 0

followRect_x1 = 0
followRect_y1 = 0
followRect_x2 = 0
followRect_y2 = 0

def on_mouse(event, x, y, flags, param):
    global followRect_x1,followRect_y1,followRect_x2,followRect_y2
    global selectRect_x1,selectRect_y1,selectRect_x2,selectRect_y2
    # if (x < 4 or x > 251 or y < 4 or y > 251):
    #     return
    if event == cv2.EVENT_LBUTTONDOWN:
        pass

    elif event == cv2.EVENT_LBUTTONUP:
        selectRect_x1 = x - 4 if x - 4 > 0 else 0
        selectRect_y1 = y - 4 if y - 4 > 0 else 0
        selectRect_x2 = x + 4 if x + 4 < 240 else 240
        selectRect_y2=  y + 4 if y + 4 < 180 else 180
    else:
        followRect_x1 = x - 4 if x - 4 > 0 else 0
        followRect_y1 = y - 4 if y - 4 > 0 else 0
        followRect_x2 = x + 4 if x + 4 < 240 else 240
        followRect_y2 = y + 4 if y + 4 < 180 else 180


if __name__ == "__main__":
    cam = ac.ArducamCamera()
    if cam.init(ac.TOFConnect.CSI,ac.TOFOutput.DEPTH,0) != 0 :
        print("initialization failed")
    if cam.start() != 0 :
        print("Failed to start camera")
    cv2.namedWindow("preview", cv2.WINDOW_AUTOSIZE)
    cv2.setMouseCallback("preview",on_mouse)
    while True:
        frame = cam.requestFrame(200)
        if frame != None:
            depth_buf = frame.getDepthData()
            amplitude_buf = frame.getAmplitudeData()
            amplitude_buf[amplitude_buf<0] = 0
            amplitude_buf[amplitude_buf>255] = 255
            cam.releaseFrame(frame)

            cv2.imshow("preview_amplitude", amplitude_buf.astype(np.uint8))

            result_image = process_frame(depth_buf,amplitude_buf)
            result_image = cv2.applyColorMap(result_image, cv2.COLORMAP_JET)
            cv2.rectangle(result_image,(selectRect_x1,selectRect_y1),(selectRect_x2,selectRect_y2),(128,128,128), 1)
            cv2.rectangle(result_image,(followRect_x1,followRect_y1),(followRect_x2,followRect_y2),(255,255,255), 1)
            print("select Rect distance:",np.mean(depth_buf[selectRect_x1:selectRect_x2,selectRect_y1:selectRect_y2]))
            cv2.imshow("preview",result_image)

            key = cv2.waitKey(1)
            if key == ord("q"):
                exit_ = True
                cam.stop()
                sys.exit(0)

Запуск

python3 your_filename.py

Результат (будет добавлен позже)

Справочник API для C

Справочник по API для C — здесь.

Справочник API для C++

Справочник по API для C++ — здесь.

Запросить цену

Укажите количество — пришлём коммерческое предложение.