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

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

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.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

 


  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
可以使用System.Drawing命名空间中的Bitmap类来读取16Tiff格式灰度图像像素值。下面是一个示例代码: ```csharp using System.Drawing; using System.Drawing.Imaging; // ... // 读取16Tiff格式灰度图像 Bitmap bitmap = new Bitmap("image.tif"); // 获取图像的宽度和高度 int width = bitmap.Width; int height = bitmap.Height; // 获取图像的像素格式 PixelFormat pixelFormat = bitmap.PixelFormat; // 判断像素格式是否为16灰度图像 if (pixelFormat != PixelFormat.Format16bppGrayScale) { throw new Exception("不是16灰度图像"); } // 锁定图数据,获取像素值 BitmapData bitmapData = bitmap.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, PixelFormat.Format16bppGrayScale); // 获取像素值的字节数 int stride = bitmapData.Stride; int bytesPerPixel = stride / width; // 定义一个二维数组存储像素值 ushort[,] pixels = new ushort[height, width]; // 逐行读取像素值 unsafe { byte* p = (byte*)bitmapData.Scan0; for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { // 获取当前像素的指针 ushort* pixelPtr = (ushort*)(p + y * stride + x * bytesPerPixel); // 获取像素值 ushort pixelValue = *pixelPtr; // 存储像素值 pixels[y, x] = pixelValue; } } } // 解锁图数据 bitmap.UnlockBits(bitmapData); ``` 上述代码使用LockBits方法锁定图数据,获取像素值之后再使用UnlockBits方法解锁图数据。在获取像素值时,使用了指针操作来提高效率。注意,由于C#中的多维数组是按行存储的,因此在存储像素值时,需要按照[y, x]的顺序存储。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值