图像压缩问题

图像压缩问题的bilibil讲解

1.问题引入

首先,图像是由像素组合成的,每个像素都有灰度值,灰度值是体现像素的颜色的。灰度值从0~255,灰度值占用的位数就是像素占用的位数。我们要存储一个图像就要存储它的所有像素。现在的问题是我们如何存储,使得存储空间最小?

思路:我们需要将图像分成m段,每段中有L[t]个像素,每个要占用b[t]个比特位,每个段都有一个端头,段头是固定的需要占用11位。因此总共需要如下存储空间。

一段像素个数最多有256个,这是题目要求的已知条件。一个像素要最少要占用多少位哩?设第t个像素的灰度值为n,b[t](每个像素占用的位数)要考虑到2种情况,第一种,n是2的整数次方,这时b[t]就是logn;第二种情况,a<logn<b(a,b为整数),这时要保证能表示灰度值,要加一再向上取整。综上,我们要满足这两种情况的并集,b[t]=log(n+1)向上取整,注意不能是log(n)+1向上取整,因为如果(n=2的x次方-1)时,这两种值就不一样了。例如,灰度值为1,我们需要一位来存储。再如,n=7,我们需要3位来存储。第t段最大的像素所占位数为max pk,得到如下图所示:

一个例子:

对于这个问题就转变成了如何分段问题。如果要用暴力求解法,我们要遍历多少种分段方法哩?

假设一共有n个像素,那么就有n-1个分割点,每个分割点可以选择分或不分,一共有2的n-1次方种分段方法

显然,比较浪费时间。

2.用动态规划算法可以减少时间复杂度,那么动态归划算法怎么划分子问题呢?

我们只用一个变量i来表示第i个像素的位置,找到第i个位置的最优解,每次增加一个像素,最终变成规模为n的像素问题。

例子:

上面例子种S[1]=4+11=15

S[2]的最优解在这两种划分方法中(1)分2段:S[1]+4+11=30  (2)分1段:S[0]+4*2+11=19

S[3]的最优解在这三种划分方法中(1)S[1]+4*2+11=34  (2)S[2]+4+11=34 (3)S[0]+4*3+11=23

S[4]的最优解在这四种划分方法中(1)S[3]+8+11=42 (2)S[2]+8*2+11 (3)S[1]+8*3+11 (4)S[0]+8*4+11

依次类推,S[6]的最优解在如上图所示这六种划分算法中。

(1)S[5]+1*2+11 (2)S[4]+2*2+11 (3) S[3]+3*8+11 (4)S[2]+4*8+11

(5)S[1]+5*8+11 (6) S[0]+6*8+11

红色部分对应代码

s[i] = s[i - 1] + bmax;//整个数组从1到i-1的最优解加i单独一段

  s[i] += header;

黄色部分对应代码

//在s[i]+j*bmax中找最好的存储方法
        for (int j = 2; j <= i && j <= Lmax; j++)
        {
            if (bmax < b[i - j + 1])//下标前移,找最大的像素
            {
                bmax = b[i - j + 1];
            }

            if (s[i] > s[i - j] + j * bmax)
            {
                s[i] = s[i - j] + j * bmax;
                l[i] = j;
            }
        }
        s[i] += header;

其中,L[i]记录S[i]的划分段数。

3.接下来,我们看看递推方程怎么表示

j-i+1i个像素中占用位数最大的像素记为b[i-j+1,i]

S[i]表示从第一个像素到第i个像素的最小存储总位数。

4.伪代码实现

s[i]来记录前i个数字的最优处理方式得到的最优解,即最小存储位数
l[i]来记录当前第i个数所在段中有多少个数,
b[i]中存放前i个像素点的最后一段中最大像素位数。

5.代码实现

