OpenCV VideoCapture阅读问题

时间:2013-07-01 18:46:13

标签: opencv computer-vision video-capture

这可能是一个愚蠢的问题,但我真的无法弄清楚。 首先:对于模糊的标题感到抱歉,我不确定如何用几个词来描述我的问题。

我在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)中更改了第一个,但这没有帮助。 我的代码的第二次迭代保存了应该在第1次迭代中保存的图像,第3次迭代应该保存在第2次中的图像,依此类推。

我可能错过了VideoCapture的一些重要内容,但我真的无法理解,所以我在这里。

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

3 个答案:

答案 0 :(得分:1)

您的实施问题是相机无法自由运行并实时捕捉图像。当您启动相机时,视频捕捉缓冲区会在等待您读取帧时填满。一旦缓冲区已满,它就不会丢弃旧帧,直到你读取并释放其中的空间。

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

答案 1 :(得分:0)

#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;
}

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

答案 2 :(得分: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;

}