实验报告显示tif图像.docx

上传人:b****8 文档编号:9349056 上传时间:2023-02-04 格式:DOCX 页数:24 大小:158.19KB
下载 相关 举报
实验报告显示tif图像.docx_第1页
第1页 / 共24页
实验报告显示tif图像.docx_第2页
第2页 / 共24页
实验报告显示tif图像.docx_第3页
第3页 / 共24页
实验报告显示tif图像.docx_第4页
第4页 / 共24页
实验报告显示tif图像.docx_第5页
第5页 / 共24页
点击查看更多>>
下载资源
资源描述

实验报告显示tif图像.docx

《实验报告显示tif图像.docx》由会员分享,可在线阅读,更多相关《实验报告显示tif图像.docx(24页珍藏版)》请在冰豆网上搜索。

实验报告显示tif图像.docx

实验报告显示tif图像

 

计算机实习报告

 

一、实验题目

显示tif图像,要求至少256色

二、程序设计要求

(一)需求分析

陈述选题任务,分析选题给出计算模型和设计方案,并:

1.确定设计程序接收的输入数据和输出数据的形式、取值范围;

2.初步列出测试数据以及测试目的。

(二)程序设计

说明程序中用到的关键数据类型的定义。

绘制主程序的流程图,以及各子程序模块间的调用关系。

(三)调式分析

1.列出调试过程中遇到的主要问题,并说明解决方法;

2.分析算法的时间和空间复杂度,如果有给出算法改进思想。

(四)使用说明

说明编写程序的使用方法,详细列出每一操作步骤。

(五)测试结果

列出若干输入的测试数据、测试目的、产生的结果。

(六)心得体会

描述本次计算机实习遇到的主要问题及得到的主要收获。

(七)附录

1.注释源程序代码;

2.如果结果中有多个文件,列出文件名清单,注明每个程序的作用。

三、需求分析

(一)设计方案

题目要求显示TIF格式的文件,但由于TIF是可扩充标记的文件,所以理论上是不可能编写一个能识别所有类别TIF格式的读写程序,所以本程序是将TIF图像转换成BMP图像,然后再使用Windows提供的API函数对其进行编辑并方便直观地显示出来。

(二)TIF格式概览

TIF由四个部分组成,分别为图像头文件、图像文件目录、目录入口、图像数据。

1、图像头文件(ImageFileHeader简称IFH):

 

 

图一IFH结构描述

IFH数据结构包含3个成员共计8个字节,Byteorder成员可能是“MM”(0x4d4d)或“II”(0x4949),0x4d4d表示该TIFF图是摩托罗拉整数格式0x4949表示该图是Intel整数格式;Version成员总是包含十进制42(0x2a),它用于进一步校验该文件是否为TIF格式,42这个数并不是一般人想象中的那样认为是TIF软件的版本,实际上,42这个数大概永远不会变化;第三个成员是IFD(接下来要说的第二个数据结构)相对文件开始处的偏移量。

2、图像文件目录(ImageFileDirectory简称IFD):

图二IFD及DE结构描述

IFD是TIF图中最重要的数据结构,它包含了一个TIF文件中最重要的信息,一个TIF图可能有多个IFD,这说明文件中有多个图像,每个IFD标识1个图像的基本属性。

IFD结构中包含了三类成员,DirectoryEntryCount指出该结构里面有多少个目录入口;接下来就是N个线性排列的DE序列,数量不定(这就是为什么称TIF格式文件为可扩充标记的文件,甚至用户可以添加自定义的标记属性),每个DE标识了图像的某一个属性;最后就是一个偏移量,标识下一个文件目录相对于文件开始处的位置,当然,如果该TIF文件只包含了一幅图像,那么就只有一个IFD,显然,这个偏移量就等于0;

3、目录入口(DirectoryEntry简称DE):

  共12个字节,见图二。

简单说,一个DE就是一幅图像的某一个属性。

例如图像的大小、分辨率、是否压缩、像素的行列数、一个像素由几位表示(1位代表黑白两色,8位代表256色等等)等。

其中:

tag成员是该属性的编号,在图像文件目录中,它是按照升序排列的。

我们可以通过读这些编号,然后到TIF格式官方白皮书中查找相应的含义。

属性是用数据来表示的,那么type就是代表着该数据的类型,TIF官方指定的有5种数据类型。

type=1就是BYTE类型(8位无标记整数)、type=2是ASCII类型(7位ASCII码加1位二进制0)、type=3是SHORT类型(16位无标记整数)、type=4是LONG类型(32位无标记整数)、type=5是RATIONAL类型(2个LONG,第一个是分子,第二个是分母)。

length成员是数据的数量而不是数据类型的长度。

第4个成员valueOffset很重要,它是tag标识的属性代表的变量值相对文件开始处的偏移量。

