【学习图像处理】编码优化

前言

这次只是对之前两次编码实验的一个小小的补充,没有很多的内容。而且临近期末了,我也不是很想去写一些很复杂的优化策略了,只用最最简单的差值预测来进行编码优化。经测试赫夫曼编码的压缩效率提高了很多,LZW依旧取决于图像,但是不会出现反向压缩的问题了。

编码优化

上次在进行LZW编解码时我提到过有反向压缩的问题,给出了一种很麻烦的解决方法,就是用变长的码表来逐一试,最终试出效果最好的那个。然而你要是全自动的试也就算了,bitset还只能手动编译,因此这种方法注定只能是权宜之计。

不出所料,这周的课程就讲了如何优化编码的效果。不过和我预想的计算可以计算最佳码表长度不一样,我们的优化是通过降低信息熵实现的。

1、无损预测编码

信息熵实际上就是衡量信息量多少的一个量化标准,根据最优编码理论,信息熵是图像压缩的下限,也就是说不论你用什么样的方法,都不可能在不损失信息的情况下,将图片的平均码长缩短到小于信息熵的程度。

信息熵H和平均码长L的计算公式如下:

H ( X ) = − ∑ i = 1 k p ( x i ) l o g p ( x i ) H(X)=-\sum_{i=1}^{k}p(x_i)logp(x_i) H(X)=i=1kp(xi)logp(xi)

L = ∑ i = 1 k p ( s i ) l i L=\sum_{i=1}^{k}p(s_i)l_i L=i=1kp(si)li

x i x_i xi表示像素值, s i s_i si表示编码, l i l_i li是码长,对于灰度图像而言就是对0-255的像素值的对应项求和。

但是往往我们的要求就是这么高,既不想损失信息,又想要尽可能地压缩,那咋办嘛?聪明的前人想到了很多种方法,它们可以暂时的将图像的信息熵减小,解码之后再复原就好了。预测编码就是其中的一个大类,而我实现的,是最不需要计算量的一种,其原理图如下:

预测优化
f ( i ) f(i) f(i)就是原始的图像数据,我们将首位设为0,然后将原始图像的像素值错位的赋值给后续位置。最后用原始数据减去错位后的数据,就可以得到一个信息熵减小的数据 e ( i ) e(i) e(i)了。原始图片的信息熵较大,是因为像素值的范围、起伏都比较大,我们通过这样的错位相减,可以使图像整体的像素分布更加集中(你可以用实验二中的方法绘制直方图,效果很明显)。

而且这样变化之后还是可以复原的,复原过程如下图:

预测优化复原
这个减小信息熵过程,叫做预测器处理,我们的算法就是预测器。用不同的预测器会有不同的效果,上面演示的属于差值预测,还有另一大类的方法叫做线性预测,一般会按照预测值的数量划分为一维、二维预测等,不再赘述了。

2、有损预测编码

既然有无损压缩这样的方法,那对应的也就有有损压缩算法。不是每个人都是列文虎克写轮眼,对于类似表情包这样的图片,我们只需要看缩略图就明白对面是什么意思了,不需要放大再放大。因此与其追求两全,不如省点流量,把图像尽可能的压缩,这就是有损预测的初衷。

有损预测为什么会有损呢?是因为它在预测器的基础上添加了一个量化器。当然这个量化也分为标量量化和矢量量化,这里只讨论标量量化。

我给你说量化器干的事,你就知道损失在哪了。编码的时候,量化器对所有像素值进行除以10后取整操作。解码的时候,量化器对所有像素值进行乘以10的操作。。。

当然人家也是有公式的,我上面只是举了一个简单的例子,公式如下:

f ′ ( x , y ) = r o u n d ( ∑ i = 1 m a i F ′ ( x , y − i ) ) f'(x,y)=round(\sum_{i=1}^ma_iF'(x,y-i)) f(x,y)=round(i=1maiF(x,yi))

最简单的有损预测编码方法是Delta调制,其公式如下:

f ′ ( n ) = a f ′ ( n − 1 ) f'(n)=af'(n-1) f(n)=af(n1)

e ( n ) = f ( n ) − f ′ ( n ) e(n)=f(n)-f'(n) e(n)=f(n)f(n)

e ′ ( n ) = { + δ , 当 e n > 0 − δ , 其 他 情 况 e'(n)= \left\{ \begin{aligned} +\delta,当e_n>0\\ -\delta,其他情况 \end{aligned} \right. e(n)={+δen>0δ

最简单当然效果也比较差了,现在一般不会再使用了。

delta调制

代码实现

没什么可讲的,按照上面的原理图一一对应就好了,只给出了预测和还原的函数,在调用其他编码算法之前使用预测函数,在用其他编码还原出预测图像后再还原即可。

预测编码:

void img_Predict(BMPFILE &src, BMPFILE &des)	//对图像进行线性预测
{
	img_Clone(src, des);
	int i, j;
	for (i = 0; i < des.imagew; i++)	//f'(i)=f(i-1)
		for (j = 0; j < des.imageh; j++)
		{
			if (i == 0 && j == 0)
			{
				des.pDataAt(i)[j] = 0;
			}
			else
			{
				if (j != 0)
				{
					des.pDataAt(i)[j] = src.pDataAt(i)[j - 1];
				}
				if (j == 0)
				{
					des.pDataAt(i)[j] = src.pDataAt(i - 1)[src.imageh - 1];
				}
			}
		}

	for (i = 0; i < des.imagew; i++)	//e(i)=f(i)-f'(i)
		for (j = 0; j < des.imageh; j++)
		{
			des.pDataAt(i)[j] = src.pDataAt(i)[j] - des.pDataAt(i)[j];
		}

	des.SaveBMPFILE("predict.bmp");
}

还原:

void img_Depredict(BMPFILE &src, BMPFILE &des)		//将经过预测编码的图像还原为原始图片
{	//src相当于e(i)
	img_Clone(src, des);
	int i, j;
	for (i = 0; i < des.imagew; i++)	//f'(i)=e(i-1)+f'(i-1)
		for (j = 0; j < des.imageh; j++)
		{
			if (i == 0 && j == 0)
			{
				des.pDataAt(i)[j] = 0;
			}
			else
			{
				if (j != 0)
				{
					des.pDataAt(i)[j] = src.pDataAt(i)[j - 1] + des.pDataAt(i)[j - 1];
				}
				if (j == 0)
				{
					des.pDataAt(i)[j] = src.pDataAt(i - 1)[src.imageh - 1] + des.pDataAt(i - 1)[des.imageh - 1];
				}
			}
		}

	for (i = 0; i < des.imagew; i++)	//f'(i)=e(i-1)+f'(i-1)
		for (j = 0; j < des.imageh; j++)
		{
			des.pDataAt(i)[j] += src.pDataAt(i)[j];
		}

	des.SaveBMPFILE("Depredict.bmp");
}

结语

我已经把这个优化整合在了赫夫曼编解码函数里,等LZW的实验检查之后我也会将其整合一下。
本次内容的完整代码及其他相关函数代码均可见我的gitee

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值