C++ 如何在C+中通过Raspberry Pi上的i2c将MLX90640热像仪图像数据导入OpenCV+;?

C++ 如何在C+中通过Raspberry Pi上的i2c将MLX90640热像仪图像数据导入OpenCV+;?,c++,opencv,raspberry-pi3,i2c,C++,Opencv,Raspberry Pi3,I2c,我使用的是Melexix 32x24热敏摄像头传感器,通过i2c连接到Raspberry Pi 3 使用来自的代码,我可以通过帧缓冲区在屏幕上显示带有假颜色的相机数据,并给出它们的示例 因为这是直接显示在帧缓冲区上,而不是视频流或相机设备,所以我无法读入它。我想使用Open CV中的视频流计算房间中的人数,但不知道如何修改fbuf代码以输出视频 它不需要是视频,只是OpenCV可以连续读取的图像流 我试过的 我在/dev/video0的Pi上安装了一个虚拟相机设备。然后我创建了一个特定区域的屏幕

我使用的是Melexix 32x24热敏摄像头传感器,通过i2c连接到Raspberry Pi 3

使用来自的代码,我可以通过帧缓冲区在屏幕上显示带有假颜色的相机数据,并给出它们的示例

因为这是直接显示在帧缓冲区上,而不是视频流或相机设备,所以我无法读入它。我想使用Open CV中的视频流计算房间中的人数,但不知道如何修改fbuf代码以输出视频

它不需要是视频,只是OpenCV可以连续读取的图像流

我试过的 我在
/dev/video0
的Pi上安装了一个虚拟相机设备。然后我创建了一个特定区域的屏幕流,fbuf代码将红外摄像机的假彩色数据写入其中。这创建了一个OpenCV可以读取的流,但它没有更新流中的热图像数据。有时图像数据会部分通过,但正常显示Pi桌面。它似乎也不雅观和马车,所以我想要一个更坚实的解决方案

迄今为止的结果 使用v4l2loopback中的示例提供了传感器的工作示例,但这是一个不同的传感器,它与SPI而不是i2c通信

我的目标是将此代码与Pimoroni的帧捕获代码fbuf结合起来,从传感器获得稳定的视频流,以便将其导入OpenCV

Lepton的代码基于v4l2loopback中的ondemandcam示例。它将自己的传感器代码添加到
grab\u frame()
函数中。
open\u vpipe()
函数与ondemandcam示例相同

如果我可以将fbuf中的帧缓冲区代码放入
grab\u frame()
函数,那么我认为它会工作。我不知道怎么做

fbuf代码段 这个for循环似乎就是我需要放在
grab\u frame()
函数中的

for(int y = 0; y < 24; y++){
            for(int x = 0; x < 32; x++){
                float val = mlx90640To[32 * (23-y) + x];
                put_pixel_false_colour((y*IMAGE_SCALE), (x*IMAGE_SCALE), val);
            }
        }
然后我按照您的建议修改了循环,但它不会编译

更新#2 现在我只有一个编译错误

error:no match for 'operator[[]' (operand types are 'cv::Mat' and 'int')
test_mat[y,x] = val;
        ^
更新#3 现在编译错误消失了,但是这些错误出现了

