首页 > 编程问答 >使用OpenCV实时检测不同形状的交通标志

使用OpenCV实时检测不同形状的交通标志

时间:2024-07-30 09:39:24浏览次数:6  
标签:python c++ ios opencv computer-vision

我正在尝试创建一个可以从摄像头检测交通标志的应用程序。然而,我在检测标志时遇到了一些困难。

由于交通标志的颜色可能不同,所以我希望先检测标志的形状。

我尝试先找到所有轮廓并尝试检测每个轮廓的形状。然而,标志的轮廓不够清晰,树木背景包含大量小轮廓,会影响检测。这样程序就无法找到交通标志的完整轮廓。我知道使用 openCV 中的 fastNlMeansDenoisingColored() 可以显着消除噪声并使检测变得更加准确。但对于实时处理来说太慢了。

我不仅检查圆形标志,还检查三角形或四边形标志。因此,我希望首先找到所有物体的轮廓,并尝试检查物体的形状。

这是我用来查找图片内部轮廓的代码,以及它的结果。我要开发一个iOS应用程序,所以它是在objective-c中。

- (cv::Mat)findSigns:(cv::Mat)src {
    Mat edge;
    Mat src_gray;
    cvtColor(src, src_gray, COLOR_RGB2GRAY);
    medianBlur(src_gray, src_gray, 5);
    Canny(src_gray, edge, 80, 80, 3);
    Mat kernel = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(3,3));
    Mat dilated;
    cv::dilate(edge, dilated, kernel);
    std::vector<std::vector<cv::Point>> contours;
    std::vector<cv::Vec4i> hierarchy;
    RNG rng(12345);
    cv::findContours(edge, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);
    Scalar color = Scalar(255, 0, 255);
    for(int i = 0; i<contours.size(); i++){
        std::vector<cv::Point> c = contours[i];
        double area = cv::contourArea(c);
        if (area > 100) {
            drawContours(src, contours, i, color, 2, 8, hierarchy);
        }
    }

    edge.release();
    src_gray.release();
    kernel.release();
    dilated.release();

    return src;
}

src图片:

src picture

result without filtering out the contours with small area

由于轮廓太多,所以我尝试去除小面积的轮廓。这是结果。

final result

此外,我还尝试检查是否 hierarchy[i][2] == -1 以查看是否有任何闭合轮廓。但它们都等于-1。

请问我应该如何检测交通标志的形状?我是否应该通过删除绿色对象来删除树背景以便于检测?


你已经在做一些事情上了!分割出交通标志(即从背景中区分出来)是一个具有挑战性的问题,特别是当这些标志可能会有不同的颜色和照明条件时。你的方法是一个良好的开端,这里有一些改进建议,以帮助你检测交通标志的形状:

1. 改进图像预处理

  • 颜色空间转换: 不要仅仅依靠灰度图像。尝试使用 HSV 或 LAB 颜色空间,这些颜色空间可以更好地分离颜色信息,并且对光照变化不太敏感。你可以隔离与交通标志颜色(红色、蓝色、黄色等)相关的特定颜色范围。
  • 自适应直方图均衡化 (CLAHE): 与标准直方图均衡不同,CLAHE 可以局部增强图像的对比度,这有助于突出显示在非均匀光照条件下的边缘。

2. 稳健的轮廓检测

  • 基于梯度的边缘检测: 除了 Canny 之外,还可以尝试使用 Sobel 或 Scharr 算子来进行边缘检测。实验不同的算子和阈值,看看哪个最适合你的场景。
  • 形态学运算: 你已经在使用膨胀来连接边缘。考虑使用形态学开运算(先腐蚀后膨胀)来消除小的噪声区域,同时保留标志的整体形状。

3. 形状检测和分析

  • 轮廓近似: 使用 cv::approxPolyDP 来简化找到的轮廓,减少数据点,同时保留其整体形状。
  • 形状分类: 一旦你有了近似的轮廓,就可以使用以下方法对其进行分类:
    • Hough 变换: 对于圆形标志,可以使用 cv::HoughCircles
    • 角点检测: 对于三角形和矩形,使用 cv::goodFeaturesToTrack 等方法检测角点,然后根据角点的数量和相对位置对其进行分类。
  • 纵横比和面积约束: 根据形状对轮廓应用纵横比和面积阈值,以过滤掉误报。例如,交通标志通常具有一定的最小面积和一定的纵横比范围。

4. 提高性能

  • 调整图像大小: 在全分辨率下处理视频帧可能会很耗时。考虑在应用图像处理技术之前先降低图像分辨率。
  • 区域建议 (ROI): 如果你知道交通标志可能出现的大致区域(例如,图像的下半部分),则可以只处理该区域,从而减少计算量。

代码示例(C++,但你可以将其调整为 Objective-C)

