繁体   English   中英

OpenCV VideoCapture 读取问题

[英]OpenCV VideoCapture reading issue

这可能是一个愚蠢的问题,但我真的想不通。 首先:抱歉标题含糊不清,我不太确定如何用几句话来描述我的问题。

我在 MS Visual Studio、C++ 中使用 OpenCV 2.4.3。 我正在使用 VideoCapture 界面从我的笔记本电脑网络摄像头捕获帧。

我的程序应该做的是:

为每个姿势循环用户的不同姿势:

  • 等待用户就位(getchar() 等待输入,只需按 Enter 即可显示“我已就位”)
  • 读取当前帧
  • 从该帧中提取感兴趣的区域
  • 将图像保存在 ROI 中,然后标记它

这是代码:

int main() {

Mat img, face_img, img_start;
Rect *face;
VideoCapture cam(0);
ofstream fout("dataset/dataset.txt");

if(!fout) {
    cout<<"Cannot open dataset file! Aborting"<<endl;
    return 1;
}

int count = 0; //   Number of the (last + 1) image in the dataset

//  Orientations are: 0°, +/- 30°, +/- 60°, +/-90°
//  Distances are just two, for now
//  So it is 7x2 images

cam.read(img_start);
IplImage image = img_start;
face = face_detector(image);


if(!face) {
    cout<<"No face detected..? Aborting."<<endl;
    return 2;
}

//  Double ROI dimensions
face->x = face->x-face->width / 2;
face->y = face->y-face->height / 2;
face->width *= 2;
face->height *=2;

for(unsigned i=0;i<14;++i) {

    //  Wait for the user to get in position
    getchar(); 

    //  Get the face ROI
    cam.read(img);

    face_img = Mat(img, *face);

    //  Save it
    stringstream sstm;
    string fname;
    sstm << "dataset/image" << (count+i) << ".jpeg";
    fname = sstm.str();
    imwrite(fname,face_img);
    //do some other things..

我对它的期望:

  • 程序启动时我站在相机前,它使用 face_detector() 函数获取 ROI 矩形
  • 当我准备好时,比如在pose0,我按下回车键并拍照
  • 从该图片中提取子图像并将其保存为 image0.jpeg
  • 循环 7 次

它的作用:

  • 节目开始时我站在镜头前,没什么特别的
  • 我按回车
  • ROI 不是从那一刻拍摄的照片中提取的,而是从第一张照片中提取的

起初,我在每个 cam.capture() 中都使用了 img,然后我更改了 cam.capture(img_start) 中的第一个,但这没有帮助。 我的代码的第二次迭代保存了应该在第一次保存的图像,第三次迭代保存了应该在第二次保存的图像,依此类推。

我可能遗漏了 VideoCapture 中的一些重要内容,但我真的无法弄清楚,所以我在这里。

感谢您的帮助,我真的很感激。

您实施的问题在于相机不能自由运行并实时捕获图像。 当您启动相机时,视频捕获缓冲区已满,等待您读取帧。 一旦缓冲区已满,在您读取并释放其中的空间之前,它不会为新帧丢弃旧帧。

解决方案是除了“进程”线程之外​​,还有一个单独的捕获线程。 每当新帧进入时,捕获线程都会从缓冲区中读取帧并将其存储在“最近帧”图像对象中。 当进程线程需要最新的帧时(即当您按下 Enter 键时),它会锁定一个互斥锁以确保线程安全,将最新的帧复制到另一个对象中并释放互斥锁,以便捕获线程继续读取新帧。

#include <iostream>
#include <stdio.h>
#include <thread>
#include <mutex>
#include <opencv2/objdetect/objdetect.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>

using namespace std;
using namespace cv;

void camCapture(VideoCapture cap, Mat* frame, bool* Capture){   
    while (*Capture==true) {
        cap >> *frame;
    }
    cout << "camCapture finished\n";
    return;
}

int main() {
    VideoCapture cap(0); // open the default camera
    if (!cap.isOpened())  // check if we succeeded
        return -1;
    Mat *frame, SFI, Input;
    frame = new Mat;
    bool *Capture = new bool;
    *Capture = true;
    //your capture thread has started
    thread captureThread(camCapture, cap, frame, Capture);
    mtx.lock();
    imshow(*frame,current_frame);
    mtx.unlock();
    //Terminate the thread
    mtx.lock();
    *Capture = false;
    mtx.unlock();
    captureThread.join();
    return 0;
}

这是我根据上述建议编写的代码。 我希望有人能从中得到帮助。

  1. 当您连续捕捉图像时,不会将捕捉到的帧存储在 opencv 缓冲区中,因此流式传输不会出现延迟。
  2. 如果您在截屏/捕获图像之间有一些时间间隔,则捕获的图像将首先存储在 opencv 缓冲区中,然后从缓冲区中检索图像。
  3. 当缓冲区已满时,当您调用captureObject >> matObject ,将返回图像的最后一帧,而不是捕获卡/网络摄像头中的当前帧。
  4. 所以只有你看到你的代码滞后。 可以通过根据网络摄像头的每秒帧数 (fps) 值和捕获屏幕截图所用的时间截取屏幕截图来解决此问题。
  5. 从缓冲区读取帧所花费的时间非常少,测量截图所花费的时间。 如果它小于 fps,我们可以假设它是从缓冲区读取的,否则意味着它是从网络摄像头捕获的。

示例代码:用于从网络摄像头捕获最近的屏幕截图。

#include <opencv2/opencv.hpp>
#include <time.h>
#include <thread>
#include <chrono>

using namespace std;
using namespace cv;

int main()
{
struct timespec start, end;
VideoCapture cap(-1); // first available webcam
Mat screenshot;
double diff = 1000;
double fps = ((double)cap.get(CV_CAP_PROP_FPS))/1000;



while (true)   
{
    clock_gettime(CLOCK_MONOTONIC, &start);

    //camera.grab();    
    cap.grab();// can also use cin >> screenshot;                  

    clock_gettime(CLOCK_MONOTONIC, &end);

    diff = (end.tv_sec - start.tv_sec)*1e9;
    diff = (diff + (end.tv_nsec - start.tv_nsec))*1e-9;

    std::cout << "\n diff time " << diff << '\n';

    if(diff > fps)
    {
        break;
    }
}

cap >> screenshot; // gets recent frame, can also use cap.retrieve(screenshot);
// process(screenshot)

cap.release(); 
screenshot.release();

return 0;

}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM