找到图片中两个圆心的最有效方法

时间:2017-04-04 17:23:32

标签: python image-processing pillow

我试图拍照(.jpg文件),并在此图片中找到两个不同颜色的圆圈的确切中心(x / y坐标)。我在python 2.7中完成了这个。我的程序运行良好,但需要很长时间,我需要大幅减少执行此操作所需的时间。我目前检查每个像素并测试其颜色,并且我知道通过预采样像素子集(例如,水平和垂直方向上的每十个像素以找到要磨练的图像区域),我可以极大地提高效率。我的问题是,是否有预先开发的函数或方法来查找比我的代码更有效的对象的x / y坐标。我已经在循环中删除了函数调用,但这只会将运行时间减少几个百分点。

这是我的代码:

from PIL import Image
import numpy as np

i = Image.open('colors4.jpg')
iar = np.asarray(i)
(numCols,numRows) = i.size
print numCols
print numRows
yellowPixelCount = 0
redPixelCount = 0

yellowWeightedCountRow = 0
yellowWeightedCountCol = 0
redWeightedCountRow = 0
redWeightedCountCol = 0

for row in range(numRows):
    for col in range(numCols):
        pixel = iar[row][col]
        r = pixel[0]
        g = pixel[1]
        b = pixel[2]

        brightEnough = r > 200 and g > 200
        if r > 2*b and g > 2*b and brightEnough: #yellow pixel
            yellowPixelCount = yellowPixelCount + 1
            yellowWeightedCountRow = yellowWeightedCountRow + row
            yellowWeightedCountCol = yellowWeightedCountCol + col

        if r > 2*g and r > 2*b and r > 100:  # red pixel
            redPixelCount = redPixelCount + 1
            redWeightedCountRow = redWeightedCountRow + row
            redWeightedCountCol = redWeightedCountCol + col

print "Yellow circle location"
print yellowWeightedCountRow/yellowPixelCount
print yellowWeightedCountCol/yellowPixelCount
print " "

print "Red circle location"
print redWeightedCountRow/redPixelCount
print redWeightedCountCol/redPixelCount
print " "

更新:正如我在下面提到的,图片有些随意,但这里是我正在使用的视频中一帧的示例:
still frame with two dots

2 个答案:

答案 0 :(得分:1)

首先你需要做一些清算:

你认为什么足够快?样本图像在哪里,所以我们可以看到你在处理什么(分辨率,每像素位数)。什么平台(特别是 CPU ,所以我们可以估算速度)。

当您处理圆圈(每个圆圈编码不同的颜色)时,它应该足以找到边界框。因此,找到每种颜色像素的最小和最大x,y坐标。然后你的圈子是:

center.x=(xmin+xmax)/2
center.y=(ymin+ymax)/2
radius  =((xmax-xmin)+(ymax-ymin))/4

如果使用您的方法编码正确,它应该只需几毫秒。对于1024x1024分辨率左右的图像,我估计平均机器上10-100 ms。你写的方法太慢但你没有指定时间本身(在某些情况下1us在其他1min中很慢就足够了,所以我们只能猜出你需要和得到的东西)。无论如何,如果你得到类似的分辨率并且时间是1-10 sec那么你最有可能使用一些慢像素访问(很可能来自GDI),如get/setpixel使用位图Scanline[]或直接像素访问{{1或者为图像使用自己的记忆。

通过使用光线投射来查找圆圈的大致位置,可以加快您的方法。

  1. 投射水平线

    它们的距离应小于您搜索的最小圆的半径。投射尽可能多的光线直到你用至少2条光线击中每个圆圈

  2. 投两条垂直线

    你可以使用#1中找到的交叉点,所以不需要投射很多光线......使用交点较近但不太近的H光。

  3. 计算您的圈子属性

    所以从4个交点计算中心和半径,因为它是轴对齐矩形+/-像素误差,它应该很容易找到任何对角线的中点,半径也明显为对角线尺寸的一半。

    circle scan

  4. 由于您没有分享任何图片,我们只能猜测您所拥有的内容,如果您没有圈子或需要不同方法的想法,请参阅:

答案 1 :(得分:0)

如果您确定圆圈的颜色,更容易的方法是使用蒙版过滤颜色,然后按照Mathew Pope的建议应用Hough圆圈。

这是一个让您快速入门的片段。

import cv2 as cv2
import numpy as np

fn = '200px-Traffic_lights_dark_red-yellow.svg.png'
# OpenCV reads image with BGR format
img = cv2.imread(fn)
# Convert to HSV format
img_hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)

# lower mask (0-10)
lower_red = np.array([0, 50, 50])
upper_red = np.array([10, 255, 255])
mask = cv2.inRange(img_hsv, lower_red, upper_red)

# Bitwise-AND mask and original image
masked_red = cv2.bitwise_and(img, img, mask=mask)

# Check for circles using HoughCircles on opencv
circles = cv2.HoughCircles(mask, cv2.cv.CV_HOUGH_GRADIENT, 1, 20, param1=30, param2=15, minRadius=0, maxRadius=0)
print 'Radius ' + 'x = ' + str(circles[0][0][0]) + ' y = ' + str(circles[0][0][1])

将其应用于图像的一个示例如下所示。首先是原始图像,然后是获得的红色遮罩,最后一个是使用OpenCV的Hough圆函数找到圆圈。

Original Image Red circle mask- mask0 circle detected using Hough Circle

使用上述方法找到的半径为Radius x = 97.5 y = 99.5

希望这有帮助! :)