Ver código fonte

添加项目

w 1 mês atrás
commit
f48f622d58
9 arquivos alterados com 195 adições e 0 exclusões
  1. 25 0
      CMakeLists.txt
  2. 48 0
      README
  3. 25 0
      include/FeedLevelDetector.h
  4. 16 0
      main.cpp
  5. 81 0
      src/FeedLevelDetector.cpp
  6. BIN
      test.jpg
  7. BIN
      test2.jpg
  8. BIN
      test3.jpg
  9. BIN
      test4.jpg

+ 25 - 0
CMakeLists.txt

@@ -0,0 +1,25 @@
+cmake_minimum_required(VERSION 3.10)
+project(FeedLevelDetection)
+
+# 设置C++标准
+set(CMAKE_CXX_STANDARD 17)
+
+# 查找OpenCV包
+find_package(OpenCV REQUIRED)
+
+# 包含头文件目录
+include_directories(
+    ${OpenCV_INCLUDE_DIRS}
+    include
+)
+
+# 添加可执行文件
+add_executable(feed_level_detection
+    src/FeedLevelDetector.cpp
+    main.cpp
+)
+
+# 链接OpenCV库
+target_link_libraries(feed_level_detection
+    ${OpenCV_LIBS}
+)

+ 48 - 0
README

@@ -0,0 +1,48 @@
+高斯模糊去噪:G(x,y) = (1/(2πσ²)) * e^(-(x²+y²)/(2σ²))
+    选择高斯核大小:通常使用奇数尺寸的核(如3*3, 5*5等)
+
+    计算高斯权重:根据σ值计算核中每个位置的权重
+
+    归一化权重:使所有权重之和为1
+
+    卷积运算:将高斯核与图像进行卷积
+
+    对于轻度噪声:σ=0.5-1.5,核大小3*3或5*5
+
+    对于较强噪声:σ=1.5-3.0,核大小5*5或7*7
+
+Canny边缘检测:一种经典的图像边缘提取算法
+        使用Sobel算子计算图像的梯度:
+
+        水平梯度Gx = Sobel_x * 图像
+
+        垂直梯度Gy = Sobel_y * 图像
+
+    梯度幅度:G = √(Gx² + Gy²)
+
+    梯度方向:θ = arctan(Gy/Gx),量化到0°、45°、90°、135°四个方向
+
+    双阈值检测
+
+    设定高阈值(Thigh)和低阈值(Tlow),通常Tlow ≈ 0.4*Thigh
+
+    梯度值 > Thigh:强边缘像素
+
+    Tlow < 梯度值 ≤ Thigh:弱边缘像素
+
+    梯度值 ≤ Tlow:抑制
+
+cv::findContours函数:OpenCV 中用于从二值图像中提取轮廓的函数,通常与边缘检测(如 Canny)或阈值处理的结果配合使用
+    输入参数:Canny函数的输出,mode 轮廓检索模式,method:轮廓近似方法
+        mode:轮廓检索模式
+            cv::RETR_EXTERNAL:只检测最外层轮廓
+            cv::RETR_LIST:检测所有轮廓,不建立层级关系
+            cv::RETR_CCOMP:检测所有轮廓,组织为两级层次结构
+            cv::RETR_TREE:检测所有轮廓,建立完整的层级树
+        method:轮廓近似方法
+            cv::CHAIN_APPROX_NONE:存储所有轮廓点
+            cv::CHAIN_APPROX_SIMPLE:压缩水平、垂直和对角线段,只保留端点
+            cv::CHAIN_APPROX_TC89_L1 或 cv::CHAIN_APPROX_TC89_KCOS:使用 Teh-Chin 链逼近算法
+    输出参数:contours:检测到的轮廓,每个轮廓存储为点向量
+
+

+ 25 - 0
include/FeedLevelDetector.h

@@ -0,0 +1,25 @@
+#ifndef FEED_LEVEL_DETECTOR_H
+#define FEED_LEVEL_DETECTOR_H
+
+#include <opencv2/opencv.hpp>
+#include <string>
+
+class FeedLevelDetector {
+public:
+    FeedLevelDetector() = default;
+    
+    // 处理图像并返回饲料距离顶部的像素距离
+    float detectFeedLevel(const std::string& imagePath);
+    
+private:
+    // 预处理图像
+    cv::Mat preprocessImage(const cv::Mat& input);
+    
+    // 检测饲料表面
+    float findFeedSurface(const cv::Mat& image);
+    
+    // 显示结果
+    void displayResult(cv::Mat& image, float distance);
+};
+
+#endif // FEED_LEVEL_DETECTOR_H

+ 16 - 0
main.cpp

@@ -0,0 +1,16 @@
+#include "FeedLevelDetector.h"
+#include <iostream>
+
+int main(int argc, char** argv) {
+    if (argc != 2) {
+        std::cerr << "Usage: " << argv[0] << " <image_path>" << 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;
+}

+ 81 - 0
src/FeedLevelDetector.cpp

@@ -0,0 +1,81 @@
+#include "FeedLevelDetector.h"
+#include <opencv2/imgproc.hpp>
+#include <iostream>
+
+cv::Mat FeedLevelDetector::preprocessImage(const cv::Mat& input) {
+    cv::Mat gray, blurred;
+    
+    // 转换为灰度图像
+    cv::cvtColor(input, gray, cv::COLOR_BGR2GRAY);
+    
+    // 高斯模糊去噪
+    cv::GaussianBlur(gray, blurred, cv::Size(5, 5), 1.5);
+    
+    return blurred;
+}
+
+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, 50, 100);
+    // 查找轮廓
+    std::vector<std::vector<cv::Point>> contours;
+    cv::findContours(edges, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
+    
+    float minY = image.rows; // 初始设置为图像高度
+    
+    // 查找所有轮廓中的最高点
+    for (const auto& contour : contours) {
+        for (const auto& point : contour) {
+            if (point.y < minY) {
+                minY = point.y;
+            }
+        }
+    }
+    
+    // 如果没有找到轮廓,返回图像高度
+    if (minY == image.rows) {
+        return image.rows;
+    }
+    
+    return minY;
+}
+
+void FeedLevelDetector::displayResult(cv::Mat& image, float distance) {
+    // 绘制饲料表面线
+    cv::line(image, cv::Point(0, distance), 
+             cv::Point(image.cols-1, distance), 
+             cv::Scalar(0, 0, 255), 2);
+    
+    // 显示距离信息
+    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) {
+    // 读取图像
+    cv::Mat image = cv::imread(imagePath);
+    if (image.empty()) {
+        std::cerr << "Could not open or find the image: " << imagePath << std::endl;
+        return -1;
+    }
+    
+    // 预处理图像
+    cv::Mat processed = preprocessImage(image);
+    
+    // 检测饲料表面
+    float distance = findFeedSurface(processed);
+    
+    // 显示结果
+    displayResult(image, distance);
+    
+    return distance;
+}

BIN
test.jpg


BIN
test2.jpg


BIN
test3.jpg


BIN
test4.jpg