Преглед изворни кода

feat: establish the basic camera with shared memory and display

lujw2 пре 8 месеци
комит
3a00500a97
6 измењених фајлова са 330 додато и 0 уклоњено
  1. 5 0
      .gitignore
  2. 30 0
      CMakeLists.txt
  3. 103 0
      src/camera.cpp
  4. 31 0
      src/camera.h
  5. 60 0
      src/main.cpp
  6. 101 0
      test/display.cpp

+ 5 - 0
.gitignore

@@ -0,0 +1,5 @@
+.cache/
+.clang-format
+
+build/
+

+ 30 - 0
CMakeLists.txt

@@ -0,0 +1,30 @@
+cmake_minimum_required(VERSION 3.16)
+project(camera_shm)
+set(CMAKE_CXX_STANDARD 17)
+
+# set(OpenCV_DIR "/opt/lib/opencv/4.5.4/lib/cmake/opencv4")
+find_package(OpenCV REQUIRED PATHS "/opt/lib/opencv/4.5.4/lib/cmake/opencv4")
+
+# include_directories("${CMAKE_CURRENT_BINARY_DIR}")
+
+file(GLOB SRC_FILES "./src/*.cpp")
+add_executable(${PROJECT_NAME} ${SRC_FILES})
+# add_executable(${PROJECT_NAME} ./src/main.cpp)
+target_link_libraries(${PROJECT_NAME} PRIVATE ${OpenCV_LIBS} )
+target_include_directories(${PROJECT_NAME} PRIVATE ${OpenCV_INCLUDE_DIRS}})
+
+add_executable(display ./test/display.cpp)
+target_link_libraries(display PRIVATE ${OpenCV_LIBS} )
+target_include_directories(display PRIVATE ${OpenCV_INCLUDE_DIRS}})
+
+# set(CMAKE_INSTALL_PREFIX /opt/daystar/hik_ptz_camera_grpc_server)
+#
+# install(TARGETS server client
+#  DESTINATION bin)
+#
+# install(TARGETS hik_ptz_camera_isapi
+#  DESTINATION lib)
+#
+# install(FILES ./hik_ptz_camera_grpc.service
+#  DESTINATION .)
+#

+ 103 - 0
src/camera.cpp

