174 lines
4.5 KiB
C++
174 lines
4.5 KiB
C++
#include "usbcamera.hpp"
|
|
|
|
#include <stdexcept>
|
|
|
|
#include "tools/logger.hpp"
|
|
#include "tools/yaml.hpp"
|
|
|
|
using namespace std::chrono_literals;
|
|
|
|
namespace io
|
|
{
|
|
USBCamera::USBCamera(const std::string & open_name, const std::string & config_path)
|
|
: open_name_(open_name), quit_(false), ok_(false), queue_(1), open_count_(0)
|
|
{
|
|
auto yaml = tools::load(config_path);
|
|
image_width_ = tools::read<double>(yaml, "image_width");
|
|
image_height_ = tools::read<double>(yaml, "image_height");
|
|
usb_exposure_ = tools::read<double>(yaml, "usb_exposure");
|
|
usb_frame_rate_ = tools::read<double>(yaml, "usb_frame_rate");
|
|
usb_gamma_ = tools::read<double>(yaml, "usb_gamma");
|
|
usb_gain_ = tools::read<double>(yaml, "usb_gain");
|
|
try_open();
|
|
|
|
// 守护线程
|
|
daemon_thread_ = std::thread{[this] {
|
|
// tools::logger()->info("daemon thread start");
|
|
while (!quit_) {
|
|
std::this_thread::sleep_for(100ms);
|
|
|
|
if (ok_) continue;
|
|
|
|
if (open_count_ > 20) {
|
|
tools::logger()->warn("Give up to open {} USB camera", this->device_name);
|
|
quit_ = true;
|
|
|
|
{
|
|
std::lock_guard<std::mutex> lock(cap_mutex_);
|
|
close(); // 先关闭摄像头
|
|
}
|
|
|
|
if (capture_thread_.joinable()) {
|
|
tools::logger()->warn("Stopping capture thread");
|
|
capture_thread_.join();
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
if (capture_thread_.joinable()) capture_thread_.join();
|
|
|
|
{
|
|
std::lock_guard<std::mutex> lock(cap_mutex_);
|
|
close();
|
|
}
|
|
try_open();
|
|
}
|
|
// tools::logger()->info("daemon thread exit");
|
|
}};
|
|
}
|
|
|
|
USBCamera::~USBCamera()
|
|
{
|
|
quit_ = true;
|
|
{
|
|
std::lock_guard<std::mutex> lock(cap_mutex_);
|
|
close();
|
|
}
|
|
if (daemon_thread_.joinable()) daemon_thread_.join();
|
|
if (capture_thread_.joinable()) capture_thread_.join();
|
|
tools::logger()->info("USBCamera destructed.");
|
|
}
|
|
|
|
cv::Mat USBCamera::read()
|
|
{
|
|
std::lock_guard<std::mutex> lock(cap_mutex_);
|
|
if (!cap_.isOpened()) {
|
|
tools::logger()->warn("Failed to read {} USB camera", this->device_name);
|
|
return cv::Mat();
|
|
}
|
|
cap_ >> img_;
|
|
return img_;
|
|
}
|
|
|
|
void USBCamera::read(cv::Mat & img, std::chrono::steady_clock::time_point & timestamp)
|
|
{
|
|
CameraData data;
|
|
queue_.pop(data);
|
|
|
|
img = data.img;
|
|
timestamp = data.timestamp;
|
|
}
|
|
|
|
void USBCamera::open()
|
|
{
|
|
std::lock_guard<std::mutex> lock(cap_mutex_);
|
|
std::string true_device_name = "/dev/" + open_name_;
|
|
cap_.open(true_device_name, cv::CAP_V4L);
|
|
if (!cap_.isOpened()) {
|
|
tools::logger()->warn("Failed to open USB camera");
|
|
return;
|
|
}
|
|
sharpness_ = cap_.get(cv::CAP_PROP_SHARPNESS);
|
|
cap_.set(cv::CAP_PROP_FOURCC, cv::VideoWriter::fourcc('M', 'J', 'P', 'G'));
|
|
cap_.set(cv::CAP_PROP_FPS, usb_frame_rate_);
|
|
cap_.set(cv::CAP_PROP_AUTO_EXPOSURE, 1);
|
|
cap_.set(cv::CAP_PROP_GAMMA, usb_gamma_);
|
|
cap_.set(cv::CAP_PROP_GAIN, usb_gain_);
|
|
|
|
if (sharpness_ == 2) {
|
|
device_name = "left";
|
|
cap_.set(cv::CAP_PROP_FRAME_WIDTH, image_width_);
|
|
cap_.set(cv::CAP_PROP_FRAME_HEIGHT, image_height_);
|
|
cap_.set(cv::CAP_PROP_EXPOSURE, usb_exposure_);
|
|
} else if (sharpness_ == 3) {
|
|
device_name = "right";
|
|
cap_.set(cv::CAP_PROP_FRAME_WIDTH, image_width_);
|
|
cap_.set(cv::CAP_PROP_FRAME_HEIGHT, image_height_);
|
|
cap_.set(cv::CAP_PROP_EXPOSURE, usb_exposure_);
|
|
}
|
|
|
|
tools::logger()->info("{} USBCamera opened", device_name);
|
|
// tools::logger()->info("USBCamera exposure time:{}", cap_.get(cv::CAP_PROP_EXPOSURE));
|
|
tools::logger()->info("USBCamera fps:{}", cap_.get(cv::CAP_PROP_FPS));
|
|
// tools::logger()->info("USBCamera gamma:{}", cap_.get(cv::CAP_PROP_GAMMA));
|
|
|
|
// 取图线程
|
|
capture_thread_ = std::thread{[this] {
|
|
ok_ = true;
|
|
std::this_thread::sleep_for(50ms);
|
|
tools::logger()->info("[{} USB camera] capture thread started ", this->device_name);
|
|
while (!quit_) {
|
|
std::this_thread::sleep_for(1ms);
|
|
|
|
cv::Mat img;
|
|
bool success;
|
|
{
|
|
std::lock_guard<std::mutex> lock(cap_mutex_);
|
|
if (!cap_.isOpened()) {
|
|
break;
|
|
}
|
|
success = cap_.read(img);
|
|
}
|
|
|
|
if (!success) {
|
|
tools::logger()->warn("Failed to read frame, exiting capture thread");
|
|
break;
|
|
}
|
|
|
|
auto timestamp = std::chrono::steady_clock::now();
|
|
queue_.push({img, timestamp});
|
|
}
|
|
ok_ = false;
|
|
}};
|
|
}
|
|
|
|
void USBCamera::try_open()
|
|
{
|
|
try {
|
|
open();
|
|
open_count_++;
|
|
} catch (const std::exception & e) {
|
|
tools::logger()->warn("{}", e.what());
|
|
}
|
|
}
|
|
|
|
void USBCamera::close()
|
|
{
|
|
if (cap_.isOpened()) {
|
|
cap_.release();
|
|
tools::logger()->info("USB camera released.");
|
|
}
|
|
}
|
|
|
|
} // namespace io
|