OpenCV物体检测 - 中心点

36
在白色背景上给定一个物体,有没有人知道OpenCV是否提供了从捕获的帧轻松检测对象的功能?我正在尝试定位物体(矩形)的角/中心点。我目前的方法是通过暴力扫描图像来实现,不够精确。我想知道是否有未被我所知道的功能在底层发挥作用。
编辑详情:物体大小与小型苏打罐差不多。相机放置在物体上方,使其具有2D /矩形感觉。相机从角点计算出的朝向/角度是随机的。
只是白色背景上有物体(黑色)。拍摄的质量与Logitech网络摄像头所见到的差不多。
一旦我得到了四个角点,我就会计算中心点。然后将中心点转换为厘米。
我想要关注的是“如何”获取这4个角的问题。您可以在此图像中看到我的暴力方法:图像
5个回答

26

在OpenCV中已经有一个如何检测矩形的示例(请查看samples/squares.c),实际上它非常简单。

以下是他们使用的粗略算法:

0. rectangles <- {}
1. image <- load image
2. for every channel:
2.1  image_canny <- apply canny edge detector to this channel
2.2  for threshold in bunch_of_increasing_thresholds:
2.2.1   image_thresholds[threshold] <- apply threshold to this channel
2.3  for each contour found in {image_canny} U image_thresholds:
2.3.1   Approximate contour with polygons
2.3.2   if the approximation has four corners and the angles are close to 90 degrees.
2.3.2.1    rectangles <- rectangles U {contour}

这不是他们正在做的确切音译,但它应该能帮助你。


我正在做一个类似的项目。我对OpenCV很新,所以你能否请发一下这些步骤的源代码? - cduck
1
我相信你正在寻找的文件现在应该是[OpenCV_proj_dir]/samples/cpp/squares.cpp。 - Clay Bridges

7

希望这能帮到你,使用矩阵法获取黑白图像的质心。

cv::Point getCentroid(cv::Mat img)
{
    cv::Point Coord;
    cv::Moments mm = cv::moments(img,false);
    double moment10 = mm.m10;
    double moment01 = mm.m01;
    double moment00 = mm.m00;
    Coord.x = int(moment10 / moment00);
    Coord.y = int(moment01 / moment00);
    return Coord;
}

4

OpenCV有很多函数可以帮助您实现这一目标。如果您使用C#语言编程,可以下载Emgu.CV作为该库的C#.NET封装。

以下是一些获取所需信息的方法:

  1. 像以前一样找到角落 - 例如 "CornerHarris" OpenCV 函数

  2. 对图像进行阈值处理并计算重心 - 参见 http://www.roborealm.com/help/Center%20of%20Gravity.php ... 这是我会使用的方法。您甚至可以在COG例程中执行阈值处理。即 cog_x += *imagePtr < 128 ? 255 : 0;

  3. 查找图像的矩来给出旋转、重心等信息 - 例如 "Moments" OpenCV 函数。(我没有使用过这个)

  4. (编辑) AForge.NET 库也有角点检测函数以及一个示例项目(MotionDetector)和用于连接网络摄像头的库。我认为这将是最容易的方法,假设您正在使用 Windows 和 .NET。


关于cvCornerHarris,你能详细介绍一下它的用法吗?从我看到的信息来看,你要创建一个图像并运行cvCornerHarris(image, cornerimg, blockSize(?), apertureSize(?))。另外,你是如何从角落图像中提取信息的? - David McGraw
据我所知,它的工作方式是对于每个像素,它会在周围的“blockSize” x “blockSize”像素组上运行大小为“apertureSize”的Sobel边缘检测器。然后,它使用公式为在此区域检测到的边缘打分。一个角落将同时具有水平和垂直边缘。 - geometrikal
生成的图像与原始图像大小相同,除了最亮的像素对应于最强的角落。选择比角落更大的块大小进行检测 - 尝试使用5或7适用于您的图像。选择apertureSize和比特率较小 - 尝试3。我自己没有使用过这个函数,所以请说一下它的运行情况。 - geometrikal

1

由于没有人发布完整的OpenCV解决方案,这里提供一个简单的方法:

  1. 获取二进制图像。 我们加载图像,将其转换为灰度图像,然后使用Otsu阈值获得二进制图像

  2. 查找外轮廓。 我们使用findContours查找轮廓,然后使用boundingRect提取边界框坐标

  3. 查找中心坐标。 由于我们有轮廓,因此可以使用moments提取轮廓的质心来查找中心坐标


这是一个带有边界框和中心点高亮显示的示例,如下所示:

输入图像 -> 输出

Center: (100, 100)

Center: (200, 200)

Center: (300, 300)

总结一下:

在一个纯白背景上给定一个物体,是否有人知道OpenCV是否提供了从捕获的帧中轻松检测对象的功能?

首先获取二进制图像(Canny边缘检测, 简单阈值处理, Otsu阈值处理自适应阈值处理),然后使用 findContours 查找轮廓。要获取边界矩形坐标,可以使用 boundingRect,它将以 x,y,w,h 的形式给出坐标。要绘制矩形,可以使用 rectangle 进行绘制。这将给出轮廓的四个角点。如果要获取中心点,请使用 moments 提取轮廓的质心。

代码

import cv2
import numpy as np

# Load image, convert to grayscale, and Otsu's threshold 
image = cv2.imread('1.png')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]

# Find contours and extract the bounding rectangle coordintes
# then find moments to obtain the centroid
cnts = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
    # Obtain bounding box coordinates and draw rectangle
    x,y,w,h = cv2.boundingRect(c)
    cv2.rectangle(image, (x, y), (x + w, y + h), (36,255,12), 2)

    # Find center coordinate and draw center point
    M = cv2.moments(c)
    cx = int(M['m10']/M['m00'])
    cy = int(M['m01']/M['m00'])
    cv2.circle(image, (cx, cy), 2, (36,255,12), -1)
    print('Center: ({}, {})'.format(cx,cy))

cv2.imshow('image', image)
cv2.waitKey()

0

在其他机器视觉库中,通常称为blob分析。我还没有使用过OpenCV。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接