zoukankan      html  css  js  c++  java
  • 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的源码:
    源码在sourcesmodulesimgcodecssrc中的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源码真是个好东西,能够从中学习到很多优秀的编程技巧,能够帮助你解决很多问题。

  • 相关阅读:
    网络安全之数字签名
    python爬取并分析淘宝商品信息
    循环与分支——python
    线性相关与线性无关
    linux之文件传输协议(FTP)与本地用户测试
    递归下降语法分析
    MySQL:索引
    一个基础又很重要的知识点:JDBC原理(基本案例和面试知识点)
    Tomcat的部署、虚拟主机及优化
    二叉树深度
  • 原文地址:https://www.cnblogs.com/ybqjymy/p/13678821.html
Copyright © 2011-2022 走看看