同时线性拟合 2d numpy 数组的每一行

Simultaneously fit linearly every line of a 2d numpy array

我在 Python 从事图像分析工作。我有一个图像(2d numpy 数组),其中有一些强度漂移。我想把它调平。

要移除图像宽度上的 increasing/decreasing 强度,我想用一条线适合 2d numpy 数组的每一行。但是,我不想遍历每一行索引。

MWE:

import numpy as np
import matplotlib.pyplot as plt


width=1500
height=2500
np.random.random((width,height))
fill_fun = lambda x,a,b : a*x+b
play_image = fill_fun(np.tile(np.arange(width),(height,1)),0.15,2)+np.random.random( (height,width) )

#For representation purposes:

#plt.imshow(play_image,cmap='Greys_r')
#plt.show()


#1) Fit every row and kill the intensity decrease/increase tendency
fit_func = lambda p,x: p[0]*x+b  
errfunc = lambda p, x, y: abs(fitfunc(p, x) - y) # Distance to the target function
x_axis=np.linspace(0,width,width)

for i in range(height):
    row_val=play_image[i,:]
    p0=[(row_val[-1]-row_val[0])/float(width),row_val[0]] #guess
    p1, success = optimize.leastsq(errfunc, p0[:], args=(x_axis,row_val))
    play_image[i,:]-= fit_func(p1,x_axis)-p1[1]

通过这样做,我有效地水平调整了图像强度。无论如何我可以用矩阵运算替换循环吗?以某种方式同时用 (height,2) 参数向量拟合所有行?

感谢帮助

您可以很容易地实施 normal equations 及其解决方案。主要挑战是跟踪适当的维度,以便所有矢量化操作都能正常工作。这是一种方法:

import numpy as np


# image size
m = 100
n = 125

# A random image to work with.
np.random.seed(123)
img = np.random.randint(0, 100, size=(m, n))

# X is the design matrix.  It is the same for each row.  It has shape (n, 2).
X = np.column_stack((np.ones(n), np.arange(n)))

# A is X.T.dot(X), but in this case we can use an explicit formula for each term.
s1 = 0.5*n*(n - 1)            # Sum of integers
s2 = n*(n - 0.5)*(n - 1)/3.0  # Sum of squared integers
A = np.array([[n, s1], [s1, s2]])

# Y has shape (2, m).  Each column is a vector on the right-hand-side of the
# normal equations.
Y = X.T.dot(img.T)

# Solve the normal equations.  beta has shape (2, m).  Each column gives the
# coefficients of the linear fit for each row of img.
beta = np.linalg.solve(A, Y)

# Create an array that holds the linear drift for each row.
# X has shape (n, 2) and beta has shape (2, m), so row_drift has shape (m, n),
# the same as img.
row_drift = X.dot(beta).T

# Remove the drift from img.
img2 = img - row_drift

拟合一条线是simple formula直接使用,在numpy中大概三段短线就可以完成(下面的大部分代码只是制作和绘制数据并拟合):

import numpy as np
import matplotlib.pyplot as plt

# make the data as sequential sections of a circle
theta = np.linspace(np.pi, 0, 120)
y = np.reshape(np.sin(theta), (10,12))
x = np.repeat(np.arange(12)[None,:], 10, axis=0)

# fit the line
m = lambda x: np.mean(x, axis=1)
beta = ( m(y*x) - m(x)*m(y) )/(m(x*x) - m(x)**2)
alpha = m(y) - beta*m(x)

# plot the data and fits
plt.plot([y[:,i] for i in range(12)], ".")  # plot the data
plt.gca().set_color_cycle(None) # reset the color cycle
fits = alpha[:,None] + beta[:,None]*x  # make lines from the fits for the plots
plt.plot(fits.T)
plt.show()