Compare commits

..

5 Commits

Author SHA1 Message Date
bmy
aed1e7e55a pref: 增加开启摄像头失败重试功能 2024-08-08 23:28:58 +08:00
bmy
7b34be682a update 2024-07-04 17:50:05 +08:00
bmy
564fd4439f 暫存 2024-07-01 01:30:45 +08:00
bmy
4b33e55c57 feat: 增加图像翻转方法 2024-06-17 22:16:28 +08:00
bmy
463c6900df pref: 预先分配路径字符串数组,避免过长时动态分配失败 2024-06-04 12:23:09 +08:00
4 changed files with 120 additions and 96 deletions

View File

@@ -9,30 +9,72 @@
#include "logc/log.h" #include "logc/log.h"
#include <unistd.h> #include <unistd.h>
capture::capture(int camera_index, int zmq_port, int width_set, int height_set, int fps_set) 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);
}
capture::capture(int camera_index, int zmq_port, int width_set, int height_set, int fps_set, bool _flip)
{ {
index = camera_index; index = camera_index;
port = zmq_port; port = zmq_port;
width = width_set; width = width_set;
height = height_set; height = height_set;
fps = fps_set; fps = fps_set;
flip = _flip;
log_info("trying open camera %d", index); log_info("尝试开启摄像头 %d", index);
cap = new cv::VideoCapture(index, cv::CAP_V4L2); cap = new cv::VideoCapture(index, cv::CAP_V4L2);
sleep(2); // 等待两秒进行构造
cap->set(cv::CAP_PROP_FRAME_WIDTH, width); cap->set(cv::CAP_PROP_FRAME_WIDTH, width);
cap->set(cv::CAP_PROP_FRAME_HEIGHT, height); cap->set(cv::CAP_PROP_FRAME_HEIGHT, height);
cap->set(cv::CAP_PROP_FPS, fps); cap->set(cv::CAP_PROP_FPS, fps);
if (!cap->isOpened()) // 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--)
{ {
log_error("Error opening video stream in %d", index); if (cap->isOpened())
{
status = true;
break;
}
log_error("开启摄像头 %d 失败,重试中", index);
cap->open(index, cv::CAP_V4L2);
usleep(100000);
status = false; status = false;
} }
if (status)
{
log_info("开启摄像头 %d 成功", index);
}
else else
{ {
log_info("Successful opening video stream in %d", index); log_fatal("开启摄像头 %d 十次重试后失败", index);
status = true;
} }
context = new zmq::context_t(1); context = new zmq::context_t(1);
@@ -42,7 +84,7 @@ capture::capture(int camera_index, int zmq_port, int width_set, int height_set,
char zmq_bind_port[10] = {0}; char zmq_bind_port[10] = {0};
sprintf(zmq_bind_port, "%d", port); sprintf(zmq_bind_port, "%d", port);
strcat(zmq_bind_addr, zmq_bind_port); strcat(zmq_bind_addr, zmq_bind_port);
log_info("set camera %d zmq address test %s", index, zmq_bind_addr); log_info("设置 %d zmq 地址 %s", index, zmq_bind_addr);
socket->bind(zmq_bind_addr); socket->bind(zmq_bind_addr);
} }
@@ -50,63 +92,82 @@ void capture::start(void)
{ {
if (this->is_open()) if (this->is_open())
{ {
log_info("start camera %d capture thread", index); log_info("开启摄像头 %d 采集和应答线程", index);
thread = new std::thread(&capture::run, this); // FIXME request 启动后若 capture 尚未读取到有效帧,则会断言
thread_capture = new std::thread(&capture::get, this);
sleep(1);
thread_request = new std::thread(&capture::req, this);
} }
else else
{ {
log_error("camera %d have not been inited, exit", index); log_error("摄像头 %d 未成功初始化,跳过", index);
} }
} }
void capture::run(void) void capture::get(void)
{ {
cv::Mat dst; cv::Mat dst;
while (1) while (1)
{ {
zmq::message_t msg_temp; *cap >> dst;
socket->recv(&msg_temp); if (dst.empty())
*cap >> frame;
if (frame.empty())
{ {
log_error("empty frame"); log_error("摄像头 %d 读取到空帧,尝试销毁后重启", index);
break;
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;
} }
// if(nullptr != writer){
// writer->write(dst);
// }
// 确保图像是连续的 // 确保图像是连续的
if (!frame.isContinuous()) if (!dst.isContinuous())
{ {
frame = frame.clone().reshape(1, frame.total()); dst = dst.clone().reshape(1, dst.total());
} }
cv::cvtColor(frame, dst, cv::COLOR_BGR2RGB); // 中心翻转处理
if (flip)
{
cv::flip(dst, dst, -1);
}
// cv::imshow(zmq_bind_addr, frame); // adjustImageTemperature(dst, 1.2);
// 将图像转换为 rgb
cv::cvtColor(dst, frame, cv::COLOR_BGR2RGB);
// 在这里添加一些延迟,以控制帧率
cv::waitKey(1);
}
}
void capture::req(void)
{
zmq::message_t msg_temp;
while (1)
{
socket->recv(&msg_temp);
// 将帧编码后发送 // 将帧编码后发送
std::vector<uchar> std::vector<uchar>
buff; buff;
cv::imencode(".jpg", dst, buff); cv::imencode(".jpg", frame, buff);
zmq::message_t message(buff.size()); zmq::message_t message(buff.size());
memcpy(message.data(), buff.data(), buff.size()); memcpy(message.data(), buff.data(), buff.size());
socket->send(message, zmq::send_flags::none); socket->send(message, zmq::send_flags::none);
// 发送帧的元数据(宽度、高度、类型等)
// 这里简单起见,只发送宽度和高度(假设类型为 CV_8UC3
// zmq::message_t header_msg(sizeof(int) * 2);
// int *header_data = static_cast<int *>(header_msg.data());
// header_data[0] = frame.cols;
// header_data[1] = frame.rows;
// socket.send(header_msg, zmq::send_flags::sndmore);
// 发送帧数据
// zmq::message_t frame_msg((size_t)frame.total() * frame.elemSize());
// memcpy(frame_msg.data(), frame.data, frame.total() * frame.elemSize());
// socket->send(frame_msg, zmq::send_flags::none);
// 在这里添加一些延迟,以控制帧率
cv::waitKey(1);
// usleep(20000);
} }
log_error("capture exit");
} }
bool capture::is_open(void) bool capture::is_open(void)

View File

@@ -15,16 +15,21 @@ public:
int height; int height;
int fps; int fps;
bool status = false; bool status = false;
bool flip = false;
char zmq_bind_addr[40] = "tcp://*:"; char zmq_bind_addr[40] = "tcp://*:";
std::thread *thread;
std::thread *thread_capture;
std::thread *thread_request;
cv::VideoCapture *cap; cv::VideoCapture *cap;
cv::Mat frame; cv::Mat frame;
zmq::context_t *context; zmq::context_t *context;
zmq::socket_t *socket; zmq::socket_t *socket;
cv::VideoWriter *writer = nullptr;
capture(int camera_index, int zmq_port, int width_set = 320, int height_set = 240, int fps_set = 20); capture(int camera_index, int zmq_port, int width_set = 320, int height_set = 240, int fps_set = 20, bool flip = false);
void start(void); void start(void);
void run(void); void get(void);
void req(void);
bool is_open(void); bool is_open(void);
}; };

