基于奇异值分解(SVD)的图片压缩实践

文章目录

    • 1. 前言
    • 2. 原理简介
      • 2.1 SVD定义
    • 3. 实践代码
    • 4. 参考文献

1. 前言

数字图片在计算机中是以矩阵形式存储的。所以可以通过矩阵理论和矩阵算法对数字图像进行分析和处理。本文通过对图片进行SVD压缩,对不同的参数下的压缩效果进行对比。

SVD概念可以参考:《统计学习方法》–奇异值分解(Singular Value Decomposition,SVD)

2. 原理简介

彩色图片有3个图层,RGB(红、绿、蓝)也就是矩阵的一个位置上存储了3个基色的数值,由3个基色混合成不同的色彩。

通过对3个图层矩阵,分别进行SVD近似,SVD奇异值是唯一的,可以取前 k 个最大的奇异值进行近似表达,最后再将3个图层的矩阵数据合并,用较少的数据去表达图片。

2.1 SVD定义

Am×n=UΣVTUUT=ImVVT=InΣ=diag(σ1,σ2,...,σp)σ1≥σ2≥...≥σp≥0p=min⁡(m,n)A_{m \times n} = U \Sigma V^T\\ UU^T=I_m\\ VV^T=I_n\\ \Sigma=diag(\sigma_1,\sigma_2,...,\sigma_p) \\ \sigma_1\ge \sigma_2 \ge...\ge\sigma_p \ge0\\ p=\min(m,n)Am×n=UΣVTUUT=ImVVT=InΣ=diag(σ1,σ2,...,σp)σ1σ2...σp0p=min(m,n)

  • UΣVTU \Sigma V^TUΣVT 称为矩阵 AAA 的奇异值分解(SVD),UUUmmm 阶正交矩阵, VVVnnn 阶正交矩阵,Σ\SigmaΣm×nm \times nm×n 的对角矩阵
  • σi\sigma_iσi 称为矩阵 AAA 的奇异值
  • UUU 的列向量,左奇异向量
  • VVV 的列向量,右奇异向量

在这里插入图片描述
Datam×n≈U[:,0:k]Σ[0:k,0:k]VT[0:k,:]Data_{m\times n} \approx U[ : , 0:k] \Sigma[0:k,0:k]V^T[0:k, :]Datam×nU[:,0:k]Σ[0:k,0:k]VT[0:k,:]

3. 实践代码

# -*- coding:utf-8 -*-
# @Python Version: 3.7
# @Time: 2020/4/21 23:38
# @Author: Michael Ming
# @Website: https://michael.blog.csdn.net/
# @File: 15.svd_pic_compress.py
# @Reference: https://blog.csdn.net/weixin_44344462/article/details/89401727import numpy as np
import matplotlib.pyplot as pltdef zip_img_by_svd(img, plotId, rate=0.8):zip_img = np.zeros(img.shape)u_shape = 0sigma_shape = 0vT_shape = 0for chanel in range(3):  # 3个图层u, sigma, v = np.linalg.svd(img[:, :, chanel])  # numpy svd函数sigma_i = 0temp = 0while (temp / np.sum(sigma)) < rate:  # 选取的奇异值和需要达到设定的权重temp += sigma[sigma_i]sigma_i += 1SigmaMat = np.zeros((sigma_i, sigma_i))  # 选取了sigma_i 最大的奇异值for i in range(sigma_i):SigmaMat[i, i] = sigma[i]  # 将奇异值填充到Sigma对角矩阵zip_img[:, :, chanel] = u[:, 0:sigma_i].dot(SigmaMat).dot(v[0:sigma_i, :])# 将分解得到的3个矩阵相乘,得到压缩后的近似矩阵u_shape = u[:, 0:sigma_i].shapesigma_shape = SigmaMat.shapevT_shape = v[0:sigma_i, :].shapefor i in range(3):  # 对三个通道的矩阵数值进行归一化处理MAX = np.max(zip_img[:, :, i])MIN = np.min(zip_img[:, :, i])zip_img[:, :, i] = (zip_img[:, :, i] - MIN) / (MAX - MIN)zip_img = np.round(zip_img * 255).astype("uint8")# 不乘255图片是黑的(接近0,0,0),数据类型uint8plt.imsave("zip_svd_img.jpg", zip_img)  # 保存压缩后的图片zip_rate = (img.size - 3 * (u_shape[0] * u_shape[1] + sigma_shape[0] * sigma_shape[1] + vT_shape[0] * vT_shape[1])) / (zip_img.size)f = plt.subplot(3, 3, plotId)f.imshow(zip_img)f.set_title("SVD压缩率 %.4f,奇异值数量:%d" % (zip_rate, sigma_i))print("设置的压缩率:", rate)print("使用的奇异值数量:", sigma_i)print("原始图片大小:", img.shape)print("压缩后用到的矩阵大小:3x({}+{}+{})".format(u_shape, sigma_shape, vT_shape))print("压缩率为:", zip_rate)if __name__ == '__main__':imgfile = "svd_img.jpg"plt.figure(figsize=(12, 12))plt.rcParams['font.sans-serif'] = 'SimHei'  # 消除中文乱码img = plt.imread(imgfile)f1 = plt.subplot(331)  # 绘制子图,3行3列,3*3个子图,现在画第1幅f1.imshow(img)f1.set_title("原始图片")for i in range(8):  # 再画8个子图rate = (i + 1) / 10.0  # 压缩率 10% - 80%zip_img_by_svd(img, i + 2, rate)plt.suptitle('图片SVD效果对比', fontsize=17, y=0.02)  # y偏移距离plt.show()

