为啥VS2010下OpenCV读取TIFF文件读取失败?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了为啥VS2010下OpenCV读取TIFF文件读取失败?相关的知识,希望对你有一定的参考价值。

openCV版本是2.1.
代码如下:
IplImage *image = cvLoadImage("F:\\myOpencvProject\\mfcTest\\testImage.TIFF", CV_LOAD_IMAGE_COLOR);
assert(image != NULL);
我能确定的是路径是对的,能读取到jpg等其它格式图片,testImage.tiff也是一个普通的tiff文件。
那么问题来了,如何判断是不是在配置opencv时出现错误导致的问题,或者其他可能?
不需要详细解决方案,我是找不到问题出在哪。

IplImage* img=0; 
  img=cvLoadImage(fileName);
  if(!img) printf("Could not load image file: %s\\n",fileName);
 支持的图像格式: BMP, DIB, JPEG, JPG, JPE, PNG, PBM, PGM, PPM,
                          SR, RAS, TIFF, TIF

OpenCV默认将读入的图像强制转换为一幅三通道彩色图像. 不过可以按以下方法修改读入方式:
img=cvLoadImage(fileName,flag);
 flag: >0 将读入的图像强制转换为一幅三通道彩色图像
       =0 将读入的图像强制转换为一幅单通道灰度图像
       <0 读入的图像通道数与所读入的文件相同.

TIFF是什么图,黑白?你自己做一张彩色的单帧tiff图再试试,CV_LOAD_IMAGE_COLOR是不是设置合适

追问

这个TIFF图像是LZW压缩,应该和这个有关系,我换了一张tif图像无压缩倒是能打开。话说这个LZW压缩后的图像能不能用opencv读取?

追答

  2.0只支持一般格式的tif,因为tif的格式比较复杂随意,不清楚opencv新版本3.0是什么情况,如果也不支持,只能自己改opencv的源代码,网上也许能找到
  或者直接自己调用libtif库读图,在把数据输入到opencv里

参考技术A 如果是TIFF大图像好像不能用OpenCV读的,可以用GDAL读。。追问

谢谢,不过种种条件限制只能用openCV,图像也不算大。

tiff文件读取

以下是VC下读取TIFF文件的代码

