动态规划之基于接缝裁剪的图像压缩

Posted Flammable_ice

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了动态规划之基于接缝裁剪的图像压缩相关的知识,希望对你有一定的参考价值。

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

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

        第一行有n种可能选取像素点方式,第二到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]对图像可视效果的破坏程度。直观地,一个像素的破坏度越低,它与相邻像素的相似度越高。再假定一条接缝的破坏度定义为包含的响度的破坏度之和。设计算法,寻找破坏度最低的接缝。分析算法的时间复杂度。

思考分析:按照要求需要删除的像素是同一列或相邻列。那么就可能删除A[i-1][j-1],A[i-1][j],A[i-1][j+1]之中的任意一个像素点。所以可得递归式:A[i][j]=d[i][j]+minA[i-1][j-1],A[i-1][j],A[i-1][j+1].

代码如下

#include <iostream>
using namespace std;
#define n 6//自定义数组行
#define m 5//自定义数组列
void OP_SEQUENCE(int **A,int i,int j);//i行j列;
int Min(int **A,int i,int j)

	int temp=0;
	if (j==1)
	
		temp=A[i-1][j]>A[i-1][j+1]?A[i-1][j+1]:A[i-1][j];
	
	else if (j==m)
	
		temp=A[i-1][j]>A[i-1][j-1]?A[i-1][j-1]:A[i-1][j];
	
	else
	
		if (A[i-1][j]>A[i-1][j-1])
		
			temp=A[i-1][j-1];
			if (A[i-1][j-1]>A[i-1][j+1])
			
				temp=A[i-1][j+1];
			 
		 
		else
		
			temp=A[i-1][j];
			if (A[i-1][j]>A[i-1][j+1])
			
				temp=A[i-1][j+1];
			
		
	
	return temp;

void seam_carving(int **d)

	int **A,i;//二维数组A表示破坏度之和。
	A=new int*[n+1];
	for (  i=0;i<=n;i++)
	
		A[i]=new int[m+1];
	
	for ( i=1;i<=m;i++)
	
		A[1][i]=d[1][i];
	
	for ( i=2;i<=n;i++)
	
		for (int j=1;j<=m;j++)
		
			A[i][j]=d[i][j]+Min(A,i,j);//递推式
		
	
	int MIN=0x7fffffff,t=0;
	for (i=1;i<=m;i++)
	
		if(A[n][i]<MIN)
		
			MIN=A[n][i];
            t=i;
		
	
	cout<<"MIN破坏点之和="<<MIN<<endl;
	OP_SEQUENCE(A,n,t);
	for ( i = 0; i <=m;  i++)  
	      delete[] A[i];                  
	delete[] A;                     


void OP_SEQUENCE(int **A,int i,int j)//i行j列
//输出一条接缝
	int T;
    if (i==0)return;
	else
	
		if (j==n)
		
			T=A[i][j]>A[i][j-1]?j-1:j;
		
		else if (j==1)
		
			T=A[i][j]>A[i][j+1]?j+1:j;
		
		else
		
			if (A[i][j]>A[i][j-1])
			
				T=j-1;
				if (A[i][j-1]>A[i][j+1])
				
					T=j+1;
				
			
			else
			
				T=j;
				if (A[i][j]>A[i][j+1])
				
					T=j+1;
				
			
		
	
	OP_SEQUENCE(A,i-1,T);
	cout<<"第"<<i<<"行"<<"第"<<T<<"列像素点->";

void main()

  int **d,i;
  d=new int*[n+1];
  for ( i=0;i<=n;i++)
  
	  d[i]=new int[m+1];
  
  int dd[n+1][m+1]=0,0,0,0,0,0,0,3,2,2,3,3,0,1,2,1,2,1,0,3,2,1,3,1,0,2,1,1,2,2,0,1,2,2,3,3,0,2,2,2,1,1;
  for ( i=0;i<=n;i++)
  
	  for (int j=0;j<=m;j++)
	  
		  d[i][j]=dd[i][j];
	  
  
  seam_carving(d);

样例输出

总结:计算上一层最小破坏度时,min函数时间为O(1).计算最小破坏度之和时,seam_carving函数需要O(mn)时间,输出一条接缝时,OP_SEQUENCE函数需要O(n)。总时间为O(mn),这个问题是第三版的新增题,递推式比较简单,程序并不复杂,还是比较容易实现的。

以上是关于动态规划之基于接缝裁剪的图像压缩的主要内容,如果未能解决你的问题,请参考以下文章

动态规划的实际应用:图片压缩算法

动态规划---例题7.图像压缩

canvas图像裁剪压缩旋转

基于连通性状态压缩的动态规划问题

c_cpp 【动态规划】图像压缩【3.7】

动态规划之字符串拆分