Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/image-processing/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Image processing 为什么可以';我不能使二维高斯收敛吗?_Image Processing_Scipy_Curve Fitting_Gaussian - Fatal编程技术网

Image processing 为什么可以';我不能使二维高斯收敛吗?

Image processing 为什么可以';我不能使二维高斯收敛吗?,image-processing,scipy,curve-fitting,gaussian,Image Processing,Scipy,Curve Fitting,Gaussian,我想拟合图像中的多个点,在局部背景校正失败的拥挤区域找到它们的真实强度 我的方法只是挑选图像的一个局部区域并进行拟合。问题是,拟合不会产生任何有用的结果,只是默认为初始参数。添加边界以使拟合完全不收敛 我做错了什么 守则: import scipy.optimize as opt import numpy as np import matplotlib.pyplot as plt import skimage.feature from collections import namedtuple

我想拟合图像中的多个点,在局部背景校正失败的拥挤区域找到它们的真实强度

我的方法只是挑选图像的一个局部区域并进行拟合。问题是,拟合不会产生任何有用的结果,只是默认为初始参数。添加边界以使拟合完全不收敛

我做错了什么

守则:

import scipy.optimize as opt
import numpy as np
import matplotlib.pyplot as plt
import skimage.feature
from collections import namedtuple
import skimage.io


def gaussian_2d(
    xy_array, amplitude, pos_x, pos_y, sigma_x, sigma_y, rotation, offset
):
    """
    Expression for a 2D gaussian function with variance in both x and y
    """
    x, y = xy_array
    a = (np.cos(rotation) ** 2) / (2 * sigma_x ** 2) + (
        np.sin(rotation) ** 2
    ) / (2 * sigma_y ** 2)
    b = -(np.sin(2 * rotation)) / (4 * sigma_x ** 2) + (
        np.sin(2 * rotation)
    ) / (4 * sigma_y ** 2)
    c = (np.sin(rotation) ** 2) / (2 * sigma_x ** 2) + (
        np.cos(rotation) ** 2
    ) / (2 * sigma_y ** 2)
    g = amplitude * np.exp(
        -(
            a * ((x - pos_x) ** 2)
            + 2 * b * (x - pos_x) * (y - pos_y)
            + c * ((y - pos_y) ** 2)
        )
    )
    g += offset

    return g.ravel()


def fit_gaussian_spots(x_guess, y_guess, array):
    Params = namedtuple(
        "Parameters", "amp, x, y, sigma_x, sigma_y, rotation, offset"
    )
    eps = 1e-8

    initial_guess = Params(
        amp=1, x=x_guess, y=y_guess, sigma_x=1, sigma_y=1, rotation=0, offset=0
    )

    # Bounds makes it even harder to converge
    min_bounds = Params(
        amp=eps,
        x=x_guess * 0.5,
        y=y_guess * 0.5,
        sigma_x=eps,
        sigma_y=eps,
        rotation=-np.inf,
        offset=eps,
    )

    max_bounds = Params(
        amp=np.max(array),
        x=x_guess * 1.5,
        y=y_guess * 1.5,
        sigma_x=np.inf,
        sigma_y=np.inf,
        rotation=2 * np.pi,
        offset=np.max(array),
    )

    try:
        X, Y = create_grid(*array.shape)
        popt, pcov = opt.curve_fit(
            f=gaussian_2d,
            xdata=(X, Y),
            ydata=array.ravel(),
            p0=initial_guess,
            # bounds=(min_bounds, max_bounds),
        )
        popt = Params(*np.round(popt))

    except ValueError:
        print("fit didn't converge!")
        popt, pcov = None, None

    return popt, pcov


def create_grid(h, w):
    """
    Creates a grid of x and y points to fit and evaluate over
    """
    x = np.arange(0, w, 1)
    y = np.arange(0, h, 1)
    x, y = np.meshgrid(x, y)
    return x, y


def evaluate_gaussian(x, y, popt):
    """
    Evaluates gaussian in coordinate positions.
    NOTE: this is not necessary for extracting intensity,
    as the pure signal is fitted as the amplitude.
    """
    z = gaussian_2d((x, y), *popt)
    return z