在这里插入图片描述

  • 可以看出在使用128个奇异值的SVD压缩情况下,就可以得到跟原图差不多效果的图片
  • 原图是703x800的尺寸,SVD使用的矩阵 ((703, 128)+(128, 128)+(128, 800))=208768
  • 可以少使用的矩阵数据比例为(703*800*3-208768*3)/(703*800*3)= 62.88%
  • 可以只用37.12%的数据量去近似表达原始图片,是不是很酷!!!
  • 在网络传输图片的过程中,终端用户可能点击,也可能不点击,那我都给他们发送SVD后的图片矩阵数据(减少了当次传输数据量),然后在终端进行矩阵运算得到压缩后的图片,当用户点击图片后,再进行传输原图片(1、用户点击是分散的,可以降低统一发送原图的网络拥挤现象;2、有的用户也不会点击,就避免了传输原图,达到了压缩的目的,节省流量)
  • 微信收到的图片、小米手机云相册的缩略图等都可能用到类似的技术来节省空间

我是外行,自己想的结论,不对的地方,请大佬指点,感谢!

4. 参考文献

本文参考了以下两篇文章,对作者表示感谢!

  • 利用SVD进行图像压缩(附Python代码)
  • 用SVD压缩图像

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/476336.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

执行文件异常报错:ImportError: attempted relative import with no known parent package

问题描述 1. 源代码中的导入代码&#xff1a; from ..utils.osutils import mkdir_if_missing #导入自己的 函数 from ..utils.serialization import write_json, read_json这个是将utils中的py文件导入到cuhk03中。但是报错&#xff01; 解决方法 1. 相对导入 其中上述…

待机、休眠、睡眠的区别和优缺点

Windows操作系统中很早就加入了待机、休眠等模式&#xff0c;而Windows Vista中更是新加入了一种叫做睡眠的模式&#xff0c;可是很多人还是习惯在不使用电脑的时候将其彻底关闭。其实充分利用这些模式&#xff0c;我们不仅可以节约电力消耗&#xff0c;还可以用尽可能短的时间…

LeetCode 508. 出现次数最多的子树元素和(递归)

1. 题目 给你一个二叉树的根结点&#xff0c;请你找出出现次数最多的子树元素和。 一个结点的「子树元素和」定义为以该结点为根的二叉树上所有结点的元素之和&#xff08;包括结点本身&#xff09;。 你需要返回出现次数最多的子树元素和。如果有多个元素出现的次数相同&…

知识图谱入门视频(一)

学习内容&#xff1a; 知识图谱导论 陈华钧 浙江大学计算机科学与技术学院 教授 小象学院 哔哩哔哩 第一章 【其实后面的方法学习只是一个框架式的学习&#xff0c;并不明白具体的操作】 1. 什么是知识图谱&#xff1f; 知识图谱是一个系统&#xff01; 从根据场景构建再到场…

onenetsim定位功能吗_经常玩手机的抓紧看看,原来手机键盘还隐藏4个实用功能,真实用...

可爱的人都关注我了&#xff0c;就差你了1在日常生活中&#xff0c;大家对手机的依赖性越来越大&#xff0c;不管走到哪&#xff0c;时时刻刻都拿着手机发信息。可是&#xff0c;用了这么久的手机&#xff0c;你真的会用手机键盘吗&#xff1f;你知道手机键盘上隐藏的小功能吗&…

程序模拟键盘鼠标操作

用代码模拟键盘鼠标操作,主要用到keybd_event/mouse_event或者SendInput API函数.使用示例如下(附注释): /** 模拟键盘输入,以按窗口键(WIN键)为例 *///keybd_event模拟键盘输入示例::keybd_event( VK_LWIN, 0, 0, 0); //按下WIN键 ::keybd_event( VK_LW…

LeetCode 520. 检测大写字母

1. 题目 给定一个单词&#xff0c;你需要判断单词的大写使用是否正确。 我们定义&#xff0c;在以下情况时&#xff0c;单词的大写用法是正确的&#xff1a; 全部字母都是大写&#xff0c;比如"USA"。 单词中所有字母都不是大写&#xff0c;比如"leetcode&qu…

不同电脑 命名管道_电脑键盘上的F1到F12,这些键都有哪些用处?用了5年总算明白了...

电脑键盘上的F1到F12&#xff0c;这些键都有哪些用处&#xff0c;用了5年总算明白了经常使用电脑的朋友会发现&#xff0c;电脑键盘上有一排F开头的键。那么这些键到底有什么用处呢&#xff1f;下面我们一起来了解一下。首先这些键都属于快捷键&#xff0c;所以每个键都有不同的…

