LIBTIFF 读取tif/tiff图像


Demo程序如下:

 1 int TestTIFFDemo()  2 {  3     //打开图像
 4     char* fileName = "D:/Image/Color/Beauty.tif";  5     //char* fileName = "D:/Image/Projects/ShipImage/01001.tif";  6     //char *fileName = "D:/Image/Color/Example400.tif";
 7     TIFF* tiff =TIFFOpen( fileName, "r");//打开Tiff文件,得到指针,以后所有的操作都通过指针进行  8 
 9     //获取图像参数
10     int width, height; 11     TIFFGetField(tiff, TIFFTAG_IMAGEWIDTH, &width); 12     TIFFGetField(tiff, TIFFTAG_IMAGELENGTH, &height); 13 
14     //读取图像 15     //注意:TIFFReadRGBAImage读取的通道顺序为:ABGR
16     uint32* image; 17     int pixelCount = width*height; 18     image = (uint32*)malloc(pixelCount * sizeof (uint32)); 19     TIFFReadRGBAImage(tiff, width, height, image, 1); 20 
21     //读取R通道 22     //由于tiff格式的图像数据与bmp图存储方式一致,是从下到上,所以读的时候,需要从下往上读
23     BYTE* RImage = new BYTE[pixelCount];    //为存放数据分配内存空间
24     uint32 *rowPointerToSrc = image + (height - 1)*width; 25     BYTE *rowPointerToR = RImage; 26     for (int y = height - 1; y >= 0; --y) 27  { 28         uint32 *colPointerToSrc = rowPointerToSrc; 29         BYTE *colPointerToR = rowPointerToR; 30         for (int x = 0; x <= width - 1; ++x) 31  { 32             colPointerToR[0] = (BYTE)TIFFGetR(colPointerToSrc[0]);//获取R通道 33             //TIFFGetB(colPointerToSrc[0]);//获取B通道 34             //TIFFGetG(colPointerToSrc[0]);//获取G通道
35 
36             colPointerToR++; 37             colPointerToSrc++; 38  } 39         rowPointerToSrc -= width; 40         rowPointerToR += width; 41  } 42 
43     //调试 44     //这里使用了OpenCV
45  Mat RImage_Mat(height, width, CV_8UC1, RImage, width); 46     imwrite("D:/111.bmp", RImage_Mat); 47 
48     //释放空间
49  _TIFFfree(image); 50  _TIFFfree(RImage); 51  TIFFClose(tiff); 52     return 0; 53 }

但是程序运行的时候出现了下面的警告提示
这里写图片描述

这里写图片描述

这里写图片描述

