我将上面的rgb图像保存为tux.jpg
。现在我想得到这个图像的最接近的近似值,它是两个向量Ie的外积,其形式为A · B T
这是我的代码 -
#load image to memory
import Image
im = Image.open('tux.jpg','r')
#save image to numpy array
import numpy as np
mat = np.asfarray(im.convert(mode='L')) # mat is a numpy array of dimension 354*300
msizex,msizey = mat.shape
x0 = np.sum(mat,axis=1)/msizex
y0 = np.sum(mat,axis=0)/msizey
X0 = np.concatenate((x0,y0)) # X0.shape is (654,)
# define error of outer product with respect to original image
def sumsquares(X):
""" sum of squares -
calculates the difference between original and outer product
input X is a 1D numpy array with the first 354 elements
representing vector A and the rest 300 representing vector B.
The error is obtained by subtracting the trial $A\cdot B^T$
from the original and then adding the square of all entries in
the matrix.
"""
assert X.shape[0] == msizex+msizey
x = X0[:msizex]
y = X0[msizex:]
return np.sum(
(
np.outer(x,y) - mat
)**2
)
#import minimize
from scipy.optimize import minimize
res = minimize(sumsquares, X0,
method='nelder-mead',
options={'disp':True}
)
xout = res.x[:msizex]
yout = res.x[msizex:]
mout = np.outer(xout,yout)
imout= Image.fromarray(mout,mode='L')
imout.show()
Optimization terminated successfully.
Current function value: 158667093349733.531250
Iterations: 19
Function evaluations: 12463
这对我来说不够好看。有没有办法改善这个?输出中的噪声甚至与原始图像中的结构的长度不同。我的猜测是算法没有通过。我该如何调试或改进?
EDIT1:我使用代码
创建了下面的图片size = 256
mat0 = np.zeros((size,size))
mat0[size/4:3*size/4,size/4:3*size/4] = 1000
#mat0[size/4:3*size/4,] = 1000
#mat0[:3*size/4,size/4:] = 1000
im0 = Image.fromarray(mat0)
im0.show()
两个注释掉的行导致另外两个图像。以下是我的实验结果 -
答案 0 :(得分:0)
1)第一张图片的渲染问题似乎是从numpy数组转换为图像的问题。我通过运行来获得正确的渲染:
imout = Image.fromarray(mout/np.max(mout)*255)
(即将图像标准化为最大值255并让它自动确定模式)。
通常,要检查Image.fromarray是否正常工作,将imout.show()的输出与
进行比较是有用的。import matplotlib.pyplot as plt
plt.matshow(mout/np.max(mout)*255, cmap=plt.cm.gray)
你应该得到相同的结果。顺便说一句,通过这样做,我得到了所有其他3个案例。
2)其次,tux.png的主要问题是不可能仅使用两个1-D向量的外积来重建具有这种详细结构的图像。
(这往往适用于简单的图像,如上面所示的块状图像,但不适用于对称性和细节很少的图像)。
要证明这一点:
存在矩阵分解技术,其允许将矩阵重构为两个低秩矩阵M = AB的乘积,例如sklearn.decomposition.NMF。
在这种情况下,将A和B的等级设置为1将等同于您的问题(使用不同的优化技术)。
使用下面的代码,您可以很容易地看到n_components = 1(相当于两个1-D向量的外积),得到的重构矩阵看起来非常类似于您的方法输出的矩阵而且,对于更大的n_components,重建越好。
重现性:
import matplotlib.pyplot as plt
from sklearn.decomposition import NMF
nmf = NMF(n_components=20)
prj = nmf.fit_transform(mat)
out = prj.dot(nmf.components_)
out = np.asarray(out, dtype=float)
imout = Image.fromarray(out)
imout.show()
为了说明,这是使用1个分量的NMF重建(这正是两个1-D矢量之间的外部产品):
有2个组成部分:
这是NMF重建的20个组成部分。
这清楚地表明单个1-D外部产品对于此图像是不够的。然而,它适用于块状图像。
如果您不局限于向量的外积,那么矩阵分解可以是另一种选择。顺便说一下,存在大量的矩阵分解技术。 sklearn的另一个选择是SVD。
3)最后,x0和y0可能存在缩放问题。请注意,np.outer(x0,y0)的元素比mat的元素高几个数量级。
虽然使用提供的代码我仍然可以获得3个块状示例的良好结果,但一般来说,在采用方差时具有可比较的比例是一个好习惯。例如,您可能希望缩放x0和y0,以使np.outer的范数与mat的范数相当。