@@ -0,0 +1,103 @@
+#include "camera.h"
+#include <opencv2/opencv.hpp>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <semaphore.h>
+#include <unistd.h>
+#include <cstring>
+#include <iostream>
+#include <string>
+
+const size_t SHM_SIZE = 640 * 480 * 3;  // 假设图像为640x480,RGB格式
+
+namespace Camera_shm {
+
+Camera::Camera(int id, int width, int height, int fps)
+    : camera_id(id), shm_name("/camera_data_" + std::to_string(id)),
+      sem_name("/camera_semaphore_" + std::to_string(id)), shm_fd(-1),
+      shm_ptr(nullptr), sem(nullptr) {
+    // 打开相机
+    cap.open(camera_id);
+    cap.set(cv::CAP_PROP_FRAME_WIDTH, width);
+    cap.set(cv::CAP_PROP_FRAME_HEIGHT, height);
+    cap.set(cv::CAP_PROP_FPS, fps);
+    cap.set(cv::CAP_PROP_FOURCC, cv::VideoWriter::fourcc('M', 'J', 'P', 'G'));
+    if (!cap.isOpened()) {
+        throw std::runtime_error("Failed to open camera " +
+                                 std::to_string(camera_id));
+    }
+
+    // 创建共享内存
+    shm_fd = shm_open(shm_name.c_str(), O_CREAT | O_RDWR, 0666);
+    if (shm_fd == -1) {
+        throw std::runtime_error("Failed to create shared memory for camera " +
+                                 std::to_string(camera_id));
+    }
+
+    // 调整共享内存大小
+    if (ftruncate(shm_fd, SHM_SIZE) == -1) {
+        throw std::runtime_error(
+            "Failed to set size of shared memory for camera " +
+            std::to_string(camera_id));
+    }
+
+    // 将共享内存映射到进程地址空间
+    shm_ptr = mmap(0, SHM_SIZE, PROT_WRITE, MAP_SHARED, shm_fd, 0);
+    if (shm_ptr == MAP_FAILED) {
+        throw std::runtime_error("Failed to map shared memory for camera " +
+                                 std::to_string(camera_id));
+    }
+
+    // 创建信号量
+    sem = sem_open(sem_name.c_str(), O_CREAT, 0666, 0);
+    if (sem == SEM_FAILED) {
+        throw std::runtime_error("Failed to create semaphore for camera " +
+                                 std::to_string(camera_id));
+    }
+}
+
+Camera::~Camera() {
+    // 释放共享内存
+    if (shm_ptr != nullptr) { munmap(shm_ptr, SHM_SIZE); }
+    if (shm_fd != -1) {
+        close(shm_fd);
+        shm_unlink(shm_name.c_str());
+    }
+
+    // 关闭信号量
+    if (sem != nullptr) {
+        sem_close(sem);
+        sem_unlink(sem_name.c_str());
+    }
+}
+
+void Camera::start() {
+    cv::Mat frame;
+    while (true) {
+        // 捕获图像
+        cap >> frame;
+        if (frame.empty()) {
+            std::cerr << "Camera " << camera_id << ": Failed to capture frame"
+                      << std::endl;
+            break;
+        }
+
+        // 确保图像大小符合共享内存
+        if (frame.total() * frame.elemSize() > SHM_SIZE) {
+            std::cerr << "Camera " << camera_id
+                      << ": Frame too large for shared memory" << std::endl;
+            break;
+        }
+
+        // 将图像数据拷贝到共享内存
+        std::memcpy(shm_ptr, frame.data, frame.total() * frame.elemSize());
+
+        // 通知其他进程
+        sem_post(sem);
+
+        // 模拟实时相机延迟
+        cv::waitKey(30);
+    }
+}
+}

+ 31 - 0
src/camera.h

@@ -0,0 +1,31 @@
+#ifndef __CAMERA_H__
+#define __CAMERA_H__
+
+#include <opencv2/opencv.hpp>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <semaphore.h>
+#include <unistd.h>
+#include <cstring>
+
+namespace Camera_shm {
+class Camera
+{
+  public:
+    Camera(int id, int width, int height, int fps);
+    ~Camera();
+    void start();
+
+  private:
+    int camera_id;
+    std::string shm_name;
+    std::string sem_name;
+    int shm_fd;
+    void* shm_ptr;
+    sem_t* sem;
+    cv::VideoCapture cap;
+};
+}  // namespace Camera_shm
+
+#endif  // __CAMERA_H__

+ 60 - 0
src/main.cpp

@@ -0,0 +1,60 @@
+#include <thread>
+#include "camera.h"
+
+int main(int argc, char** argv) {
+    Camera_shm::Camera camera(0, 640, 480, 30);
+
+    std::thread t1 = std::thread([&]() { camera.start(); });
+    std::this_thread::sleep_for(std::chrono::seconds(10));
+    t1.join();
+    return 0;
+}
+
+// #include <opencv2/opencv.hpp>
+// #include <iostream>
+//
+// using namespace cv;
+// using namespace std;
+//
+// int main() {
+//     // 创建VideoCapture对象,参数为0表示打开默认摄像头
+//     VideoCapture cap(0);
+//     cap.set(CAP_PROP_FRAME_WIDTH, 640);
+//     cap.set(CAP_PROP_FRAME_HEIGHT, 480);
+//     cap.set(CAP_PROP_FPS, 30);
+//     cap.set(CAP_PROP_FOURCC, cv::VideoWriter::fourcc('M', 'J', 'P', 'G'));
+//
+//     // 检查摄像头是否成功打开
+//     if (!cap.isOpened()) {
+//         cout << "Failed to open camera!" << endl;
+//         return -1;
+//     }
+//
+//     // 创建窗口
+//     namedWindow("Camera", WINDOW_NORMAL);
+//
+//     // 循环读取摄像头捕捉到的帧并显示
+//     while (true) {
+//         // 读取一帧图像
+//         Mat frame;
+//         cap.read(frame);
+//
+//         // 检查是否成功读取到一帧图像
+//         if (frame.empty()) {
+//             cout << "Failed to read frame from camera!" << endl;
+//             break;
+//         }
+//
+//         // 显示图像
+//         imshow("Camera", frame);
+//
+//         // 按下q键退出循环
+//         if (waitKey(1) == 'q') break;
+//     }
+//
+//     // 释放摄像头资源和所有窗口
+//     cap.release();
+//     destroyAllWindows();
+//
+//     return 0;
+// }