View File

@@ -1,10 +1,10 @@
[server] [server]
server_0_index = 0 server_0_index = 10
server_0_port = 5555 server_0_port = 5555
server_1_index = 2 server_1_index = 15
server_1_port = 5556 server_1_port = 5556
server_2_index = 4 server_2_index = 20
server_2_port = 5557 server_2_port = 5557

60
main.cc
View File

@@ -15,11 +15,9 @@ int main(int argc, char **argv)
FILE *fp; FILE *fp;
char errbuf[200]; char errbuf[200];
char *config_path; char config_path[200];
config_path = getcwd(NULL, 0); sprintf(config_path, "%s/%s", getcwd(NULL, 0), config_file_path);
sprintf(config_path, "%s/%s", config_path, config_file_path); log_info("[capture] 从以下路径加载配置:%s", config_path);
log_info("load config from %s", config_path);
fp = fopen(config_path, "r"); fp = fopen(config_path, "r");
if (!fp) if (!fp)
{ {
@@ -43,60 +41,20 @@ int main(int argc, char **argv)
toml_datum_t server_0_index = toml_int_in(server, "server_0_index"); toml_datum_t server_0_index = toml_int_in(server, "server_0_index");
toml_datum_t server_1_index = toml_int_in(server, "server_1_index"); toml_datum_t server_1_index = toml_int_in(server, "server_1_index");
toml_datum_t server_2_index = toml_int_in(server, "server_2_index"); // toml_datum_t server_2_index = toml_int_in(server, "server_2_index");
toml_datum_t server_0_port = toml_int_in(server, "server_0_port"); toml_datum_t server_0_port = toml_int_in(server, "server_0_port");
toml_datum_t server_1_port = toml_int_in(server, "server_1_port"); toml_datum_t server_1_port = toml_int_in(server, "server_1_port");
toml_datum_t server_2_port = toml_int_in(server, "server_2_port"); // toml_datum_t server_2_port = toml_int_in(server, "server_2_port");
capture cap0(server_0_index.u.i, server_0_port.u.i); capture cap0(server_0_index.u.i, server_0_port.u.i);
capture cap1(server_1_index.u.i, server_1_port.u.i, 320, 240, 25); capture cap1(server_1_index.u.i, server_1_port.u.i, 320, 240, 60, true);
capture cap2(server_2_index.u.i, server_2_port.u.i); // capture cap2(server_2_index.u.i, server_2_port.u.i, 640, 480);
cap0.start(); cap0.start();
cap1.start(); cap1.start();
cap2.start(); // cap2.start();
while (1) cap1.thread_request->join();
{
usleep(1);
}
// while (true)
// {
// cap >> frame;
// if (frame.empty())
// {
// std::cerr << "Empty frame" << std::endl;
// break;
// }
// // 确保图像是连续的
// if (!frame.isContinuous())
// {
// frame = frame.clone().reshape(1, frame.total());
// }
// // std::cout << frame.cols << ":" << frame.rows << std::endl;
// // cv::imshow("realtime", frame);
// // 发送帧的元数据(宽度、高度、类型等)
// // 这里简单起见,只发送宽度和高度(假设类型为 CV_8UC3
// zmq::message_t header_msg(sizeof(int) * 2);
// int *header_data = static_cast<int *>(header_msg.data());
// header_data[0] = frame.cols;
// header_data[1] = frame.rows;
// // socket.send(header_msg, zmq::send_flags::sndmore);
// // 发送帧数据
// zmq::message_t frame_msg((size_t)frame.total() * frame.elemSize());
// memcpy(frame_msg.data(), frame.data, frame.total() * frame.elemSize());
// socket.send(frame_msg, zmq::send_flags::none);
// // 在这里添加一些延迟,以控制帧率
// cv::waitKey(1);
// }
// // 关闭视频捕获和 ZMQ 套接字
// cap.release();
// socket.close();
return 0; return 0;
} }