#include <iostream>   
using namespace std;const int N = 8;int length(int i);
void Compress(int n, int p[], int s[], int l[], int b[]);
void Tracebace(int n, int& i, int s[], int l[]);
void Output(int s[], int l[], int b[], int n);int main()
{int p[] = { 0,10,12,15,255,1,2,0 };//图像灰度数组 下标从1开始计数  int s[N], l[N], b[N];
/**s[i]来记录前i个数字的最优处理方式得到的最优解,即最小存储位数
l[i]来记录当前第i个数所在段中有多少个数,
b[i]中存放前i个像素点的最后一段中最大像素位数。**/cout << "图像的灰度序列为:" << endl;for (int i = 1; i < N; i++) //输出原灰度序列 {cout << p[i] << " ";}cout << endl;Compress(N - 1, p, s, l, b);Output(s, l, b, N - 1);return 0;
}void Compress(int n, int p[], int s[], int l[], int b[])
{int Lmax = 256, header = 11;s[0] = 0;for (int i = 1; i <= n; i++){b[i] = length(p[i]); //计算像素点p需要的存储位数  int bmax = b[i];s[i] = s[i - 1] + bmax;//整个数组从1到i-1的最优解加i单独一段l[i] = 1;
//在s[i]+j*bmax中找最好的存储方法for (int j = 2; j <= i && j <= Lmax; j++){if (bmax < b[i - j + 1])//下标前移,找最大的像素{bmax = b[i - j + 1];}if (s[i] > s[i - j] + j * bmax){s[i] = s[i - j] + j * bmax;l[i] = j;}}s[i] += header;}
}
/***求数组中的元素用多少位二进制表示***/
int length(int i) //i表示p数组中元素的值 
{int k = 1;i = i / 2;while (i > 0){k++;i = i / 2;}return k;
}
/**s[i]来记录前i个数字的最优处理方式得到的最优解,即最小存储位数
l[i]来记录当前第i个数所在段中有多少个数,
b[i]中存放前i个像素点的最后一段中最大像素位数。**/
/*递归找寻分段的位置*/
void Traceback(int n, int& i, int s[], int l[])
{if (n == 0)return;Traceback(n - l[n], i, s, l);s[i++] = n - l[n];//重新为s[]数组赋值,用来存储分段位置  
}void Output(int s[], int l[], int b[], int n)
{//在输出s[n]存储位数后,s[]数组则被重新赋值,用来存储分段的位置  cout << "图像压缩后的最小空间为:" << s[n] << endl;int m = 0;Traceback(n, m, s, l);s[m] = n;cout << "将原灰度序列分成" << m << "段序列段" << endl;for (int j = 1; j <= m; j++){l[j] = l[s[j]];//在下标为s[j]的地方划分b[j] = b[s[j]];}for (int j = 1; j <= m; j++){cout << "段长度:" << l[j] << ",所需存储位数:" << b[j] << endl;}
}

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

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

相关文章

车载电子电器架构 —— 关于bus off汇总

车载电子电器架构 —— 关于bus off汇总 我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 屏蔽力是信息过载时代一个人的特殊竞争力,任何消耗你的人和事,多看一眼都是你的不对。非必要不费力证明…

【uniapp】H5+、APP模拟浏览器环境内部打开网页

前言 今天将智能体嵌入到我的项目中&#xff0c;当作app应用时&#xff0c;发现我使用的webview组件&#xff0c;无论H5怎么登录都是未登录&#xff0c;而APP却可以&#xff0c;于是进行了测试&#xff0c;发现以下几种情况&#xff1a; 方法<a>标签webviewAPP✅✅网页…

spring高级篇(八)

本篇对Spring MVC 的执行流程做一个简单总结 MVC执行流程总结 当浏览器发送一个请求&#xff0c;例如http://localhost:8080/hello&#xff0c;请求到达服务器后&#xff0c;一般会进行如下操作&#xff1a; 1、首先会经过DispatcherServlet&#xff0c;默认映射路径为 /&…

GRU模块:nn.GRU层的输出state与output

在 GRU&#xff08;Gated Recurrent Unit&#xff09;中&#xff0c;output 和 state 都是由 GRU 层的循环计算产生的&#xff0c;它们之间有直接的关系。state 实际上是 output 中最后一个时间步的隐藏状态。 GRU 的基本公式 GRU 的核心计算包括更新门&#xff08;update gat…

用于密集预测任务的通道知识蒸馏——关键字:蒸馏

摘要 https://arxiv.org/pdf/2011.13256 知识蒸馏(KD)已被证明是训练紧凑密集预测模型的简单有效工具。通过从大型教师网络转移而来的额外监督来训练轻量级学生网络。大多数先前的针对密集预测任务的KD变体都在空间域中对学生网络和教师网络的激活图进行对齐,通常是通过在每…

【Linux】进程间通信 - 管道

文章目录 1. 进程间通信介绍1.1 进程间通信目的1.2 进程间通信发展1.3 进程间通信分类 2. 管道2.1 什么是管道2.2 匿名管道2.3 用 fork 来共享管道原理2.4 站在文件描述符角度 - 深入理解管道2.5 站在内核角度 - 管道本质2.6 管道读写规则2.7 管道特点 3. 命名管道3.1 匿名管道…

linux代码实操——信号的使用

信号的基本概念 信号是系统响应某个条件而产生的事件&#xff0c;进程接收到信号会执行相应的操作。 与信号有关的系统调用在“signal.h”头文件中有声明 常见信号的值&#xff0c;及对应的功能说明&#xff1a; 修改信号的响应方式 – signal() 我们来做个小实验: 在键盘上…

推荐书单|提升境界、思维能力

1、《别做正常的傻瓜》 豆瓣评分&#xff1a;8.1 通过揭示人们在日常生活中常见的非理性行为&#xff0c;引导读者认识并克服这些行为&#xff0c;从而做出更明智的决策。 2、《活法》 豆瓣评分&#xff1a;8.1 稻盛和夫分享其人生哲学和经营哲学的著作&#xff0c;强调了正确…

【C++】模板初阶:泛型编程的起点

&#x1f49e;&#x1f49e; 前言 hello hello~ &#xff0c;这里是大耳朵土土垚~&#x1f496;&#x1f496; &#xff0c;欢迎大家点赞&#x1f973;&#x1f973;关注&#x1f4a5;&#x1f4a5;收藏&#x1f339;&#x1f339;&#x1f339; &#x1f4a5;个人主页&#x…

富文本编辑器CKEditor4简单使用-08(段落首行缩进插件 + 处理粘贴 Microsoft Word 中的内容后保持原始内容格式(包括首行缩进))

富文本编辑器CKEditor4简单使用-08&#xff08;段落首行缩进插件 处理粘贴 Microsoft Word 中的内容后保持原始内容格式&#xff08;包括首行缩进&#xff09;&#xff09; 1. 缩进&#xff0c;特殊方式处理——修改原工具栏里的增加缩进量2 缩进&#xff0c;插件处理2.1 下载…

C语言-链表实现贪吃蛇控制台游戏

使用C语言和链表实现贪吃蛇游戏 一、引言 贪吃蛇游戏是一个经典的游戏&#xff0c;它的玩法简单而富有挑战性。在这个博客中&#xff0c;我将分享如何使用C语言和链表数据结构来自主实现贪吃蛇游戏。我会详细介绍游戏的设计思路、编码过程、遇到的问题及解决方案&#xff0c;…

翻译《The Old New Thing》 - Why does the CreateProcess function do autocorrection?

Why does the CreateProcess function do autocorrection? - The Old New Thing (microsoft.com)https://devblogs.microsoft.com/oldnewthing/20050623-03/?p35213 Raymond Chen 在 2005 年 6 月 23 日 为什么 CreateProcess 函数会进行自动更正&#xff1f; 译注&#xff…

13_Scala面向对象编程_伴生对象

文章目录 1.伴生对象1.1 scala的一个性质&#xff0c;scala文件中的类都是公共的&#xff1b;1.2 scala使用object关键字也可以声明对象&#xff1b; 3.关于伴生对象和类4.权限修饰符&#xff0c;scala仅有private;5.伴生对象可以访问伴生类中的私有属性&#xff1b;6.案例7.伴…

世界十大最具影响力人物颜廷利:真正的高人,靠谱的行为

对于真正的‘高人’&#xff0c; 在面对‘狗洞’时&#xff0c; 他们都比较理智&#xff0c; 从来都不趾高气扬&#xff0c; 因为他们晓得&#xff0c; 倘若说不能弯下腰&#xff0c; 并而直立着身子走路的话&#xff0c; 那么&#xff0c; 他们就不是纯粹的‘高人’&#xff0…

1850H-The Third Letter

题目链接&#xff1a;The Third Letter 本道题目就是带权并查集的模板题&#xff0c;但又好久没学忘了&#xff0c;再复习一遍。。。 路径压缩函数模板&#xff1a; int root(int x){if(pre[x]!x){int troot(pre[x]);d[x]d[pre[x]];pre[x]t;}return pre[x]; } 之后就模拟一…

c++ 红黑树学习及简单实现

1. 了解红黑树 1.1. 概念 红黑树&#xff0c;是一种二叉搜索树&#xff0c;但在每个节点增加一个存储位表示节点的颜色&#xff0c;可以是红色&#xff0c;或是黑色&#xff0c;通过对任何一条从根到叶子的路径上各个节点的着色方式进行限制&#xff0c;红黑树确保没有一条路…

初识webpack项目

新建一个空的工程 -> % mkdir webpack-project 为了方便追踪执行每一个命令&#xff0c;最终产生了哪些变更&#xff0c;将这个空工程初始化成git项目 -> % cd webpack-project/-> % git init Initialized empty Git repository in /Users/lixiang/frontworkspace/…

AI文章框架分析

大家在文章写作的时候结构难免会有点凌乱&#xff0c;但是自己可能无法发现问题所在&#xff0c;那么有没有一款工具可以帮你自动分析你写的文章框架存在的问题&#xff0c;然后并给你详细的分析报告呢&#xff1f;今天给大家介绍一下文件框架分析助手&#xff01; 使用说明 打…

如何配置X86应用程序启用大地址模式(将用户态虚拟内存从2GB扩充到3GB),以解决用户态虚拟内存不够用问题?(项目实战案例解析)

目录 1、概述 2、为什么不直接将程序做成64位的&#xff1f; 3、进程内存不足导致程序发生闪退的案例分析 3.1、问题说明 3.2、将Windbg附加到程序进程上进行动态调试 3.3、动态调试的Windbg感知到了中断&#xff0c;中断在DebugBreak函数调用上 3.4、malloc或new失败的…

IoTDB 入门教程 问题篇②——RPC远程连接IoTDB服务器失败

文章目录 一、前文二、发现问题三、分析问题四、检查6667端口是否监听所有IP五、检查ECS云服务器的安全组是否允许六、检查Linux防火墙是否允许 一、前文 IoTDB入门教程——导读 二、发现问题 使用本地IP127.0.0.1可以连接IoTDB服务器使用远程IPxx.xx.xx.xx却连接不到。提示你…