Quellcode durchsuchen

可实现usb摄像头间隔10s、30s、60s采集图片并输出高度信息,但在单图片模式下会报错 Could not open camera 但不影响输出

w vor 1 Monat
Ursprung
Commit
95b692ac32
3 geänderte Dateien mit 141 neuen und 22 gelöschten Zeilen
  1. 18 2
      include/FeedLevelDetector.h
  2. 25 9
      main.cpp
  3. 98 11
      src/FeedLevelDetector.cpp

+ 18 - 2
include/FeedLevelDetector.h

@@ -3,15 +3,25 @@
 
 #include <opencv2/opencv.hpp>
 #include <string>
+#include <chrono>
 
 class FeedLevelDetector {
 public:
-    FeedLevelDetector() = default;
-    
+    FeedLevelDetector() ;
+
+    // 设置采集频率(秒)
+    void setCaptureInterval(int interval);
+
+    // 开始检测(从摄像头)
+    void startDetectionFromCamera();
+
     // 处理图像并返回饲料距离顶部的像素距离
     float detectFeedLevel(const std::string& imagePath);
     
 private:
+    int captureInterval; // 采集间隔(秒)
+    cv::VideoCapture camera;
+
     // 预处理图像
     cv::Mat preprocessImage(const cv::Mat& input);
     
@@ -20,6 +30,12 @@ private:
     
     // 显示结果
     void displayResult(cv::Mat& image, float distance);
+
+    // 时间戳记录
+    std::chrono::time_point<std::chrono::system_clock> lastCaptureTime;
+
+    // 检查是否到达采集时间
+    bool shouldCaptureNow();
 };
 
 #endif // FEED_LEVEL_DETECTOR_H

+ 25 - 9
main.cpp

@@ -2,15 +2,31 @@
 #include <iostream>
 
 int main(int argc, char** argv) {
-    if (argc != 2) {
-        std::cerr << "Usage: " << argv[0] << " <image_path>" << std::endl;
+
+    FeedLevelDetector detector;
+
+    // 解析命令行参数
+    if (argc == 2) {
+        // 单张图片模式
+        detector.detectFeedLevel(argv[1]);
+        FeedLevelDetector detector;
+        float distance = detector.detectFeedLevel(argv[1]);
+        std::cout << "Feed level distance from top: " << distance << " pixels" << std::endl;
+
+        cv::waitKey(0);
+    } else if (argc == 3 && std::string(argv[1]) == "--camera") {
+        // 摄像头模式,设置采集频率
+        int interval = std::stoi(argv[2]);
+        detector.setCaptureInterval(interval);
+        detector.startDetectionFromCamera();
+    } else {
+        std::cerr << "Usage:" << std::endl;
+        std::cerr << "  1. Image mode: " << argv[0] << " <image_path>" << std::endl;
+        std::cerr << "  2. Camera mode: " << argv[0] << " --camera <interval_sec>" << std::endl;
+        std::cerr << "     (interval_sec: 10, 30, or 60)" << std::endl;
         return -1;
     }
-    
-    FeedLevelDetector detector;
-    float distance = detector.detectFeedLevel(argv[1]);
-    
-    std::cout << "Feed level distance from top: " << distance << " pixels" << std::endl;
-    
+
     return 0;
-}
+}
+

+ 98 - 11
src/FeedLevelDetector.cpp

@@ -1,6 +1,67 @@
 #include "FeedLevelDetector.h"
 #include <opencv2/imgproc.hpp>
 #include <iostream>
