#include <iostream>
#include <opencv2/opencv.hpp>
#include <thread>
#include <conio.h>
#include <windows.h>
#include <time.h>
#include <condition_variable>
#include <semaphore>
using namespace std;
//使用锁来实现一个信号量类
class MySemaphore {
public:
MySemaphore(int initialValue) : count(initialValue), x(-1) {}
int acquire() {
std::unique_lock<std::mutex> lock(mutex);//锁保护{}
condition.wait(lock, [this]() { return count > 0; });
count--;
x++;//帧个数+1
std::cout << "acquire目前还有" << count << "个信号量" << std::endl;
return x;
}
void release() {
cout << "释放一个信号量!!" << endl;
std::unique_lock<std::mutex> lock(mutex);//锁保护{}
count++;//信号量个数+1
condition.notify_one();
std::cout << "目前还有" << count << "个信号量" << std::endl;
}
int getX() {
std::unique_lock<std::mutex> lock(mutex);//锁保护{}
return x;
}
private:
int count;
int x;
std::mutex mutex;
std::condition_variable condition;
};
counting_semaphore sem(0);//现实信号量
int width = 640; // 设置视频帧宽度
int heigth = 480; // 设置视频帧高度
int FPS_SET = 30; // 设置帧率
int key = 0; // 进程控制标志
std::mutex g_mutex1; // 创建互斥锁,用于保护共享资源
std::mutex g_mutex2; // 创建互斥锁,用于保护共享资源
std::map<int64_t, cv::Mat> frames; //创建map,用于存储转换后的帧 // 创建队列,用于存储图像帧
std::map<int64_t, cv::Mat> frames_re; //创建map,用于存储转换后的帧
void reverseFrame(const cv::Mat& inputFrame, cv::Mat& outputFrame) {
cv::cvtColor(inputFrame, outputFrame, cv::COLOR_BGR2RGB); // 图像反转函数
}
void getframe(MySemaphore& sem) {
cout << "正在打开摄像头" << endl;
cv::VideoCapture cap;
/* cap.open(1);*/
cap.open("H:\\WeChatfile\\WeChat Files\\wxid_4h6srkxhh8z022\\FileStorage\\Video\\2023-10\\df8caca82576ca92c088b26ab901b241.mp4");
cap.set(cv::CAP_PROP_FRAME_WIDTH, width); // 设置视频帧宽度
cap.set(cv::CAP_PROP_FRAME_HEIGHT, heigth); // 设置视频帧高度
cap.set(cv::CAP_PROP_FOURCC, cv::VideoWriter::fourcc('M', 'J', 'P', 'G')); // 设置视频流格式
cap.set(cv::CAP_PROP_FPS, FPS_SET); // 设置帧率
if (!cap.isOpened()) {
cout << "打开失败" << endl;
return;
}
cout << "打开成功" << endl;
int i = 0;
int delay = 1000 / FPS_SET;
cv::Mat frame2;
while (key != 27) {
//while (frames.size() > 10)//定义缓冲区大小
// Sleep(delay);
Sleep(delay);
cap >> frame2;
std::unique_lock<std::mutex> lock1(g_mutex1);
frames[i] = frame2;
lock1.unlock();
//释放一个帧信号量
sem.release();
i++;
}
cout << "正在解除摄像头占用" << endl;
cap.release();
cout << "成功解除摄像头占用" << endl;
}
void changeframe(MySemaphore& sem) {
cv::Mat frame1;
cv::Mat reversedframe;
int index;
do {
index = sem.acquire();//获取帧信号量
std::unique_lock<std::mutex> lock1(g_mutex1);//上锁
frame1 = frames[index];//获取当前处理的是第几帧
lock1.unlock();
reverseFrame(frame1, reversedframe); // 反转图像帧
std::unique_lock<std::mutex> lock2(g_mutex2);//上锁
frames_re[index] = reversedframe;
lock2.unlock();
} while (key != 27);
}
void showframe() {
int font_face = cv::FONT_HERSHEY_COMPLEX;
double font_scale = 1;
int thickness = 2;
int baseline;
cv::Point origin;
origin.x = 10;
origin.y = 30;
int FPS = 0;
double time = 0;
LARGE_INTEGER nFreq;
LARGE_INTEGER nBeginTime;
LARGE_INTEGER nEndTime;
QueryPerformanceFrequency(&nFreq);//查询性能计数器的频率
cv::Mat frame;
cv::namedWindow("frame");
int i = 0;//全局变量判断当前应该是第几帧哦
do {
cout << "显示while开始运行" << endl;
QueryPerformanceCounter(&nBeginTime);
std::unique_lock<std::mutex> lock2(g_mutex2);
auto it = frames_re.find(i); // 查找键为5的元素查找第i帧是否含有
if (it != frames_re.end()) {
cout << "显示成功" << endl;
frame = frames_re[i];
lock2.unlock();
i++;
string s = "FPS:" + to_string(FPS);
cv::putText(frame, s.c_str(), origin, font_face, font_scale, cv::Scalar(0, 255, 255), thickness, 8, 0);
if (!frame.empty())
cv::imshow("frame", frame);
cv::waitKey(1000 / FPS_SET);
QueryPerformanceCounter(&nEndTime);
time = (double)(nEndTime.QuadPart - nBeginTime.QuadPart) / (double)nFreq.QuadPart;
FPS = 1 / time;
}
else
{
cout << "显示失败" << endl;
lock2.unlock();
}
} while (key != 27);
cv::destroyWindow("frame");
}
int main() {
MySemaphore sem(0); // 初始信号量为0
thread t1(getframe, std::ref(sem)); // 启动获取帧的线程
t1.detach();
thread t2(showframe); // 启动显示帧的线程
t2.detach();
thread t3(changeframe, std::ref(sem)); // 启动转换帧的线程
t3.detach();
thread t4(changeframe, std::ref(sem)); // 启动转换帧的线程
t4.detach();
thread t5(changeframe, std::ref(sem)); // 启动转换帧的线程
t5.detach();
//不让主线程结束
while (1) {
Sleep(500);
if (_kbhit())
break;
}
key = 27; // 通知其他线程结束
Sleep(1000); // 等待线程结束
return 0;
}
互斥锁实现可以计数的信号量
于 2023-10-23 20:39:13 首次发布