在自己写代码之前,参考了站内许多前辈的文章,其中对我比较有用的是这三篇,
1、tiff文件读取
http://blog.csdn.net/zhouxuguang236/article/details/7846615
http://blog.csdn.net/han_jiang_xue/article/details/8266207
http://blog.csdn.net/nli123/article/details/4300949
其中第一篇是两段源码,我的代码就是在其中第一段源码基础上修改的,第二第三篇都是类似帮助文档的东西,比较有用。
首先,我觉得对TIFF和BMP这两种图像格式的一些基本知识需要掌握,在写代码过程中因为有些知识点的理解不清着实吃了不少苦头,然而这些网络上都有,这里就不再介绍了。
下面就开始介绍我做的事情:
我所使用的TIFF图像的部分信息是这样的:
TIFF image
XYZdim:2448/2984/1
XYZ size [mm ormicron]:1.00/1.00/1.00
Bits persample/Samples per pixel: 16/1
Data offset:512
可以看到这里的Samples per pixel为1,而Bits per sample为16,我想知道的朋友大概也可以猜出这幅图像的作用了,然后上面第一篇文章中代码适用于24位图,也就是3*8的tiff图。我本身也用网上下载的一些tiff图像做了测试,确实可以正确存储为BMP并显示出来。然而直接对我的图像做操作的话,在读取图像数据时需要做些变化。
文章中读取图像数据是通过这样的代码来实现:
raster = (uint32*)malloc(width * height * sizeof (uint32));
TIFFReadRGBAImage(tiff, width, height, raster,0);
可以推测,TIFFReadRGBAImage是适用于三通道采样的TIFF图像的,而单通道采样的或许可以使用TIFFReadScanline来读取,可我经过尝试没有成功,可能是我自己本身没有使用正确吧。
这样,我就不得不放弃使用libtiff所提供的函数了,没办法我就去使用了windows的API,现在回头一看,其实完全不需要libtiff也应该是可以实现的吧。直接上代码:
FILE * finput = fopen("C:\\Users\\Administrator.WIN7U-20141205O\\Desktop\\image.tif", "rb");
if(finput){
long size = filesize(finput);
byte *pbuf = new byte[size+1];
fread(pbuf, sizeof(byte), size, finput);
uint32 IFDOffset=pbuf[4]+255*pbuf[5]+65535*pbuf[6]+16721425*pbuf[7]; //第一个IFD偏移量
uint16 num = pbuf[IFDOffset]+pbuf[IFDOffset+1]*255; //DE(目录入口)个数
long Size = size-(IFDOffset+6+12*num);
BYTE* pImageData = new BYTE[Size];
MoveMemory(pImageData,(pbuf+size-dwLeng),dwLeng);<pre name="code" class="cpp"> for (int i=0;i<(width*height);i++)
{
uint16 temp=pImageData[2*i]+255*pImageData[2*i+1]; //第i点的像素值
uint8 tmp = 255*temp/65535; //新的像素值
pData[i*3+0]=tmp;
pData[i*3+1]=tmp;
pData[i*3+2]=tmp;
}
LPBITMAPINFO pInfo = new BITMAPINFO;
pInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
pInfo->bmiHeader.biWidth = width;
pInfo->bmiHeader.biHeight = height;
pInfo->bmiHeader.biCompression = BI_RGB;//BI_BITFIELDS; //bmp为16位色bmp//BI_RGB;
pInfo->bmiHeader.biClrUsed = 0;
pInfo->bmiHeader.biClrImportant = 0;
pInfo->bmiHeader.biPlanes = 1;
pInfo->bmiHeader.biBitCount = 24; //记录像素的位数,很重要的数值,图像的颜色数由该值决定。
pInfo->bmiHeader.biSizeImage = width*height*3;
float xres,yres;
uint16 res_unit;
//解析度单位:如是英寸,厘米
TIFFGetFieldDefaulted(tiff, TIFFTAG_RESOLUTIONUNIT, &res_unit);
if(TIFFGetField(tiff, TIFFTAG_XRESOLUTION, &xres) == 0)
{
pInfo->bmiHeader.biXPelsPerMeter = 0;
}
else
{
if(res_unit == 2) //英寸
{
pInfo->bmiHeader.biXPelsPerMeter = xres * 10000 / 254;
}
else if(res_unit == 3) //厘米
{
pInfo->bmiHeader.biXPelsPerMeter = xres * 100;
}
else
{
pInfo->bmiHeader.biXPelsPerMeter = 0;
}
}
//得到该帧TIFF纵向解析度,并计算出m_pInfo->bmiHeader.biYPelsPerMeter
BITMAPFILEHEADER bmheader;
bmheader.bfType=0x4d42;
bmheader.bfSize=0;
bmheader.bfReserved1=0;
bmheader.bfReserved2=0;
bmheader.bfOffBits=54;
//这几句是生成bmp文件的头结构
CFile bmpFile;
bmpFile.Open(_T("test.bmp"),CFile::modeCreate|CFile::modeWrite);
bmpFile.Write(&bmheader,sizeof(BITMAPFILEHEADER));
bmpFile.Write(&(pInfo->bmiHeader),sizeof(BITMAPINFOHEADER));
bmpFile.Write(pData,height*width*3);
bmpFile.Close();
//这里,把该帧TIFF保存到了C盘的test.bmp中,可以用看图软件打开浏览一下。
delete pImageData;
pImageData = NULL;
delete pInfo;
pInfo = NULL;
//delete pData;
pData = NULL;
}
这段用windows API实现的代码其实也使用了部分libtiff库的功能,主要是一些读取文件信息头的函数,通过读取文件信息头,计算出实际图像数据的偏移量,再通过文件流的方式将图像数据读取出来,然后16位深转换为8位深BMP图像,并显示即可。
本实验所用libtiff库我已上传至资源中心,站内一些资源貌似都不是很全,需要的可以去下载。
http://download.csdn.net/detail/ssuperliang/8336293