Compare commits
7 Commits
b9a57f196d
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| aed1e7e55a | |||
| 7b34be682a | |||
| 564fd4439f | |||
| 4b33e55c57 | |||
| 463c6900df | |||
| 8897841258 | |||
| 69e2d61fae |
@@ -11,6 +11,8 @@ set(main main.cc
|
|||||||
set(LOGC logc/log.c)
|
set(LOGC logc/log.c)
|
||||||
set(TOML tomlc99/toml.c)
|
set(TOML tomlc99/toml.c)
|
||||||
|
|
||||||
|
# 设置彩色日志输出
|
||||||
|
add_definitions(-DLOG_USE_COLOR)
|
||||||
|
|
||||||
# 查找并添加 OpenCV 的头文件目录
|
# 查找并添加 OpenCV 的头文件目录
|
||||||
set(OpenCV_DIR ${CMAKE_SOURCE_DIR}/opencv-mobile-4.9.0-armlinux/lib/cmake/opencv4)
|
set(OpenCV_DIR ${CMAKE_SOURCE_DIR}/opencv-mobile-4.9.0-armlinux/lib/cmake/opencv4)
|
||||||
@@ -19,6 +21,9 @@ find_package(OpenCV REQUIRED)
|
|||||||
set(ZMQ zmq)
|
set(ZMQ zmq)
|
||||||
set(PTHREAD pthread)
|
set(PTHREAD pthread)
|
||||||
|
|
||||||
|
message("copy config file")
|
||||||
|
file(COPY config.toml DESTINATION ./)
|
||||||
|
|
||||||
message(STATUS " version: ${OpenCV_VERSION}")
|
message(STATUS " version: ${OpenCV_VERSION}")
|
||||||
message(STATUS " include path: ${OpenCV_INCLUDE_DIRS}")
|
message(STATUS " include path: ${OpenCV_INCLUDE_DIRS}")
|
||||||
include_directories(${OpenCV_INCLUDE_DIRS})
|
include_directories(${OpenCV_INCLUDE_DIRS})
|
||||||
|
|||||||
137
capture.cc
137
capture.cc
@@ -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)
|
||||||
|
|||||||
11
capture.h
11
capture.h
@@ -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);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
61
main.cc
61
main.cc
@@ -8,14 +8,17 @@
|
|||||||
#include "tomlc99/toml.h"
|
#include "tomlc99/toml.h"
|
||||||
#include "capture.h"
|
#include "capture.h"
|
||||||
|
|
||||||
#define config_file_path "../config.toml"
|
#define config_file_path "config.toml"
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
char errbuf[200];
|
char errbuf[200];
|
||||||
|
|
||||||
fp = fopen(config_file_path, "r");
|
char config_path[200];
|
||||||
|
sprintf(config_path, "%s/%s", getcwd(NULL, 0), config_file_path);
|
||||||
|
log_info("[capture] 从以下路径加载配置:%s", config_path);
|
||||||
|
fp = fopen(config_path, "r");
|
||||||
if (!fp)
|
if (!fp)
|
||||||
{
|
{
|
||||||
log_error("can not open conifg file");
|
log_error("can not open conifg file");
|
||||||
@@ -38,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;
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user