到网上找了下解决方案,都没有解决,最后,在OpenCV源码中找到了解决方案
修改后的程序如下:

 1 //警告处理
 2 static int grfmt_tiff_err_handler_init = 0;  3 static void GrFmtSilentTIFFErrorHandler(const char*, const char*, va_list) {}  4 int TestTIFFDemo()  5 {  6     //警告处理:防止出现unknown field with tag 33500 encountered警告
 7     if (!grfmt_tiff_err_handler_init)  8  {  9         grfmt_tiff_err_handler_init = 1; 10 
11  TIFFSetErrorHandler(GrFmtSilentTIFFErrorHandler); 12  TIFFSetWarningHandler(GrFmtSilentTIFFErrorHandler); 13  } 14 
15     //打开图像
16     char* fileName = "D:/Image/Color/Beauty.tif"; 17     //char* fileName = "D:/Image/Projects/ShipImage/01001.tif"; 18     //char *fileName = "D:/Image/Color/Example400.tif";
19     TIFF* tiff =TIFFOpen( fileName, "r");//打开Tiff文件,得到指针,以后所有的操作都通过指针进行 20 
21     //获取图像参数
22     int width, height; 23     TIFFGetField(tiff, TIFFTAG_IMAGEWIDTH, &width); 24     TIFFGetField(tiff, TIFFTAG_IMAGELENGTH, &height); 25 
26     //读取图像 27     //注意:TIFFReadRGBAImage读取的通道顺序为:ABGR
28     uint32* image; 29     int pixelCount = width*height; 30     image = (uint32*)malloc(pixelCount * sizeof (uint32)); 31     TIFFReadRGBAImage(tiff, width, height, image, 1); 32 
33     //读取R通道 34     //由于tiff格式的图像数据与bmp图存储方式一致,是从下到上,所以读的时候,需要从下往上读
35     BYTE* RImage = new BYTE[pixelCount];    //为存放数据分配内存空间
36     uint32 *rowPointerToSrc = image + (height - 1)*width; 37     BYTE *rowPointerToR = RImage; 38     for (int y = height - 1; y >= 0; --y) 39  { 40         uint32 *colPointerToSrc = rowPointerToSrc; 41         BYTE *colPointerToR = rowPointerToR; 42         for (int x = 0; x <= width - 1; ++x) 43  { 44             colPointerToR[0] = (BYTE)TIFFGetR(colPointerToSrc[0]);//获取R通道 45             //TIFFGetB(colPointerToSrc[0]);//获取B通道 46             //TIFFGetG(colPointerToSrc[0]);//获取G通道
47 
48             colPointerToR++; 49             colPointerToSrc++; 50  } 51         rowPointerToSrc -= width; 52         rowPointerToR += width; 53  } 54 
55     //调试 56     //这里使用了OpenCV
57  Mat RImage_Mat(height, width, CV_8UC1, RImage, width); 58     imwrite("D:/111.bmp", RImage_Mat); 59 
60     //释放空间
61  _TIFFfree(image); 62  _TIFFfree(RImage); 63  TIFFClose(tiff); 64     return 0; 65 }

新程序可以正常运行了。
原图
这里写图片描述

结果图

这里写图片描述

原来是需要加入一个警告处理。

注意:
1、由于tiff格式的图像数据与bmp图存储方式一致,是从下到上,所以读的时候,需要从下往上读,否则图像会出错
2、 image = (uint32*)malloc(pixelCount * sizeof (uint32)); 如果需要申请的图像内存比较大,可以通过修改VS属性的办法申请大内存:properties->Linker->System->Heap Reserve Size
这里写图片描述

这里顺便贴出tiff的OpenCV的源码:
源码在sources\modules\imgcodecs\src\中的grfmt_tiff.hpp和grfmt_tiff.cpp中
相关源码如下:

 1 //tif图像解码器(grfmt_tiff.hpp)
 2 class TiffDecoder : public BaseImageDecoder  3 {  4 public:  5  TiffDecoder();  6     virtual ~TiffDecoder();  7 
 8     bool readHeader();  9     bool  readData( Mat& img ); 10     void close(); 11     bool nextPage(); 12 
13     size_t signatureLength() const; 14     bool checkSignature( const String& signature ) const; 15     ImageDecoder newDecoder() const; 16 
17 protected: 18     void* m_tif; 19     int normalizeChannelsNumber(int channels) const; 20     bool readHdrData(Mat& img); 21     bool m_hdr; 22 };