g++ -I. -std=c++11 -std=c++11   -c -o examples/fbuf.o examples/fbuf.cpp
g++ -L/home/pi/mlx90640-library examples/fbuf.o examples/lib/fb.o libMLX90640_API.a -o fbuf -lbcm2835
examples/fbuf.o: In function `cv::Mat::Mat(int, int, int, void*, unsigned int)':
fbuf.cpp:(.text._ZN2cv3MatC2EiiiPvj[_ZN2cv3MatC5EiiiPvj]+0x144): undefined reference to `cv::error(int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, char const*, char const*, int)'
fbuf.cpp:(.text._ZN2cv3MatC2EiiiPvj[_ZN2cv3MatC5EiiiPvj]+0x21c): undefined reference to `cv::error(int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, char const*, char const*, int)'
fbuf.cpp:(.text._ZN2cv3MatC2EiiiPvj[_ZN2cv3MatC5EiiiPvj]+0x2ac): undefined reference to `cv::Mat::updateContinuityFlag()'
examples/fbuf.o: In function `cv::Mat::~Mat()':
fbuf.cpp:(.text._ZN2cv3MatD2Ev[_ZN2cv3MatD5Ev]+0x3c): undefined reference to `cv::fastFree(void*)'
examples/fbuf.o: In function `cv::Mat::release()':
fbuf.cpp:(.text._ZN2cv3Mat7releaseEv[_ZN2cv3Mat7releaseEv]+0x68): undefined reference to `cv::Mat::deallocate()'
collect2: error: ld returned 1 exit status
Makefile:37: recipe for target 'fbuf' failed
make: *** [fbuf] Error 1
$(I2C_LIBS)$(CPPFLAGS
到以下命令:

fbuf: examples/fbuf.o examples/lib/fb.o libMLX90640_API.a
    $(CXX) -L/home/pi/mlx90640-library $^ -o $@ $(I2C_LIBS) $(CPPFLAGS) $(LDLIBS)
现在我的循环看起来是这样的,但是当我运行程序时没有输出。因为我不再使用假图像功能,我如何显示来自mat的图像

更新5-已解决 多亏了Pimoroni的原始代码,我现在有了将MLX90640传感器数据导入OpenCV的代码。我还能够用OpenCV中内置的
applyColorMap
函数替换假彩色函数

现在我可以开始使用OpenCV来处理数据了。我使用了多次Mat转换来获得最终图像。可能有一种更有效的方法可以做到这一点

完整工作代码
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括“标题/MLX90640_API.h”
#包括“opencv2/opencv.hpp”
使用名称空间cv;
使用名称空间std;
#定义MLX_I2C_地址0x33
//有效帧速率为1、2、4、8、16、32和64
//i2c波特率设置为1mhz以支持这些功能
#定义FPS 8
#定义帧时间微米(1000000/FPS)
//尽管帧率表面上是FPS-hz
//镜框往往没有及时准备好
//此偏移量将添加到帧时间微米
//要解释这一点。
#定义偏移量_MICROS 850
int main(){
静态uint16_t eeMLX90640[832];
浮子发射率=1;
uint16_t帧[834];
静态浮点图像[768];
静态浮动MLX90640至[768];
浮动eTa;
静态uint16_t数据[768*sizeof(浮动)];
自动帧时间=标准::计时::微秒(帧时间+偏移量);
MLX90640_设置设备模式(MLX_I2C_地址,0);
MLX90640_设置子页面重复(MLX_I2C_地址,0);
开关(FPS){
案例1:
MLX90640_设置刷新率(MLX_I2C_地址,0b001);
打破
案例2:
MLX90640_设置刷新速率(MLX_I2C_地址,0b010);
打破
案例4:
MLX90640_设置刷新速率(MLX_I2C_地址,0b011);
打破
案例8:
MLX90640_设置刷新速率(MLX_I2C_地址,0b100);
打破
案例16:
MLX90640_设置刷新速率(MLX_I2C_地址,0b101);
打破
案例32:
MLX90640_设置刷新速率(MLX_I2C_地址,0b110);
打破
案例64:
MLX90640_设置刷新速率(MLX_I2C_地址,0b111);
打破
违约:
printf(“不支持的帧速率:%d”,FPS);
返回1;
}
MLX90640_设置棋盘模式(MLX_I2C_地址);
paramsMLX90640 mlx90640;
MLX90640_DumpEE(MLX_I2C_地址,eeMLX90640);
MLX90640_提取参数(eeMLX90640和MLX90640);
而(1){
自动启动=标准::时钟::系统时钟::现在();
MLX90640_获取帧数据(MLX_I2C_地址,帧);
MLX90640_插值器(帧,eeMLX90640);
eTa=MLX90640_GetTa(帧和MLX90640);
MLX90640_计算到(帧和MLX90640,发射率,eTa,mlx90640To);
材料IR_Mat(32,24,CV_32FC1,数据);
对于(int y=0;y<24;y++){
对于(int x=0;x<32;x++){
浮动值=MLX90640至[32*(23-y)+x];
IR_mat.at(x,y)=val;
}
}
//使垫子正常化
普通垫;
正常化(IR_-mat、normal_-mat、0,1.0、normal_-MINMAX、CV_-32FC1);
//将Mat转换为CV_U8以使用applyColorMap
双最小值,最大值;
minMaxLoc(正常、最小和最大值);
垫u8_垫;
正常材料转换成(u8材料,CV材料,255.0/(最大值-最小值),-最小值);
//调整垫子大小
垫子尺寸;
调整大小(u8_mat,size_mat,size(240320),INTER_CUBIC);
//涂色
鞋垫颜色(鞋垫);;
applyColorMap(尺寸图、假彩色图、彩色图);
//在窗口中显示流
我
g++ -I. -std=c++11 -std=c++11   -c -o examples/fbuf.o examples/fbuf.cpp
g++ -L/home/pi/mlx90640-library examples/fbuf.o examples/lib/fb.o libMLX90640_API.a -o fbuf -lbcm2835
examples/fbuf.o: In function `cv::Mat::Mat(int, int, int, void*, unsigned int)':
fbuf.cpp:(.text._ZN2cv3MatC2EiiiPvj[_ZN2cv3MatC5EiiiPvj]+0x144): undefined reference to `cv::error(int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, char const*, char const*, int)'
fbuf.cpp:(.text._ZN2cv3MatC2EiiiPvj[_ZN2cv3MatC5EiiiPvj]+0x21c): undefined reference to `cv::error(int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, char const*, char const*, int)'
fbuf.cpp:(.text._ZN2cv3MatC2EiiiPvj[_ZN2cv3MatC5EiiiPvj]+0x2ac): undefined reference to `cv::Mat::updateContinuityFlag()'
examples/fbuf.o: In function `cv::Mat::~Mat()':
fbuf.cpp:(.text._ZN2cv3MatD2Ev[_ZN2cv3MatD5Ev]+0x3c): undefined reference to `cv::fastFree(void*)'
examples/fbuf.o: In function `cv::Mat::release()':
fbuf.cpp:(.text._ZN2cv3Mat7releaseEv[_ZN2cv3Mat7releaseEv]+0x68): undefined reference to `cv::Mat::deallocate()'
collect2: error: ld returned 1 exit status
Makefile:37: recipe for target 'fbuf' failed
make: *** [fbuf] Error 1
CPPFLAGS = `pkg-config --cflags opencv`
LDLIBS = `pkg-config --libs opencv`
fbuf: examples/fbuf.o examples/lib/fb.o libMLX90640_API.a
    $(CXX) -L/home/pi/mlx90640-library $^ -o $@ $(I2C_LIBS) $(CPPFLAGS) $(LDLIBS)
#include <stdint.h>
#include <iostream>
#include <cstring>
#include <fstream>
#include <chrono>
#include <thread>
#include <math.h>
#include "headers/MLX90640_API.h"

#include "opencv2/opencv.hpp"

using namespace cv;
using namespace std;

#define MLX_I2C_ADDR 0x33

// Valid frame rates are 1, 2, 4, 8, 16, 32 and 64
// The i2c baudrate is set to 1mhz to support these
#define FPS 8
#define FRAME_TIME_MICROS (1000000/FPS)

// Despite the framerate being ostensibly FPS hz
// The frame is often not ready in time
// This offset is added to the FRAME_TIME_MICROS
// to account for this.
#define OFFSET_MICROS 850

int main(){
    static uint16_t eeMLX90640[832];
    float emissivity = 1;
    uint16_t frame[834];
    static float image[768];
    static float mlx90640To[768];
    float eTa;
    static uint16_t data[768*sizeof(float)];

    auto frame_time = std::chrono::microseconds(FRAME_TIME_MICROS + OFFSET_MICROS);

    MLX90640_SetDeviceMode(MLX_I2C_ADDR, 0);
    MLX90640_SetSubPageRepeat(MLX_I2C_ADDR, 0);
    switch(FPS){
        case 1:
            MLX90640_SetRefreshRate(MLX_I2C_ADDR, 0b001);
            break;
        case 2:
            MLX90640_SetRefreshRate(MLX_I2C_ADDR, 0b010);
            break;
        case 4:
            MLX90640_SetRefreshRate(MLX_I2C_ADDR, 0b011);
            break;
        case 8:
            MLX90640_SetRefreshRate(MLX_I2C_ADDR, 0b100);
            break;
        case 16:
            MLX90640_SetRefreshRate(MLX_I2C_ADDR, 0b101);
            break;
        case 32:
            MLX90640_SetRefreshRate(MLX_I2C_ADDR, 0b110);
            break;
        case 64:
            MLX90640_SetRefreshRate(MLX_I2C_ADDR, 0b111);
            break;
        default:
            printf("Unsupported framerate: %d", FPS);
            return 1;
    }
    MLX90640_SetChessMode(MLX_I2C_ADDR);

    paramsMLX90640 mlx90640;
    MLX90640_DumpEE(MLX_I2C_ADDR, eeMLX90640);
    MLX90640_ExtractParameters(eeMLX90640, &mlx90640);

    while (1){
        auto start = std::chrono::system_clock::now();
        MLX90640_GetFrameData(MLX_I2C_ADDR, frame);
        MLX90640_InterpolateOutliers(frame, eeMLX90640);

        eTa = MLX90640_GetTa(frame, &mlx90640);
        MLX90640_CalculateTo(frame, &mlx90640, emissivity, eTa, mlx90640To);

        Mat IR_mat (32,24, CV_32FC1, data); 

        for(int y = 0; y < 24; y++){
            for(int x = 0; x < 32; x++){
                float val = mlx90640To[32 * (23-y) + x];
                IR_mat.at<float>(x,y) = val;
            }
        }

        // Normalize the mat
        Mat normal_mat;
        normalize(IR_mat, normal_mat, 0,1.0, NORM_MINMAX, CV_32FC1);

        // Convert Mat to CV_U8 to use applyColorMap
        double minVal, maxVal;
        minMaxLoc(normal_mat, &minVal, &maxVal);
        Mat u8_mat;
        normal_mat.convertTo(u8_mat, CV_8U, 255.0/(maxVal - minVal), -minVal);

        // Resize mat
        Mat size_mat;
        resize(u8_mat, size_mat, Size(240,320), INTER_CUBIC);

        // Apply false color
        Mat falsecolor_mat;
        applyColorMap(size_mat, falsecolor_mat, COLORMAP_JET);

        // Display stream in window
        namedWindow( "IR Camera Window");
        imshow ("IR Camera Window", falsecolor_mat);
        waitKey(1);

        auto end = std::chrono::system_clock::now();
        auto elapsed = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
        std::this_thread::sleep_for(std::chrono::microseconds(frame_time - elapsed));
    }


    return 0;
}