多媒体技术及应用实验报告
班级: 电信0805
姓名: 程 成
学号: U200812862
Huffman编码
一. 实验内容
1、了解BMP图像的格式,实现BMP图片格式的数据域及文件头的分离
2、熟悉Huffman编码原理
3、用C语言使用Huffman编码算法对给定图像文件进行编解码
二. 实验原理
Huffman编码:
Huffman编码是一种基于图像统计特征的变长编码方法:概率小的符号用较长的码字表示,概率大的符号用较短的码字表示。
Huffman编码的步骤:
- 根据待编码的符号串,统计各个符号的概率;
- 根据符号的概率统计特征,构建霍夫曼编码表,即计算每个符号的编码结果;
- 用得到的编码表对符号序列进行编码。
位图BMP文件格式
文件头:
Typedef struct tagBITMAPFILEHEADER
{
WORD bfType; // 必须是0x424D,”BM”
DWORD bfSize; // 文件大小,包括结构本身
WORD bfReserved1;
WORD bfReserved2;
DWORD bfOffBits; // 实际图像数据便宜量
}BITMAPFILEHEADER;
信息头:
typedef struct tagBITMAPINFOHEADER
{
DWORD biSize; //结构本身的大小-40
LONG biWidth; //图像宽度
LONG biHeight; //图像高度
WORD biPlanes; //显示设备的平面数目-1
WORD biBitCount //描述每个象素颜色需要的位数
DWORD biCompression;//是否压缩
DWORD biSizeImage;//实际的位图数据占用的字节数
LONG biXPelsPerMeter;//显示设备的分辨率
LONG biYPelsPerMeter;
DWORD biClrUsed;//指定本图象实际用到的颜色数,如果该值为零,则用到的颜色数为2的biBitCount次方。
DWORD biClrImportant;//重要颜色数目,如果为零,则都是重要的。
}BITMAPINFOHEADER;
调色板:
typedef struct tagRGBQUAD
{
BYTE rgbBlue; //蓝色分量
BYTE rgbGreen; //绿色分量
BYTE rgbRed; //红色分量
BYTE rgbReserved; //保留值
} RGBQUAD;
三. 实现过程
(1)huffman树数据结构
由于huffman树为二叉树,定义数据结构为:
struct SNode {
long int freq; // 频率
int depth; // 深度,编码长度
char gray;
struct SNode * pPar; // 父结点
struct SNode * pLeft; // 左结点
struct SNode * pRight; // 右结点
char * code; // 字节编码
} ;
(2)灰度概率统计与排序
读取文件流时,跳过文件头的54个字节,直接读取数据域,从头到尾遍历统计,将统计结果存入freq中,通过链表的插入排序算法形成有序链表:
void addtolist(struct SNode* pNode)
{
if (head ==NULL) // 队列为空,
{
head = pNode;// 直接加入头部
}
else
{
if (pNode->freq < head->freq)//当新加入的结点的频数小于head结点的频数时,将新结点放到队首
{
pNode->pPar=head;
head=pNode;
}
else
{
struct SNode* p = head;
while ( (p->pPar!= 0) && (p->pPar->freq < pNode->freq))
{
p = p->pPar;
}
pNode->pPar = p->pPar;
p->pPar = pNode;
}
}
}
(3)Huffman树生成与编码
同页1图示中编码算法,有已知的有序单链表生成huffman树:
void createcodetree(struct SNode *ptree,int len)
{
int offset ,i=0;
while ( head!= NULL&& head->pPar != NULL)
{
// 取出前两个频数最小结点
struct SNode *p1 = head;
struct SNode *p2 = head->pPar;
head = p2->pPar;
offset=len+i;
ptree[offset].freq = p1->freq + p2->freq; // 频率为两者之和
ptree[offset].pLeft = p1;
ptree[offset].pRight = p2;
p1->pPar =&ptree[offset];
p2->pPar = &ptree[offset];
AddChildLen(&ptree[offset]);//调整树中每个结点的深度
addtolist(&ptree[offset]);//将新产生的结点,放到临时队列中
i++;
}
// 构建树完成,生成编码
for ( i = 0; i < 256; i++)
{
if (nodes[i].freq > 0)
{
createcode(&nodes[i]);
}
}
}
(4)解码
解码过程为编码的逆过程。编码是从叶子节点自下而上编码(即先生成最末位向前编码),而解码是从根节点自上而下,直到节点为叶子节点截止:
void decode(){
FILE * hufin,*hufout,*imgin;
struct SNode *p;
int i=0,n=0,num=0;
char b;
char debuf[507132];//507132是当前目录huffma.txt文件中所有字符的个数,也就是'0'和'1'的个数。
if((imgin=fopen("lena.bmp","rb"))==NULL){
printf("file open error\n");
exit(1);
}
if((hufout=fopen("decode.bmp","wb+"))==NULL){//打开存储解码结果的文件
printf("file open error");
exit(1);
}
if((hufin=fopen("huffman.txt","rt+"))==NULL){//打开存储编码结果的文件
printf("huffman.txt open error\n");
exit(1);
}
fread(debuf,sizeof(char),54,imgin);//读出原始图像的文件头,图像信息放到b中,因为文件头没有进行编码所以无需解码直接拷贝
fwrite(debuf,sizeof(char),54,hufout);//将文件头,图像信息放到解码后的文件中
//n=len+1;
fgets(debuf,507132,hufin); //从文件中读出所有的编码序列,只读n-1个第,并自动使b【n】为‘\0’
p=head; //每次解码都要从树的根节点开始
for(i=0;debuf[i]!='\0';i++){//开始解码
switch(debuf[i]){
case '0':{
if(p->pLeft!=NULL) {//如果编码为0并且左孩子不为空,那么p指向p的左孩子。
p=p->pLeft;
break;
}
else{ //如果左孩子为空,则此结点为叶子结点,取出其灰度值作为解码结果
b=p->gray;
fwrite(&b,sizeof(char),1,hufout);
p=head;
i=i-1;//此时i指向下一个码元的开始位置,但是for循环还有一个i++所以此时需要将i减一
break;
}
}
case '1':{
if(p->pRight!=NULL){//如果编码为1并且右孩子孩子不为空,那么p指向p的右孩子。
p=p->pRight;
break;
}
else{//如果右孩子孩子为空,则此结点为叶子结点,取出其灰度值作为解码结果
b=p->gray;
fwrite(&b,sizeof(char),1,hufout);
p=head;
i=i-1;
break;
}
}
default: break;
}
}
b=p->gray;//上面的switch语句未能统计左后一个解码结果,所以在此统计一下
fwrite(&b,sizeof(char),1,hufout);
}
基于深度的图像修
一. 实验内容
1、单幅图像的修补
2、结合彩色图像和深度图像的图像修补
二. 实验原理
图像修复技术:
应用图像修复技术可以保证图像信息的完整性,是利用图像的空间相关性对图像上信息缺损区域进行填充的过程
图像修复技术的用途:
艺术品修复、文物保护、影视特技制作、多余目标物体剔除、图像缩放、图像的有损压缩、视频通信的错误隐匿。
图像中常有缺失或者损坏的部分,即空白区域或者有误的区域。图像修补就是根据这些区域周围的信息完成对空白区域的填充,以实现图像的恢复。
基本方法
利用深度图的图像修补
1图像的前景与背景
实际场景中存在前景与背景的区别,前景会遮挡背景,而且前景与背景往往差距比较大。
2深度图
用于表示3D空间中的点与成像平面距离的灰度图。0~255表示,灰度值越大,表示场景距离成像平面越近,反之,灰度值越小,表示场景距离成像平面越远。
前景的灰度值大,背景的灰度值小。
如下左彩色图,右深度图
3普通的图像修补区分不了图像的前景和背景,简单的加权求和填补空白点的方法会导致前景和背景的混杂。引入深度图之后,可以利用深度图区分图像的前景和背景,在对背景进行修补的时候,可以利用深度图滤除那些前景参考点的影响,从而使背景的空白点只由背景点加权求和得到,前景亦然。
三. 实现过程
基本思想:
1. 读入一个像素点,判断其是否为空白点;
2. 若不是空白点,则跳过该点,判断下一个点;
3. 若该点是空白点,则选取以该店为中心的41*41大小的区域为参考窗口,由上述的基于深度图的修补公式进行修补;
4. 重复上述步骤,对图像中的每一个点都进行如此处理,直至全图处理完毕,则图像修补完成;
具体实现代码(matlab):
clear all;
close all;
I=imread('color-blend-f034.bmp');
B=imread('depth-cam4-f034.bmp');
figure,subplot(1,2,1);
imshow(I);
title('原始图像');
[m,n,hh]=size(I);
A=rgb2gray(I);
I1=I;
[rowind,columnind]=find(A<5);
pointnum=length(rowind);
rowstart=rowind-20;rowend=rowind+20;
rowstart(rowstart<1)=1;rowend(rowend>m)=m;
columnstart=columnind-20;columnend=columnind+20;
columnstart(columnstart<1)=1;columnend(columnend>n)=n;
for num=1:pointnum
x=rowind(num);
y=columnind(num);
basedepth=B(x,y);
xstart=rowstart(num);
xend=rowend(num);
x1=x-xstart+1;
ystart=columnstart(num);
yend=columnend(num);
y1=y-ystart+1;
depthpos=A(xstart:xend,ystart:yend)>4&(B(xstart:xend,ystart:yend)-basedepth)<4;
[locind1,locind2]=find(depthpos);
W=(locind1-x1).*(locind1-x1)+(locind2-y1).*(locind2-y1)+1;
TT=1./W;T=sum(TT);
Aloc=I(xstart:xend,ystart:yend,1);
Aloc=double(Aloc(depthpos));
R=Aloc.*TT;R=sum(R);
I1(x,y,1)=R/(T+0.1);
Aloc=I(xstart:xend,ystart:yend,2);
Aloc=double(Aloc(depthpos));
R=Aloc.*TT;R=sum(R);
I1(x,y,2)=R/(T+0.1);
Aloc=I(xstart:xend,ystart:yend,3);
Aloc=double(Aloc(depthpos));
R=Aloc.*TT;R=sum(R);
I1(x,y,3)=R/(T+0.1);
end
subplot(1,2,2);
imshow(I1);
title('修复图像');
figure,imshow(I,[]);
figure,imshow(I1,[]);
第二篇:多媒体技术实验报告四
甘肃政法学院 本科生实验报告 (四)
姓名:
学院:
专业:
班级:
实验课程名称: 多媒体技术 实验日期: 20xx年11月20日 指导教师及职称: 王云峰 实验成绩:
开课时间:2012——2013学年第一学期
甘肃政法学院实验管理中心印制