Mat detectTrafficSigns(Mat src) {
  // 转换为 HSV 颜色空间
  Mat hsv;
  cvtColor(src, hsv, COLOR_BGR2HSV);

  // 定义你感兴趣的颜色范围(例如,红色)
  Scalar lower_red1(0, 100, 100);
  Scalar upper_red1(10, 255, 255);
  Scalar lower_red2(170, 100, 100);
  Scalar upper_red2(180, 255, 255);

  // 创建颜色掩码
  Mat mask1, mask2, mask;
  inRange(hsv, lower_red1, upper_red1, mask1);
  inRange(hsv, lower_red2, upper_red2, mask2);
  bitwise_or(mask1, mask2, mask);

  // 形态学开运算
  Mat kernel = getStructuringElement(MORPH_ELLIPSE, Size(5, 5));
  morphologyEx(mask, mask, MORPH_OPEN, kernel);

  // 边缘检测
  Mat edges;
  Canny(mask, edges, 50, 150);

  // 查找轮廓
  vector<vector<Point>> contours;
  findContours(edges, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);

  // 分析轮廓
  for (const auto &contour : contours) {
    double area = contourArea(contour);
    if (area > 100) {
      // 近似轮廓
      vector<Point> approx;
      approxPolyDP(contour, approx, 0.02 * arcLength(contour, true), true);

      // 根据角点的数量对形状进行分类
      if (approx.size() == 3) {
        // 三角形
        drawContours(src, vector<vector<Point>>{approx}, -1, Scalar(0, 255, 0), 2);
      } else if (approx.size() == 4) {
        // 矩形或方形
        drawContours(src, vector<vector<Point>>{approx}, -1, Scalar(255, 0, 0), 2);
      } else if (approx.size() >= 8) {
        // 圆形
        drawContours(src, vector<vector<Point>>{approx}, -1, Scalar(0, 0, 255), 2);
      }
    }
  }

  return src;
}

请记住,这些只是一些一般性建议,可能需要根据的具体需求和挑战来试验不同的技术和参数。

标签:python,c++,ios,opencv,computer-vision
From: 53279905

相关文章

  • Python,计算HSV图像的直方图,忽略背景
    我正在尝试使用openCV计算HSV图像的直方图,使用以下代码:defistogrammaHSV(image,histSize):hsv_planes=cv2.split(image)histSize=histSizehistRange=(0,256)accumulate=Falseh_hist=np.array(cv2.calcHist(hsv_planes,[0],None,[......
  • opencv 目标检测之canny算法
    cannycanny的目标有3个1.低错误率检测出的边缘都是真正的边缘2.定位良好边缘上的像素点与真正的边缘上的像素点距离应该最小3.最小响应边缘只能标识一次,噪声不应该标注为边缘canny分几步1.滤掉噪声比如高斯滤波2.计算梯度比如用索贝尔算子算出梯度3.非极大值......
  • opencv 霍夫曼变换
    霍夫变换不仅可以找出图片中的直线,也可以找出圆,椭圆,三角形等等,只要你能定义出直线方程,圆形的方程等等.不得不说,现在网上的各种博客质量真的不行,网上一堆文章,乱TM瞎写,误人子弟.本身自己就没有理解的很清楚,又不去读算法实现的源码,写的云山雾罩的,越看越懵逼.霍夫......
  • opencv 为图像添加边界
    我们经常会有对图像边缘做扩展的需求.比如希望卷积后得到的矩阵大小不变希望改变图像大小,但是不改变宽高比opencv实现opencv中使用copyMakeBorder()来完成这一功能apisrc是原图像矩阵dst是新图像矩阵top/bottom/left/right是边界扩展的大小(比如5就代表5个像素)b......
  • opencv 膨胀与腐蚀
    腐蚀和膨胀Erosion/Dilationerosion/dilation,用白话说,就是让图像亮的区域收缩和扩张.原理我们定义一个卷积核矩阵.这个矩阵可以是任何形状的,但通常而言,是矩形或者圆形的.同时要定义一个锚点位置.用这个卷积核矩阵挨个地划过原始图像矩阵,同时更改锚点位置的像素值.......
  • python性能分析器:cProfile
    代码:(1)importcProfileimportrecProfile.run('re.compile("foo|bar")')运行结果:(2)importcProfiledefrunRe():importrecProfile.runctx('re.compile("foo|bar")',None,locals())runRe()运行结果:(3)i......
  • 基于Python网络招聘数据可视化分析系统的设计与实现
    基于Python网络招聘数据可视化分析系统的设计与实现DesignandImplementationofPython-basedNetworkRecruitmentDataVisualizationAnalysisSystem完整下载链接:基于Python网络招聘数据可视化分析系统的设计与实现文章目录基于Python网络招聘数据可视化分析系......
  • C/C++ 字符常量的注意事项
    在C/C++中,字符常量是一个或多个字符的固定序列,用于表示程序中的字符值。它们是用单引号('')括起来的单个字符,例如 'a' 或 '1'。在使用字符常量时,有几个重要的注意事项需要考虑:字符长度:字符常量只能包含一个字符。如果你尝试在单引号中包含多于一个字符,比如'ab',这会导致......
  • 从opencv视频文件夹中读取并提取关键点
    我的文件夹中有一个视频列表(每个视频10秒),我试图循环遍历每个动作视频以提取关键点并将它们保存为json文件。path="pathtovideofolder"forfileinos.listdir(path):cap=cv2.VideoCapture(path+file)whilecap.isOpened():try:ret,frame=cap.......
  • 即使使用 docker run -dit 命令,python-Docker 容器也会在运行两秒后退出
    我想从此处使用Dockerfile测试自定义kubernetes调度程序:FROMpython:3.7RUNpipinstallkubernetesCOPYscheduler.py/scheduler.pyCMDpython/scheduler.py一旦创建了映像和容器:dockerbuild-tapp.dockercontainerrun-d-it--namemy-sched......