C/C++ 多线程问题

该博客介绍了在处理两个视频流时遇到的问题,即两个线程同时从帧中取数据导致内存错误。通过引入互斥锁(mutex)解决了线程安全问题。代码示例展示了如何使用CUDA进行深度学习推理,特别是针对YOLOv5模型,处理来自RTSP摄像头的帧。程序实现了预处理、模型推理和结果解析,包括目标检测和特定行为识别。此外,还涉及了OpenCV、CUDA、线程管理和实时视频处理的细节。

两个线程同时取frame,无序push到queue,导致内存出错

mutex互斥锁解决

#include <iostream>
#include <opencv2/opencv.hpp>
#include <stdio.h>
#include "cuda_utils.h"
#include "logging.h"
#include "common.hpp"
#include "utils.h"
#include "calibrator.h"
#include <unistd.h>
#include <thread>
#include <chrono>
#include <string>
#include <queue>
#include <vector>
#include "invade.h"

using namespace cv;
using namespace std;

#define NMS_THRESH 0.4
#define CONF_THRESH 0.5
#define BATCH_SIZE 1

// stuff we know about the network and the input/output blobs
static const int INPUT_H = Yolo::INPUT_H;
static const int INPUT_W = Yolo::INPUT_W;
static const int OUTPUT_SIZE = Yolo::MAX_OUTPUT_BBOX_COUNT * sizeof(Yolo::Detection) / sizeof(float) + 1;  // we assume the yololayer outputs no more than MAX_OUTPUT_BBOX_COUNT boxes that conf >= 0.1
const char* INPUT_BLOB_NAME = "data";
const char* OUTPUT_BLOB_NAME = "prob";
static Logger gLogger;

const char *class_name[4] = {"1","2","3","4"};



class WrapData{
public:
    Mat img;
    string rtsp;
    int channel;
};

//WrapData::WrapData(cv::Mat& img,int channel, string& rtsp_address)

Mat get_secimg(Mat image,cv::Rect r)
{
    cout<<"r -> "<<r<<endl;
    Mat secimg = image(r);
    cv::imwrite("test.jpg",secimg);
}


int capture_show(int& channel, string& rtsp_address, queue<WrapData>& Wrap_images)
{
//    WrapData* Wrap_img = new WrapData();
//    this_thread.sleep_for()
    Mat frame;
    VideoCapture cap;
    cap.open(rtsp_address);
    if (!cap.isOpened()) {
        cerr << "ERROR! Unable to open camera\n";
        return -1;
    }
    for (;;)
    {
        WrapData* Wrap_img = new WrapData();
        // wait for a new frame from camera and store it into 'frame'
        cap.read(frame);
        // check if we succeeded
        if (frame.empty() || frame.cols == 0 || frame.rows == 0) {
            cerr << "ERROR! blank frame grabbed\n";
            continue;
        }
        if (Wrap_images.size() < 2|| Wrap_images.size()%2 == channel ){
            Wrap_img->rtsp = rtsp_address;
            Wrap_img->img = frame;
            Wrap_img->channel = channel;
            Wrap_images.push(*Wrap_img);

        }
        else{
            delete Wrap_img;
        }

    }
    cap.release();
    return 1;
}


void doInference(IExecutionContext& context, cudaStream_t& stream, void **buffers, float* input, float* output, int batchSize) {
    // DMA input batch data to device, infer on the batch asynchronously, and DMA output back to host
    CUDA_CHECK(cudaMemcpyAsync(buffers[0], input, batchSize * 3 * INPUT_H * INPUT_W * sizeof(float), cudaMemcpyHostToDevice, stream));
    context.enqueue(batchSize, buffers, stream, nullptr);
    CUDA_CHECK(cudaMemcpyAsync(output, buffers[1], batchSize * OUTPUT_SIZE * sizeof(float), cudaMemcpyDeviceToHost, stream));
    cudaStreamSynchronize(stream);
}


