前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【目标跟踪】奇葩需求如何处理(二)

【目标跟踪】奇葩需求如何处理(二)

作者头像
读书猿
发布2024-03-22 08:48:27
710
发布2024-03-22 08:48:27
举报
文章被收录于专栏:无人驾驶感知无人驾驶感知

一、前言

  1. 在工作中往往出现些奇葩需求。
  2. 上一篇介绍了一些奇葩需求奇葩需求如何处理(一) ,今天给大家分享一些更奇葩的需求。

二、奇葩需求

2.1、井盖

昨天突然接到一个需求,识别井盖且判断是否有井盖或无井盖。而且时间紧急,比赛突然加的需求,只给一天时间。一天时间用深度学习方法大概率是来不及了,采集数据标注数据训练模型都要花时间。

下面是现场用手机拍的图片,给可以看看。图片中一个有井盖、一个无井盖

1、首先要判断前方井盖位置。2、其次要判断是否真的存在井盖。

传统的方法,那无疑是分割了,分割然后判断圆形,最后统计分布,寻找能区分的特征量,能够有简单区分的值是最好的。

然后花了 20min 得出一个检测圆的代码。

python 代码

代码语言:javascript
复制
import cv2
import numpy as np


def cover_detect(image):
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)  # 转换为灰度图像
    roi_x, roi_y, roi_w, roi_h = 0, height // 2, width - 1, height // 2 - 1
    roi = gray[roi_y:roi_y + roi_h, roi_x:roi_x + roi_w]
    blurred = cv2.GaussianBlur(roi, (5, 5), 0)  # 应用高斯滤波去噪
    edges = cv2.Canny(blurred, 100, 200)  # 应用Canny边缘检测
    cv2.imshow("show", edges)
    cv2.waitKey(100)

    # 应用霍夫圆变换检测圆形物体
    circles = cv2.HoughCircles(edges, cv2.HOUGH_GRADIENT, 2, 1000, param1=50, param2=35, minRadius=80, maxRadius=100)
    # 确保检测到了圆
    if circles is not None:
        # 将坐标和半径转换为整数
        circles = np.uint16(np.around(circles))
        # 遍历检测到的每个圆
        for i in circles[0, :]:
            # 在原图上绘制圆形轮廓和圆心
            cv2.circle(image, (i[0], i[1] + roi_y), i[2], (0, 255, 0), 2)
            cv2.circle(image, (i[0], i[1] + roi_y), 2, (0, 0, 255), 3)

            x, y, r = i
            mask = np.zeros_like(roi)
            cv2.circle(mask, (x, y), r, (255, 255, 255), -1)
            cv2.putText(image, "Well Cover", (i[0] - 50, i[1] - 50 + roi_y), cv2.FONT_HERSHEY_SIMPLEX, 0.75,
                        (0, 255, 0), 2)
    return image

c++ 代码

代码语言:javascript
复制
#include <opencv2/opencv.hpp>  
#include <iostream>  
  
using namespace std;  
using namespace cv;  

Mat cover_detect(Mat image) {  
    Mat gray;  
    cvtColor(image, gray, COLOR_BGR2GRAY); // 转换为灰度图像  
  
    int height = image.rows;  
    int width = image.cols;  
    int roi_x = 0;  
    int roi_y = height / 2;  
    int roi_w = width;  
    int roi_h = height / 2; // 注意:这里应该是height / 2而不是height / 2 - 1,除非你有特别的理由要减去1  
  
    Mat roi(gray, Rect(roi_x, roi_y, roi_w, roi_h));  
    GaussianBlur(roi, roi, Size(5, 5), 0); // 应用高斯滤波去噪  
  
    Mat edges;  
    Canny(roi, edges, 100, 200); // 应用Canny边缘检测,注意:这里应该是Canny而不是Canny  
  
    // 显示边缘检测结果(如果需要)  
    // namedWindow("show", WINDOW_AUTOSIZE);  
    // imshow("show", edges);  
    // waitKey(100);  
  
    // 应用霍夫圆变换检测圆形物体  
    vector<Vec3f> circles;  
    HoughCircles(edges, circles, HOUGH_GRADIENT, 1, 100, 50, 35, 80, 100); // 注意:这里是HOUGH_GRADIENT而不是HOUGH_GRADIENT  
  
    // 遍历检测到的每个圆  
    for (size_t i = 0; i < circles.size(); i++) {  
        Vec3f c = circles[i];  
        Point center(cvRound(c[0]), cvRound(c[1]) + roi_y);  
        int radius = cvRound(c[2]);  
  
        // 在原图上绘制圆形轮廓和圆心  
        circle(image, center, radius, Scalar(0, 255, 0), 2);  
        circle(image, center, 2, Scalar(0, 0, 255), 3);  
  
        // 在图像上添加文本  
        putText(image, "Well Cover", Point(center.x - 50, center.y - 50), FONT_HERSHEY_SIMPLEX, 0.75, Scalar(0, 255, 0), 2);  
    }  
  
    return image;  
}  
  
