2018-11-14 00:33:29 weixin_40276644 阅读数 1581

前言

矩阵变化中有非常重要的变换为奇异值分解SVD。形式很简单,但是在具体处理中却具有非常重要的物理意义。

SVD分解

SVD分解在图像处理中,也可理解为二维数据处理中具有非常重要的意义。如下:A=UDVTA=UDV^T
在这里插入图片描述

这里U和V均满足UUT=IUU^T=I,VVT=IVV^T=I
在这里插入图片描述

其中D如下:
在这里插入图片描述
现在:假如A代表一条曲线,如左边,U的每个列向量代表直线,向下的曲线和转折的曲线等等,而β1,2,3\beta_{1,2,3}代表的是有D和VTV^T决定,我们可以认为U是基向量输入,D是增益系数,V是输出控制矩阵(按照控制理论理解)
在这里插入图片描述那么在图像领域应该如何理解尼?这里有一张像素非常大的图片(2000,1000(大致的值))
在这里插入图片描述
我们对它做svd分解正常应该分解出一个2000,2000的基向量矩阵,但我们只取其前4列的基向量:
在这里插入图片描述
我们可以看见前四行的重构基本还原了大体结构,接下来我们来看D矩阵中对角线上数值的变化:

在这里插入图片描述可以看到,这个值下降得非常快,前文我们说过,中间矩阵D相当于增益矩阵,说明图像大部分有较大的增益控制,所以我们只需要采用增益值大的所对应的基向量就基本可以表示这张图形。例子如下:
在这里插入图片描述
左图是原图,右两图都是舍弃掉了D矩阵中较小的值所对应的列向量所构成。
也就是说我们在进行某些识别工作时,可以用较少的数据空间代表原来数据的绝大部分特征,而通常这样的特征也基本够做分类与判别。
更有趣的是,当我们获得一张图像的基向量矩阵U时如下图·:
在这里插入图片描述
我们改变其D和V矩阵(改变输出)就可以刻画比如年龄的变化:

在这里插入图片描述
这是不是就和美图秀秀里的样貌变化功能有异曲同工之妙尼。下面附上简单的svd重构代码:

clear,clc;
close all;
img=double(imread('filepath'))
figure(1);
subplot(211);
imshow(img,[]);title('original');
[m,n] = size(img);
[U,S,V] = svd(img);%SVD分解
decomp = U(:,:)*S(:,1:n)*V(:,1:n)';%n值根据情况取得,这里基向量矩阵仍然可以保持完整,也可以取前n列,感兴趣的朋友可以去试一下两者间的不同
subplot(212);imshow(decomp,[]);title('svd-前n个特征重构');


2017-12-31 19:17:23 zhengwei223 阅读数 799

目标

利用SVD思想将图像做不同程度的压缩,查看效果

思路

主要利用这个近似公式Am×n=Um×mΣm×nVTn×nUm×kΣk×kVTk×n

代码

import numpy as np
from PIL import Image

def rebuild2(u,sigma,v,k):
    "k:前k维"
    uk = u[:,:k] # 前k列
    sigma_k=np.diag(sigma[:k])  # 前k个奇异值
    vk = v[:k,:] # 前k行

    dot1 = np.dot(uk, sigma_k)
    return np.dot(dot1,vk)  # uk*Σk*vk

pic = Image.open('/Users/zhengwei/Pictures/zxt.jpg', 'r')
# 灰度转换
pic = pic.convert("L")
# 转换为矩阵
pic_arr = np.array(pic)
print(pic_arr.shape)
# SVD
u, sigma, v = np.linalg.svd(pic_arr[:, :])
print(sigma.shape)
# 十分之一维,前64,共640维
L = rebuild2(u, sigma, v,k=64)
Image.fromarray(L).show()
# 五分之一维,前128,共640维
L = rebuild2(u, sigma, v,k=128)
Image.fromarray(L).show()

这里写图片描述

控制奇异值占比

即控制ki=1σini=1σi的比例。

def rebuild(u, sigma, v, per=0.9):
    'per:奇异值占比'
    m = len(u)
    n = len(v)
    a = np.zeros((m, n))
    sigma_sum = int(sum(sigma))
    cur_sum = 0
    k = 0
    while cur_sum <= sigma_sum * per:
        # 取1列
        uk = u[:, k].reshape(m, 1)
        # 取一行
        vk = v[k].reshape(1, n)

        a += sigma[k] * np.dot(uk, vk)

        cur_sum += sigma[k]  # 累加奇异值
        k += 1
    a[a < 0] = 0
    a[a > 255] = 255
    print("k/n==%d/%d==%.2f" % (k, n, k / n))
    return np.rint(a).astype("uint8")

调用代码同上,传参时注意per是奇异值占比。

经计算per=0.9时对应k/n==214/640,也就是说取前三分之的奇异值就能还原原图的百分之九十。

