SVD and best rank-k In the following code I am using Python's pillow/PIL library. I have successfully been able to read in an image file and store it as a matrix, access the red, blue, green channel which is an unsigned integer unit8 and convert each channel to float64.
However now I am looking to see if I did the next part correct. In my code below in addition to the above details I have applied the svd from numpy.linalg to each channel. Have I done this correctly? Also how might I use it to compute the rank-k approximation? Any help is greatly appreciated as I am not sure how I would compute the rank-k approximation if I implemented the svd from numpy.linalg to each channel correctly
Here is my code:
import numpy as np
from PIL import Image
img = Image.open('house.jpg')
image = np.array(img)
arr[20,30]
red = np.float64(image[:,:, 0])
green = np.float64(image[:,:,1])
blue = np.float64(image[:,:,2])

Applying it to the red channel:
P, D, Q = np.linalg.svd(red, full_matrices=False)
red_a = np.matmul(np.matmul(P, np.diag(D)), Q)
print(np.std(red), np.std(red_a), np.std(red - red_a))

resulting in:
58.34304856581507 58.34304856581494 9.996264017664882e-13

Applying it to the green channel:
P, D, Q = np.linalg.svd(green, full_matrices=False)
green_a = np.matmul(np.matmul(P, np.diag(D)), Q)
print(np.std(green), np.std(green_a), np.std(green - green_a))

resulting in:
51.90828777139797 51.90828777139794 2.5106850520519223e-13

finally applying it to the blue channel:
P, D, Q = np.linalg.svd(blue, full_matrices=False)
blue_a = np.matmul(np.matmul(P, np.diag(D)), Q)
print(np.std(blue), np.std(blue_a), np.std(blue - blue_a))

resulting in:
77.28319292372947 77.28319292372947 1.4848230006060346e-12

 A: I'm not certain if what you're doing works because of you're taking image data. I think a different approach needs to be done. 
import numpy as np
from PIL import Image
img = Image.open('house.jpg')
image = np.array(img)

red = np.float64(image[:,:, 0])
green = np.float64(image[:,:,1])
blue = np.float64(image[:,:,2])

def low_rank_k(u,s,vh,num):
# rank k approx

    u = u[:,:num]
    vh = vh[:num,:]
    s = s[:num]
    s = np.diag(s)
    my_low_rank = np.dot(np.dot(u,s),vh)
    return my_low_rank

# Take the svd
u,s,vh = np.linalg.svd(red, full_matrices= False)
# determine the matrix rank
my_rank_r = np.linalg.matrix_rank(red)
# generate the rank k approximation
my_rank_k_r = low_rank_k(u,s,vh,my_rank_r)

u,s,vh = np.linalg.svd(green,full_matrices=False)
my_rank_g = np.linalg.matrix_rank(green)
my_rank_k_g = low_rank_k(u,s,vh,my_rank_g)

u,s,vh = np.linalg.svd(blue,full_matrices=False)
my_rank_b = np.linalg.matrix_rank(blue)
my_rank_k_b = low_rank_k(u,s,vh,my_rank_b)


new_red = np.uint8(my_rank_k_r)
new_green = np.uint8(my_rank_k_g)
new_blue = np.uint8(my_rank_k_b)

my_array = np.array([new_red,new_green,new_blue])

note this array isn't right..
