图像压缩问题

问题描述

给定一张灰度图,其像素为长度为 n n n的灰度值序列:{ p 1 , p 2 , ⋯   , p n p_1,p_2,\cdots,p_n p1,p2,,pn},其中 p i ∈ [ 0 : 1 : 255 ] p_i \in [0:1:255] pi[0:1:255]可表示为8位二进制数。现使用一种变位压缩方式对图像进行压缩,具体压缩过程如下:
将{ p 1 , p 2 , ⋯   , p n p_1,p_2,\cdots,p_n p1,p2,,pn}分割成为 m m m段: S 1 , S 2 , ⋯   , S m S_1,S_2,\cdots,S_m S1,S2,,Sm
l [ i ] l[i] l[i] S i S_i Si段的像素数,要求 l [ i ] ≤ 256 l[i]\leq 256 l[i]256
h i h_i hi S i S_i Si段中最大像素灰度值对应的二进制位数,则有 h i = ⌈ log ⁡ ( max ⁡ p k ∈ s i { p k } + 1 ) ⌉ h_i=\left \lceil\log\left(\max\limits_{p_k \in s_i}\{p_k\}+1\right)\right\rceil hi=log(pksimax{pk}+1)
b [ i ] b[i] b[i] S i S_i Si段中所有像素的灰度值二进制表示的最小位数,则有 h i ≤ b [ i ] ≤ 8 h_i \leq b[i] \leq 8 hib[i]8
每个分段 S i S_i Si的段头都有11位
b [ i ] ≤ 8 b[i]\leq 8 b[i]8的二进制表示:3位
l [ i ] ≤ 256 l[i]\leq 256 l[i]256的二进制表示:8位
S i S_i Si段的二进制总位数(占用空间): 11 + b [ i ] × l [ i ] 11+b[i]\times l[i] 11+b[i]×l[i]

可以看出,不同的分段方案 T = { S 1 , S 2 , ⋯   , S j } T=\{S_1,S_2,\cdots,S_j\} T={S1,S2,,Sj}导致不同的变位压缩结果,即占用不同大小的总空间。现需要确定空间占用最小的分段方案,即 min ⁡ T { ∑ i = 1 j ( b [ i ] × l [ i ] + 11 ) } \min\limits_{T}\left\{\sum_{i=1}^{j}(b[i]\times l[i]+11)\right\} Tmin{i=1j(b[i]×l[i]+11)}

约束条件

图像压缩问题中约束条件是: l [ i ] ≤ 256 l[i]\leq 256 l[i]256,即每个段中的像素数不超过256个。也就是说只要不违背这个约束条件的所有解均是可行解。

目标函数

图像压缩问题是最小化问题,其目标函数是:各个分段占用空间之和,即
∑ i = 1 j ( b [ i ] × l [ i ] + 11 ) \sum_{i=1}^{j}(b[i]\times l[i]+11) i=1j(b[i]×l[i]+11)

算法设计

子问题边界参数化

在该问题中,我们将问题的左侧边界固定,右侧边界进行参数化,所有子问题可建模为:像素序列 P i = { p 1 , p 2 , ⋯   , p i } , i = 1 , 2 , ⋯   , n P_i=\{p_1,p_2,\cdots,p_i\}, i=1,2,\cdots,n Pi={p1,p2,,pi},i=1,2,,n

递推方程设计

