16位TIFF灰度图像转存BMP图像总结

来源:互联网 发布:小众旅游 知乎 编辑:程序博客网 时间:2024/05/22 08:19

在自己写代码之前,参考了站内许多前辈的文章,其中对我比较有用的是这三篇,

1、tiff文件读取

http://blog.csdn.net/zhouxuguang236/article/details/7846615

2、TIFF图像文件详解

http://blog.csdn.net/han_jiang_xue/article/details/8266207

3、libtiff使用小记

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所提供的函数了,没办法我就去使用了windowsAPI,现在回头一看,其实完全不需要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.biYPelsPerMeterBITMAPFILEHEADER 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



0 0
原创粉丝点击