文章目录
持续更改中。。。
DPCM 压缩系统的实现和分析
掌握DPCM编解码系统的基本原理。初步掌握实验用C/C++等语言编程实现DPCM编码器,并分析其压缩效率。
DPCM是差分预测编码调制的缩写,是比较典型的预测编码系统。在DPCM系统中,需要注意的是预测器的输入是已经解码以后的样本。之所以不用原始样本来做预测,是因为在解码端无法得到原始样本,只能得到存在误差的样本。因此,在DPCM编码器中实际内嵌了一个解码器,如编码器中虚线框中所示。在一个DPCM系统中,有两个因素需要设计:预测器和量化器。理想情况下,预测器和量化器应进行联合优化。实际中,采用一种次优的设计方法:分别进行线性预测器和量化器的优化设计。

在本次实验中,我们采用固定预测器和均匀量化器。
在DPCM编码器实现的过程中可同时输出预测误差图像和重建图像。将预测误差图像写入文件并将该文件输入Huffman编码器,得到输出码流、给出概率分布图并计算压缩比。
将原始图像文件输入Huffman编码器,得到输出码流、给出概率分布图并计算压缩比。
最后比较两种系统(1.DPCM+熵编码和2.仅进行熵编码)之间的编码效率(压缩比和图像质量)。压缩质量以PSNR进行计算。
#pragma once
#define uchar unsigned char
void dpcm(int h, int w, uchar* origin_buf, uchar* rebuild_buf, uchar* error_buf, int Qbit);
double psnr(int h, int w, uchar* origin_buf, uchar* rebuild_buf, int Qbit);
void prob(int h, int w, uchar* input_buf, double* output_buf);
#define _CRT_SECURE_NO_DEPRECATE
#include<iostream>
#include<windows.h>
#include"header.h"
#define uchar unsigned char
using namespace std;
int main()
{
// 1.定义变量
FILE* originFile = NULL;
FILE* rebuildFile = NULL;
FILE* errorFile = NULL;
FILE* origintxt = NULL;
FILE* errortxt = NULL;
BITMAPINFOHEADER INFO_header;
int Qbit = 2;
// 2.打开文件
if (fopen_s(&originFile, "Lena256B.yuv", "rb") == 0) cout << "原文件打开成功" << endl;
if (fopen_s(&rebuildFile, "rebuildlena.yuv", "wb") == 0) cout << "重建文件创建成功" << endl;
if (fopen_s(&errorFile, "errorlena.yuv", "wb") == 0) cout << "预测误差文件创建成功" << endl;
if (fopen_s(&origintxt, "origin.txt", "wb") == 0) cout << "记录原图概率分布文件创建成功" << endl;
if (fopen_s(&errortxt, "error.txt", "wb") == 0) cout << "记录预测误差的概率分布的文件创建成功" << endl;
int height = 256;
int weight = 256;
// 3.开缓冲
uchar* y_buffer = new uchar[weight * height];
uchar* u_buffer = new uchar[(weight * height) / 4];
uchar* v_buffer = new uchar[(weight * height) / 4];
//uchar* y_buffer = (uchar*)malloc(sizeof(weight * height)*1.5);
uchar* rebuild_buf = new uchar [height * weight];
uchar* error_buf = new uchar[height * weight];
double* origin_prob = new double[256];
double* error_prob = new double[256];
// 4.读取文件到buffer
fread(y_buffer, sizeof(uchar), height * weight, originFile);
fread(u_buffer, sizeof(uchar), (weight * height) / 4, originFile);
fread(v_buffer, sizeof(uchar), (weight * height) / 4, originFile);
// 5.dpcm
dpcm(height, weight, y_buffer, rebuild_buf, error_buf,Qbit);
// 6.psnr
psnr(height, weight, y_buffer, rebuild_buf, Qbit);
// 7.统计概率分布
prob(height, weight, y_buffer, origin_prob);
prob(height, weight, error_buf, error_prob);
// 8.写入文件
fwrite(rebuild_buf, sizeof(uchar), height * weight, rebuildFile);
fwrite(u_buffer, sizeof(uchar), height * weight / 4, rebuildFile);
fwrite(v_buffer, sizeof(uchar), height * weight / 4, rebuildFile);
fwrite(error_buf, sizeof(uchar), height * weight, errorFile);
fwrite(u_buffer, sizeof(uchar), height * weight / 4, errorFile);
fwrite(v_buffer, sizeof(uchar), height * weight / 4, errorFile);
// 概率分布写进txt中
for (int i = 0; i < 256; i++)
{
fprintf(origintxt, "%lf\n", *(origin_prob + i));
fprintf(errortxt, "%lf\n", *(error_prob + i));
}
// 9.关闭文件
fclose(originFile);
fclose(rebuildFile);
fclose(errorFile);
fclose(origintxt);
fclose(errortxt);
delete[] y_buffer;
delete[] u_buffer;
delete[] v_buffer;
delete[] rebuild_buf;
delete[] error_buf;
delete[] origin_prob;
delete[] error_prob;
return 0;
}
采用左向预测,第一列像素的误差值设为128.
预测误差图像:当前值-前一个像素的重建值
e
(
n
)
=
y
(
n
)
−
r
e
(
n
−
1
)
−
−
−
预
测
误
差
e(n)=y(n)-re(n-1)---预测误差
e(n)=y(n)−re(n−1)−−−预测误差
e ^ ( n ) = e ( n ) + 255 🔺 ∗ 0.5 🔺 − − − 量 化 后 的 预 测 误 差 \hat{e}(n)=\frac{e(n)+255}{🔺}*0.5🔺---量化后的预测误差 e^(n)=🔺e(n)+255∗0.5🔺−−−量化后的预测误差
重建图像:预测误差值+前一个像素的重建值
r
e
(
n
)
=
e
^
(
n
)
+
r
e
(
n
−
1
)
re(n)=\hat{e}(n)+re(n-1)
re(n)=e^(n)+re(n−1)
#include<iostream>
#include<math.h>
#define uchar unsigned char
using namespace std;
double Quant(int Qbit, int error)
{
double k = ((error + 255) / pow(2, 9 - Qbit));
return k;
}
double InverseQuant(int Qbit, uchar pred)
{
double k = (pred * pow(2, 9 - Qbit) - 255);
return k;
}
void dpcm(int h, int w, uchar* origin_buf, uchar* rebuild_buf, uchar* error_buf, int Qbit)
{
int error;
for(int i=0;i<h;i++)
{
for (int j = 0; j < w; j++)
{
if (j == 0)
{
// 当前像素-预测值=误差值
error = (origin_buf[i * w + j]) - 128;//假设第一列的预测值为128;
// 对第一列像素值做量化
error_buf[i * w + j] = Quant(Qbit, error);
cout <<(int) error_buf[i * w + j] << endl;
// 重建像素做反量化
rebuild_buf[i * w + j] = InverseQuant(Qbit, error_buf[i * w + j])+128;
}
else
{
// e(n)=y(n)-re(n-1)
error = (origin_buf[i * w + j]) - rebuild_buf[i * w + j - 1];
error_buf[i * w + j] = Quant(Qbit, error);
cout << (int)error_buf[i * w + j] << endl;
// re(n)=\hat e(n)+re(n-1)
rebuild_buf[i * w + j] = InverseQuant(Qbit, error_buf[i * w + j]) + rebuild_buf[i * w + j-1];
}
}
}
int max = pow(2, Qbit) - 1;
for (int i = 0; i < h * w; i++)
{
if (error_buf[i] < 0)
error_buf[i] = 0;
if (error_buf[i] > max)
error_buf[i] = max;
if (rebuild_buf[i] < 0)
rebuild_buf[i] = 0;
if (rebuild_buf[i] > 255)
rebuild_buf[i] = 255;
}
}
PSNR,峰值信噪比,通过判断psnr的值来衡量压缩质量。计算规则如下:
P
S
N
R
=
10
l
g
(
2
b
i
t
s
−
1
)
2
M
S
E
PSNR=10lg\frac{(2^{bits}-1)^2}{MSE}
PSNR=10lgMSE(2bits−1)2
均方误差MSE:
M
S
E
=
∑
i
=
0
M
∑
j
=
0
N
[
f
(
I
,
j
)
−
f
‘
(
I
,
j
)
]
2
M
N
MSE=\frac{\sum_{i=0}^{M}\sum_{j=0}^{N}[f(I,j)-f^‘(I,j)]^2}{MN}
MSE=MN∑i=0M∑j=0N[f(I,j)−f‘(I,j)]2
图像压缩质量衡量规则:
double psnr(int h, int w, uchar* origin_buf, uchar* rebuild_buf, int Qbit)
{
double mse = 0, psnr = 0;
for (int i = 0; i < h * w; i++)
{
mse += pow((origin_buf[i] - rebuild_buf[i]), 2);
}
mse = mse / (h * w);
psnr = 10 * log10(pow(255, 2) / mse);
cout << Qbit << "比特量化时psnr=" << psnr << endl;
return psnr;
}
void prob(int h, int w, uchar* input_buf, double* output_buf)
{
double size = h * w;
int num[256] = { 0 };
double prob[256] = { 0 };
for (int i = 0; i < size; i++)
{
num[(int)*(input_buf + i)]++;
prob[(int)*(input_buf + i)] = num[(int)*(input_buf + i)] / size;
}
for (int i = 0; i < 256; i++)
{
*(output_buf + i) = prob[i];
}
}
原图:
| 原图 | 原图的灰度值的概率分布 |
|---|---|
![]() | |
![]() | |
![]() |

