基于接缝裁剪的图像压缩

来源:互联网 发布:Centos mysqldb安装 编辑:程序博客网 时间:2024/05/02 04:59

题目出自《算法导论》P234,T15-8

给定一副彩色图像,它由一个mxn的像素数组A[1..m,1..n]构成,每个像素是一个红绿蓝(RGB)亮度的三元组。假定我们希望轻度压缩这幅图像。具体地,我们希望从每一行中删除一个像素,使得图像变窄一个像素。但为了避免影响视觉效果,我们要求相邻两行中删除的像素必须位于同一列或相邻列。也就是说,删除的像素构成从顶端行到底端行的一条“接缝”(seam),相邻像素均在垂直或对角线方向上相邻。

        a.证明:可能的接缝数量是m的指数函数,假定n>1.

        第1行有n种可能选取像素点方式,第2到m行中每行有2-3种(可能选中A[i][j-1],A[i][j],A[i][j+1]. (j=1 or j=n时,是2种可能)),所以总共有至少大于n*2^(m-1).

        b 假定现在对每个像素A[i,j]我们都已计算出一个实型的“破坏度”d[i,j],表示删除像素A[i,j]对图像可视效果的破坏程度。直观地,一个像素的破坏度越低,它与相邻像素的相似度越高。再假定一条接缝的破坏度定义为包含的响度的破坏度之和。设计算法,寻找破坏度最低的接缝。分析算法的时间复杂度。

求破坏度最低的接缝很简单,c[i,j]记录接缝走到当前像素的最低破坏度。从第一行开始,c[i,j]只有当前像素的破坏度,直接赋值即可;第i行,每个像素的上一个像素来源一共有三个,左上、正上和右上方,每次计算c[i,j]时,需要去三种情况中破坏度最低的情况然后加上当前像素的破坏度,就是接缝走到当前像素的最低破坏度。递推式为c[i][j]=d[i][j]+min{c[i-1][j-1],c[i-1][j],c[i-1][j+1]}.

难的是怎样求这个路径。

有两种方法,

方法一算法如下:

1. 很容易确定在第m行(第0行的d[i][j]数据全为0)中c[m][j](1=<j<=n)的最小值,记录下此时的j值(其实这时已经初步锁定了路线了)。

2. 根据这个j值向上查找,在第m-1行,比较c[m-1][j-1],c[m-1][j],c[m-1][j+1]的大小(因为c[m][j]只可能由这三种情况其中的一种而得到)。记录此时三个值中最小值的j值(实际上进一步缩小了路线范围)。

3. 根据这个j值向上查找,在第m-2行,比较c[m-2][j-1],c[m-2][j],c[m-2][j+1]的大小(因为c[m-1][j]只可能由这三种情况其中的一种而得到)。记录此时三个值中最小值的j值。

4.  ...

      ...

直到i=1为止。


在这里有一个求解三个值中最小值的j值的小技巧。

void SC_SEQUENCE(int **c,int i,int j)//i行j列{//输出一条接缝    int T;    if (i==0)       return;  //递归出口    else{    if (j==n)    {T=c[i][j]>c[i][j-1]?j-1:j;    }    else if (j==1)    {T=c[i][j]>c[i][j+1]?j+1:j;    }    else    {if (c[i][j]>c[i][j-1]){     T=j-1;      //记住这种小技巧,省得比较来比较去乱七八糟<span style="font-family: Arial;">的</span>     if (c[i][j-1]>c[i][j+1])     {T=j+1;      }}else{      T=j;      if (c[i][j]>c[i][j+1])      { T=j+1;       } }     }}OP_SEQUENCE(c,i-1,T);cout<<"第"<<i<<"行"<<"第"<<T<<"列像素点->";  //用递归来逆向输出}

方法二:

动归输出普遍采用的方法,递归法,可以比较最大公共子序列的输出和活动选择问题的动归法的输出,可以得出一般结论。

r[i][j]记录当前结点来自于上一行的那个像素(用-1,0,1分别表示左上,正上和右上方向),和c[i][j]是同时被确定的。

代码如下:

调用 print(m,t,r);  //t是最后一行c[m][j](1=<j<=n)的最小值的j值。

void print(int i,int j,int r[m+1][n+1])    {            if(i=0)           return ;            if(r[i][j]==0)         {              print(i-1,j,r);           printf("%d ",j);         }           else if(r[i][j]==-1)                     {              print(i-1,j-1,r); //说明 print(i,j,r) 是由print(i-1,j-1,r)进化而来           printf("%d ",j);         }             else            {              print(i-1,j+1,r);           printf("%d ",j);         }   }    


参考资料:

http://blog.csdn.net/z84616995z/article/details/38562467

http://blog.csdn.net/yuan3683084/article/details/35994157

0 0
原创粉丝点击