char* szFileName = "K:\\\\地图\\\\fujian-DEM\\\\fujian1.tif";
	TIFF* tiff = TIFFOpen(szFileName, "r");//打开Tiff文件,得到指针,以后所有的操作都通过指针进行

	int nTotalFrame = TIFFNumberOfDirectories(tiff);	//得到图像的总帧数

	//TIFFSetDirectory(tiff,0);
	//我们打开第一幅图,也就是第0帧,如果是第1帧,第二个参数写1,由此类推。因为Windows下图像基本
	//操作都是以BMP格式进行,我们读出该帧并转成BMP格式。

	char *dtitle;
	TIFFGetField(tiff,TIFFTAG_PAGENAME,&dtitle);
	//得到该帧的名字,存放在dtitle中。

	int width,height;
	TIFFGetField(tiff, TIFFTAG_IMAGEWIDTH, &width);  //得到宽度
	TIFFGetField(tiff, TIFFTAG_IMAGELENGTH, &height);//得到高度

	float resolution = max(width,height);

	uint16 bitspersample = 1;
	uint16 samplesperpixel = 1;

	TIFFGetField(tiff, TIFFTAG_SAMPLESPERPIXEL, &samplesperpixel);
	//每个像素占多少机器字,24位图samplesperpixel应该等于3。
	TIFFGetField(tiff, TIFFTAG_BITSPERSAMPLE, &bitspersample);
	//每一个机器字长,这里应为8。

	uint16 bitsperpixel = bitspersample * samplesperpixel;
	//算出每个像素占多少bit,24位图,值为24
	DWORD dwBytePerLine = (width*bitsperpixel+31)/32 *4;
	//由上面几个参数算出图像每行所占字节(BYTE)数。


	DWORD64 dwLeng = height*dwBytePerLine;//在内存里存放这帧图像数据所需要的长度
	BYTE* pData = new BYTE[dwLeng];    //为存放数据分配内存空间


	uint32* raster;        
	uint32 *row;
	raster = (uint32*)malloc(width * height * sizeof (uint32));
	TIFFReadRGBAImage(tiff, width, height, (uint32*)pData, 1); 
	//以上几行读出该帧数据,保存到raster中。

	row = &raster[0];
	LPBYTE bits2 = pData;
	for (int y = 0; y < height; y++) 
	

		LPBYTE bits = bits2;
		for (int x = 0; x < width; x++) 
		
			*bits++ = (BYTE)TIFFGetB(row[x]);
			*bits++ = (BYTE)TIFFGetG(row[x]);
			*bits++ = (BYTE)TIFFGetR(row[x]);
		
		row += width;
		bits2 += dwBytePerLine;
	
	_TIFFfree(raster);

	//因为Tif的数据存放顺序和Windows下的BMP相反,上面这几句进行转换。
	//转换结束后,数据存在pData里,释放raster所用内存。



	LPBITMAPINFO pInfo = new BITMAPINFO;
	pInfo->bmiHeader.biSize        = sizeof(BITMAPINFOHEADER);
	pInfo->bmiHeader.biWidth        = width;
	pInfo->bmiHeader.biHeight        = width;
	pInfo->bmiHeader.biCompression    = BI_RGB;

	pInfo->bmiHeader.biClrUsed        = 0;
	pInfo->bmiHeader.biClrImportant    = 0;
	pInfo->bmiHeader.biPlanes        = 1;
	pInfo->bmiHeader.biBitCount = 24;
	pInfo->bmiHeader.biSizeImage        = dwLeng;

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

	if(TIFFGetField(tiff, TIFFTAG_YRESOLUTION, &yres) == 0)
	
		pInfo->bmiHeader.biYPelsPerMeter = 0;
	
	else
	
		if(res_unit == 2)    //英寸
		
			pInfo->bmiHeader.biYPelsPerMeter = yres * 10000 / 254;
		
		else if(res_unit == 3)    //厘米
		
			pInfo->bmiHeader.biYPelsPerMeter = yres * 100;
		
		else
		
			pInfo->bmiHeader.biYPelsPerMeter = 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("c://test.bmp"),CFile::modeCreate|CFile::modeWrite);
	bmpFile.Write(&bmheader,sizeof(BITMAPFILEHEADER));
	bmpFile.Write(&(pInfo->bmiHeader),sizeof(BITMAPINFOHEADER));
	bmpFile.Write(pData,dwLeng);
	bmpFile.Close();

	//这里,把该帧TIFF保存到了C盘的test.bmp中,可以用看图软件打开浏览一下。

	//记得释放内存空间
	delete pInfo;
	pInfo = NULL;
	delete pData;
	pData = NULL;
	//如果想直接显示,就不需要释放,调用StretchDIBits在客户区的DC上就可以显示了。


	//如果再打开其他帧的话,从TIFFSetDirectory开始循环运行,比如取下一帧就是
	TIFFSetDirectory(tiff,1);
	//记得保存时另换一个bmp文件名。
	//最后,对这个TIFF文件全部操作结束,记得调用
	TIFFClose(tiff);

下面的代码是用GDAL打开的

