You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用2D高斯拟合定位光斑中心:真实图像拟合失败求助

真实图像2D高斯拟合失败排查求助

我需要定位序列图像中亮斑的中心,计划通过拟合2D高斯函数找到最大值,用scipy.optimize.curve_fit实现。模拟数据拟合效果良好,但处理真实图像时拟合失败,请求帮助排查原因。

模拟数据拟合代码与结果

import scipy.optimize as opt
import numpy as np
import pylab as plt
import cv2

# 定义2D高斯函数
def gauss2dFunc(xy, xo, yo, sigma):
        x = xy[0]
        y = xy[1]
        return np.exp( -((x-xo)*(x-xo) + (y-yo)*(y-yo)) / (2.*sigma*sigma) ).ravel()
    

xvec = np.array(range(200))
yvec = np.array(range(200))
X,Y = np.meshgrid(xvec,yvec)
initial_guess = [100,100,10] # xo,yo,sigma

# 创建高斯分布数据
def gauss2d(shape=(200,200),sigma=20):
    m,n = [(ss-1.)/2. for ss in shape]
    y,x = np.ogrid[-m:m+1,-n:n+1]
    h = np.exp( -(x*x + y*y) / (2.*sigma*sigma) )
    h[ h < np.finfo(h.dtype).eps*h.max() ] = 0
    h = h / h.max()
    return h[:200, :200]

# 添加噪声
gauss2d_noise = gauss2d() + 0.2*np.random.normal(size=gauss2d().shape)

# 拟合2D高斯函数
popt, pcov = opt.curve_fit(gauss2dFunc, (X, Y), gauss2d_noise.ravel() , p0=initial_guess)

fit = gauss2dFunc((X,Y), *popt)

f, axarr = plt.subplots(1,2)
axarr[0].imshow(gauss2d_noise, cmap='gray')
axarr[1].imshow(fit.reshape(200,200), cmap='gray')

模拟数据拟合效果:左侧为带噪声的模拟高斯图像,右侧为拟合结果,两者匹配度很高。

真实图像拟合代码与结果

import scipy.optimize as opt
import numpy as np
import pylab as plt
import cv2

# 定义2D高斯函数
def gauss2dFunc(xy, xo, yo, sigma):
        x = xy[0]
        y = xy[1]
        return np.exp( -((x-xo)*(x-xo) + (y-yo)*(y-yo)) / (2.*sigma*sigma) ).ravel()
    

xvec = np.array(range(200))
yvec = np.array(range(200))
X,Y = np.meshgrid(xvec,yvec)
initial_guess = [100,100,10] # xo,yo,sigma

# 读取图像
image = cv2.imread('cor.png', 0)   
print(np.shape(image))

# 拟合2D高斯函数
popt, pcov = opt.curve_fit(gauss2dFunc, (X, Y), image.ravel() , p0=initial_guess)

fit = gauss2dFunc((X,Y), *popt)

f, axarr = plt.subplots(1,2)
axarr[0].imshow(image, cmap='gray')
axarr[1].imshow(fit.reshape(200,200), cmap='gray')

真实图像拟合效果:左侧为真实亮斑图像,右侧为拟合结果,拟合结果完全不符合真实图像特征。

我是Python新手,不清楚失败原因,希望得到帮助。


问题排查与解决方案

1. 高斯模型过于简单

你当前使用的高斯函数是无振幅、无背景偏移的简化模型,仅包含中心坐标xo,yo和标准差sigma,但真实图像的亮斑通常存在固定背景灰度、亮斑振幅,甚至x/y方向标准差不同的椭圆分布。

修改为完整2D高斯模型:

def gauss2dFunc(xy, xo, yo, sigma_x, sigma_y, amp, offset):
    x = xy[0]
    y = xy[1]
    return offset + amp * np.exp( -((x-xo)**2/(2*sigma_x**2) + (y-yo)**2/(2*sigma_y**2)) ).ravel()

2. 初始猜测值偏差太大

模拟数据的亮斑正好在图像中心,但真实图像亮斑位置可能不在中心,固定初始值[100,100,10]会导致拟合算法无法收敛到正确值。

解决方法:先定位亮斑大致中心:

# 找到图像灰度最大值的坐标作为初始中心
y_max, x_max = np.unravel_index(np.argmax(image), image.shape)
# 适配新模型的初始猜测:中心坐标、x/y标准差、振幅、背景偏移
initial_guess = [x_max, y_max, 5, 5, image.max() - image.min(), image.min()]

3. 灰度范围不匹配

模拟数据灰度范围在[0,1.2]左右,而真实图像是8位灰度图(范围[0,255]),简化模型输出始终在[0,1],与真实数据差距极大,导致拟合失败。使用完整模型后,amp(振幅)和offset(背景偏移)会自动适配真实图像的灰度范围。

4. 添加参数约束

给拟合算法添加参数边界,避免出现无意义的负值(比如标准差为负):

# 设定参数上下限:确保坐标在图像范围内,标准差、振幅为正
bounds = (
    [0, 0, 1e-3, 1e-3, 1e-3, 0],  # 下限
    [image.shape[1]-1, image.shape[0]-1, 50, 50, 255, 255]   # 上限
)
popt, pcov = opt.curve_fit(gauss2dFunc, (X, Y), image.ravel(), p0=initial_guess, bounds=bounds)

完整修正后的真实图像拟合代码

import scipy.optimize as opt
import numpy as np
import pylab as plt
import cv2

# 完整2D高斯函数模型
def gauss2dFunc(xy, xo, yo, sigma_x, sigma_y, amp, offset):
    x = xy[0]
    y = xy[1]
    return offset + amp * np.exp( -((x-xo)**2/(2*sigma_x**2) + (y-yo)**2/(2*sigma_y**2)) ).ravel()

# 生成网格
xvec = np.arange(200)
yvec = np.arange(200)
X,Y = np.meshgrid(xvec,yvec)

# 读取图像
image = cv2.imread('cor.png', 0)   
print(f"图像形状: {np.shape(image)}")

# 获取亮斑初始位置
y_max, x_max = np.unravel_index(np.argmax(image), image.shape)
initial_guess = [x_max, y_max, 5, 5, image.max() - image.min(), image.min()]

# 设置参数边界
bounds = (
    [0, 0, 1e-3, 1e-3, 1e-3, 0],
    [image.shape[1]-1, image.shape[0]-1, 50, 50, 255, 255]
)

# 拟合
popt, pcov = opt.curve_fit(gauss2dFunc, (X, Y), image.ravel(), p0=initial_guess, bounds=bounds)

# 生成拟合结果
fit = gauss2dFunc((X,Y), *popt).reshape(image.shape)

# 可视化
f, axarr = plt.subplots(1,2)
axarr[0].imshow(image, cmap='gray')
axarr[0].set_title('真实图像')
axarr[1].imshow(fit, cmap='gray')
axarr[1].set_title('拟合结果')
plt.show()

# 输出拟合得到的中心坐标
print(f"拟合得到的亮斑中心: ({popt[0]:.2f}, {popt[1]:.2f})")

内容的提问来源于stack exchange,提问作者Martins85

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 14:20:40