如果变量值占用的空间小于4个字节,那么该值就存放在valueOffset中即可,没必要再另外指向一个地方了

4、图像数据

本程序提供的图像是基于256灰度级的,即一个字节代表一个像素点,它是0x00~0xff区间中256个灰度级的任意一个整数。

通过使用UltraEdit工具观察,我们发现该图像文件的组织形式是:

IFH--数据--IFD。

以下的示例说明遵循了这一观察结果。

四、程序设计

1、VC创建一个MFCAppWizard(exe)工程取名TiffTest,选择单文档程序。

2、添加TiffStruct.h文件,定义IFH和DE结构(参考前面的结构描述),用来接收读TIF文件的信息。

#ifndef_TIFFSTRUCT_

#define_TIFFSTRUCT_

  typedefstructtagIMAGEFILEHEADER

  {

    WORDbyteOrder;

    WORDversion;

    DWORDoffsetToIFD;

  }IFH;

  typedefstructtagDIRECTORYENTRY

  {

    WORDtag;

  WORDtype;

    DWORDlength;

    DWORDvalueOffset;

  }DE;

  #endif

3、在文档类中添加4个公有变量,并将其初始化为0。

在TiffTestDoc.cpp中#include"TiffStruct.h"

DWORDm_dwBmSize;  //图象的数据部分的大小

  CPalettem_palDIB;  //BMP图象调色板

  HANDLEm_hDIB;   //BMP图象内存块句柄

  CSizem_sizeDoc;  //图象的长和宽

4、在文档类的OnOpenDocument函数中定义局部工具变量并读文件

DWORDdwFileLength=0;

  CStringstrTemp=_T("");

  WORDwDECount=0;

  BYTE*pDIB=NULL;

  inti=0;

  IFHifh;

  ZeroMemory(&ifh,sizeof(IFH));

  CFilefile;

  CFileExceptionfe;

  if(0==file.Open(lpszPathName,CFile:

:

modeRead|CFile:

:

shareDenyWrite,&fe))

  {

    AfxMessageBox("打开文件失败");

    returnFALSE;

  }

  dwFileLength=file.GetLength();

5、读IFH文件头

if(sizeof(IFH)!

=file.Read(&ifh,sizeof(IFH)))

  {

    AfxMessageBox("读TIF文件头失败");

    returnFALSE;

  }

  if(0x2a!

=ifh.version)

  {

    AfxMessageBox("该文件不是TIF格式,读文件失败");

    returnFALSE;

  }

  if(0x4949!

=ifh.byteOrder)

  {

    AfxMessageBox("该TIF文件不是IBMPC字节序,读文件失败");

    returnFALSE;

  }

  file.Seek(ifh.offsetToIFD,CFile:

:

begin);//将文件指针定位到IFD

6、读文件有多少个目录入口

if(2!

=file.Read(&wDECount,2))

  {

    AfxMessageBox("无法获得TIF文件目录入口数量");

    returnFALSE;

  }

  strTemp.Format("该TIF文件有%d个目录入口",wDECount);

  AfxMessageBox(strTemp);//显示有多少个目录入口

 7、创建DE数组,接收信息,数组中有wDECount个元素

DE*pde=newDE[wDECount];

  DE*pTemp=pde;

  memset(pde,0,sizeof(DE)*wDECount);

  if(sizeof(DE)*wDECount!

=file.ReadHuge(pde,sizeof(DE)*wDECount))

  {

    AfxMessageBox("读图象文件目录失败");

    delete[]pde;

    returnFALSE;

  }  

 8、显示图像文件目录信息

