Python SVD 修复特征值的个数来重建图像?
Python SVD fix the number of eigenvalues to rebuild the image?
我正在尝试重建我之前使用 SVD 分解的图像。图片是这样的:
我用这段代码成功分解了图像:
from PIL import Image
import numpy as np
import matplotlib.pyplot as plt
img = Image.open('steve.jpg')
img = np.mean(img, 2)
U,s,V = np.linalg.svd(img)
s
图像的 奇异值 数组。我取的奇异值越多,重建后的图像就越接近原图。
例如,如果我取 20 个奇异值:
n = 20
S = np.zeros(np.shape(img))
for i in range(0, n):
S[i, i] = s[i]
recon_img = U@S@V
plt.imshow(recon_img)
plt.axis('off')
plt.show()
我想修正奇异值的最小数量以获得良好结果:与原始图像pretty
相似的图像。此外,我想看看当我采用更多的奇异值时结果会发生多少变化。我尝试了一个动画但没有成功:
from PIL import Image
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
img = Image.open('steve.jpg')
img = np.mean(img, 2)
U,s,V = np.linalg.svd(img)
fig = plt.figure()
def update(i):
S = np.zeros(np.shape(img))
n = 20
for i in range(0, n):
S[i, i] = s[i]
recon_img = U@S@V
plt.imshow(recon_img)
plt.axis('off')
ani = FuncAnimation(fig = fig, func = update, frames = 20, interval = 10)
plt.show()
如果绘制 s
奇异值,您会看到一条非常陡峭的下降曲线,如果对 y 轴使用对数刻度则更好:
plt.semilogy(s, 'k-')
如您所见,前 50 个奇异值是最重要的:几乎每个奇异值都超过 1000。从 ~50 到 ~250 的值低一个数量级,并且它们的值缓慢下降:斜率包含曲线的(记住对数 y 标度)。那个蜜蜂说我会取前50个元素来重塑你的形象。
关于动画:
当动画逐帧更新时,计数器 i
增加 1。在您的代码中,您错误地使用 i
来分割 s
并定义 S
;你应该重命名计数器。
此外,随着动画的进行,您需要采用越来越多的奇异值,这是由 n
设置的,您逐帧保持不变。您需要在每个循环中更新 n
,因此您可以将其用作计数器。
此外,您需要擦除之前绘制的图像,因此需要在 update
函数的开头添加一个 plt.gca().cla()
。
检查以下代码以供参考:
from PIL import Image
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
img = Image.open('steve.jpg')
img = np.mean(img, 2)
U,s,V = np.linalg.svd(img)
fig, ax = plt.subplots(1, 2, figsize = (4, 4))
ax[0].imshow(img)
ax[0].axis('off')
ax[0].set_title('Original')
def init():
ax[1].cla()
ax[1].imshow(np.zeros(np.shape(img)))
ax[1].axis('off')
ax[1].set_title('Reconstructed\nn = 00')
def update(n):
ax[1].cla()
S = np.zeros(np.shape(img))
for i in range(0, n):
S[i, i] = s[i]
recon_img = U@S@V
ax[1].imshow(recon_img)
ax[1].axis('off')
ax[1].set_title(f'Reconstructed\nn = {n:02}')
ani = FuncAnimation(fig = fig, func = update, frames = 50, init_func = init, interval = 10)
ani.save('ani.gif', writer = 'imagemagick')
plt.show()
它给出了这个动画:
如您所见,前 50 个元素足以很好地重建图像。其余元素添加了一些噪音并稍微改变了背景。
我正在尝试重建我之前使用 SVD 分解的图像。图片是这样的:
我用这段代码成功分解了图像:
from PIL import Image
import numpy as np
import matplotlib.pyplot as plt
img = Image.open('steve.jpg')
img = np.mean(img, 2)
U,s,V = np.linalg.svd(img)
s
图像的 奇异值 数组。我取的奇异值越多,重建后的图像就越接近原图。
例如,如果我取 20 个奇异值:
n = 20
S = np.zeros(np.shape(img))
for i in range(0, n):
S[i, i] = s[i]
recon_img = U@S@V
plt.imshow(recon_img)
plt.axis('off')
plt.show()
我想修正奇异值的最小数量以获得良好结果:与原始图像pretty
相似的图像。此外,我想看看当我采用更多的奇异值时结果会发生多少变化。我尝试了一个动画但没有成功:
from PIL import Image
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
img = Image.open('steve.jpg')
img = np.mean(img, 2)
U,s,V = np.linalg.svd(img)
fig = plt.figure()
def update(i):
S = np.zeros(np.shape(img))
n = 20
for i in range(0, n):
S[i, i] = s[i]
recon_img = U@S@V
plt.imshow(recon_img)
plt.axis('off')
ani = FuncAnimation(fig = fig, func = update, frames = 20, interval = 10)
plt.show()
如果绘制 s
奇异值,您会看到一条非常陡峭的下降曲线,如果对 y 轴使用对数刻度则更好:
plt.semilogy(s, 'k-')
如您所见,前 50 个奇异值是最重要的:几乎每个奇异值都超过 1000。从 ~50 到 ~250 的值低一个数量级,并且它们的值缓慢下降:斜率包含曲线的(记住对数 y 标度)。那个蜜蜂说我会取前50个元素来重塑你的形象。
关于动画:
当动画逐帧更新时,计数器 i
增加 1。在您的代码中,您错误地使用 i
来分割 s
并定义 S
;你应该重命名计数器。
此外,随着动画的进行,您需要采用越来越多的奇异值,这是由 n
设置的,您逐帧保持不变。您需要在每个循环中更新 n
,因此您可以将其用作计数器。
此外,您需要擦除之前绘制的图像,因此需要在 update
函数的开头添加一个 plt.gca().cla()
。
检查以下代码以供参考:
from PIL import Image
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
img = Image.open('steve.jpg')
img = np.mean(img, 2)
U,s,V = np.linalg.svd(img)
fig, ax = plt.subplots(1, 2, figsize = (4, 4))
ax[0].imshow(img)
ax[0].axis('off')
ax[0].set_title('Original')
def init():
ax[1].cla()
ax[1].imshow(np.zeros(np.shape(img)))
ax[1].axis('off')
ax[1].set_title('Reconstructed\nn = 00')
def update(n):
ax[1].cla()
S = np.zeros(np.shape(img))
for i in range(0, n):
S[i, i] = s[i]
recon_img = U@S@V
ax[1].imshow(recon_img)
ax[1].axis('off')
ax[1].set_title(f'Reconstructed\nn = {n:02}')
ani = FuncAnimation(fig = fig, func = update, frames = 50, init_func = init, interval = 10)
ani.save('ani.gif', writer = 'imagemagick')
plt.show()
它给出了这个动画:
如您所见,前 50 个元素足以很好地重建图像。其余元素添加了一些噪音并稍微改变了背景。