我是靠谱客的博主 聪明小虾米,最近开发中收集的这篇文章主要介绍动态规划的图像压缩问题,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

动态规划的图像压缩问题

      • 2022.5.15
        • 动态规划的图像压缩问题
          • 问题描述(参照算法设计与分析教材)
          • 举例
          • 动态规划解决问题

2022.5.15

动态规划的图像压缩问题

问题描述(参照算法设计与分析教材)

​ 计算机中的图像由一系列像点构成,每个像点称为一个像素,图像分辨率越高,使用的像素就越多,例如Windows桌面的图片经常使用的设置是1024×768个,大概达到106量级.图像传输和视频处理有时在1秒钟内要处理几十帧图片,这些图片的像素就很可观了,因此图像处理常常需要大量的存储空间和高的处理速度,图像压缩问题就成了计算机科学技术中的重要研究课题之一.

​ 以黑白图像的处理来说明图像压缩中的问题.每幅黑白图像由像点构成,每个像点具有灰度值,用0~255之间的整数表示.如果每个整数都用相同的二进制位来表示,那么需要用8个二进制位.假设一幅图像有n个像素,那么这n个像素的灰度值构成一个整数序列:P = <p1,p2,…,pn>

其中p表示第i个像素的灰度.存储这幅图片时,可以像数组一样连续把这些整数存起来,共需要8n个二进制位.

下面考虑一种图像压缩方法.一般来说,在一幅图片中许多连续区域中像点的灰度值是接近的.比如有些交通标志图片,大片的区域是白的,可能少量区域有颜色,而且是比较单调的颜色.对这样的图片是否可以采用分段存储的方法:对灰度值较小的段的像素采用比较少的位数,比如2位;对灰度值较大的段的像素采用较多的位数,比如8位,这样就可能减少空间的占用.这就是变位压缩技术的基本想法.这种技术节省了空间,但在读取图像时带来了新的问题.在每个像素8位的存储方法中,读取图像时每8位就是一个像素的灰度值,不会出错.但是对于分段压缩的图像,看起来就是一个长长的0-1序列.当读取这个序列时,怎么知道每段的划分位置及每段像素占用的二进制位数呢?这里需要对段的划分和段中像素使用的二进制位数(要求同一段内不同像素用的存储位数都一样)给出明确的信息.为此,我们对每个段给出两个整数值,一个表示该段含有的像素个数,一个表示每个像素所占用的二进制位数.
比如第i段,有l[i]个像素,每个像素用b[i]位.由于某些技术要求,规定每段像素总数不超过256,即l[i]≤256.于是可以用8位来表示l[i](8位二进制数恰好有256个值).此外,由于每个灰度值在0~255之间,表达每个灰度值所用二进制数的位数b[i]不超过8,于是记录b[i]还需要3个二进制位.对每段来说,这额外的11位作为段头信息.从直觉上来说,分段越多,每段内部像素所占用的位数会减少,但过多的段头会消耗较多的二进制位.相反,分段越少,段内像素的空间消耗会增加,但是段头消耗少.

总结:

  • 基本思路:对这样的图片是否可以采用分段存储的方法:对灰度值较小的段的像素采用比较少的位数,比如2位;对灰度值较大的段的像素采用较多的位数,比如8位,这样就可能减少空间的占用.这就是变位压缩技术的基本想法

  • 具体实现:对每个段给出两个整数值,一个表示该段含有的像素个数,一个表示每个像素所占用的二进制位数.比如第i段,有l[i]个像素,每个像素用b[i]位.

  • 特点:分段越多,每段内部像素所占用的位数会减少,但过多的段头会消耗较多的二进制位.相反,分段越少,段内像素的空间消耗会增加,但是段头消耗少.

举例

请看下面的例子.设输入的灰度值序列是:

P =<10,12,15,255,1,2,1,1,2,2,1,1>

分法1 S1= <10,12,15>,S2 =<255>,S3=<1,2,1,1,2,2,1,1>

