【发布时间】:2013-05-26 10:06:45
【问题描述】:
我试图让python 尽可能接近地返回图像中最明显聚类的中心,如下图所示:
在我的previous question 中,我询问了如何获得二维数组的全局最大值和局部最大值,并且给出的答案非常有效。问题是我可以通过对不同 bin 大小获得的全局最大值进行平均得到的中心估计值总是比我设置的值稍有偏差通过眼睛,因为我只考虑了最大的 bin,而不是 group 最大的 bin(就像人眼看到的那样)。
我尝试使 answer to this question 适应我的问题,但结果表明我的图像噪音太大,该算法无法正常工作。这是我实现该答案的代码:
import numpy as np
from scipy.ndimage.filters import maximum_filter
from scipy.ndimage.morphology import generate_binary_structure, binary_erosion
import matplotlib.pyplot as pp
from os import getcwd
from os.path import join, realpath, dirname
# Save path to dir where this code exists.
mypath = realpath(join(getcwd(), dirname(__file__)))
myfile = 'data_file.dat'
x, y = np.loadtxt(join(mypath,myfile), usecols=(1, 2), unpack=True)
xmin, xmax = min(x), max(x)
ymin, ymax = min(y), max(y)
rang = [[xmin, xmax], [ymin, ymax]]
paws = []
for d_b in range(25, 110, 25):
# Number of bins in x,y given the bin width 'd_b'
binsxy = [int((xmax - xmin) / d_b), int((ymax - ymin) / d_b)]
H, xedges, yedges = np.histogram2d(x, y, range=rang, bins=binsxy)
paws.append(H)
def detect_peaks(image):
"""
Takes an image and detect the peaks usingthe local maximum filter.
Returns a boolean mask of the peaks (i.e. 1 when
the pixel's value is the neighborhood maximum, 0 otherwise)
"""
# define an 8-connected neighborhood
neighborhood = generate_binary_structure(2,2)
#apply the local maximum filter; all pixel of maximal value
#in their neighborhood are set to 1
local_max = maximum_filter(image, footprint=neighborhood)==image
#local_max is a mask that contains the peaks we are
#looking for, but also the background.
#In order to isolate the peaks we must remove the background from the mask.
#we create the mask of the background
background = (image==0)
#a little technicality: we must erode the background in order to
#successfully subtract it form local_max, otherwise a line will
#appear along the background border (artifact of the local maximum filter)
eroded_background = binary_erosion(background, structure=neighborhood, border_value=1)
#we obtain the final mask, containing only peaks,
#by removing the background from the local_max mask
detected_peaks = local_max - eroded_background
return detected_peaks
#applying the detection and plotting results
for i, paw in enumerate(paws):
detected_peaks = detect_peaks(paw)
pp.subplot(4,2,(2*i+1))
pp.imshow(paw)
pp.subplot(4,2,(2*i+2) )
pp.imshow(detected_peaks)
pp.show()
这是结果(改变 bin 大小):
很明显,我的背景太嘈杂以至于该算法无法工作,所以问题是:我怎样才能使该算法不那么敏感?如果存在替代解决方案,请告诉我。
编辑
按照 Bi Rico 的建议,我尝试在将二维数组传递给局部最大值查找器之前对其进行平滑处理,如下所示:
H, xedges, yedges = np.histogram2d(x, y, range=rang, bins=binsxy)
H1 = gaussian_filter(H, 2, mode='nearest')
paws.append(H1)
这些是sigma 为 2、4 和 8 的结果:
编辑 2
mode ='constant' 似乎比nearest 工作得更好。它以sigma=2 收敛到右侧中心,以获得最大的 bin 大小:
那么,如何获得最后一张图片中显示的最大值的坐标?
【问题讨论】:
-
在应用算法之前,您是否尝试过平滑数据?高斯和/或中值滤波器可能会有所帮助。
-
请查看更新后的问题。
-
怎么样,
np.unravel_index(array.argmax(), array.shape)。 -
一个简单的阈值也可能有很大帮助。
-
您能在多大程度上描述您尝试检测的峰的特性?它总是一个峰值吗?您希望它是对称的,还是具有特征性的空间尺度?另外,背景噪声的特性是什么——它是空间结构的吗?
标签: python image-processing numpy matplotlib