Ubuntu下C++ OpenCV实时图像处理集成UART中断出现Core Dumped问题
问题根因
- 你将
VideoCapture vid定义为全局变量,它的初始化在main函数执行前就完成,此时Linux下V4L2设备驱动上下文、OpenCV用户态运行环境还未完全就绪,本身就存在稳定性隐患,结合异步信号中断更容易触发内存访问错误。 SIGIO信号是异步触发的,可能在执行vid.set、vid.read的任意阶段打断代码运行,而OpenCV的VideoCapture类成员函数没有做异步信号安全的保证,信号打断后恢复执行时,VideoCapture内部状态已经被破坏,因此触发段错误。你删除分辨率配置代码后程序正常运行,是因为vid.set属于耗时较长的IO操作,被SIGIO信号打断的概率远高于帧读取操作,只是避开了问题触发场景,并没有从根源解决问题。- 你尝试把
vid.set两行放到全局作用域会报错,是因为全局作用域只能声明变量、定义函数,不能直接执行普通的成员函数调用语句,编译器会把这行当成类型定义解析,自然报vid does not name a type错误。
解决方案
- 将全局的
VideoCapture定义移到main函数内部,避免全局对象初始化的不稳定问题,所有VideoCapture的操作都放在main函数的可控流程中执行。 - 信号处理函数仅做信号到达标记,不要执行任何非异步信号安全的操作(比如printf、read等),所有UART数据读取逻辑移到主循环轮询处理,避免信号打断OpenCV的执行流程。
- 给sigaction添加
SA_RESTART标志,让被信号打断的系统调用自动重启,避免OpenCV内部的V4L2调用被打断后返回错误导致状态异常。 vid.set的调用放在vid.isOpened()判断之后、UART配置完成之前,确保VideoCapture初始化完成后第一时间设置参数,避免后续信号打断参数配置流程。
修改后的核心代码参考:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/types.h> #include <fcntl.h> #include <sys/signal.h> #include <errno.h> #include <termios.h> #include <opencv2/opencv.hpp> #include <iostream> using namespace std; using namespace cv; // 异步信号安全的全局标记位,仅用于标记UART信号到达 volatile sig_atomic_t uart_received = 0; void signal_handler_IO(int status); int main(int argc, char *argv[]) { // VideoCapture移到main内部定义 VideoCapture vid("/dev/video0", CAP_V4L2); int fd; struct termios termAttr; struct sigaction saio; const int fps = 20; Mat frame; fd = open("/dev/ttyUSB0", O_RDWR | O_NOCTTY | O_NDELAY); if (fd == -1) { perror("open_port: Unable to open /dev/ttyUSB0\n"); exit(1); } saio.sa_handler = signal_handler_IO; // 添加SA_RESTART标志,自动重启被信号打断的系统调用 saio.sa_flags = SA_RESTART; saio.sa_restorer = NULL; sigaction(SIGIO,&saio,NULL); fcntl(fd, F_SETFL, FNDELAY|FASYNC); fcntl(fd, F_SETOWN, getpid()); tcgetattr(fd,&termAttr); cfsetispeed(&termAttr,B9600); cfsetospeed(&termAttr,B9600); termAttr.c_cflag &= ~PARENB; termAttr.c_cflag &= ~CSTOPB; termAttr.c_cflag &= ~CSIZE; termAttr.c_cflag |= CS8; termAttr.c_cflag |= (CLOCAL | CREAD); termAttr.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); termAttr.c_iflag &= ~(IXON | IXOFF | IXANY); termAttr.c_oflag &= ~OPOST; tcsetattr(fd, TCSANOW, &termAttr); printf("UART1 configured....\n"); if (!vid.isOpened()) { return -1; } // 进入主循环前先完成分辨率配置,此时不会被UART信号打断 vid.set(CAP_PROP_FRAME_WIDTH, 1280); vid.set(CAP_PROP_FRAME_HEIGHT, 720); while (vid.read(frame)) { imshow("webcam", frame); // 轮询UART事件,处理数据 if (uart_received) { char buf[256] = {0}; int len = read(fd, buf, sizeof(buf)-1); if (len > 0) { printf("received UART data: %.*s\n", len, buf); // 此处添加你的UART数据处理逻辑 } uart_received = 0; } if (waitKey(1000/fps) >= 0) break; } destroyAllWindows(); vid.release(); close(fd); exit(0); } void signal_handler_IO (int status) { // 仅修改标记位,不做其他操作 uart_received = 1; }
内容的提问来源于stack exchange,提问作者ayashlokumu
相关产品推荐
相关产品推荐