if __name__ == "__main__":
    # Create x and y indices
    np.random.seed(4)
    h, w = 200, 200
    x, y = create_grid(h=h, w=w)

    # create data
    img = []
    for _ in range(10):
        randx = np.random.randint(10, w - 10)
        randy = np.random.randint(10, h - 10)
        amp = 100
        d = gaussian_2d(
            xy_array=(x, y),
            amplitude=amp,
            pos_x=randx,
            pos_y=randy,
            sigma_x=9,
            sigma_y=3,
            rotation=3,
            offset=0,
        )
        # d = d + np.random.normal(0, 5, d.shape) # add noise
        # d += 100  # add offset
        img.append(d)
    img = np.sum(img, axis=0)
    img = img.reshape(h, w)
    print("max intensity: {:.2f}".format(img.max()))

    # Detect soem possible spots first
    spots = skimage.feature.peak_local_max(img, num_peaks=20, min_distance=10)
    fig, ax = plt.subplots(ncols=2)

    h, w = img.shape
    local_area = 20
    fit = []

    # skimage returns rows, columns (y,x) while matplotlib operates in (x,y)
    for idx, (pre_y, pre_x) in enumerate(spots):
        # Fit gaussian in local area
        popt, pcov = fit_gaussian_spots(
            x_guess=pre_x,
            y_guess=pre_y,
            # Avoid falling off the edge of the image
            array=img[
                max(pre_y - local_area, 0) : pre_y + local_area,
                max(pre_x - local_area, 0) : pre_x + local_area,
            ],
        )
        if popt is None:
            continue
        print(popt)

        ax[0].add_patch(
            plt.Circle(
                (pre_x, pre_y), 5, linewidth=0.5, fill=False, color="red"
            )
        )
        ax[1].add_patch(
            plt.Rectangle(
                (pre_x - local_area, pre_y - local_area),
                width=local_area * 2,
                height=local_area * 2,
                fill=False,
                color="yellow",
            )
        )

        fit.append(evaluate_gaussian(x, y, popt))
    fit = np.sum(fit, axis=0)

    ax[0].set_title("true")
    ax[0].imshow(
        img, origin="bottom", extent=(x.min(), x.max(), y.min(), y.max())
    )
    ax[1].set_title("predicted")
    ax[1].imshow(
        fit.reshape(img.shape),
        origin="bottom",
        extent=(x.min(), x.max(), y.min(), y.max()),
    )

    plt.show()

事实证明,我最大的错误是忘记了要在图像子集中拟合的坐标当然是相对的。事实上,只要使用中心就可以了。我最终使用了下面的代码,没有任何限制,因为我发现使用首字母进行匹配总体上只会快一点

import scipy.optimize as opt
import numpy as np
import matplotlib.pyplot as plt
import skimage.feature
from collections import namedtuple
import skimage.io
import matplotlib.patches
import skimage.filters
import warnings
from scipy.optimize import OptimizeWarning


def zoom_array(array, xy, square_radius):
    """
    Return a zoomed array at location
    """
    x, y = xy
    minix = int(max(x - square_radius, 0))
    miniy = int(max(y - square_radius, 0))
    maxix = int(x + square_radius)
    maxiy = int(y + square_radius)
    return array[miniy:maxiy, minix:maxix]


def gaussian_2d(
    xy_array, amplitude, pos_x, pos_y, sigma_x, sigma_y, angle, offset
):
    """
    Expression for a 2D gaussian function with variance in both x and y
    """
    x, y = xy_array

    a = (np.cos(angle) ** 2) / (2 * sigma_x ** 2) + (np.sin(angle) ** 2) / (
        2 * sigma_y ** 2
    )
    b = -(np.sin(2 * angle)) / (4 * sigma_x ** 2) + (np.sin(2 * angle)) / (
        4 * sigma_y ** 2
    )
    c = (np.sin(angle) ** 2) / (2 * sigma_x ** 2) + (np.cos(angle) ** 2) / (
        2 * sigma_y ** 2
    )

    g = offset + amplitude * np.exp(
        -(
            a * ((x - pos_x) ** 2)
            + 2 * b * (x - pos_x) * (y - pos_y)
            + c * ((y - pos_y) ** 2)
        )
    )
    return g.ravel()


def fit_gaussian_spots(x_guess, y_guess, array):
    Params = namedtuple(
        "Parameters", "amp, x, y, sigma_x, sigma_y, angle, offset"
    )

    initial_guess = Params(
        amp=np.max(array),
        x=x_guess,
        y=y_guess,
        sigma_x=1,
        sigma_y=1,
        angle=0,
        offset=np.abs(np.min(array)),
    )

    with warnings.catch_warnings():
        warnings.simplefilter("error", OptimizeWarning)
        try:
            X, Y = create_grid(*array.shape)
            popt, pcov = opt.curve_fit(
                f=gaussian_2d,
                xdata=(X, Y),
                ydata=array.ravel(),
                p0=initial_guess,
                maxfev=200,
                method="lm"
                # constraints make it slower. Better to time out bad fits
                # bounds=(min_bounds, max_bounds),
            )
            popt = Params(*np.round(popt))
        except (OptimizeWarning, ValueError, RuntimeError):
            popt, pcov = None, None
    return popt, pcov


