2024-05-24 19:10:41 +08:00
|
|
|
#include "capture.h"
|
|
|
|
|
|
|
|
|
|
#include <vector>
|
|
|
|
|
#include <thread>
|
2024-05-27 16:00:05 +08:00
|
|
|
#include <opencv2/core.hpp>
|
|
|
|
|
#include <opencv2/opencv.hpp>
|
2024-05-24 19:10:41 +08:00
|
|
|
#include <opencv2/highgui.hpp>
|
|
|
|
|
#include <zmq.hpp>
|
|
|
|
|
#include "logc/log.h"
|
2024-05-27 16:00:05 +08:00
|
|
|
#include <unistd.h>
|
2024-05-24 19:10:41 +08:00
|
|
|
|
2024-08-08 23:28:58 +08:00
|
|
|
void adjustImageTemperature(cv::Mat &img, float scale)
|
|
|
|
|
{
|
|
|
|
|
// 分离通道
|
|
|
|
|
std::vector<cv::Mat> channels;
|
|
|
|
|
split(img, channels);
|
|
|
|
|
|
|
|
|
|
// 增加蓝色通道和绿色通道的值,减少红色通道的值
|
|
|
|
|
channels[0] = channels[0] * scale; // 蓝色通道
|
|
|
|
|
channels[1] = channels[1] * scale; // 绿色通道
|
|
|
|
|
channels[2] = channels[2] / scale; // 红色通道
|
|
|
|
|
|
|
|
|
|
// 合并通道
|
|
|
|
|
merge(channels, img);
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-17 22:16:28 +08:00
|
|
|
capture::capture(int camera_index, int zmq_port, int width_set, int height_set, int fps_set, bool _flip)
|
2024-05-24 19:10:41 +08:00
|
|
|
{
|
|
|
|
|
index = camera_index;
|
|
|
|
|
port = zmq_port;
|
|
|
|
|
width = width_set;
|
|
|
|
|
height = height_set;
|
|
|
|
|
fps = fps_set;
|
2024-06-17 22:16:28 +08:00
|
|
|
flip = _flip;
|
2024-05-24 19:10:41 +08:00
|
|
|
|
2024-08-08 23:28:58 +08:00
|
|
|
log_info("尝试开启摄像头 %d", index);
|
2024-05-24 19:10:41 +08:00
|
|
|
|
|
|
|
|
cap = new cv::VideoCapture(index, cv::CAP_V4L2);
|
2024-08-08 23:28:58 +08:00
|
|
|
|
|
|
|
|
sleep(2); // 等待两秒进行构造
|
|
|
|
|
|
2024-05-24 19:10:41 +08:00
|
|
|
cap->set(cv::CAP_PROP_FRAME_WIDTH, width);
|
|
|
|
|
cap->set(cv::CAP_PROP_FRAME_HEIGHT, height);
|
|
|
|
|
cap->set(cv::CAP_PROP_FPS, fps);
|
|
|
|
|
|
2024-08-08 23:28:58 +08:00
|
|
|
// if (10 == camera_index)
|
|
|
|
|
// {
|
|
|
|
|
// int fourcc = cv::VideoWriter::fourcc('M', 'J', 'P', 'G'); // 例如,使用 MJPG 编码
|
|
|
|
|
// // 设置输出视频的分辨率和帧率,与输入视频一致或根据需要调整
|
|
|
|
|
// cv::Size frameSize = cv::Size((int)cap->get(cv::CAP_PROP_FRAME_WIDTH),
|
|
|
|
|
// (int)cap->get(cv::CAP_PROP_FRAME_HEIGHT));
|
|
|
|
|
// int fps = (int)cap->get(cv::CAP_PROP_FPS);
|
|
|
|
|
// writer = new cv::VideoWriter("/home/evan/Workplace/project_capture/capture.avi", fourcc, fps, frameSize, true);
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
int cnt = 1;
|
|
|
|
|
for (int i = 20; i > 0; i--)
|
2024-05-24 19:10:41 +08:00
|
|
|
{
|
2024-08-08 23:28:58 +08:00
|
|
|
if (cap->isOpened())
|
|
|
|
|
{
|
|
|
|
|
status = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
log_error("开启摄像头 %d 失败,重试中", index);
|
|
|
|
|
cap->open(index, cv::CAP_V4L2);
|
|
|
|
|
usleep(100000);
|
2024-05-24 19:10:41 +08:00
|
|
|
status = false;
|
|
|
|
|
}
|
2024-08-08 23:28:58 +08:00
|
|
|
|
|
|
|
|
if (status)
|
2024-05-24 19:10:41 +08:00
|
|
|
{
|
2024-07-04 17:50:05 +08:00
|
|
|
log_info("开启摄像头 %d 成功", index);
|
2024-08-08 23:28:58 +08:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
log_fatal("开启摄像头 %d 十次重试后失败", index);
|
2024-05-24 19:10:41 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
context = new zmq::context_t(1);
|
2024-05-29 21:51:28 +08:00
|
|
|
socket = new zmq::socket_t(*context, ZMQ_REP);
|
|
|
|
|
// int hwm = 10;
|
|
|
|
|
// socket->setsockopt(ZMQ_SNDHWM, &hwm, sizeof(hwm));
|
2024-05-24 19:10:41 +08:00
|
|
|
char zmq_bind_port[10] = {0};
|
|
|
|
|
sprintf(zmq_bind_port, "%d", port);
|
|
|
|
|
strcat(zmq_bind_addr, zmq_bind_port);
|
2024-07-04 17:50:05 +08:00
|
|
|
log_info("设置 %d zmq 地址 %s", index, zmq_bind_addr);
|
2024-05-24 19:10:41 +08:00
|
|
|
socket->bind(zmq_bind_addr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void capture::start(void)
|
|
|
|
|
{
|
|
|
|
|
if (this->is_open())
|
|
|
|
|
{
|
2024-07-04 17:50:05 +08:00
|
|
|
log_info("开启摄像头 %d 采集和应答线程", index);
|
|
|
|
|
// FIXME request 启动后若 capture 尚未读取到有效帧,则会断言
|
|
|
|
|
thread_capture = new std::thread(&capture::get, this);
|
|
|
|
|
sleep(1);
|
|
|
|
|
thread_request = new std::thread(&capture::req, this);
|
2024-05-24 19:10:41 +08:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2024-07-04 17:50:05 +08:00
|
|
|
log_error("摄像头 %d 未成功初始化,跳过", index);
|
2024-05-24 19:10:41 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-07-04 17:50:05 +08:00
|
|
|
void capture::get(void)
|
2024-05-24 19:10:41 +08:00
|
|
|
{
|
2024-05-27 16:00:05 +08:00
|
|
|
cv::Mat dst;
|
2024-05-24 19:10:41 +08:00
|
|
|
while (1)
|
|
|
|
|
{
|
2024-07-04 17:50:05 +08:00
|
|
|
*cap >> dst;
|
|
|
|
|
if (dst.empty())
|
2024-05-24 19:10:41 +08:00
|
|
|
{
|
2024-07-04 17:50:05 +08:00
|
|
|
log_error("摄像头 %d 读取到空帧,尝试销毁后重启", index);
|
|
|
|
|
|
|
|
|
|
cap->release();
|
|
|
|
|
// delete cap;
|
|
|
|
|
|
|
|
|
|
cap = new cv::VideoCapture(index, cv::CAP_V4L2);
|
|
|
|
|
cap->set(cv::CAP_PROP_FRAME_WIDTH, width);
|
|
|
|
|
cap->set(cv::CAP_PROP_FRAME_HEIGHT, height);
|
|
|
|
|
cap->set(cv::CAP_PROP_FPS, fps);
|
|
|
|
|
|
|
|
|
|
log_warn("摄像头 %d 重新构造完成\r\n", index);
|
|
|
|
|
*cap >> dst;
|
2024-05-24 19:10:41 +08:00
|
|
|
}
|
|
|
|
|
|
2024-08-08 23:28:58 +08:00
|
|
|
// if(nullptr != writer){
|
|
|
|
|
// writer->write(dst);
|
|
|
|
|
// }
|
|
|
|
|
|
2024-05-24 19:10:41 +08:00
|
|
|
// 确保图像是连续的
|
2024-07-04 17:50:05 +08:00
|
|
|
if (!dst.isContinuous())
|
2024-05-24 19:10:41 +08:00
|
|
|
{
|
2024-07-04 17:50:05 +08:00
|
|
|
dst = dst.clone().reshape(1, dst.total());
|
2024-05-24 19:10:41 +08:00
|
|
|
}
|
2024-07-01 01:30:45 +08:00
|
|
|
|
|
|
|
|
// 中心翻转处理
|
2024-06-17 22:16:28 +08:00
|
|
|
if (flip)
|
|
|
|
|
{
|
2024-07-04 17:50:05 +08:00
|
|
|
cv::flip(dst, dst, -1);
|
2024-06-17 22:16:28 +08:00
|
|
|
}
|
2024-05-27 16:00:05 +08:00
|
|
|
|
2024-08-08 23:28:58 +08:00
|
|
|
// adjustImageTemperature(dst, 1.2);
|
|
|
|
|
|
2024-07-01 01:30:45 +08:00
|
|
|
// 将图像转换为 rgb
|
2024-07-04 17:50:05 +08:00
|
|
|
cv::cvtColor(dst, frame, cv::COLOR_BGR2RGB);
|
|
|
|
|
|
|
|
|
|
// 在这里添加一些延迟,以控制帧率
|
|
|
|
|
cv::waitKey(1);
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-05-24 19:10:41 +08:00
|
|
|
|
2024-07-04 17:50:05 +08:00
|
|
|
void capture::req(void)
|
|
|
|
|
{
|
|
|
|
|
zmq::message_t msg_temp;
|
|
|
|
|
while (1)
|
|
|
|
|
{
|
|
|
|
|
socket->recv(&msg_temp);
|
2024-05-24 19:10:41 +08:00
|
|
|
// 将帧编码后发送
|
2024-05-27 16:00:05 +08:00
|
|
|
std::vector<uchar>
|
|
|
|
|
buff;
|
2024-07-04 17:50:05 +08:00
|
|
|
cv::imencode(".jpg", frame, buff);
|
2024-05-24 19:10:41 +08:00
|
|
|
zmq::message_t message(buff.size());
|
|
|
|
|
memcpy(message.data(), buff.data(), buff.size());
|
|
|
|
|
socket->send(message, zmq::send_flags::none);
|
|
|
|
|
}
|
2024-07-01 01:30:45 +08:00
|
|
|
|
|
|
|
|
log_error("capture exit");
|
2024-05-24 19:10:41 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool capture::is_open(void)
|
|
|
|
|
{
|
|
|
|
|
return status;
|
|
|
|
|
}
|