通过多线程技巧的使用进行视频处理

代码运行环境:

ubuntu16.04,QtCreator,Opencv3.4.10

其中一个线程用来获取视频流,一个线程用来显示,其余用于对视频帧的处理。

#include <thread>
#include <mutex>
#include <unistd.h>
#include <sys/time.h>
#include <opencv2/opencv.hpp>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>

int idxInputImage=0;  //image index of input video
int idxShowImage=0;   //next frame index to be display
bool bReading=true;   //flag of input

typedef std::pair<int,cv::Mat> imagePair;
class pairComp{
public:
    bool operator()(const imagePair&n1,const imagePair&n2) const{
        if(n1.first==n2.first) return n1.first>n2.first;
        return n1.first>n2.first;
    }
};

std::mutex mtxQueueInput;  //mutex of input queue
std::mutex mtxQueueShow;   //mutex of output queue

std::queue<std::pair<int,cv::Mat> > queueInput;
std::priority_queue<imagePair,std::vector<imagePair>,pairComp> queueShow;

double what_time_is_it_now()
{
    struct timeval time;
    if (gettimeofday(&time,NULL)){
        return 0;
    }
    return (double)time.tv_sec + (double)time.tv_usec * .000001;
}

void videoCapture(const char* videoDir)
{
        cpu_set_t mask;
        int cpuid = 2;

        CPU_ZERO(&mask);
        CPU_SET(cpuid, &mask);

        if (pthread_setaffinity_np(pthread_self(), sizeof(mask), &mask) < 0){
                std::cerr << "set thread affinity failed" <<std::endl;
        }
        printf("Bind VideoCapture process to CPU %d\n", cpuid);
//    std::string videoDir="rtsp://admin:yltx8888@192.168.37.210:554/h264/ch1/main/av_stream";
    cv::VideoCapture cap;
    cap.open(videoDir);
    if(!cap.isOpened()){
        printf("the video can't open succ!");
        return ;
    }
    while(true){
        usleep(1000);
        cv::Mat img;
        cap>>img;
        if(img.empty()){
            std::cerr<<"Fail to read image from rtsp"<<std::endl;
            break;
        }
        mtxQueueInput.lock();
        queueInput.push(std::make_pair(idxInputImage++,img));
        if(queueInput.size()>=30){
            mtxQueueInput.unlock();
            std::cout<<"[Warning] input queue size is "<<queueInput.size()<<std::endl;
            sleep(1);
        }
        else {
            mtxQueueInput.unlock();
        }

        if(bReading){
            continue;
        }
        else{
            cap.release();
            break;
        }
    }
}
void run_process(int thread_id)
{
    cpu_set_t mask;
    int cpuid = 0;
    //int ret = 0;

    if (thread_id == 0){
        cpuid = 4;
    }
    else if (thread_id == 1){
        cpuid = 5;
    }
    else if(thread_id==2){
        cpuid=6;
    }
     else{
        cpuid = 0;
    }

    CPU_ZERO(&mask);
    CPU_SET(cpuid, &mask);

        if (pthread_setaffinity_np(pthread_self(), sizeof(mask), &mask) < 0){
            std::cerr << "set thread affinity failed" << std::endl;
        }
    printf("Bind  run_process(%d) to CPU %d\n", thread_id, cpuid);
    while(true){
        std::pair<int,cv::Mat>pairIndexImage;
        mtxQueueInput.lock();
        if(queueInput.empty()){
            mtxQueueInput.unlock();
            usleep(1000);
            if(bReading){
                continue;
            }else{
                break;
            }
        }
        else{
            pairIndexImage=queueInput.front();
            queueInput.pop();
            mtxQueueInput.unlock();
        }
        cv::resize(pairIndexImage.second,pairIndexImage.second,cv::Size(640,360));
        cv::cvtColor(pairIndexImage.second,pairIndexImage.second,cv::COLOR_BGR2GRAY);
        cv::Canny(pairIndexImage.second,pairIndexImage.second,30,150,3);
        mtxQueueShow.lock();
        queueShow.push(pairIndexImage);
        mtxQueueShow.unlock();
    }
}

void displayImage()
{
    cpu_set_t mask;
    int cpuid = 3;

    CPU_ZERO(&mask);
    CPU_SET(cpuid, &mask);

    if (pthread_setaffinity_np(pthread_self(), sizeof(mask), &mask) < 0){
        std::cerr << "set thread affinity failed" << std::endl;
    }
    printf("Bind Display process to CPU %d\n", cpuid);
    cv::Mat img;
    int fps;
    double firstTime,lastTime;
    firstTime=what_time_is_it_now();
    while(true){
        mtxQueueShow.lock();
        if(queueShow.empty()){
            mtxQueueShow.unlock();
            usleep(1000);
        }
        else if(idxShowImage==queueShow.top().first){
            cv::Mat img=queueShow.top().second;
            std::string a=std::to_string(fps)+"FPS";
            cv::putText(img,a,cv::Point(15,15),1,1,cv::Scalar{0,0,255},2);
            cv::imshow("Test",img);
            idxShowImage++;
            queueShow.pop();
            mtxQueueShow.unlock();

            if(cv::waitKey(1)==27){
                cv::destroyAllWindows();
                bReading=false;
                break;
            }
            lastTime=what_time_is_it_now();
            fps=(int) 1/(lastTime-firstTime);
            firstTime=what_time_is_it_now();
        }else{
            mtxQueueShow.unlock();
        }
    }
}

int main()
{
    const char* rtsp="/home/images/test.avi";
    std::array<std::thread,5> threads;
    threads={std::thread(videoCapture,rtsp),
             std::thread(run_process,0),
             std::thread(run_process,1),
             std::thread(run_process,2),
             std::thread(displayImage)
             };

    for(int i=0;i<5;i++){
        threads[i].join();
    }

    return 0;
}

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值