在OpenCL-OpenCV-Realtime-Threads中正确使用互斥锁

Correctly using mutex in OpenCL-OpenCV-Realtime-Threads?

本文关键字:OpenCL-OpenCV-Realtime-Threads      更新时间:2023-10-16

我试图在gpu线程中通过usb网络摄像头实时获得立体声视频流(比通过cpu获取和处理图像快得多),在第二个线程中处理该流以获取面部并通过键盘在主函数中控制线程(将在稍后实现)。目前,代码正常运行(显示链接/Rechts,并在我的脸周围画一个矩形)约30秒,然后崩溃,因为"……未处理的异常(opencv_core2499 .dll)".

我尝试使用互斥锁保护来处理变量"链接"/"Rechts"和面孔,但我不确定如何在Mat-context中使用它们,因为我没有找到任何适合OpenCV的例子。另外:它是正确的如何引用链接/Rechts/面对线程/它是最快的线程安全的品种?

我的互斥锁被排除在代码之外。谢谢你的帮助。

#include <thread>
#include <iostream>
#include <functional>
#include <opencv2/objdetect/objdetect.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include "opencv2/ocl/ocl.hpp"
#include <mutex>
using namespace std;
using namespace cv;
Mat Links = Mat::zeros(960,1080, CV_8UC3);                                          
Mat Rechts = Mat::zeros(960,1080, CV_8UC3);                                         
Mat facesMat =Mat::zeros(960,1080,CV_8UC3);                                         
std::vector<Rect> faces;
void change(Mat& Links, Mat& Rechts)
{
Mat captureFrame;
VideoCapture LeftCam(1);
VideoCapture RightCam(0);
LeftCam.set(CV_CAP_PROP_FRAME_WIDTH,1920);              
LeftCam.set(CV_CAP_PROP_FRAME_HEIGHT,1080);
RightCam.set(CV_CAP_PROP_FRAME_WIDTH,1920);
RightCam.set(CV_CAP_PROP_FRAME_HEIGHT,1080);
FileStorage fs, fs2, fs3, fs4;
Mat map1x, map1y, map2x, map2y; 
Mat mapi1x, mapi1y, mapi2x, mapi2y;
fs.open("mx1.xml", FileStorage::READ);
fs2.open("my1.xml", FileStorage::READ);
fs3.open("mx2.xml", FileStorage::READ);
fs4.open("my2.xml", FileStorage::READ);
fs["mx1"] >> map1x;
fs2["my1"] >> map1y;
fs3["mx2"] >> map2x;
fs4["my2"] >> map2y;
fs.release();
fs2.release();
fs3.release();
fs4.release();
ocl::oclMat map1xocl(map1x), map1yocl(map1y), map2xocl(map2x), map2yocl(map2y);
while (true)
{
    cv::Mat3b frame0, frame1, LeftframeRaw, RightframeRaw, LeftRoi, RightRoi, framecon;
    LeftCam >> frame0;
    RightCam >> frame1;
    LeftRoi = frame0(Rect(420,60,1080,960));                                                                    //960*1080 passend zuschneiden
    RightRoi = frame1(Rect(420,60,1080,960));
    ocl::oclMat Leftr(LeftRoi), Rightr(RightRoi), Leftt, Lefttf, Rightt, Righttf, LeftRemappedocl, RightRemappedocl;
    ocl::transpose(Leftr, Leftt);                                                                               //ACHTUNG: ocl::transpose src darf nicht dst-image sein, sonst gibts starke Bildartefakte!
    ocl::transpose(Rightr, Rightt);
    ocl::flip(Leftt, Lefttf, 1);                                                                                //ACHTUNG: ocl::flip src darf nicht dst-image sein, sonst gibts starke Bildartefakte!
    ocl::flip(Rightt, Rightt, 1);
    ocl::remap(Lefttf, LeftRemappedocl, map1xocl, map1yocl, CV_INTER_LINEAR, BORDER_CONSTANT, 0);
    ocl::remap(Rightt, RightRemappedocl, map2xocl, map2yocl, CV_INTER_LINEAR, BORDER_CONSTANT, 0);

    Links = LeftRemappedocl.clone();                                                                            //kopiere sauber in neues Mat: leer
    Rechts = RightRemappedocl.clone();                                                                          //kopiere sauber in neues Mat: leer
}
}
void facefind(Mat& f, vector<Rect>&e)
{
CascadeClassifier face_cascade;
face_cascade.load("haarcascade_frontalface_alt.xml");
while (true)
{
    Mat Lokalesf;
    Lokalesf = f.clone();
    Mat grau;
    cvtColor(Lokalesf, grau, CV_BGR2GRAY);
    equalizeHist(grau, grau);
    face_cascade.detectMultiScale(grau, faces, 1.1, 3, CASCADE_SCALE_IMAGE|CV_HAAR_SCALE_IMAGE, Size(30,30));
        e=faces;                                                                                        //kopiere sauber in neues vector<rect>
}
}
int main()
{
    Mat stereo;
    std::thread t1(change,std::ref(Links),std::ref(Rechts));
    std::thread t2(facefind,std::ref(Links),std::ref(faces));
    while (true)
    {
        for(int i = 0; i < faces.size(); i++)
        {
            Point pt1(faces[i].x + faces[i].width, faces[i].y + faces[i].height);
            Point pt2(faces[i].x, faces[i].y);
            rectangle(Links, pt1, pt2, cvScalar(0, 255, 0, 0), 1, 8, 0);
        }
        imshow("rechts", Rechts);
        imshow("links", Links);
        waitKey(10);
    }
    t1.join();
    t2.join();
    return 0;
}
编辑:我试着理解Mr.Worshipme的代码,并包括我的代码使其工作。我得到了两个关于大小的断言错误。宽度/高度在cv::imshow和ROI,谁能帮我吗?
#include <memory>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <vector>
#include <cmath>
#include <opencv2/objdetect/objdetect.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include "opencv2/ocl/ocl.hpp"
#include <functional>
using namespace std;
using namespace cv;
typedef unsigned char uchar;
typedef unsigned int uint;
class FaceDetector
{
mutex imageLock, facesLock;
condition_variable imageAqcuired;
bool newImageAvailable;
Mat _img;
Mat _imgToWorkOn;
Mat _faceImages;
bool quit;
void acquireImage()
{
    Mat captureFrame;
    VideoCapture LeftCam(1);
    LeftCam.set(CV_CAP_PROP_FRAME_WIDTH,1920);              
    LeftCam.set(CV_CAP_PROP_FRAME_HEIGHT,1080);
    FileStorage fs, fs2;
    Mat map1x, map1y; 
    Mat mapi1x, mapi1y;
    fs.open("mx1.xml", FileStorage::READ);
    fs2.open("my1.xml", FileStorage::READ);
    fs["mx1"] >> map1x;
    fs2["my1"] >> map1y;
    fs.release();
    fs2.release();
    ocl::oclMat map1xocl(map1x), map1yocl(map1y);
    while (!quit)
    {
        unique_lock<mutex> ulock(imageLock);
        imageAqcuired.wait(ulock,[&](){return !newImageAvailable;}); //only take
//new image after current one was consumed
        cv::Mat3b frame0, frame1, LeftframeRaw, RightframeRaw, LeftRoi,     RightRoi,framecon;
            LeftCam >> frame0;
           LeftRoi=frame0(Rect(420,60,1080,960));                                                                   //960*1080 passend zuschneiden
        ocl::oclMat Leftr(LeftRoi), Leftt, Lefttf, LeftRemappedocl;
        ocl::transpose(Leftr, Leftt);                                                                               //ACHTUNG: ocl::transpose src darf nicht dst-image sein, sonst gibts starke Bildartefakte!
        ocl::flip(Leftt, Lefttf, 1);                                                                                //ACHTUNG: ocl::flip src darf nicht dst-image sein, sonst gibts starke Bildartefakte!
        ocl::remap(Lefttf, LeftRemappedocl, map1xocl, map1yocl, CV_INTER_LINEAR, BORDER_CONSTANT, 0);
        _img = LeftRemappedocl.clone();
        ulock.unlock();
        newImageAvailable = true;
        imageAqcuired.notify_one(); //notify that a new image is available
    }
}
void processImage()
{
    CascadeClassifier face_cascade;
    face_cascade.load("haarcascade_frontalface_alt.xml");
    while (!quit)
    {
        unique_lock<mutex> ulock(imageLock);
        imageAqcuired.wait(ulock,[&](){return newImageAvailable;}); //wait untill a new image is available
        _imgToWorkOn = _img;
        ulock.unlock();
        newImageAvailable = false;
        imageAqcuired.notify_one(); //notify the current image can be replaced by a newer one
        unique_lock<mutex> lockFace(facesLock);
        Mat grau;
        cvtColor(_imgToWorkOn, grau, CV_BGR2GRAY);
        equalizeHist(grau, grau);
        std::vector<Rect> faces;
        face_cascade.detectMultiScale(grau, faces, 1.1, 3, CASCADE_SCALE_IMAGE|CV_HAAR_SCALE_IMAGE, Size(30,30));
        for(int i = 0; i < faces.size(); i++)
        {
            Point pt1(faces[i].x + faces[i].width, faces[i].y + faces[i].height);
            Point pt2(faces[i].x, faces[i].y);
            rectangle(_imgToWorkOn, pt1, pt2, cvScalar(0, 255, 0, 0), 1, 8, 0);
        }
        _faceImages = _imgToWorkOn;
        lockFace.unlock();
    }
}
public:
FaceDetector() : newImageAvailable(false) {}
void start() {
    quit = false;
    thread t1(&FaceDetector::acquireImage,this);
    t1.detach();
    thread t2(&FaceDetector::processImage,this);
    t2.detach();
}
void stop() {
    quit = true;
}
Mat getImage() {
    lock_guard<mutex> lock(imageLock);
    return _img;
}
Mat getProcessedImage() {
    lock_guard<mutex> lock(facesLock);
    return _faceImages;
}
};

int main()
{
Mat img = Mat::zeros(960,1080, CV_8UC3);                                                //notwendig
Mat imgs = Mat::zeros(960,1080, CV_8UC3);                                               //notwendig
bool quit(false);
FaceDetector faceDet;
faceDet.start();
thread input([](bool &quitFlag) { getchar(); quitFlag = true; },ref(quit)); //stop on user press Enter
input.detach();
while (!quit) {
    Mat img = faceDet.getImage();
    imshow("links", img);
    Mat imgs = faceDet.getProcessedImage();
    imshow("gsichter", imgs);
    waitKey(1);
    this_thread::sleep_for(chrono::milliseconds(33)); //no need to show more than 30 fps...
}
faceDet.stop();
return 0;
}

编辑2:再次编辑代码,以允许深度复制的垫子图像,因为它被建议(facetracker目前不做任何事情和ocl-mat-stuff/facecascade擦除代码的简单性),并得到了代码的工作,但它的行为奇怪。我的摄像头在运行的时候会亮起一个led灯,大约每隔500毫秒它就会亮起来,通过imshow给我显示一张新图像,然后它就会回到待机状态,尽管它应该尽可能快地更新_img。我不知道如何在互斥环境中设置视频捕获,只运行一次来设置帧。宽度和高度,然后作为网络摄像头图像缓冲区自由运行。下面是上述代码:

#include <memory>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <vector>
#include <cmath>
#include <opencv2/objdetect/objdetect.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include "opencv2/ocl/ocl.hpp"
#include <functional>
using namespace std;
using namespace cv;
typedef unsigned char uchar;
typedef unsigned int uint;
class FaceDetector
{
mutex imageLock, facesLock;
condition_variable imageAqcuired;
bool newImageAvailable;
Mat _img;
Mat _imgToWorkOn;
Mat _faceImages;
bool quit;
int c;
void acquireImage()
{
    while (!quit)
    {
        unique_lock<mutex> ulock(imageLock);
        imageAqcuired.wait(ulock,[&](){return !newImageAvailable;}); //only take new image after current one was consumed
        VideoCapture captureDevice(0);
        if (c = 1)
        {
        captureDevice.set(CV_CAP_PROP_FRAME_WIDTH, 620);
        captureDevice.set(CV_CAP_PROP_FRAME_HEIGHT, 480);
        c = 0;
        }
        Mat captureFrame;
        captureDevice>>captureFrame;
        transpose(captureFrame,captureFrame);
        flip(captureFrame,captureFrame,1);
        _img = captureFrame.clone();
        ulock.unlock();
        newImageAvailable = true;
        imageAqcuired.notify_one(); //notify that a new image is available
    }
}
void processImage()
{
    while (!quit)
    {
        unique_lock<mutex> ulock(imageLock);
        imageAqcuired.wait(ulock,[&](){return newImageAvailable;}); //wait untill a new image is available
        _imgToWorkOn = _img.clone();
        ulock.unlock();
        newImageAvailable = false;
        imageAqcuired.notify_one(); //notify the current image can be replaced by a newer one
        unique_lock<mutex> lockFace(facesLock);
        //arbeit
        lockFace.unlock();
    }
}
public:
FaceDetector() : newImageAvailable(false) {}
void start() {
    quit = false;
    thread t1(&FaceDetector::acquireImage,this);
    t1.detach();
    thread t2(&FaceDetector::processImage,this);
    t2.detach();
}
void stop() {
    quit = true;
}
Mat getImage() {
    if (quit)
        return Mat();
    lock_guard<mutex> lock(imageLock);
    return _img;
}
Mat getProcessedImage() {
    if (quit)
        return Mat();
    lock_guard<mutex> lock(facesLock);
    return _faceImages;
}
};

int main()
{
bool quit(false);
int c = 1;
FaceDetector faceDet;
faceDet.start();
thread input([](bool &quitFlag) { getchar(); quitFlag = true; },ref(quit)); //stop on user press Enter
input.detach();
while (!quit) {

    Mat img = faceDet.getImage();
    Mat imgc = img.clone();
    imshow("links", imgc);
    /*
    imgs = faceDet.getProcessedImage();
    Mat imgsc = imgs.clone();
    imshow("gsichter", imgsc);
    */
    waitKey(30);
    this_thread::sleep_for(chrono::milliseconds(33)); //no need to show more than 30 fps...
}
faceDet.stop();
return 0;
}

我制作了一个示例代码供您根据需要修改。如果有不清楚的地方,欢迎提问。

#include <memory>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <vector>
#include <cmath>

using namespace std;
typedef unsigned char uchar;
typedef unsigned int uint;
class FaceDetector
{
    mutex imageLock, facesLock;
    condition_variable imageAqcuired;
    bool newImageAvailable;
    vector<uchar> _img;
    vector<uchar> _imgToWorkOn;
    vector<uchar> _faceImages;
    bool quit;
    void acquireImage()
    {
        while (!quit)
        {
            unique_lock<mutex> ulock(imageLock);
            imageAqcuired.wait(ulock,[&](){return !newImageAvailable;}); //only take new image after current one was consumed
            //aqcuire image from camera into _img here
            ulock.unlock();
            newImageAvailable = true;
            imageAqcuired.notify_one(); //notify that a new image is available
        }
    }
    void processImage()
    {
        while (!quit)
        {
            unique_lock<mutex> ulock(imageLock);
            imageAqcuired.wait(ulock,[&](){return newImageAvailable;}); //wait untill a new image is available
            _imgToWorkOn = _img;
            ulock.unlock();
            newImageAvailable = false;
            imageAqcuired.notify_one(); //notify the current image can be replaced by a newer one
            unique_lock<mutex> lockFace(facesLock);
            //process _imgToWorkOn, face detect... 
            lockFace.unlock();
        }
    }
public:
    FaceDetector() : _img(100000),_imgToWorkOn(100000), _faceImages(100000), newImageAvailable(false) {}
    void start() {
        quit = false;
        thread t1(&FaceDetector::acquireImage,this);
        t1.detach();
        thread t2(&FaceDetector::processImage,this);
        t2.detach();
    }
    void stop() {
        quit = true;
    }
    vector<uchar> getImage() {
        if (quit)
            return vector<uchar>();
        lock_guard<mutex> lock(imageLock);
        return _img;
    }
    vector<uchar> getProcessedImage() {
        if (quit)
            return vector<uchar>();
        lock_guard<mutex> lock(facesLock);
        return _faceImages;
    }
};

int main()
{
    bool quit(false);
    FaceDetector faceDet;
    faceDet.start();
    thread input([](bool &quitFlag) { getchar(); quitFlag = true; },ref(quit)); //stop on user press Enter
    input.detach();
    while (!quit) {
        vector<uchar> img = faceDet.getImage();
        if (img.size()) 
        {  /*show image*/ }  
        img = faceDet.getProcessedImage();
        if (img.size()) {  /*show image*/ }
        this_thread::sleep_for(chrono::milliseconds(33)); //no need to show more than 30 fps...
    }
    faceDet.stop();
    return 0;
}