熵编码结果:


| 压缩比 | 大小/kB | 压缩比 | |
|---|---|---|---|
| 原图 | 96 | 1 | ![]() |
| 仅熵编码 | 69 | 1.6 | ![]() |
| 8bitDPCM+熵编码 | 46 | 2.1 | ![]() |
| 4bitDPCM+熵编码 | 24 | 4 | ![]() |
| 2bitDPCM+熵编码 | 23 | 4.17 | ![]() |
量化器的选择:
压缩方案的选择:
为什么先有失真编码再无失真编码?
老师讲信息论的时候,这个问题也是要求重点掌握的知识点。做过实验后才真正明白其中的意义。根据无失真信源编码定理(香农第一定理),平均码长的下界为信源熵。在压缩方面,信源熵越小,平均码长越短,压缩效率越高。
这样一来,问题转变为要使得信源熵变小。也就是要使得信源序列的分布变得不均匀。利用信源间的相关性进行差分预测编码或去除信源间的相关性的变换编码可以使得信源序列的分布变得不均匀。
和实际信号的分布相比,差分预测误差是关于0的高尖峰。因此,预测误差总是具有比原始密度更小的熵。这意味着,预测的过程是把样值间的大部分冗余给去掉了。
疑问
❓huffman编码后的概率分布有点问题
128那里有个奇怪的值,不懂为啥。