其部分实现(grfmt_tiff.cpp)

 1 #include "tiff.h"
 2 #include "tiffio.h"
 3 
 4 static int grfmt_tiff_err_handler_init = 0;  5 static void GrFmtSilentTIFFErrorHandler( const char*, const char*, va_list ) {}  6 
 7 TiffDecoder::TiffDecoder()  8 {  9     m_tif = 0;  10 
 11     //警告处理:防止出现unknown field with tag 33500 encountered警告
 12     if( !grfmt_tiff_err_handler_init )  13  {  14         grfmt_tiff_err_handler_init = 1;  15 
 16  TIFFSetErrorHandler( GrFmtSilentTIFFErrorHandler );  17  TIFFSetWarningHandler( GrFmtSilentTIFFErrorHandler );  18  }  19     m_hdr = false;  20 }  21 
 22 
 23 void TiffDecoder::close()  24 {  25     if( m_tif )  26  {  27         TIFF* tif = (TIFF*)m_tif;  28  TIFFClose( tif );  29         m_tif = 0;  30  }  31 }  32 
 33 TiffDecoder::~TiffDecoder()  34 {  35  close();  36 }  37 
 38 size_t TiffDecoder::signatureLength() const
 39 {  40     return 4;  41 }  42 
 43 bool TiffDecoder::checkSignature( const String& signature ) const
 44 {  45     return signature.size() >= 4 &&
 46         (memcmp(signature.c_str(), fmtSignTiffII, 4) == 0 ||
 47         memcmp(signature.c_str(), fmtSignTiffMM, 4) == 0);  48 }  49 
 50 int TiffDecoder::normalizeChannelsNumber(int channels) const
 51 {  52     return channels > 4 ? 4 : channels;  53 }  54 
 55 ImageDecoder TiffDecoder::newDecoder() const
 56 {  57     return makePtr<TiffDecoder>();  58 }  59 
 60 //读取文件头
 61 bool TiffDecoder::readHeader()  62 {  63     bool result = false;  64 
 65     TIFF* tif = static_cast<TIFF*>(m_tif);  66     if (!m_tif)  67  {  68         // TIFFOpen() mode flags are different to fopen(). A 'b' in mode "rb" has no effect when reading.  69         // http://www.remotesensing.org/libtiff/man/TIFFOpen.3tiff.html
 70         //打开tif文件
 71         tif = TIFFOpen(m_filename.c_str(), "r");  72  }  73 
 74     if( tif )  75  {  76         uint32 wdth = 0, hght = 0;  77         uint16 photometric = 0;  78         m_tif = tif;  79 
 80         //获取属性
 81         if( TIFFGetField( tif, TIFFTAG_IMAGEWIDTH, &wdth ) &&
 82             TIFFGetField( tif, TIFFTAG_IMAGELENGTH, &hght ) &&
 83             TIFFGetField( tif, TIFFTAG_PHOTOMETRIC, &photometric ))  84  {  85             uint16 bpp=8, ncn = photometric > 1 ? 3 : 1;  86             TIFFGetField( tif, TIFFTAG_BITSPERSAMPLE, &bpp );  87             TIFFGetField( tif, TIFFTAG_SAMPLESPERPIXEL, &ncn );  88 
 89             m_width = wdth;  90             m_height = hght;  91             if((bpp == 32 && ncn == 3) || photometric == PHOTOMETRIC_LOGLUV)  92  {  93                 m_type = CV_32FC3;  94                 m_hdr = true;  95                 return true;  96  }  97             m_hdr = false;  98 
 99             if( bpp > 8 &&
100                ((photometric != 2 && photometric != 1) ||
101                 (ncn != 1 && ncn != 3 && ncn != 4))) 102                 bpp = 8; 103 
104             int wanted_channels = normalizeChannelsNumber(ncn); 105             switch(bpp) 106  { 107                 case 8: 108                     m_type = CV_MAKETYPE(CV_8U, photometric > 1 ? wanted_channels : 1); 109                     break; 110                 case 16: 111                     m_type = CV_MAKETYPE(CV_16U, photometric > 1 ? wanted_channels : 1); 112                     break; 113 
114                 case 32: 115                     m_type = CV_MAKETYPE(CV_32F, photometric > 1 ? 3 : 1); 116                     break; 117                 case 64: 118                     m_type = CV_MAKETYPE(CV_64F, photometric > 1 ? 3 : 1); 119                     break; 120 
121                 default: 122                     result = false; 123  } 124             result = true; 125  } 126  } 127 
128     if( !result ) 129  close(); 130 
131     return result; 132 } 133 
134 bool TiffDecoder::nextPage() 135 { 136     // Prepare the next page, if any.
137     return m_tif &&
138            TIFFReadDirectory(static_cast<TIFF*>(m_tif)) &&
139  readHeader(); 140 } 141 
142 //读取图像数据
143 bool  TiffDecoder::readData( Mat& img ) 144 { 145     if(m_hdr && img.type() == CV_32FC3) 146  { 147         return readHdrData(img); 148  } 149     bool result = false; 150     bool color = img.channels() > 1; 151     uchar* data = img.ptr(); 152 
153     if( img.depth() != CV_8U && img.depth() != CV_16U && img.depth() != CV_32F && img.depth() != CV_64F ) 154         return false; 155 
156     //读图像数据
157     if( m_tif && m_width && m_height ) 158  { 159         TIFF* tif = (TIFF*)m_tif; 160         uint32 tile_width0 = m_width, tile_height0 = 0; 161         int x, y, i; 162         int is_tiled = TIFFIsTiled(tif); 163  uint16 photometric; 164         TIFFGetField( tif, TIFFTAG_PHOTOMETRIC, &photometric ); 165         uint16 bpp = 8, ncn = photometric > 1 ? 3 : 1; 166         TIFFGetField( tif, TIFFTAG_BITSPERSAMPLE, &bpp ); 167         TIFFGetField( tif, TIFFTAG_SAMPLESPERPIXEL, &ncn ); 168         const int bitsPerByte = 8; 169         int dst_bpp = (int)(img.elemSize1() * bitsPerByte); 170         int wanted_channels = normalizeChannelsNumber(img.channels()); 171 
172         if(dst_bpp == 8) 173  { 174             char errmsg[1024]; 175             if(!TIFFRGBAImageOK( tif, errmsg )) 176  { 177  close(); 178                 return false; 179  } 180  } 181 
182         if( (!is_tiled) ||
183             (is_tiled &&
184             TIFFGetField( tif, TIFFTAG_TILEWIDTH, &tile_width0 ) &&
185             TIFFGetField( tif, TIFFTAG_TILELENGTH, &tile_height0 ))) 186  { 187             if(!is_tiled) 188                 TIFFGetField( tif, TIFFTAG_ROWSPERSTRIP, &tile_height0 ); 189 
190             if( tile_width0 <= 0 ) 191                 tile_width0 = m_width; 192 
193             if( tile_height0 <= 0 ) 194                 tile_height0 = m_height; 195 
196             AutoBuffer<uchar> _buffer( size_t(8) * tile_height0*tile_width0); 197             uchar* buffer = _buffer; 198             ushort* buffer16 = (ushort*)buffer; 199             float* buffer32 = (float*)buffer; 200             double* buffer64 = (double*)buffer; 201             int tileidx = 0; 202 
203             for( y = 0; y < m_height; y += tile_height0, data += img.step*tile_height0 ) 204  { 205                 int tile_height = tile_height0; 206 
207                 if( y + tile_height > m_height ) 208                     tile_height = m_height - y; 209 
210                 for( x = 0; x < m_width; x += tile_width0, tileidx++ ) 211  { 212                     int tile_width = tile_width0, ok; 213 
214                     if( x + tile_width > m_width ) 215                         tile_width = m_width - x; 216 
217                     switch(dst_bpp) 218  { 219                         case 8: 220  { 221                             uchar * bstart = buffer; 222                             if( !is_tiled ) 223                                 ok = TIFFReadRGBAStrip( tif, y, (uint32*)buffer ); 224                             else
225  { 226                                 ok = TIFFReadRGBATile( tif, x, y, (uint32*)buffer ); 227                                 //Tiles fill the buffer from the bottom up
228                                 bstart += (tile_height0 - tile_height) * tile_width0 * 4; 229  } 230                             if( !ok ) 231  { 232  close(); 233                                 return false; 234  } 235 
236                             for( i = 0; i < tile_height; i++ ) 237                                 if( color ) 238  { 239                                     if (wanted_channels == 4) 240  { 241                                         icvCvt_BGRA2RGBA_8u_C4R( bstart + i*tile_width0*4, 0, 242                                                              data + x*4 + img.step*(tile_height - i - 1), 0, 243                                                              cvSize(tile_width,1) ); 244  } 245                                     else
246  { 247                                         icvCvt_BGRA2BGR_8u_C4C3R( bstart + i*tile_width0*4, 0, 248                                                              data + x*3 + img.step*(tile_height - i - 1), 0, 249                                                              cvSize(tile_width,1), 2 ); 250  } 251  } 252                                 else
253                                     icvCvt_BGRA2Gray_8u_C4C1R( bstart + i*tile_width0*4, 0, 254                                                               data + x + img.step*(tile_height - i - 1), 0, 255                                                               cvSize(tile_width,1), 2 ); 256                             break; 257  } 258 
259                         case 16: 260  { 261                             if( !is_tiled ) 262                                 ok = (int)TIFFReadEncodedStrip( tif, tileidx, (uint32*)buffer, (tsize_t)-1 ) >= 0; 263                             else
264                                 ok = (int)TIFFReadEncodedTile( tif, tileidx, (uint32*)buffer, (tsize_t)-1 ) >= 0; 265 
266                             if( !ok ) 267  { 268  close(); 269                                 return false; 270  } 271 
272                             for( i = 0; i < tile_height; i++ ) 273  { 274                                 if( color ) 275  { 276                                     if( ncn == 1 ) 277  { 278                                         icvCvt_Gray2BGR_16u_C1C3R(buffer16 + i*tile_width0*ncn, 0, 279                                                                   (ushort*)(data + img.step*i) + x*3, 0, 280                                                                   cvSize(tile_width,1) ); 281  } 282                                     else if( ncn == 3 ) 283  { 284                                         icvCvt_RGB2BGR_16u_C3R(buffer16 + i*tile_width0*ncn, 0, 285                                                                (ushort*)(data + img.step*i) + x*3, 0, 286                                                                cvSize(tile_width,1) ); 287  } 288                                     else if (ncn == 4) 289  { 290                                         if (wanted_channels == 4) 291  { 292                                             icvCvt_BGRA2RGBA_16u_C4R(buffer16 + i*tile_width0*ncn, 0, 293                                                 (ushort*)(data + img.step*i) + x * 4, 0, 294                                                 cvSize(tile_width, 1)); 295  } 296                                         else
297  { 298                                             icvCvt_BGRA2BGR_16u_C4C3R(buffer16 + i*tile_width0*ncn, 0, 299                                                 (ushort*)(data + img.step*i) + x * 3, 0, 300                                                 cvSize(tile_width, 1), 2); 301  } 302  } 303                                     else
304  { 305                                         icvCvt_BGRA2BGR_16u_C4C3R(buffer16 + i*tile_width0*ncn, 0, 306                                                                (ushort*)(data + img.step*i) + x*3, 0, 307                                                                cvSize(tile_width,1), 2 ); 308  } 309  } 310                                 else
311  { 312                                     if( ncn == 1 ) 313  { 314                                         memcpy((ushort*)(data + img.step*i)+x, 315                                                buffer16 + i*tile_width0*ncn, 316                                                tile_width*sizeof(buffer16[0])); 317  } 318                                     else
319  { 320                                         icvCvt_BGRA2Gray_16u_CnC1R(buffer16 + i*tile_width0*ncn, 0, 321                                                                (ushort*)(data + img.step*i) + x, 0, 322                                                                cvSize(tile_width,1), ncn, 2 ); 323  } 324  } 325  } 326                             break; 327  } 328 
329                         case 32: 330                         case 64: 331  { 332                             if( !is_tiled ) 333                                 ok = (int)TIFFReadEncodedStrip( tif, tileidx, buffer, (tsize_t)-1 ) >= 0; 334                             else
335                                 ok = (int)TIFFReadEncodedTile( tif, tileidx, buffer, (tsize_t)-1 ) >= 0; 336 
337                             if( !ok || ncn != 1 ) 338  { 339  close(); 340                                 return false; 341  } 342 
343                             for( i = 0; i < tile_height; i++ ) 344  { 345                                 if(dst_bpp == 32) 346  { 347                                     memcpy((float*)(data + img.step*i)+x, 348                                            buffer32 + i*tile_width0*ncn, 349                                            tile_width*sizeof(buffer32[0])); 350  } 351                                 else
352  { 353                                     memcpy((double*)(data + img.step*i)+x, 354                                          buffer64 + i*tile_width0*ncn, 355                                          tile_width*sizeof(buffer64[0])); 356  } 357  } 358 
359                             break; 360  } 361                         default: 362  { 363  close(); 364                             return false; 365  } 366  } 367  } 368  } 369 
370             result = true; 371  } 372  } 373 
374     return result; 375 }

OpenCV源码真是个好东西,能够从中学习到很多优秀的编程技巧,能够帮助你解决很多问题。


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM