[CPP] ArduCAM

HyoSeok·2024년 10월 23일
#include <ros/ros.h>
#include <sensor_msgs/Image.h>
#include <cv_bridge/cv_bridge.h>
#include <opencv2/opencv.hpp>
#include <jsoncpp/json/json.h>
#include <fstream>
#include <iostream>
#include <string>
#include <vector>
#include <ctime>
#include <thread>

class FPSCounter {
public:
    FPSCounter() : frame_count(0), start_time(std::chrono::steady_clock::now()) {}

    void displayFPS(const cv::Mat& frame) {
        frame_count++;
        auto current_time = std::chrono::steady_clock::now();
        std::chrono::duration<double> elapsed = current_time - start_time;

        if (elapsed.count() >= 1.0) {
            std::cout << "Width: " << frame.cols 
                      << " Height: " << frame.rows 
                      << " FPS: " << frame_count << std::endl;
            frame_count = 0;
            start_time = current_time;
        }
    }

private:
    int frame_count;
    std::chrono::steady_clock::time_point start_time;
};


class Camera {
public:
    Camera(int index = 0, int selector = cv::CAP_V4L2)
        : index(index), selector(selector), width(0), height(0), fps(0) {}

    cv::VideoCapture cap;


    void open() {
        cap.open(index, selector);
        cap.set(cv::CAP_PROP_FOURCC, cv::VideoWriter::fourcc('M', 'J', 'P', 'G'));
        cap.set(cv::CAP_PROP_FPS, 60);

        if (width > 0 && height > 0) {
            set(cv::CAP_PROP_FRAME_WIDTH, width);
            set(cv::CAP_PROP_FRAME_HEIGHT, height);
        }

        if (fps > 0) {
            set(cv::CAP_PROP_FPS, fps);
        }
    }

    void setWidth(int w) { width = w; }
    void setHeight(int h) { height = h; }
    void setFPS(int f) { fps = f; }

    void setFocus(int val) { set(cv::CAP_PROP_FOCUS, val); }

    void set(int property, double value) {
        if (cap.isOpened()) {
            cap.set(property, value);
        } else {
            std::cerr << "Camera is not opened!" << std::endl;
        }
    }

    bool read(cv::Mat& frame) { return cap.read(frame); }

    void restart() {
        release();
        std::this_thread::sleep_for(std::chrono::milliseconds(500));
        open();
    }

    void release() { cap.release(); }

    bool isOpened() const { return cap.isOpened(); }
    

private:
    int index;
    int selector;
    int width;
    int height;
    int fps;
};




int main(int argc, char** argv) {

    ros::init(argc, argv, "arducam_publisher");
    ros::NodeHandle nh;
    ros::Publisher image_pub = nh.advertise<sensor_msgs::Image>("/camera/image_raw", 1000);
    cv_bridge::CvImage bridge;

    int width = 640, height = 480, fps = 50, index = 0;
    std::string output_path;
    int restart_times = 5;

    Camera camera(index);
    camera.setWidth(width);
    camera.setHeight(height);
    camera.setFPS(fps);
    camera.open();

    if (!camera.isOpened()) {
        std::cerr << "Can't open camera" << std::endl;
        return -1;
    }

    cv::namedWindow("video", cv::WINDOW_NORMAL);
    cv::resizeWindow("video", 800, 600);

    FPSCounter fps_counter;
    cv::Mat frame;

    while (ros::ok()) {
        if (!camera.read(frame)) {
            std::cerr << "Unable to read video frame" << std::endl;
            bool success = false;
            for (int i = 1; i <= restart_times; ++i) {
                std::cerr << "Reopening camera (" << i << " times)" << std::endl;
                camera.cap.open(index);
                if (camera.isOpened()) {
                    success = true;
                    break;
                }
            }
            if (!success) {
                std::cerr << "Failed to reopen camera" << std::endl;
                break;
            }
        }

        bridge.header.stamp = ros::Time::now();
        bridge.encoding = "bgr8";
        bridge.image = frame;
        image_pub.publish(bridge.toImageMsg());
        
        fps_counter.displayFPS(frame);
        cv::imshow("video", frame);

        char key = cv::waitKey(1);
        if (key == 'q') {
            break;
        } else if (key == 's') {
            std::time_t t = std::time(nullptr);
            char time_str[100];
            std::strftime(time_str, sizeof(time_str), "%Y-%m-%d_%H_%M_%S", std::localtime(&t));
            output_path = std::to_string(width) + "x" + std::to_string(height) + "_" + time_str + ".jpg";
            cv::imwrite(output_path, frame);
            std::cout << "Save success, file name: " << output_path << std::endl;
        }
    }

    camera.release();
    cv::destroyAllWindows();
    return 0;
}
profile
hola!

0개의 댓글