# coding=utf-8

from PIL import Image
from numpy import *
from pylab import imshow,show

zero = 1e-10
def inverseSVD2(U, sigma, VT):
    m = U.shape[0]; n = VT.shape[0]
    if m > n:
        # 令U中的前n列数据乘以相应的sigma值，因为numpy.array shape(n,m) * shape(n,1) 等价于 重复相乘 shape(n,m)*shape(n,m),所以要转置
        redish = (U[:, :n].T * array([sigma]).T).T          # = [s1*u1, s2*u2 .. sn*un]; [UA UB] * [S;0] = UA*S = U(:,0:n)*S
                                                            # 每行n以后的部分乘以的是0对计算无影响，直接不计算
        redish = mat(redish) * VT
    else :
        redish = (U.T * array([sigma]).T).T
        redish = mat(redish) * VT[:m, :]                    # = [U*S 0] * [ A B; C D] = [U*S*A U*S*B] = U*S*[A B] = U*S*VT(0:m,:)

    redish = array(redish)
    indexes = nonzero(abs(redish) < zero)           # 找到所有小于1e-10的数的下标
    redish[indexes] = 0                         # 将这些数置为 0
    return redish

img = array(Image.open("../Data/Image/banboo.png"))
newimg = img
step = 10
for chanel in range(3):
    U, sig, VT = linalg.svd(img[:, :, chanel])
    sigSum = sum(sig)
    sigUse = 0
    for i in range(0, len(sig), step):
        sigUse += sum(sig[i : i + step])
        if sigUse / sigSum > 0.9 : break
    sig[(i+1):] = 0
    newimg[:, :, chanel] = inverseSVD2(U, sig, VT)

imshow(uint8(newimg))
show()