def create_grid(h, w):
    """
    Creates a grid of x and y points to fit and evaluate over
    """
    x = np.arange(0, w, 1)
    y = np.arange(0, h, 1)
    x, y = np.meshgrid(x, y)
    return x, y


def evaluate_gaussian(x, y, popt):
    """
    Evaluates gaussian in coordinate positions.
    NOTE: this is not necessary for extracting intensity,
    as the pure signal is fitted as the amplitude.
    """
    z = gaussian_2d((x, y), *popt)
    return z


def _simulate_data():
    """Create data"""
    img = []
    for _ in range(N_SPOTS):
        POSX = np.random.randint(0, W)
        POSY = np.random.randint(0, H)
        AMP = 100
        g = gaussian_2d(
            xy_array=(Xi, Yi),
            amplitude=AMP,
            pos_x=POSX,
            pos_y=POSY,
            sigma_x=2,
            sigma_y=2,
            angle=0,
            offset=0,
        )
        img.append(g)
    img = np.sum(img, axis=0)
    img = img.reshape(H, W)
    img = img + np.random.normal(5, 5, len(img.ravel())).reshape(img.shape)
    return img


if __name__ == "__main__":
    # Create x and y indices
    np.random.seed(4)
    PLOT_ROWS = 3
    PLOT_COLS = 3

    H, W = 200, 400
    N_SPOTS = 50
    Xi, Yi = create_grid(h=H, w=W)
    img = _simulate_data()

    # Detect a generous amount of spots to be safe
    spots = skimage.feature.peak_local_max(img, num_peaks=300, min_distance=5)

    figimg, aximg = plt.subplots()
    aximg.imshow(
        img, origin="bottom", extent=(Xi.min(), Xi.max(), Yi.min(), Yi.max())
    )

    figzoom, axzoom = plt.subplots(nrows=PLOT_ROWS, ncols=PLOT_COLS)
    axzoom = axzoom.ravel()

    zoom_ctr = 6
    # skimage returns rows, columns (y,x) while matplotlib operates in (x,y)
    idx = 0
    for guessy, guessx in spots:
        # Plot on the full image
        # Initial
        aximg.add_patch(
            plt.Circle(
                (guessx, guessy),
                3,
                linewidth=0.5,
                fill=False,
                alpha=0.5,
                color="yellow",
            )
        )

        # Fit
        local_arr = zoom_array(img, (guessx, guessy), square_radius=zoom_ctr)
        popt, pcov = fit_gaussian_spots(
            x_guess=zoom_ctr, y_guess=zoom_ctr, array=local_arr
        )

        # Throw away bad fits
        if popt is None or popt.sigma_x < 1 or popt.sigma_y < 1:
            continue

        predx = guessx + popt.x - zoom_ctr
        predy = guessy + popt.y - zoom_ctr

        # Plot on each of zooms
        # Predicted
        try:
            axzoom[idx].imshow(local_arr, origin="bottom")
            axzoom[idx].add_patch(
                matplotlib.patches.Ellipse(
                    (popt.x, popt.y),
                    width=popt.sigma_x * 3,
                    height=popt.sigma_y * 3,
                    angle=popt.angle,
                    color="red",
                    fill=False,
                )
            )
            axzoom[idx].set_title(
                "fit: {:.1f} + {:.1f}\n"
                "est: {:.1f} + {:.1f}".format(
                    popt.amp, popt.offset, np.max(local_arr), np.min(local_arr)
                )
            )
        except IndexError:
            pass

        # Predicted
        aximg.add_patch(
            plt.Circle((predx, predy), 4, linewidth=2, fill=False, color="red")
        )

        idx += 1

    plt.tight_layout()
    plt.show()
