如何定位图像中亮点的中心?

8

这是我将要处理的图像种类的示例:

Balls
(来源:csverma at pages.cs.wisc.edu)

每个球上都有一个亮点。我想找到亮点中心的坐标。我应该如何在Python或Matlab中实现呢?我目前遇到的问题是,亮点上的多个点具有相同(或大致相同)的白色颜色,但我需要找到这些白点“簇”的中心。

此外,对于最左边和最右边的图像,我如何找到整个圆形对象的中心?


使用2D圆形掩模(例如高斯)进行卷积,并找到给出最大相关性的掩模坐标? - Luis Mendo
2
为什么不直接取图像亮度的95%分位数中的像素的平均坐标呢?当存在多个亮点时,这种方法可能行不通,但对于单个亮点来说,这应该是最简单的解决方案。 - knedlsepp
您还可以将其转换为灰度图像,阈值化并查找阈值结果的平均坐标。无需过滤。 - rayryeng
@bla - 哦,是的。优美的代码。 - rayryeng
虽然我认为这个问题似乎是合理的,因为你并没有请求工具或离线资源,但也没有任何代码示例表明存在问题。不太确定该怎么办... - Timothy Groote
显示剩余6条评论
2个回答

9
您可以简单地对图像进行阈值处理,并找到剩余部分的平均坐标。这种情况处理了具有相同强度的多个值的情况。当您对图像进行阈值处理时,显然会有多个明亮的白色像素,因此如果要将它们全部合并在一起,可以找到质心或平均坐标来确定所有这些白色明亮像素的中心。在这种特殊情况下,没有必要进行过滤。以下是MATLAB中的示例代码。
我直接读入该图像,转换为灰度并清除了围绕每个图像的白色边框。接下来,我将图像分成5个块,对其进行阈值处理,找到剩余部分的平均坐标,并在每个中心位置放置一个点:
im = imread('http://pages.cs.wisc.edu/~csverma/CS766_09/Stereo/callight.jpg');
im = rgb2gray(im);
im = imclearborder(im);

%// Split up images and place into individual cells
split_point = floor(size(im,2) / 5);
images = mat2cell(im, size(im,1), split_point*ones(5,1));

%// Show image to place dots
imshow(im);
hold on;

%// For each image...
for idx = 1 : 5
    %// Get image
    img = images{idx}; 

    %// Threshold
    thresh = img > 200;

    %// Find coordinates of thresholded image
    [y,x] = find(thresh);

    %// Find average
    xmean = mean(x);
    ymean = mean(y);

    %// Place dot at centre
    %// Make sure you offset by the right number of columns
    plot(xmean + (idx-1)*split_point, ymean, 'r.', 'MarkerSize', 18);
end        

我得到了这个:

enter image description here


如果您需要Python解决方案,我建议使用scikit-imagenumpymatplotlib进行绘图。以下是上述代码的Python转录。请注意,我手动将链接引用的图像保存在磁盘上并命名为balls.jpg
import skimage.io
import skimage.segmentation
import numpy as np
import matplotlib.pyplot as plt

# Read in the image
# Note - intensities are floating point from [0,1]
im = skimage.io.imread('balls.jpg', True)

# Threshold the image first then clear the border
im_clear = skimage.segmentation.clear_border(im > (200.0/255.0))

# Determine where to split up the image
split_point = int(im.shape[1]/5)

# Show image in figure and hold to place dots in
plt.figure()
plt.imshow(np.dstack([im,im,im]))

# For each image...
for idx in range(5):

  # Extract sub image
  img = im_clear[:,idx*split_point:(idx+1)*split_point]

  # Find coordinates of thresholded image
  y,x = np.nonzero(img)

  # Find average
  xmean = x.mean()
  ymean = y.mean()

  # Plot on figure
  plt.plot(xmean + idx*split_point, ymean, 'r.', markersize=14)

# Show image and make sure axis is removed
plt.axis('off')
plt.show()

我们得到这个数字:

enter image description here

小提示

我完全可以跳过上面的代码,直接使用regionprops(MATLAB链接, scikit-image链接)。你可以简单地对图像进行阈值处理,然后应用regionprops来查找每个白色像素簇的质心,但我想展示一种更手动的方式,这样你就能欣赏算法并理解它。


希望这有所帮助!

好的完整答案。由于找到正确的阈值(这里是200/255)可能有些棘手,我建议应用非线性凹函数(例如我在我的答案中解释的exp,或_gamma校正_操作)非常重要,因为它使最亮点更加强烈。这使得检测更加稳健。此外,在任何情况下以自动方式找到正确的阈值都可以使用直方图来完成;例如通过找到所有像素中1%(按百分位计算)最亮的像素的值。 - Sohail Si
@SohailSi,类似于Otsu的算法可以像你建议的那样评估直方图。应用非线性滤波也是一个好主意,但我会把这个留给OP。我认为我已经为这篇文章做足了功夫! - rayryeng

1

使用二维卷积,然后找到最高强度的点。在应用2D卷积之前,可以对强度值应用凹非线性函数(例如exp),以加强图像亮点相对于暗部的对比度。类似于conv2(exp(img),ker)


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