1

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

我在 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 中的一些重要内容,但我真的想不通,所以我来了。

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

4

3 回答 3

1

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

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

于 2013-07-02T09:10:18.910 回答
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;

}
于 2020-09-24T12:57:02.270 回答
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;
}

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

于 2015-10-15T02:32:27.657 回答