2019-12-28 12:15:55 xjp_xujiping 阅读数 12

一开始做图像奇异值分解实验,用的

u, sigma, v = np.linalg.svd()

出来的全是乱码图像

怎么调整都不行,简直要抓狂了 ` 0 ` !!! 

后来在别人电脑上跑了一下,竟然有效果!

找问题!!调整numpy的版本,

pip install numpy==1.16.5

果然解决了!!!

应该是numpy版本问题,或者文件损坏了,么得办法!

把numpy升级到最新版的命令如下,但可能会如系统中的tensorflow版本不兼容:

pip install -U numpy

pip install --upgrade numpy

 


from PIL import Image
import numpy as np

def rebuild_img(u, sigma, v, p): #p表示奇异值的百分比
    print (p)
    m = len(u)
    n = len(v)
    a = np.zeros((m, n))
    
    count = (int)(sum(sigma))
    curSum = 0
    k = 0
    while curSum <= count * p:
        uk = u[:, k].reshape(m, 1)
        vk = v[k].reshape(1, n)
        a += sigma[k] * np.dot(uk, vk)
        curSum += sigma[k]
        k += 1
    print ('k:',k)
    a[a < 0] = 0
    a[a > 255] = 255
    #按照最近距离取整数,并设置参数类型为uint8
    return np.rint(a).astype("uint8")
    
if __name__ == '__main__':
    img = Image.open('lena.jpg', 'r')
    a = np.array(img)
    print("a.shape: ",a.shape)
    
    for p in np.arange(0.1, 1, 0.1):
        u, sigma, v = np.linalg.svd(a[:, :, 0])
        print("R:sigma.shape :",sigma.shape)
        R = rebuild_img(u, sigma, v, p)
        
        u, sigma, v = np.linalg.svd(a[:, :, 1])
        print("G:sigma.shape :",sigma.shape)
        G = rebuild_img(u, sigma, v, p)
        
        u, sigma, v = np.linalg.svd(a[:, :, 2])
        print("B:sigma.shape :",sigma.shape)
        B = rebuild_img(u, sigma, v, p)
        
        I = np.stack((R, G, B), 2)
        #保存图片在img文件夹下
        print(I.shape)              
                 
        Image.fromarray(I).save("lena_" + str(p * 100) + ".jpg")
        
  

 

lena.jpg

 

 

2019-11-03 19:52:44 m0_37772174 阅读数 114

前言

  SVD即奇异值分解(singular value decomposition),是将矩阵分解为奇异向量和奇异值。
  每次写相关文章的时候,都会面临一个常见的问题,矩阵是什么?套用平冈和幸的话来说,矩阵即是映射,令矩阵y=Ax,那么矩阵A就是由向量x到向量y的一个映射。从另一个角度看,矩阵又是数的排列。SVD的核心思想是,通过较数据量较少的多个矩阵的映射去还原一个数据量更大的数的排列。即只要A,x两者的数字数量相加小于y,我们就实现了数据压缩。对于图像的压缩,可以通过PSNR进行判断。
  SVD的用处之一,即是用于图像的数据压缩。因为实际图像各像素点之间具有高度相关性,因此,使用更少的像素取表示整张图像的信息是可行的。

代码

# -*- coding: utf-8 -*-
'''
author@cclplus
date:2019/11/3
'''
import cv2
import matplotlib as mpl
import numpy as np
import matplotlib.pyplot as plt
#转为u8类型
def restore1(u, sigma, v, k):
    m = len(u)
    n = len(v)
    a = np.zeros((m, n))
    a = np.dot(u[:, :k], np.diag(sigma[:k])).dot(v[:k, :])
    a[a < 0] = 0
    a[a > 255] = 255
    return np.rint(a).astype('uint8')
def SVD(frame,K=10):
    a = np.array(frame)
    #由于是彩色图像,所以3通道。a的最内层数组为三个数,分别表示RGB,用来表示一个像素
    u_r, sigma_r, v_r = np.linalg.svd(a[:, :, 0])
    u_g, sigma_g, v_g = np.linalg.svd(a[:, :, 1])
    u_b, sigma_b, v_b = np.linalg.svd(a[:, :, 2])
    R = restore1(u_r, sigma_r, v_r, K)
    G = restore1(u_g, sigma_g, v_g, K)
    B = restore1(u_b, sigma_b, v_b, K)
    I = np.stack((R, G, B), axis = 2)
    return I
      

if __name__ == "__main__":
    mpl.rcParams['font.sans-serif'] = [u'simHei']
    mpl.rcParams['axes.unicode_minus'] = False
    frame = cv2.imread("./liuyifei.bmp")
    I = SVD(frame,40)
    plt.imshow(I)
    cv2.imwrite("out.bmp",I)

  原图
在这里插入图片描述
  取二十个特征值
在这里插入图片描述

没有更多推荐了,返回首页