导入scipy.optimize作为选项
将numpy作为np导入
将matplotlib.pyplot作为plt导入
导入skimage.feature
从集合导入namedtuple
导入skimage.io
导入matplotlib.patches
导入撇渣过滤器
进口警告
从scipy.optimize导入优化警告
def缩放阵列(阵列、xy、方形半径):
"""
返回位置处的缩放数组
"""
x、 y=xy
minix=int(最大值(x-平方半径,0))
最小值=整数(最大值(y-平方半径,0))
maxix=int(x+平方半径)
maxiy=int(y+平方半径)
返回数组[miniy:maxiy,minix:maxix]
def gaussian_2d(
xy_阵列、振幅、位置x、位置y、西格玛_x、西格玛_y、角度、偏移
):
"""
具有x和y方差的二维高斯函数的表达式
"""
x、 y=xy_阵列
a=(np.cos(角度)**2)/(2*sigma_x**2)+(np.sin(角度)**2)/(
2*sigma_y**2
)
b=-(np.sin(2*角))/(4*σx**2)+(np.sin(2*角))/(
4*sigma_y**2
)
c=(np.sin(角度)**2)/(2*sigma_x**2)+(np.cos(角度)**2)/(
2*sigma_y**2
)
g=偏移量+振幅*np.exp(
-(
a*((x-位置x)**2)
+2*b*(x-位置x)*(y-位置y)
+c*((y-位置y)**2)
)
)
returng.ravel()
def拟合高斯点(x猜,y猜,阵列):
Params=namedtuple(
“参数”,“放大器,x,y,sigma_x,sigma_y,角度,偏移”
)
初始猜测=参数(
amp=np.最大值(阵列),
我猜,
你猜是吧,
sigma_x=1,
sigma_y=1,
角度=0,
偏移量=np.abs(np.min(数组)),
)
带有警告。捕获警告()
警告。simplefilter(“错误”,优化警告)
尝试:
十、 Y=创建网格(*array.shape)
popt,pcov=最佳曲线拟合(
f=高斯分布,
扩展数据=(X,Y),
ydata=array.ravel(),
p0=初始猜测,
maxfev=200,
method=“lm”
#约束会使它变慢。最好暂停不合适的配合
#界限=(最小界限,最大界限),
)
popt=参数(*np.圆形(popt))
除了(OptimizeWarning、ValueError、RuntimeError):
popt,pcov=无,无
返回波普
def创建网格(h,w):
"""
创建x点和y点的栅格,以便在其上进行拟合和计算
"""
x=np.arange(0,w,1)
y=np.arange(0,h,1)
x、 y=np.meshgrid(x,y)
返回x,y
def评估_高斯(x,y,popt):
"""
在坐标位置计算高斯分布。
注意:这对于提取强度不是必需的,
因为纯信号被拟合为振幅。
"""
z=高斯分布(x,y),*popt)
返回z
def_模拟_数据():
“”“创建数据”“”
img=[]
对于范围内的(N个点):
POSX=np.random.randint(0,W)
POSY=np.random.randint(0,H)
AMP=100
g=高斯分布(
xy_数组=(Xi,Yi),
振幅=安培,
pos_x=POSX,
pos_y=POSY,
sigma_x=2,
sigma_y=2,
角度=0,
偏移量=0,
)
img.append(g)
img=np.和(img,轴=0)
img=img.重塑(H,W)
img=img+np.random.normal(5,5,len(img.ravel())。重塑(img.shape)
返回img
如果名称=“\uuuuu main\uuuuuuuu”:
#创建x和y索引
np.随机种子(4)
绘图行数=3
PLOT_COLS=3
H、 W=200400
N_点=50
席,Y= =创建网格(H=H,W=W)
img=_模拟_数据()
#检测大量斑点以确保安全
斑点=撇毛。特征。峰值\局部\最大值(img,峰值数=300,最小距离=5)
figimg,aximg=plt.subplot()
aximg.imshow(
IMG,Orth=“底部”,Exp=(席)(席),X.Max(),YI. min(),I.
)
图空间,axzoom=plt.子图(nrows=PLOT\u行,ncols=PLOT\u列)
axzoom=axzoom.ravel()
缩放比例=6
#skimage返回行、列(y,x),而matplotlib在(x,y)中操作
idx=0
对于猜测,在点中猜测X:
#在完整图像上绘图
#首字母
aximg.add_补丁(
小圆圈(
(猜,猜),
3.
线宽=0.5,
填充=假,
α=0.5,
color=“黄色”,
)
)
#合身
局部arr=缩放数组(img,(猜X,猜Y),正方形半径=缩放中心)
popt,pcov=拟合高斯点(
x_guess=zoom_ctr,y_guess=zoom_ctr,array=local_arr
)
#扔掉不合身的衣服
如果popt为None或popt.sigma_x<1或popt.sigma_y<1:
持续
predx=猜测x+弹出x-缩放
predy=猜测+弹出y-缩放
#在每个缩放上绘图
#预测
尝试:
axzoom[idx].imshow(local\u arr,origin=“bottom”)
axzoom[idx]。添加修补程序(
matplotlib.patches.Ellipse(
(popt.x,popt.y),
宽度=popt.sigma_x*3,
高度=popt.sigma_y*3,
角度=popt.angle,
color=“红色”,