知识图谱入门视频(二)

学习内容 小象学院 b站 第二章 【其实后面的方法学习只是一个框架式的学习&#xff0c;并不明白具体的操作】 第二部 典型知识库项目简介 CYC&#xff08;读音&#xff1a; 赛克&#xff09; CYC&#xff1a; 1984年由Douglas Lenat开始创建&#xff0c;最初的目标是建立人类…

InterDev 调试错误信息: Unable to set server into correct debugging state automatically....的解决办法...

InterDev 调试错误信息: Unable to set server into correct debugging state automatically....权威解决方法了&#xff1a;1、安装 vs6.0 cd2 vid_ss/setup.exe 2、安装 vs6.0 cd2 vid_ss/setup.exe3、配置dcom&#xff0c;设置用户权限4、打开IIS的调试功能5、OK详情见微软…

LeetCode 521. 最长特殊序列 Ⅰ

1. 题目 给你两个字符串&#xff0c;请你从这两个字符串中找出最长的特殊序列。 「最长特殊序列」定义如下&#xff1a;该序列为某字符串独有的最长子序列&#xff08;即不能是其他字符串的子序列&#xff09;。 子序列 可以通过删去字符串中的某些字符实现&#xff0c;但不…

wordpress acf字段 不同样式_提升wordpress执行效率二次开发实录

wordpress 对分类增加广告配置功能 wp_terms 增加admaster字段 varchar 200 wp-admin/edit-tag-form.php 小资料&#xff1a; wordpress wp_terms分类表 wp_term_taxonomy分类类型表、wp_term_relationships分类关联表 这三个表单相互关联 wordpress优化效率 当wordpress执行…

知识图谱入门知识(一)知识图谱应用以及常用方法概述

学习内容 搜集各种博客&#xff0c;理解实体识别、关系分类、关系抽取、实体链指、知识推理等&#xff0c;并且总结各种分类中最常用的方法、思路。 由于自己刚刚接触知识图谱&#xff0c;对该领域的概念和方法的描述还不是很清楚&#xff0c;所以只是简单的列出框架和添加链接…

openMP学习笔记(一)

声明&#xff1a;欢迎任何人和组织转载本blog中文章&#xff0c;但必须标记文章原始链接和作者信息。 本文链接&#xff1a;http://blog.csdn.net/li_007/archive/2009/04/30/4139211.aspx 开拓进取的小乌龟------->CSDN点滴点点滴滴Blog 之前大概看了一下openMP&#xff0c…

LeetCode 532. 数组中的K-diff数对

1. 题目 给定一个整数数组和一个整数 k, 你需要在数组里找到不同的 k-diff 数对。 这里将 k-diff 数对定义为一个整数对 (i, j), 其中 i 和 j 都是数组中的数字&#xff0c;且两数之差的绝对值是 k. 示例 1: 输入: [3, 1, 4, 1, 5], k 2 输出: 2 解释: 数组中有两个 2-diff …

python随机生成六位数密码_python生成6位包含数字和字母的密码

初学python&#xff0c;简单敲了几行生成6位包含数字和字母密码的代码(我是在python 3上敲的)首先理清思路&#xff1a;1、包含数字和字母的六位口令共有36^6个2、将0-9和a-z合成一个字符串pwd,用pwd[0-35]表示所有数字和小写字母&#xff0c;即pwd[0]0,pwd[1]1…pwd[34]y,pwd[…

知识图谱入门视频(三)

学习内容 小象学院 b站 第三章 【其实后面的方法学习只是一个框架式的学习&#xff0c;并不明白具体的操作】 链接 问题&#xff1a; 知识图谱究竟是什么&#xff1f; 可以看看开放知识图谱 其实就是将我们的语言拆分转换为符号表达&#xff0c;之后经过机器学习来将离散式的…

博客新皮肤上市

原创&#xff1a;冰极峰 有朋友说原来的博客不好看&#xff0c;趁着五一节放假&#xff0c;花了点时间重新制作了一套样式&#xff0c;图片借用一个外国博客的图片。 样式全部基于自定义皮肤样式改写的。 说实话&#xff0c;改写博客园样式是一件比较痛苦的事情&#xff0c;你不…

python调用接口测试_Python接口测试实战2 - 使用Python发送请求

本节内容requests安装requests使用JSON类型解析requests库详解带安全认证的请求序言上节课我们学习了接口测试的理论&#xff0c;抓包工具及使用Postman手工测试各种接口&#xff0c;这节课我们主要讲解使用Python语言来发送接口请求&#xff0c;实现接口测试自动化。发送请求,…

LeetCode 551. 学生出勤记录 I

1. 题目 给定一个字符串来代表一个学生的出勤记录&#xff0c;这个记录仅包含以下三个字符&#xff1a; A : Absent&#xff0c;缺勤 L : Late&#xff0c;迟到 P : Present&#xff0c;到场如果一个学生的出勤记录中 不超过一个’A’(缺勤) 并且 不超过两个连续的’L’(迟到…