for(i=0;i

{

pTemp=pde+i;

strTemp.Format("DE[%d].tag=%d\r\nDE[%d].type=%d\r\nDE[%d].length=%d\r\nDE[%d].valueOffset=%d",i,pTemp->tag,i,pTemp->type,i,pTemp->length,i,pTemp->valueOffset);    

AfxMessageBox(strTemp);//显示目录文件信息

}

 9、把图像的大小和图像数据的容量保存到成员变量中

for(i=0;i

  {

    pTemp=pde+i;

    if(256==pTemp->tag)  //tag为256的目录入口中的变量标识了图象宽度

    {

      m_sizeDoc.cx=pTemp->valueOffset;

    }

    if(257==pTemp->tag)  //tag为257的目录入口中的变量标识了图象长度

    {

      m_sizeDoc.cy=pTemp->valueOffset;

    }

    if(273==pTemp->tag)  //计算图象数据占用字节数

    {

     m_dwBmSize=m_sizeDoc.cx*m_sizeDoc.cy;

    }

  }

10、在文档类中创建一个成员工具函数CreateBmpBuffer,申请全局内存块以存放BMP文件结构数据

BOOLCTiffTestDoc:

:

CreateBmpBuffer()

  {

    //申请BMP内存块

    m_hDIB=GlobalAlloc(GMEM_MOVEABLE|GMEM_ZEROINIT,

      sizeof(BITMAPFILEHEADER)+

      sizeof(BITMAPINFOHEADER)+

      256*sizeof(RGBQUAD)+

      m_dwBmSize);

    if(NULL==m_hDIB)

    {

      AfxMessageBox("申请BMP内存块失败");

      returnFALSE;

    }

    else

    {

      returnTRUE;

    }

  }

 11、回到OnOpenDocument成员函数中调用工具函数并获得全局内存块指针

//构造BMP图象内存块

  if(!

CreateBmpBuffer())

  {

    AfxMessageBox("构造BMP图象内存块失败");

    delete[]pde;

    returnFALSE;

  }

  //获得BMP内存块指针

  pDIB=(BYTE*)GlobalLock(m_hDIB);

  if(NULL==pDIB)

  {

    AfxMessageBox("获得BMP内存块指针失败");

    GlobalUnlock(m_hDIB);

    delete[]pde;

    returnFALSE;

  }  

 12、将图像信息填充到BMP内存块中,(注:

BMP文件中图像数据的第一行代表的是最终显示光栅的最后一行,所以在数据排列中要颠倒过来。

//构造BITMAPFILEHEADER并复制到BMP内存块

  BITMAPFILEHEADERbmfHdr;

  memset(&bmfHdr,0,sizeof(BITMAPFILEHEADER));

  bmfHdr.bfOffBits=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+

           256*sizeof(RGBQUAD);

  bmfHdr.bfReserved1=0;

  bmfHdr.bfReserved2=0;

  bmfHdr.bfSize=bmfHdr.bfOffBits+m_dwBmSize;

  bmfHdr.bfType=0x4d42;

  memmove(pDIB,&bmfHdr,sizeof(BITMAPFILEHEADER));

  

  //构造BITMAPINFOHEADER并复制到BMP内存块

  BITMAPINFOHEADERbmiHdr;

  memset(&bmiHdr,0,sizeof(BITMAPINFOHEADER));

  bmiHdr.biBitCount=8;

  bmiHdr.biClrImportant=0;

  bmiHdr.biClrUsed=0;

  bmiHdr.biCompression=0;

  bmiHdr.biHeight=m_sizeDoc.cy;

  bmiHdr.biPlanes=1;

  bmiHdr.biSize=sizeof(BITMAPINFOHEADER);

  bmiHdr.biSizeImage=0;

  bmiHdr.biWidth=m_sizeDoc.cx;

  bmiHdr.biXPelsPerMeter=2834;

  bmiHdr.biYPelsPerMeter=2834;

  memmove((BITMAPFILEHEADER*)pDIB+1,&bmiHdr,sizeof(BITMAPINFOHEADER));

  //构造256个RGBQUAD并复制到BMP内存块

  RGBQUAD*pRgbQuad=(RGBQUAD*)(pDIB+sizeof(BITMAPFILEHEADER)+

sizeof(BITMAPINFOHEADER));

  RGBQUAD*pOldQuad=pRgbQuad;

  RGBQUADrgbQuad;

  memset(&rgbQuad,0,sizeof(RGBQUAD));

  for(i=0;i<256;i++)

  {

    rgbQuad.rgbBlue=i;

    rgbQuad.rgbGreen=i;

    rgbQuad.rgbRed=i;

    rgbQuad.rgbReserved=0;

    pRgbQuad=pOldQuad+i;

    memmove(pRgbQuad,&rgbQuad,sizeof(RGBQUAD));

  }

  //填充所有像素数据,颠倒图象数据从最后一行开始读起

  intj=0;

  for(i=m_sizeDoc.cy-1;i>=0;i--)

  {

    file.Seek(sizeof(IFH)+i*m_sizeDoc.cx,CFile:

:

begin);

    file.Read((BYTE*)(pRgbQuad+1)+j*m_sizeDoc.cx,m_sizeDoc.cx);

    j++;

  }  

13、初始化BMP调色板,为显示BMP文件做准备

//初始化专用调色板

  BYTEbuf[2+2+4*256];

  LOGPALETTE*pPal=(LOGPALETTE*)buf;

  pPal->palVersion=0x300;

  pPal->palNumEntries=256;

  for(i=0;i<255;i++)

  {

    pPal->palPalEntry[i].peBlue=i;

    pPal->palPalEntry[i].peFlags=0;

    pPal->palPalEntry[i].peGreen=i;

    pPal->palPalEntry[i].peRed=i;

  }

  m_palDIB.CreatePalette(pPal);

14、(附加功能)生成bmp文件

CFilefileWrite("C:

\DocumentsandSettings\Administrator\桌面\mytiff.bmp",CFile:

:

modeCreate|CFile:

:

modeWrite);

fileWrite.WriteHuge(pDIB,sizeof(BITMAPFILEHEADER)+

sizeof(BITMAPINFOHEADER)+256*sizeof(RGBQUAD)+m_dwBmSize);

15、OnOpenDocument成员函数返回前的清理工作

GlobalUnlock(m_hDIB);

  delete[]pde;

  returnTRUE;

  至此,TIF文件信息已转换为BMP图像并保存在全局内存块中了,接下来就可以在OnDraw中调用WinAPI函数StretchDIBits来显示它。

 

流程图:

N

Y

N

Y

N

Y

N

Y

Y

Y

Y

Y

 

 

 

五、使用说明

方法一:

1、双击图标TiffView

2、点击文件

 

3、点打开,并找到自己所要显示的TIF图片点击即可

方法二:

1、双击图标TiffVie.dsp

 

2、进行编译和链接,然后点击运行

3、点击文件

 

4、点打开,并找到自己所要显示的TIF图片点击即可

六、测试结果

1、使用方法一打开文件夹中的测试图片。

 

2、图片显示如下:

 

七、心得体会

本次我的实验题目为:

显示TIF文件格式。

刚刚接触这个题目时,并没有什么想法,因为平时看图片都是直接用图片浏览器看,并没有自己动手编程来实现过。

拿道题目之后,我到网上查阅了相关资料,初步了解了什么是TIF格式,并初步掌握了TIF格式的组成部分,但在查阅资料的时候,我也发现了一个问题,就是TIF是可扩充标记的文件,所以理论上是不可能编写一个能识别所有类别TIF格式的读写程序,于是我结合相关知识,以及网上的一些程序,觉得可以将TIF图像先转换成BMP图像,然后再将其显示出来。

在程序的编写过程中,因为要实现可视化的功能,所以我建立了工程,在以前的编程题目中很少有需要建工程来完成的题目,所以对此我也是比较陌生的,关于此我请教了一些同学,并对工程有了初步的认识。

在编写具体代码的时候,多少遇到了一些困难,于是我主要是参照网上和书上的一些代码和程序块,结合自己所需要的程序,进行了拼接和修改,并对自己很不熟悉的语句进行了逐一的查找和翻译,最终实现了功能。

本次的实验,让我重新巩固了之前学习过的编程知识和程序的编译和调试,虽然在过程中遇到了不少的困难,但是结果还是令人欣喜的,同时感谢指导老师对我耐心的指导。

八、附录

核心源代码:

BOOLCTiffViewDoc:

:

OnOpenDocument(LPCTSTRlpszPathName)

{

if(!

CDocument:

:

OnOpenDocument(lpszPathName))

returnFALSE;

/*初始化*/

DWORDdwFileLength=0;

CStringstrTemp=_T("");

WORDwDECount=0;

BYTE*pDIB=NULL;

inti=0;

IFHifh;

ZeroMemory(&ifh,sizeof(IFH));//将IFH对应变量的空间大小赋予ifh

CFilefile;//定义文件

CFileExceptionfe;

if(0==file.Open(lpszPathName,CFile:

:

modeRead|CFile:

:

shareDenyWrite,&fe))

{

AfxMessageBox("打开文件失败");

returnFALSE;

}

dwFileLength=file.GetLength();//读取文件长度赋值

if(sizeof(IFH)!

=file.Read(&ifh,sizeof(IFH)))//判断规模是否相同(字节)

{

AfxMessageBox("读TIF文件头失败");

returnFALSE;

}

if(0x2a!

=ifh.version)

{

AfxMessageBox("该文件不是TIF格式,读文件失败");

returnFALSE;

}

if(0x4949!

=ifh.byteOrder)//判断整数格式

{

AfxMessageBox("该TIF文件不是IBMPC字节序,读文件失败");

returnFALSE;

}

file.Seek(ifh.offsetToIFD,CFile:

:

begin);//寻找偏移量(找目录)

if(2!

=file.Read(&wDECount,2))

{

AfxMessageBox("无法获得TIF文件目录入口数量");

returnFALSE;

}

strTemp.Format("该TIF文件有%d个目录入口",wDECount);

//AfxMessageBox(strTemp);//显示具体的入口数

DE*pde=newDE[wDECount];

DE*pTemp=pde;

memset(pde,0,sizeof(DE)*wDECount);//初始化pde(置零大小不变)

if(sizeof(DE)*wDECount!

=file.ReadHuge(pde,sizeof(DE)*wDECount))

{

AfxMessageBox("读图象文件目录失败");

delete[]pde;

returnFALSE;

}

//显示图象目录入口信息--测试用

for(i=0;i

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 高等教育 > 医学

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1