我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看rubyzip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d
我正在使用的第三方API的文档状态:"[O]urAPIonlyacceptspaddedBase64encodedstrings."什么是“填充的Base64编码字符串”以及如何在Ruby中生成它们。下面的代码是我第一次尝试创建转换为Base64的JSON格式数据。xa=Base64.encode64(a.to_json) 最佳答案 他们说的padding其实就是Base64本身的一部分。它是末尾的“=”和“==”。Base64将3个字节的数据包编码为4个编码字符。所以如果你的输入数据有长度n和n%3=1=>"=="末尾用于填充n%
我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i
我正在使用ruby1.9解析以下带有MacRoman字符的csv文件#encoding:ISO-8859-1#csv_parse.csvName,main-dialogue"Marceu","Giveittohimóhe,hiswife."我做了以下解析。require'csv'input_string=File.read("../csv_parse.rb").force_encoding("ISO-8859-1").encode("UTF-8")#=>"Name,main-dialogue\r\n\"Marceu\",\"Giveittohim\x97he,hiswife.\"\
有时我需要处理键/值数据。我不喜欢使用数组,因为它们在大小上没有限制(很容易不小心添加超过2个项目,而且您最终需要稍后验证大小)。此外,0和1的索引变成了魔数(MagicNumber),并且在传达含义方面做得很差(“当我说0时,我的意思是head...”)。散列也不合适,因为可能会不小心添加额外的条目。我写了下面的类来解决这个问题:classPairattr_accessor:head,:taildefinitialize(h,t)@head,@tail=h,tendend它工作得很好并且解决了问题,但我很想知道:Ruby标准库是否已经带有这样一个类? 最佳
我正在尝试在Ruby中复制Convert.ToBase64String()行为。这是我的C#代码:varsha1=newSHA1CryptoServiceProvider();varpasswordBytes=Encoding.UTF8.GetBytes("password");varpasswordHash=sha1.ComputeHash(passwordBytes);returnConvert.ToBase64String(passwordHash);//returns"W6ph5Mm5Pz8GgiULbPgzG37mj9g="当我在Ruby中尝试同样的事情时,我得到了相同sha
我正在尝试使用Curbgem执行以下POST以解析云curl-XPOST\-H"X-Parse-Application-Id:PARSE_APP_ID"\-H"X-Parse-REST-API-Key:PARSE_API_KEY"\-H"Content-Type:image/jpeg"\--data-binary'@myPicture.jpg'\https://api.parse.com/1/files/pic.jpg用这个:curl=Curl::Easy.new("https://api.parse.com/1/files/lion.jpg")curl.multipart_form_
无论您是想搭建桌面端、WEB端或者移动端APP应用,HOOPSPlatform组件都可以为您提供弹性的3D集成架构,同时,由工业领域3D技术专家组成的HOOPS技术团队也能为您提供技术支持服务。如果您的客户期望有一种在多个平台(桌面/WEB/APP,而且某些客户端是“瘦”客户端)快速、方便地将数据接入到3D应用系统的解决方案,并且当访问数据时,在各个平台上的性能和用户体验保持一致,HOOPSPlatform将帮助您完成。利用HOOPSPlatform,您可以开发在任何环境下的3D基础应用架构。HOOPSPlatform可以帮您打造3D创新型产品,HOOPSSDK包含的技术有:快速且准确的CAD
本教程将在Unity3D中混合Optitrack与数据手套的数据流,在人体运动的基础上,添加双手手指部分的运动。双手手背的角度仍由Optitrack提供,数据手套提供双手手指的角度。 01 客户端软件分别安装MotiveBody与MotionVenus并校准人体与数据手套。MotiveBodyMotionVenus数据手套使用、校准流程参照:https://gitee.com/foheart_1/foheart-h1-data-summary.git02 数据转发打开MotiveBody软件的Streaming,开始向Unity3D广播数据;MotionVenus中设置->选项选择Unit
文章目录一、概述简介原理模块二、配置Mysql使用版本环境要求1.操作系统2.mysql要求三、配置canal-server离线下载在线下载上传解压修改配置单机配置集群配置分库分表配置1.修改全局配置2.实例配置垂直分库水平分库3.修改group-instance.xml4.启动监听四、配置canal-adapter1修改启动配置2配置映射文件3启动ES数据同步查询所有订阅同步数据同步开关启动4.验证五、配置canal-admin一、概述简介canal是Alibaba旗下的一款开源项目,Java开发。基于数据库增量日志解析,提供增量数据订阅&消费。Git地址:https://github.co