int main() {  
    // 读取图像  
    Mat image = imread("path_to_your_image.jpg");  
    if (image.empty()) {  
        cerr << "Error: Could not open or find the image!" << endl;  
        return -1;  
    }  
  
    // 调用函数并显示结果  
    Mat result = cover_detect(image);  
    namedWindow("Result", WINDOW_AUTOSIZE);  
    imshow("Result", result);  
    waitKey(0);  
  
    return 0;  
}

上述代码注释很清晰,大概思路也很明了。

  1. 转换为灰度图像
  2. 取一定区域进行操作
  3. 高斯滤波去噪
  4. Canny 边缘检测
  5. HoughCircles 霍夫曼圆找圆
  6. 画图

在找到圆中可以添加一些过滤条件,过滤一些误检的圆。这里可以根据具体需求操作,比如分割特征、形状、纹理、颜色等方式。

分割效果图

结果图

看看效果还不错,第二步我们要区分是否真的有井盖。第一个想到的是利用灰度分布,毕竟受光照影响小。

灰度分布结果

看到这里其实结果就显而易见了。找出相应的特征计算。最终通过计算结果,270帧图片检测结果,共400左右个井盖,分类正确率高达99%

2.2、管线

识别管线、跟踪+定位、发送消息给规控。

如图中绳子、管子等。

  1. 深度学习分割出绳子如 segformer 模型,后处理找出像素包络框,
  2. 计算最小矩形框,跟踪,赋值id。
  3. 发送凸包以及相应的距离信息。

流程图

(一)最小矩形框

由于检测分割管线,输入的是管线像素的包络点。点的输入可能会大于2000,单纯对点的跟踪耗时长且不稳定。 首先对输入的点求最小矩形框,用最小矩形框去跟踪与航迹管理(分配id)。

红色框为检测后的最小矩形框

代码语言:javascript
复制
cv::Rect_<float> Tracking::GetMinBox(std::vector<cv::Point> points)
{
    cv::Point_<float> minPoint, maxPoint;
    minPoint.x = minPoint.y = FLT_MAX;
    maxPoint.x = maxPoint.y = -FLT_MAX;
    for (cv::Point point:points) {
        minPoint.x = std::min(minPoint.x, float(point.x));
        maxPoint.x = std::max(maxPoint.x, float(point.x));
        minPoint.y = std::min(minPoint.y, float(point.y));
        maxPoint.y = std::max(maxPoint.y, float(point.y));
    }
    cv::Rect_<float> res = cv::Rect_<float>(minPoint, maxPoint);
    return res;
}

(二)凸包计算

box可以跟踪,但是最终输出给下游的应该是世界坐标系的点。而点应该是包络框的形式,则需要计算凸包减少点的传递,避免增加无效的计算。(你要是一次性传上千个点,你看规控的人打不打你坏笑.jpg)。

蓝色框是跟踪框包络点的最小凸包。获得了凸包的像素点,直接输出像素点的世界坐标,最终得到的包络框输出给规控。

计算凸包可以利用 opencv 中 cv::convexHull 函数,输入所有点像素,得出凸包点像素。根据凸包点像素发送俯视图下的位置就可。

代码语言:javascript
复制
#include <opencv2/opencv.hpp>  
#include <vector>  
  
int main() {  
    std::vector<cv::Point2f> points = {  
        {0, 0}, {10, 0}, {10, 10}, {5, 4}, {0, 10}  
    };  
  
    std::vector<int> hullIndices;  
    cv::convexHull(points, hullIndices, false, false);  
  
    std::vector<cv::Point2f> hullPoints(hullIndices.size());  
    for (size_t i = 0; i < hullIndices.size(); ++i) {  
        hullPoints[i] = points[hullIndices[i]];  
    }  
  
    // Draw the points and the convex hull  
    cv::Mat img(200, 200, CV_8UC3, cv::Scalar(255, 255, 255));  
    for (const auto& pt : points) {  
        cv::circle(img, pt, 2, cv::Scalar(0, 0, 255), -1);  
    }  
    for (size_t i = 0; i < hullPoints.size(); ++i) {  
        const auto& pt1 = hullPoints[i];  
        const auto& pt2 = hullPoints[(i + 1) % hullPoints.size()];  
        cv::line(img, pt1, pt2, cv::Scalar(0, 255, 0), 2);  
    }  
  
    cv::imshow("Convex Hull", img);  
    cv::waitKey(0);  
  
    return 0;  
}

三、后记

除了上面这些需求,博主还遇到更加奇葩的,今天就到这,下次分享更奇葩的。欢迎大家交流

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2024-03-21,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、前言
  • 二、奇葩需求
    • 2.1、井盖
      • 2.2、管线
      • 三、后记
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档