c++ - 如何使用 OpenCV 解决图像处理相机 IO 延迟
问题描述
我有一个像这样工作的 OpenCV 程序:
VideoCapture cap(0);
Mat frame;
while(true) {
cap >> frame;
myprocess(frame);
}
问题是如果myprocess
花费的时间长于相机的IO间隔,则捕获的帧会延迟,无法获得与实时同步的帧。
所以,我认为要解决这个问题,应该让相机流和myprocess
并行运行。一个线程做 IO 操作,另一个做 CPU 计算。当相机完成捕获后,发送到工作线程进行处理。
这个想法对吗?有没有更好的策略来解决这个问题?
演示:
int main(int argc, char *argv[])
{
cv::Mat buffer;
cv::VideoCapture cap;
std::mutex mutex;
cap.open(0);
std::thread product([](cv::Mat& buffer, cv::VideoCapture cap, std::mutex& mutex){
while (true) { // keep product the new image
cv::Mat tmp;
cap >> tmp;
mutex.lock();
buffer = tmp.clone(); // copy the value
mutex.unlock();
}
}, std::ref(buffer), cap, std::ref(mutex));
product.detach();
while (cv::waitKey(20)) { // process in the main thread
mutex.lock();
cv::Mat tmp = buffer.clone(); // copy the value
mutex.unlock();
if(!tmp.data)
std::cout<<"null"<<std::endl;
else {
std::cout<<"not null"<<std::endl;
cv::imshow("test", tmp);
}
}
return 0;
}
或者使用线程不断清除缓冲区。
int main(int argc, char *argv[])
{
cv::Mat buffer;
cv::VideoCapture cap;
std::mutex mutex;
cap.open(0);
std::thread product([](cv::Mat& buffer, cv::VideoCapture cap, std::mutex& mutex){
while (true) { // keep product the new image
cap.grab();
}
}, std::ref(buffer), cap, std::ref(mutex));
product.detach();
int i;
while (true) { // process in the main thread
cv::Mat tmp;
cap.retrieve(tmp);
if(!tmp.data)
std::cout<<"null"<<i++<<std::endl;
else {
cv::imshow("test", tmp);
}
if(cv::waitKey(30) >= 0) break;
}
return 0;
}
我认为第二个演示应该是基于https://docs.opencv.org/3.0-beta/modules/videoio/doc/reading_and_writing_video.html#videocapture-grab的工作,但它不是......
解决方案
在具有多目标跟踪的项目中,我为帧(cv::Mat frames[2])和 2 个线程使用了 2 个缓冲区:
一个线程用于捕获下一帧并检测对象。
第二个线程用于跟踪检测到的对象并在框架上绘制结果。
我使用 index = [0,1] 进行缓冲区交换,并且该索引受到互斥锁的保护。对于工作结束的信号,使用了 2 个条件变量。
首先使用帧 [capture_ind] 缓冲区使用 CatureAndDetect,然后使用以前的帧 [1-capture_ind] 缓冲区进行跟踪。下一步 - 切换缓冲区:capture_ind = 1 - capture_ind。
你可以在这里做这个项目吗:Multitarget-tracker。
推荐阅读
- javascript - 使可滚动的子 div 独立于父级的滚动
- python - 将 Airflow(版本 1.10.5)与 Bigquery 连接
- python - 将两个数字与对应位置的整数合并在一起(不使用str)
- javascript - JS上的数组仅迭代一次,第二次单击时不显示信息
- postgresql - 获取与函数的选定行/字段关联的字段值
- python - 如何从 Python 将 csv 文件导入 QuestDb?
- mysql - 如何处理涉及不同货币的数据库结构
- oauth-2.0 - Keycloak Gatekeeper/ Luketo Proxy 的替代品
- rust - 如何有效地将切片复制到 Rust VecDeque
- kotlin - 在 Kotlin 中使用 Set 时 assertEquals 无法正常工作