char* szFileName = "K:\\\\地图\\\\fujian-DEM\\\\fujian1.tif";
	GDALDataset *poDataset;   //GDAL数据集
	GDALAllRegister();

	poDataset = (GDALDataset*)GDALOpen(szFileName,GA_ReadOnly);
	if( poDataset == NULL )
	
		AfxMessageBox(_T("文件打开失败!!!"));
		return;
	 

	GDALRasterBand *poBand;   //遥感的一个波段
	int nBandCount = poDataset->GetRasterCount();
	poBand = poDataset->GetRasterBand(1);   //和数组下标有点不同

	//获得图像显示窗口的尺寸
	GetClientRect(&m_ViewRect);

	int nImgSizeX = poDataset->GetRasterXSize();
	int nImgSizeY = poDataset->GetRasterYSize();

	double adfGeoTransform[6];
	poDataset->GetGeoTransform( adfGeoTransform );

	double right  = adfGeoTransform[0] + nImgSizeX*adfGeoTransform[1];
	double bottom  = adfGeoTransform[3] + nImgSizeY*adfGeoTransform[5];

	int nBufferSizeX,nBufferSizeY;

	nBufferSizeX = nImgSizeX;
	nBufferSizeY = nImgSizeY;

	int nScrrenWidth = m_ViewRect.Width();
	int nScrrenHeight= m_ViewRect.Height();

	BYTE *pafScanblock1,*TempLock1;
	pafScanblock1 = (BYTE *) CPLMalloc((nScrrenWidth)*(nScrrenHeight));
	TempLock1 = pafScanblock1;

	poBand->RasterIO( GF_Read, 0, 0,nBufferSizeX,nBufferSizeY, 
		pafScanblock1,nScrrenWidth,nScrrenHeight, GDT_Byte,0, 0 );

	//在View逐点显示图像
	DWORD dwBytes = (nScrrenWidth * 24) / 8;
	while(((DWORD) dwBytes) % 4) 
	
		dwBytes++;
	

	BYTE *szBuffer = new BYTE[nScrrenHeight*dwBytes];
	memset(szBuffer,0,nScrrenHeight*dwBytes);
	BYTE *pTemp = szBuffer;
	CClientDC dc(this);
	int nIndex = 0;
	for (int i=0;i<nScrrenHeight;i++)
	
		for (int j=0;j<nScrrenWidth;j++)
		

			BYTE dn1 = *pafScanblock1;

			memcpy(szBuffer,(char*)(&dn1),1);
			szBuffer += 1;

			pafScanblock1 ++;

		

		szBuffer = pTemp+dwBytes*i;

	
	CPLFree(TempLock1);

	BITMAPINFOHEADER bmiHdr;
	BITMAPINFO MapInfo;
	memset(&bmiHdr, 0, sizeof(BITMAPINFOHEADER));
	bmiHdr.biBitCount = 3*8;
	bmiHdr.biClrImportant = 0;
	bmiHdr.biClrUsed = 0;
	bmiHdr.biCompression = BI_RGB;
	bmiHdr.biHeight = -nScrrenHeight;
	bmiHdr.biPlanes = 1;
	bmiHdr.biSize = sizeof(BITMAPINFOHEADER);
	bmiHdr.biSizeImage = 0;
	bmiHdr.biWidth = nScrrenWidth;

	bmiHdr.biXPelsPerMeter = 0;
	bmiHdr.biYPelsPerMeter = 0;

	MapInfo.bmiHeader = bmiHdr;
	MapInfo.bmiColors[0].rgbBlue = 0;
	MapInfo.bmiColors[0].rgbGreen = 0;
	MapInfo.bmiColors[0].rgbRed = 0;
	MapInfo.bmiColors[0].rgbReserved = 0;

	dc.SetStretchBltMode(MAXSTRETCHBLTMODE);
	::StretchDIBits(dc.GetSafeHdc(), 0, 0, nScrrenWidth, nScrrenHeight,
		0, 0, bmiHdr.biWidth, -bmiHdr.biHeight,
		pTemp, (LPBITMAPINFO)(&MapInfo), DIB_RGB_COLORS, SRCCOPY);

	GDALClose(poDataset);
	delete []pTemp;



 

以上是关于为啥VS2010下OpenCV读取TIFF文件读取失败?的主要内容,如果未能解决你的问题,请参考以下文章

tiff文件读取

OpenCV Tiff 错误的颜色值读数

vs2010里编译opencv程序运行后,看不见图像,但在命令行下运行,图像又可以看见。。请问这是怎么回事?

读取指定目录下的所有文件(windows 和 linux 版)

为啥用Python的openCV读取图片与PIL读取的图片像素值会不一样?

有没有办法在不读取整个文件的情况下推断文件是啥图像格式?