s [ i ] s[i] s[i]是像素序列 P i = { p 1 , p 2 , ⋯   , p i } , i = 1 , 2 , ⋯   , n P_i=\{p_1,p_2,\cdots,p_i\},i=1,2,\cdots,n Pi={p1,p2,,pi}i=1,2,,n的最优分段所需存储的位数,则递推关系设计如下:
{ s [ i ] = min ⁡ 1 ≤ j ≤ min ⁡ { i , 256 } { s [ i − j ] + j × b m a x ( i − j + 1 , i ) + 11 } s [ 0 ] = 0 \begin{cases} s[i]=\min\limits_{1\leq j \leq \min\{i,256\}}\left\{s[i-j]+j\times b_{max}(i-j+1,i)+11\right\} \\ s[0] = 0 \end{cases} s[i]=1jmin{i,256}min{s[ij]+j×bmax(ij+1,i)+11}s[0]=0
其中, b m a x ( i − j + 1 , i ) = ⌈ log ⁡ ( max ⁡ p k ∈ S m p k + 1 ) ⌉ ≤ 8 b_{max}(i-j+1,i)=\left\lceil \log \left ( \max\limits_{p_k \in S_m}p_k + 1 \right )\right\rceil \leq 8 bmax(ij+1,i)=log(pkSmmaxpk+1)8

算法的伪代码描述

 function Compress(n, p, l, s, b)
 	lmax ← 256;header ← 11;s[0] ← 0
	for i = 1 → n do
		b[i] ← length(p[i])
		bmax ← b[i]
		s[i] ← s[i − 1] + bmax
		l[i] ← 1
		for j = 2 → min i, lmax do
			if bmax < b[i − j + 1] then
 				bmax ← b[i − j + 1]
 			if s[i] > s[i − j] + j ∗ bmax then
 				s[i] ← s[i − j] + j ∗ bmax
				 l[i] ← j
 		s[i] ← s[i] + header
 	return s, b, l
 end function
 
function Traceback(n, i, s, l)
	i ← 0
	if n == 0 then
		return
	Traceback(n − l[n], i, s, l)
	s[i + +] ← n − l[n]
end function

算法时空效率估计

(1)估计算法Compress的时间复杂度,试给出详细过程。

Compress只需 O ( n ) O(n) O(n),由于在算法中j的次数不超过256次,故对每一个确定的i可在 O ( 1 ) O(1) O(1)时间内完成,因此时间复杂度为 O ( n ) O(n) O(n).

(2)估计算法Traceback的时间复杂度,试给出详细过程。

由于数组 l [ i ] , b [ i ] l[i],b[i] l[i],b[i]记录了最优分段所需的信息,最优分段的最后一段的段长度和像素位数分别存在 l [ n ] , b [ n ] l[n],b[n] l[n],b[n]中,其前一段的段长度和像素位数存储于 l [ n − l [ n ] ] l[n-l[n]] l[nl[n]] b [ n − l [ n ] ] b[n-l[n]] b[nl[n]]中,依次类推,在 O ( n ) O(n) O(n)时间内构造最优解。

编码实现

#include<iostream>
#include<vector>
using namespace std;
//灰度值二进制位数 
int Length(int i){
	int k = 1;
	i = i/2;
	while(i > 0){
		k ++;
		i = i/2;
	}
	return k;
}
//迭代备忘录实现动态规划 
void Compress(int n,vector<int> &p,vector<int> &s,vector<int> &l,vector<int> &b){
	int lmax = 256;
	int header = 11;//分段首部 
	s[0] = 0;
	int bmax;
	for(int i = 1;i <= n;i ++){
		b[i] = Length(p[i]);
		bmax = b[i]; 
		s[i] = s[i-1] + bmax;
		l[i] = 1;
		int k = 0;
		if(i > lmax){
			k = lmax;
		}else{
			k = i;
		}//k取lmax和 i的较小值 
		for(int j = 2;j <= k;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] = s[i] + header;//加上首部 
	}
}
//递归追踪解 
void Traceback(int n,int& i,vector<int> &s,vector<int> &l){
	if(n == 0){
		return;
	}
	Traceback(n-l[n],i,s,l);
	s[i++] = n-l[n];//用s表记录分段位置 
}

int main(){
	int n;
	cin >> n;
	vector<int> s,b,l,p;
	for(int i = 0;i <= n;i ++){
		s.push_back(0);
		b.push_back(0);
		l.push_back(0);
		p.push_back(0);
	}
	for(int i = 1;i <= n;i ++){
		int p1;
		cin >> p1;
		p[i] = p1;
	}
	Compress(n,p,s,l,b);
	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]];
		b[j] = b[s[j]];
	}
	for(int j = 1;j <= m;j ++){
		cout << "此段个数:" << l[j] << "所需储存位数:" << b[j] << endl; 
	}
	return 0;
}

结果展示

在这里插入图片描述

结束语

若结局非你所愿,请在尘埃定前奋力一搏

作者:花城

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
动态规划在图像压缩问题中的应用可以通过以下Java代码实现: ```java public class ImageCompression { public static int compressImage(int[][] image, int compressionRate) { int rows = image.length; int cols = image.length; // 创建一个二维数组来保存每个像素点的最优压缩比率 int[][] dp = new int[rows][cols]; // 初始化第一行和第一列的最优压缩比率 dp = image; for (int i = 1; i < rows; i++) { dp[i] = dp[i-1] + image[i]; } for (int j = 1; j < cols; j++) { dp[j] = dp[j-1] + image[j]; } // 计算每个像素点的最优压缩比率 for (int i = 1; i < rows; i++) { for (int j = 1; j < cols; j++) { dp[i][j] = Math.min(dp[i-1][j], dp[i][j-1]) + image[i][j]; } } // 返回最后一个像素点的最优压缩比率 return dp[rows-1][cols-1]; } public static void main(String[] args) { int[][] image = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}; int compressionRate = 2; int optimalCompressionRate = compressImage(image, compressionRate); System.out.println("Optimal compression rate: " + optimalCompressionRate); } } ``` 这段代码实现了一个`compressImage`方法,该方法接受一个二维数组`image`表示图像的像素点灰度值,以及一个整数`compressionRate`表示压缩比率。方法通过动态规划计算出图像的最优压缩比率,并返回最后一个像素点的最优压缩比率。 在上述代码中,我们使用一个二维数组`dp`来保存每个像素点的最优压缩比率。首先,我们初始化第一行和第一列的最优压缩比率,然后通过遍历每个像素点,计算出其最优压缩比率。最后,返回最后一个像素点的最优压缩比率。 请注意,上述代码仅为示例,实际的图像压缩问题可能涉及更复杂的算法和数据结构。此外,还需要根据具体的需求进行适当的调整和优化。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值