在OpenCV Python=>冻结视频中通过视频从ESP32获取数据

2024-05-20 22:04:42 发布

您现在位置:Python中文网/ 问答频道 /正文

我在一个项目中工作,我需要通过视频实时显示外部数据(来自带有BME280传感器的ESP32)。我正在使用Python中的opencv从我的网络摄像头获取视频。 视频工作正常,直到我将获取传感器数据的代码放在视频上,它变得非常慢,每1/2秒冻结一次(与ESP32代码中的延迟有关)。 我也发现超时(在python代码中)有一个非常重要的作用。。。如果我把它放在0的视频流罚款,但数据不能正常显示。 因此,我知道我的代码中的readline()具有阻塞行为,如果它不接收行的最后一个字符(“\n”),它就不能“while”继续循环。 问题是,我如何重新定义我的代码来避免这种情况

Python代码:

import serial
import cv2 as cv
import datetime

cap = cv.VideoCapture(0)
if not cap.isOpened():
    print("Camera cannot open")
    exit()
    
    
arduino = serial.Serial('COM7', baudrate=115200, timeout = 0)

while True:

    ret , frame= cap.read()
    
    if not ret:
        print("void frame")
        break
    
    #reading line from ESP32

    rawString = str(arduino.readline())
    print(rawString)
    # replace "\r" and "\n" for ""

    rawString = rawString.replace("\\r\\n'","")
    rawString = rawString.replace("b'","")
    
    #Add data to video (real time and sensor)
    hora = str(datetime.datetime.now())
    print(type(hora))
    font = cv.FONT_HERSHEY_SIMPLEX
    cv.putText(frame, hora,(10,50), font, 0.8,(255,0,0),2,cv.LINE_AA)
    cv.putText(frame, rawString,(10,80), font, 0.8,(255,0,0),2,cv.LINE_AA)

    #show the video
    cv.imshow("Video", frame)
    
    if cv.waitKey(1) == ord('q'):
        break

arduino.close()
cap.release()
cv.destroyAllWindows()

ESP32代码:

#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>



Adafruit_BME280 bme; // I2C

unsigned long delayTime;

void setup() {
  Serial.begin(115200);
  Serial.println(F("BME280 test"));

  bool status;

  // default settings
  // (you can also pass in a Wire library object like &Wire2)
  status = bme.begin(0x77);  
  if (!status) {
    Serial.println("Could not find a valid BME280 sensor, check wiring!");
    while (1);
  }

  Serial.println("-- Default Test --");
  delayTime = 500;

}


void loop() { 
  printValues();
  delay(delayTime);
}

void printValues() {

  Serial.println(bme.readTemperature());

}

Tags: 数据代码视频ifserialframecvcap
1条回答
网友
1楼 · 发布于 2024-05-20 22:04:42

我可以马上想出三种方法来解决你的问题

简单的解决方案是以非阻塞方式从ESP32读取温度。作为一种有用的方法,您可以在创建pyserial端口时指定一个非常小的超时值,比如1毫秒。如果ESP32的串行缓冲区中没有数据,那么readline()将不返回任何内容。发生这种情况时,只需跳过更新变量rawString。见notes on ^{}

arduino = serial.Serial('COM7', baudrate=115200, timeout = 0.001)
...
    serialData = arduino.readline()
    if serialData:
        rawString = str(serialData)
...

请注意,正确地实现非阻塞读取需要将pyserial超时参数设置为0(正如您所做的),然后使用^{}逐字节读取ESP32从pyserial缓冲区发送的任何内容。您必须自己进行字符串处理以检测传感器数据行。这并不难,所以您可以自己实施

高级解决方案是线程readline()是一种阻塞操作,此类操作应该在单独的线程中运行,以避免阻塞视频处理。因此,您可以自由地启动一个新线程,并在那里运行与ESP32的所有通信。要将温度传播到主线程,只需使用一个共享全局变量或类似的东西(Python中最简单的带有原子更新的数字类型)

一个糟糕的解决方案是更新ESP32,以与视频帧速率相同的频率发送温度更新。我会避免这样:)

相关问题 更多 >