动态规划——图像压缩

目录

问题描述

最优子结构性质

递归计算最优值


问题描述

在计算机中常用像素点灰度值序列{P1,P2, … ,Pn}表示图像。其中整数Pi,1<=i<=n,表示像素点i的灰度值。通常灰度值的范围是0~255,一个像素需要8位表示。

实际情况下,若一个像素灰度值小于8,则只需要3位来表示;灰度值小于16,则只需要4位表示……由此可以看出,如果用定长8位来表示灰度图中的每一个像素,就会造成很大的空间浪费。图像压缩问题要求确定像素序列{P1,P2,…Pn}的最优分段,使得以此分段所需要的存储空间最小。

另外,如果图像压缩的操作对象是一个彩色图像,那么需要将其先转换为灰度图,计算原始大小再进行DP压缩;并且,计算压缩比后要将图像恢复。

最优子结构性质

设l[i],b[i],1<=i<=m是{p1,p1,……pn}的一个最优分段,则l[1],b[1]是{p1,……,pl[1]}的一个最优分段,且l[i],b[i],2<=i<=m是{pl[1]+1,……,pn}的一个最优分段。即图像压缩问题满足最优子结构性质。

递归计算最优值

设s[i],1<=i<=n是像素序列{p1,p1,……pi}的最优分段所需的存储位数,由最优子结构性质可得:

s[i]=min_{1\leq k\leq min{i,256}}{s[i-k]+k*b_m{max}(i-k+1,i)}+11其中,b_{max}(i,j)=\left \lceil log(max_{i\leq k \leq j}{p_k}+1) \right \rceil 。

核心代码如下:

void Compress(int n, int p[], int s[], int l[], int b[])  //令s[i]为前i个段最优合并的存储位数
{ 
    int Lmax = 256, header = 11;
    s[0] = 0;
    for(int i=1; i<=n; i++)  //i表示前几段
    {
        b[i] = length(p[i]); //计算像素点p需要的存储位数
        int bmax = b[i];
        cout<<i<<"bmax: "<<bmax<<endl;
        s[i] = s[i-1] + bmax; 
        l[i] = 1;
        for(int j=2; j<=i && j<=Lmax; j++)   //递推关系:s[i]=  min(1<=j<=i)(lsum(i-j+1, i)<=256) {s[i-j]+ lsum(i-j+1,i)*bmax(i-j+1,i) } + 11
        {
            if(bmax < b[i-j+1])
                bmax = b[i-j+1];
            if(s[i] > s[i-j] + j*bmax)   //因为一开始所有序列并没有分段,所以可以看作每一段就是一个数,故lsum(i-j+1, i) = j;
            {
                s[i] = s[i-j] + j*bmax;
                l[i] = j;   //最优断开位置,l[i]表示前i段的最优分段方案中应该是在i-j处断开  比如l[5] = 3,这表示前五段的最优分段应该是(5-3=2)处断开,s[5] = s[2] + 3*bmax   
                            //即 12 | 345,以此类推,得到l[n];之后构造最优解时再由l[n]向前回溯
            }
        }
        s[i] += header;
    }
}
void Traceback(int n, int &m, int s[], int l[])
{
    if(n == 0) return;
    Traceback(n-l[n], m, s, l);
    s[m++] = n-l[n];  //重新为s[]数组赋值,用来存储分段位置
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值