分法2 S1=<10,12,15,255,1,2,1,1,2,2,1,1>

分法3 S1=<10>,S2=<12>,S3=<15>,S4=<255>,S5=<1>,S6=<2>,S7=<1>,S8=<1>,S9=<2>,S10=<2>,S11=<1>,S12=<1>

分法1有3段,第1段3个像素,每个像素用4位;第2段1个像素,每个像素用8位;第3段8个像素,每个像素用2位;加上3个段头,每个段头11位,总计位数是:(一个像素值取值范围0-255,最多用8位二进制数可以表示)
4×3+8×1+2×8+3×11=69

分法2有1段,12个像素,每个像素用8位,段头11位,总计位数是:
8×12+11=107

分法3有12段,前3段的像素用4位,第4段像素用8位,后面有5段像素用1位,3段像素用2位,还有12个段头,每个11位,总计位数是:
4×3+8×1+1×5+2×3+11×12=163

看起来分法1占用的位数最少.我们的问题是寻找存储位数最少的分段方法.

动态规划解决问题

问题一:

子问题的划分边界问题: 设像素序列x1,x2,x3,。先把它分为两段,尾段和前段。我们假设尾端是没有分割的。并且前段是已经被分割成了最优解。则我们只需要遍历尾段的长度,就可以得到整个序列的最优解。也就是

假设最后一段只有一个元素x3,用x3的长度+一个段头+min(x1,x2)

假设尾段(X2,x3),加上min(x1);

这两个结果比较,就可以拿到最小值

而min(x1,x2)就是子问题

所以递推公式是

dp[i] = dp[i - j] + j x log(max(Pi-j+1,…,Pi)) + 11

log2max(Pi-j+1,…,Pi)是在不分割的情况下,存储序列所需要的最大值。

动态规划五部曲:

  • 确定dp数组(dp table)以及下标的含义 :d[i]=j,表示前i个像素值存储所需要的最小空间是j
  • 确定递推公式 :dp[i] = dp[i - j] + j x log(max(Pi-j+1,…,Pi)) + 11
  • dp数组如何初始化:s[0]=0
  • 确定遍历顺序:从前向后遍历
  • 举例推导dp数组

代码:

使用10,12,15,255,1,2序列测试

输出结果:57

    /**
     *
     * @param dots:二进制序列
     * @return
     */
    public static int optimalBits(int[] dots){
        int n= dots.length;
        int[] s=new int[n+1];
        s[0]=0;
        for(int i=1;i<=n;i++){
            s[i] = s[i-1]+minBit(dots[i-1])+11;
            for(int j=1;j<=i;j++){
                //本次划分使用的内存值
               int Lmin=s[i-j]+j*(minBit(maxNumber(dots,i-j+1,i)))+11;
               if(Lmin<s[i]){
                   s[i]=Lmin;
               }
            }
        }
        //返回s数组最后一个值
        return s[s.length-1];
    }
    private static int maxNumber(int[] dots, int start, int end){
        int[] copy =  Arrays.copyOfRange(dots,start -1,end);
        Arrays.sort(copy);
        return copy[copy.length -1];
    }
    /**
     * 求解数字number所需要的最小二进制位数
     * @param number
     * @return
     */
    private static int minBit(int number){
        int min = 0;
        //最多8位
        for(int i = 1; i <= 8; i++){
            if(Math.pow(2,i-1) - 1 <= number && Math.pow(2,i) - 1 >= number){
                min = i;
                break;
            }
        }
        return min;
    }
    public static void main(String[] args){
        int[] text=new int[]{10,12,15,255,1,2};
        System.out.println(optimalBits(text));
    }

最后

以上就是聪明小虾米为你收集整理的动态规划的图像压缩问题的全部内容,希望文章能够帮你解决动态规划的图像压缩问题所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(51)

评论列表共有 0 条评论

立即
投稿
返回
顶部