int main()
{
    queue<WrapData> Wrap_images;
    Mat image;
    string imgname;
    vector<string> rtsps;
    vector<int> channels;
    int head_num,person_num,cellphone_num = 0;
    float sum,blacksum, black_rate = 0;
    string rtsp1 = "rtsp://admin:a12345678@192.168.1.2:554/Streaming/Channels/302";
    string rtsp2 = "rtsp://admin:a12345678@192.168.1.2:554/Streaming/Channels/202";
//    string rtsp1 = "rtsp://192.168.11.116/stream1";
//    string rtsp2 = "rtsp://192.168.11.116/stream2";


    int chno1 = 0;
    int chno2 = 1;
    rtsps.push_back(rtsp1);
    rtsps.push_back(rtsp2);

    channels.push_back(chno1);
    channels.push_back(chno2);


    // std::thread thread_size(printsize,std::ref(images));

    std::string engine_name = "rail_trt7.engine";
    // deserialize the .engine and run inference
    std::ifstream file(engine_name, std::ios::binary);
    if (!file.good()) {
        std::cerr << "read " << engine_name << " error!" << std::endl;
        return -1;
    }

    char *trtModelStream = nullptr;
    size_t size = 0;
    file.seekg(0, file.end);
    size = file.tellg();
    file.seekg(0, file.beg);
    trtModelStream = new char[size];
    assert(trtModelStream);
    file.read(trtModelStream, size);
    file.close();

    static float data[BATCH_SIZE * 3 * INPUT_H * INPUT_W];
    printf("batch_size: %d --- data_size: %d!!!\n",BATCH_SIZE,BATCH_SIZE * 3 * INPUT_H * INPUT_W);
    static float prob[BATCH_SIZE * OUTPUT_SIZE];
    IRuntime* runtime = createInferRuntime(gLogger);
    assert(runtime != nullptr);
    ICudaEngine* engine = runtime->deserializeCudaEngine(trtModelStream, size);
    assert(engine != nullptr);
    IExecutionContext* context = engine->createExecutionContext();
    assert(context != nullptr);
    delete[] trtModelStream;
    assert(engine->getNbBindings() == 2);
    void* buffers[2];
    // In order to bind the buffers, we need to know the names of the input and output tensors.
    // Note that indices are guaranteed to be less than IEngine::getNbBindings()
    const int inputIndex = engine->getBindingIndex(INPUT_BLOB_NAME);
    const int outputIndex = engine->getBindingIndex(OUTPUT_BLOB_NAME);
    assert(inputIndex == 0);
    assert(outputIndex == 1);
    // Create GPU buffers on device
    CUDA_CHECK(cudaMalloc(&buffers[inputIndex], BATCH_SIZE * 3 * INPUT_H * INPUT_W * sizeof(float)));
    CUDA_CHECK(cudaMalloc(&buffers[outputIndex], BATCH_SIZE * OUTPUT_SIZE * sizeof(float)));
    // Create stream
    cudaStream_t stream;
    CUDA_CHECK(cudaStreamCreate(&stream));

    string window_name1 = "Yolov5 USB Camera1";
    string window_name2 = "Yolov5 USB Camera2";
    namedWindow(window_name1);
    namedWindow(window_name2);

    std::thread video1(capture_show, std::ref(channels[0]), std::ref(rtsps[0]), std::ref(Wrap_images));
    std::thread video2(capture_show, std::ref(channels[1]), std::ref(rtsps[1]), std::ref(Wrap_images));

    while(1)
    {

        if (Wrap_images.size()>0)
        {

            if (Wrap_images.front().img.cols == 0 || Wrap_images.front().img.rows == 0){continue;}
            cv::Mat pr_img = preprocess_img(Wrap_images.front().img, INPUT_W, INPUT_H); // letterbox BGR to RGB & resize
            cv::Mat ori_img = pr_img.clone();
            // TODO: remove these parameters, no batch inteference
            int b=0, i=0;
            int fcount = 1;

            // This for loop is convert the cv::Mat into 1D Float array and pass into doInteference
            for (int row = 0; row < INPUT_H; ++row) {
                uchar* uc_pixel = pr_img.data + row * pr_img.step;
                for (int col = 0; col < INPUT_W; ++col) {
                    data[b * 3 * INPUT_H * INPUT_W + i] = (float)uc_pixel[2] / 255.0;
                    data[b * 3 * INPUT_H * INPUT_W + i + INPUT_H * INPUT_W] = (float)uc_pixel[1] / 255.0;
                    data[b * 3 * INPUT_H * INPUT_W + i + 2 * INPUT_H * INPUT_W] = (float)uc_pixel[0] / 255.0;
                    uc_pixel += 3;
                    ++i;
                }
            }

            // Run inference
            auto start = std::chrono::system_clock::now();
            doInference(*context, stream, buffers, data, prob, BATCH_SIZE);
            auto end = std::chrono::system_clock::now();
             std::cout << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() << "ms" << std::endl;
            // std::cout<<"FPS: "<<int(1000/std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count())<<std::endl;
            std::vector<std::vector<Yolo::Detection>> batch_res(fcount);

            for (int b = 0; b < fcount; b++) {
                auto& res = batch_res[b];
                nms(res, &prob[b * OUTPUT_SIZE], CONF_THRESH, NMS_THRESH);
            }

            for (int b = 0; b < fcount; b++) {
                auto& res = batch_res[b];

                for (size_t j = 0; j < res.size(); j++) {
                    cv::Rect r = get_rect(pr_img, res[j].bbox);
                    cv::Rect helmet_r = cv::Rect(r.x,r.y,r.width,r.height/2);
                    cv::rectangle(pr_img, r, cv::Scalar(0x27, 0xC1, 0x36), 2);

                    if ((int)res[j].class_id == 0)
                    {
                        cv:Mat imgThresholded;
                        sum = 0;
                        blacksum = 0;
                        black_rate = 0;
                        head_num++;
                        cv::Mat dst = ori_img(helmet_r);
                        inRange(dst, Scalar(0, 0, 0), Scalar(127, 127, 127), imgThresholded); //黑色
                        for(int i = 0; i < imgThresholded.rows; ++i){         //遍历行
                            for(int j = 0; j < imgThresholded.cols; ++j){
                                sum++;
                                if (imgThresholded.at<uchar>(i, j)>10){blacksum++;}}}
                        black_rate = blacksum/sum;
                        if (black_rate > 0.85){
                            cv::putText(pr_img, " helmet W", cv::Point(r.x, r.y - 1), cv::FONT_HERSHEY_PLAIN, 1.2, cv::Scalar(0xFF, 0xFF, 0xFF), 2);
                        }
                    }

                    if ((int)res[j].class_id == 1)
                    {
                        pr_img = get_invade_area_scene1(pr_img);
                    }
                    if ((int)res[j].class_id == 2)
                    {
                        cv::putText(pr_img, " cellphone W", cv::Point(r.x, r.y - 1), cv::FONT_HERSHEY_PLAIN, 1.2, cv::Scalar(0xFF, 0xFF, 0xFF), 2);

                    }
                    cv::putText(pr_img, class_name[(int)res[j].class_id], cv::Point(r.x, r.y - 1), cv::FONT_HERSHEY_PLAIN, 1.2, cv::Scalar(0xFF, 0xFF, 0xFF), 2);
                }

                if (Wrap_images.front().channel == 0){
                    imshow(window_name1, pr_img);
                }
                if (Wrap_images.front().channel == 1){
                    imshow(window_name2, pr_img);
                }
            }
            Wrap_images.pop();

        }
         if (waitKey(10) == 27)
        {
            cout << "Esc key is pressed by user. Stoppig the video" << endl;
            break;
        }
    }
    cudaStreamDestroy(stream);
    CUDA_CHECK(cudaFree(buffers[inputIndex]));
    CUDA_CHECK(cudaFree(buffers[outputIndex]));
    // Destroy the engine
    context->destroy();
    engine->destroy();
    runtime->destroy();

}


评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值