+ 101 - 0
test/display.cpp

@@ -0,0 +1,101 @@
+#include <opencv2/opencv.hpp>
+#include <opencv2/imgcodecs.hpp>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <semaphore.h>
+#include <unistd.h>
+#include <iostream>
+#include <string>
+
+const int WIDTH = 640;
+const int HEIGHT = 480;
+const size_t SHM_SIZE = HEIGHT * WIDTH * 3; // 假设图像为640x480,RGB格式
+
+class SharedMemoryReader {
+private:
+    int camera_id;
+    std::string shm_name;
+    std::string sem_name;
+    int shm_fd;
+    void* shm_ptr;
+    sem_t* sem;
+
+public:
+    SharedMemoryReader(int id)
+        : camera_id(id),
+          shm_name("/camera_data_" + std::to_string(id)),
+          sem_name("/camera_semaphore_" + std::to_string(id)),
+          shm_fd(-1),
+          shm_ptr(nullptr),
+          sem(nullptr) {
+        // 打开共享内存
+        shm_fd = shm_open(shm_name.c_str(), O_RDONLY, 0666);
+        if (shm_fd == -1) {
+            throw std::runtime_error("Failed to open shared memory for camera " + std::to_string(camera_id));
+        }
+
+        // 将共享内存映射到进程地址空间
+        shm_ptr = mmap(0, SHM_SIZE, PROT_READ, MAP_SHARED, shm_fd, 0);
+        if (shm_ptr == MAP_FAILED) {
+            throw std::runtime_error("Failed to map shared memory for camera " + std::to_string(camera_id));
+        }
+
+        // 打开信号量
+        sem = sem_open(sem_name.c_str(), 0);
+        if (sem == SEM_FAILED) {
+            throw std::runtime_error("Failed to open semaphore for camera " + std::to_string(camera_id));
+        }
+    }
+
+    ~SharedMemoryReader() {
+        // 释放共享内存
+        if (shm_ptr != nullptr) {
+            munmap(shm_ptr, SHM_SIZE);
+        }
+        if (shm_fd != -1) {
+            close(shm_fd);
+        }
+
+        // 关闭信号量
+        if (sem != nullptr) {
+            sem_close(sem);
+        }
+    }
+
+    void read_and_display() {
+        cv::Mat frame(HEIGHT, WIDTH, CV_8UC3); // 假设图像为 640x480 的 RGB 格式
+        while (true) {
+            // 等待信号量通知
+            sem_wait(sem);
+
+            // 从共享内存中读取数据
+            std::memcpy(frame.data, shm_ptr, SHM_SIZE);
+            static int count = 0;
+            count++;
+
+            // 显示图像
+            // cv::imshow("Camera " + std::to_string(camera_id), frame);
+            cv:imwrite("./test_"+ std::to_string(count)+".jpg", frame);
+            std::cout << "Camera " << camera_id << " frame " << count << " saved.\n";
+
+            // 按 ESC 键退出
+            if (cv::waitKey(30) == 27) {
+                break;
+            }
+        }
+    }
+};
+
+int main() {
+    try {
+        // 假设读取相机 0 的共享内存
+        SharedMemoryReader reader(0);
+        reader.read_and_display();
+    } catch (const std::exception& e) {
+        std::cerr << "Error: " << e.what() << std::endl;
+    }
+
+    return 0;
+}
+