+#include <thread>
+
+FeedLevelDetector::FeedLevelDetector() : captureInterval(10) {
+    camera.open(0); // 默认打开第一个摄像头
+    if (!camera.isOpened()) {
+        std::cerr << "Error: Could not open camera!" << std::endl;
+    }
+    lastCaptureTime = std::chrono::system_clock::now();
+}
+
+void FeedLevelDetector::setCaptureInterval(int interval) {
+    if (interval == 10 || interval == 30 || interval == 60) {
+        captureInterval = interval;
+    } else {
+        std::cerr << "Invalid interval. Using default (10s)." << std::endl;
+    }
+}
+
+bool FeedLevelDetector::shouldCaptureNow() {
+    auto now = std::chrono::system_clock::now();
+    auto elapsed = std::chrono::duration_cast<std::chrono::seconds>(now - lastCaptureTime).count();
+    return (elapsed >= captureInterval);
+}
+
+void FeedLevelDetector::startDetectionFromCamera() {
+    if (!camera.isOpened()) {
+        std::cerr << "Camera not available!" << std::endl;
+        return;
+    }
+
+    cv::Mat frame;
+    while (true) {
+        camera >> frame; // 获取当前帧
+        if (frame.empty()) break;
+
+        // 显示实时画面(但不处理)
+        cv::imshow("Camera Feed", frame);
+
+        // 按ESC退出
+        if (cv::waitKey(1) == 27) break;
+
+        // 检查是否到达采集时间
+        if (shouldCaptureNow()) {
+            cv::Mat processed = preprocessImage(frame);
+            float distance = findFeedSurface(processed);
+
+            // 显示结果
+            displayResult(frame, distance);
+            //std::cout << "[Detection] Distance: " << distance << " pixels" << std::endl;
+
+            // 更新时间戳
+            lastCaptureTime = std::chrono::system_clock::now();
+
+            // 控制台输出当前距离(可选)
+            std::cout << "Detected distance: " << distance << " pixels" << std::endl;
+        }
+    }
+
+    camera.release();
+    cv::destroyAllWindows();
+}
 
 cv::Mat FeedLevelDetector::preprocessImage(const cv::Mat& input) {
     cv::Mat gray, blurred;
@@ -18,8 +79,8 @@ float FeedLevelDetector::findFeedSurface(const cv::Mat& image) {
     cv::Mat edges;
     
     // Canny边缘检测
-    //cv::Canny(image, edges, 100, 150);
-    cv::Canny(image, edges, 100, 200);
+    cv::Canny(image, edges, 100, 150);
+    //cv::Canny(image, edges, 100, 200);
     //cv::Canny(image, edges, 50, 100);
     // 查找轮廓
     std::vector<std::vector<cv::Point>> contours;
@@ -45,19 +106,45 @@ float FeedLevelDetector::findFeedSurface(const cv::Mat& image) {
 }
 
 void FeedLevelDetector::displayResult(cv::Mat& image, float distance) {
+    // 创建显示副本
+    cv::Mat displayImage = image.clone();
+
     // 绘制饲料表面线
-    cv::line(image, cv::Point(0, distance), 
+    cv::line(displayImage, cv::Point(0, distance),
              cv::Point(image.cols-1, distance), 
              cv::Scalar(0, 0, 255), 2);
+
+    // 显示距离信息
+    std::string infoText = "Interval: " + std::to_string(captureInterval) + "s | " +
+                           "Distance: " + std::to_string(distance) + " pixels";
+
+    cv::putText(displayImage, infoText,
+                cv::Point(20, 30),
+                cv::FONT_HERSHEY_SIMPLEX,
+                0.8, cv::Scalar(0, 255, 0), 2);
+
+    // 显示处理间隔信息
+    auto now = std::chrono::system_clock::now();
+    auto nextCapture = lastCaptureTime + std::chrono::seconds(captureInterval);
+    auto remain = std::chrono::duration_cast<std::chrono::seconds>(nextCapture - now).count();
+
+//    std::string timerText = "Next capture in: " + std::to_string(remain) + "s";
+//    cv::putText(displayImage, timerText,
+//                cv::Point(20, 60),
+//                cv::FONT_HERSHEY_SIMPLEX,
+//                0.6, cv::Scalar(255, 255, 0), 1);
+
+    // 更新显示
+    cv::imshow("Feed Level Monitoring", displayImage);
     
-    // 显示距离信息(图像坐标系原点在左上角)
-    std::string distanceText = "Distance: " + std::to_string(distance) + " pixels";
-    cv::putText(image, distanceText, cv::Point(20, 30), 
-                cv::FONT_HERSHEY_SIMPLEX, 0.8, cv::Scalar(0, 255, 0), 2);
-    
-    // 显示图像
-    cv::imshow("Feed Level Detection", image);
-    cv::waitKey(0);
+//    // 显示距离信息(图像坐标系原点在左上角)
+//    std::string distanceText = "Distance: " + std::to_string(distance) + " pixels";
+//    cv::putText(image, distanceText, cv::Point(20, 30),
+//                cv::FONT_HERSHEY_SIMPLEX, 0.8, cv::Scalar(0, 255, 0), 2);
+//
+//    // 显示图像
+//    cv::imshow("Feed Level Detection", image);
+//    cv::waitKey(0);
 }
 
 float FeedLevelDetector::detectFeedLevel(const std::string& imagePath) {