码迷,mamicode.com
首页 > 其他好文 > 详细

使用libtiff读取tif/tiff图像

时间:2015-05-26 14:28:56      阅读:1575      评论:0      收藏:0      [点我收藏+]

标签:tiff

这几天在写tif图像的程序,需要用libtiff读取tif图像(当然用OpenCV的imread和GDAL会更加方便),Demo程序如下:

int TestTIFFDemo()
{
    //打开图像
    char* fileName = "D:/Image/Color/Beauty.tif";
    //char* fileName = "D:/Image/Projects/ShipImage/01001.tif";
    //char *fileName = "D:/Image/Color/Example400.tif";
    TIFF* tiff =TIFFOpen( fileName, "r");//打开Tiff文件,得到指针,以后所有的操作都通过指针进行

    //获取图像参数
    int width, height;
    TIFFGetField(tiff, TIFFTAG_IMAGEWIDTH, &width);
    TIFFGetField(tiff, TIFFTAG_IMAGELENGTH, &height);

    //读取图像
    //注意:TIFFReadRGBAImage读取的通道顺序为:ABGR
    uint32* image;
    int pixelCount = width*height;
    image = (uint32*)malloc(pixelCount * sizeof (uint32));
    TIFFReadRGBAImage(tiff, width, height, image, 1);

    //读取R通道
    //由于tiff格式的图像数据与bmp图存储方式一致,是从下到上,所以读的时候,需要从下往上读
    BYTE* RImage = new BYTE[pixelCount];    //为存放数据分配内存空间
    uint32 *rowPointerToSrc = image + (height - 1)*width;
    BYTE *rowPointerToR = RImage;
    for (int y = height - 1; y >= 0; --y)
    {
        uint32 *colPointerToSrc = rowPointerToSrc;
        BYTE *colPointerToR = rowPointerToR;
        for (int x = 0; x <= width - 1; ++x)
        {
            colPointerToR[0] = (BYTE)TIFFGetR(colPointerToSrc[0]);//获取R通道
            //TIFFGetB(colPointerToSrc[0]);//获取B通道
            //TIFFGetG(colPointerToSrc[0]);//获取G通道

            colPointerToR++;
            colPointerToSrc++;
        }
        rowPointerToSrc -= width;
        rowPointerToR += width;
    }

    //调试
    //这里使用了OpenCV
    Mat RImage_Mat(height, width, CV_8UC1, RImage, width);
    imwrite("D:/111.bmp", RImage_Mat);

    //释放空间
    _TIFFfree(image);
    _TIFFfree(RImage);
    TIFFClose(tiff);
    return 0;
}

但是程序运行的时候出现了下面的警告提示
技术分享

技术分享

技术分享

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

//警告处理
static int grfmt_tiff_err_handler_init = 0;
static void GrFmtSilentTIFFErrorHandler(const char*, const char*, va_list) {}
int TestTIFFDemo()
{
    //警告处理:防止出现unknown field with tag  33500 encountered警告
    if (!grfmt_tiff_err_handler_init)
    {
        grfmt_tiff_err_handler_init = 1;

        TIFFSetErrorHandler(GrFmtSilentTIFFErrorHandler);
        TIFFSetWarningHandler(GrFmtSilentTIFFErrorHandler);
    }

    //打开图像
    char* fileName = "D:/Image/Color/Beauty.tif";
    //char* fileName = "D:/Image/Projects/ShipImage/01001.tif";
    //char *fileName = "D:/Image/Color/Example400.tif";
    TIFF* tiff =TIFFOpen( fileName, "r");//打开Tiff文件,得到指针,以后所有的操作都通过指针进行

    //获取图像参数
    int width, height;
    TIFFGetField(tiff, TIFFTAG_IMAGEWIDTH, &width);
    TIFFGetField(tiff, TIFFTAG_IMAGELENGTH, &height);

    //读取图像
    //注意:TIFFReadRGBAImage读取的通道顺序为:ABGR
    uint32* image;
    int pixelCount = width*height;
    image = (uint32*)malloc(pixelCount * sizeof (uint32));
    TIFFReadRGBAImage(tiff, width, height, image, 1);

    //读取R通道
    //由于tiff格式的图像数据与bmp图存储方式一致,是从下到上,所以读的时候,需要从下往上读
    BYTE* RImage = new BYTE[pixelCount];    //为存放数据分配内存空间
    uint32 *rowPointerToSrc = image + (height - 1)*width;
    BYTE *rowPointerToR = RImage;
    for (int y = height - 1; y >= 0; --y)
    {
        uint32 *colPointerToSrc = rowPointerToSrc;
        BYTE *colPointerToR = rowPointerToR;
        for (int x = 0; x <= width - 1; ++x)
        {
            colPointerToR[0] = (BYTE)TIFFGetR(colPointerToSrc[0]);//获取R通道
            //TIFFGetB(colPointerToSrc[0]);//获取B通道
            //TIFFGetG(colPointerToSrc[0]);//获取G通道

            colPointerToR++;
            colPointerToSrc++;
        }
        rowPointerToSrc -= width;
        rowPointerToR += width;
    }

    //调试
    //这里使用了OpenCV
    Mat RImage_Mat(height, width, CV_8UC1, RImage, width);
    imwrite("D:/111.bmp", RImage_Mat);

    //释放空间
    _TIFFfree(image);
    _TIFFfree(RImage);
    TIFFClose(tiff);
    return 0;
}

新程序可以正常运行了。
原图
技术分享

结果图

技术分享

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

注意:
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中
相关源码如下:

//tif图像解码器(grfmt_tiff.hpp)
class TiffDecoder : public BaseImageDecoder
{
public:
    TiffDecoder();
    virtual ~TiffDecoder();

    bool  readHeader();
    bool  readData( Mat& img );
    void  close();
    bool  nextPage();

    size_t signatureLength() const;
    bool checkSignature( const String& signature ) const;
    ImageDecoder newDecoder() const;

protected:
    void* m_tif;
    int normalizeChannelsNumber(int channels) const;
    bool readHdrData(Mat& img);
    bool m_hdr;
};

其部分实现(grfmt_tiff.cpp)

#include "tiff.h"
#include "tiffio.h"

static int grfmt_tiff_err_handler_init = 0;
static void GrFmtSilentTIFFErrorHandler( const char*, const char*, va_list ) {}

TiffDecoder::TiffDecoder()
{
    m_tif = 0;

    //警告处理:防止出现unknown field with tag  33500 encountered警告
    if( !grfmt_tiff_err_handler_init )
    {
        grfmt_tiff_err_handler_init = 1;

        TIFFSetErrorHandler( GrFmtSilentTIFFErrorHandler );
        TIFFSetWarningHandler( GrFmtSilentTIFFErrorHandler );
    }
    m_hdr = false;
}


void TiffDecoder::close()
{
    if( m_tif )
    {
        TIFF* tif = (TIFF*)m_tif;
        TIFFClose( tif );
        m_tif = 0;
    }
}

TiffDecoder::~TiffDecoder()
{
    close();
}

size_t TiffDecoder::signatureLength() const
{
    return 4;
}

bool TiffDecoder::checkSignature( const String& signature ) const
{
    return signature.size() >= 4 &&
        (memcmp(signature.c_str(), fmtSignTiffII, 4) == 0 ||
        memcmp(signature.c_str(), fmtSignTiffMM, 4) == 0);
}

int TiffDecoder::normalizeChannelsNumber(int channels) const
{
    return channels > 4 ? 4 : channels;
}

ImageDecoder TiffDecoder::newDecoder() const
{
    return makePtr<TiffDecoder>();
}

//读取文件头
bool TiffDecoder::readHeader()
{
    bool result = false;

    TIFF* tif = static_cast<TIFF*>(m_tif);
    if (!m_tif)
    {
        // TIFFOpen() mode flags are different to fopen().  A ‘b‘ in mode "rb" has no effect when reading.
        // http://www.remotesensing.org/libtiff/man/TIFFOpen.3tiff.html
        //打开tif文件
        tif = TIFFOpen(m_filename.c_str(), "r");
    }

    if( tif )
    {
        uint32 wdth = 0, hght = 0;
        uint16 photometric = 0;
        m_tif = tif;

        //获取属性
        if( TIFFGetField( tif, TIFFTAG_IMAGEWIDTH, &wdth ) &&
            TIFFGetField( tif, TIFFTAG_IMAGELENGTH, &hght ) &&
            TIFFGetField( tif, TIFFTAG_PHOTOMETRIC, &photometric ))
        {
            uint16 bpp=8, ncn = photometric > 1 ? 3 : 1;
            TIFFGetField( tif, TIFFTAG_BITSPERSAMPLE, &bpp );
            TIFFGetField( tif, TIFFTAG_SAMPLESPERPIXEL, &ncn );

            m_width = wdth;
            m_height = hght;
            if((bpp == 32 && ncn == 3) || photometric == PHOTOMETRIC_LOGLUV)
            {
                m_type = CV_32FC3;
                m_hdr = true;
                return true;
            }
            m_hdr = false;

            if( bpp > 8 &&
               ((photometric != 2 && photometric != 1) ||
                (ncn != 1 && ncn != 3 && ncn != 4)))
                bpp = 8;

            int wanted_channels = normalizeChannelsNumber(ncn);
            switch(bpp)
            {
                case 8:
                    m_type = CV_MAKETYPE(CV_8U, photometric > 1 ? wanted_channels : 1);
                    break;
                case 16:
                    m_type = CV_MAKETYPE(CV_16U, photometric > 1 ? wanted_channels : 1);
                    break;

                case 32:
                    m_type = CV_MAKETYPE(CV_32F, photometric > 1 ? 3 : 1);
                    break;
                case 64:
                    m_type = CV_MAKETYPE(CV_64F, photometric > 1 ? 3 : 1);
                    break;

                default:
                    result = false;
            }
            result = true;
        }
    }

    if( !result )
        close();

    return result;
}

bool TiffDecoder::nextPage()
{
    // Prepare the next page, if any.
    return m_tif &&
           TIFFReadDirectory(static_cast<TIFF*>(m_tif)) &&
           readHeader();
}

//读取图像数据
bool  TiffDecoder::readData( Mat& img )
{
    if(m_hdr && img.type() == CV_32FC3)
    {
        return readHdrData(img);
    }
    bool result = false;
    bool color = img.channels() > 1;
    uchar* data = img.ptr();

    if( img.depth() != CV_8U && img.depth() != CV_16U && img.depth() != CV_32F && img.depth() != CV_64F )
        return false;

    //读图像数据
    if( m_tif && m_width && m_height )
    {
        TIFF* tif = (TIFF*)m_tif;
        uint32 tile_width0 = m_width, tile_height0 = 0;
        int x, y, i;
        int is_tiled = TIFFIsTiled(tif);
        uint16 photometric;
        TIFFGetField( tif, TIFFTAG_PHOTOMETRIC, &photometric );
        uint16 bpp = 8, ncn = photometric > 1 ? 3 : 1;
        TIFFGetField( tif, TIFFTAG_BITSPERSAMPLE, &bpp );
        TIFFGetField( tif, TIFFTAG_SAMPLESPERPIXEL, &ncn );
        const int bitsPerByte = 8;
        int dst_bpp = (int)(img.elemSize1() * bitsPerByte);
        int wanted_channels = normalizeChannelsNumber(img.channels());

        if(dst_bpp == 8)
        {
            char errmsg[1024];
            if(!TIFFRGBAImageOK( tif, errmsg ))
            {
                close();
                return false;
            }
        }

        if( (!is_tiled) ||
            (is_tiled &&
            TIFFGetField( tif, TIFFTAG_TILEWIDTH, &tile_width0 ) &&
            TIFFGetField( tif, TIFFTAG_TILELENGTH, &tile_height0 )))
        {
            if(!is_tiled)
                TIFFGetField( tif, TIFFTAG_ROWSPERSTRIP, &tile_height0 );

            if( tile_width0 <= 0 )
                tile_width0 = m_width;

            if( tile_height0 <= 0 )
                tile_height0 = m_height;

            AutoBuffer<uchar> _buffer( size_t(8) * tile_height0*tile_width0);
            uchar* buffer = _buffer;
            ushort* buffer16 = (ushort*)buffer;
            float* buffer32 = (float*)buffer;
            double* buffer64 = (double*)buffer;
            int tileidx = 0;

            for( y = 0; y < m_height; y += tile_height0, data += img.step*tile_height0 )
            {
                int tile_height = tile_height0;

                if( y + tile_height > m_height )
                    tile_height = m_height - y;

                for( x = 0; x < m_width; x += tile_width0, tileidx++ )
                {
                    int tile_width = tile_width0, ok;

                    if( x + tile_width > m_width )
                        tile_width = m_width - x;

                    switch(dst_bpp)
                    {
                        case 8:
                        {
                            uchar * bstart = buffer;
                            if( !is_tiled )
                                ok = TIFFReadRGBAStrip( tif, y, (uint32*)buffer );
                            else
                            {
                                ok = TIFFReadRGBATile( tif, x, y, (uint32*)buffer );
                                //Tiles fill the buffer from the bottom up
                                bstart += (tile_height0 - tile_height) * tile_width0 * 4;
                            }
                            if( !ok )
                            {
                                close();
                                return false;
                            }

                            for( i = 0; i < tile_height; i++ )
                                if( color )
                                {
                                    if (wanted_channels == 4)
                                    {
                                        icvCvt_BGRA2RGBA_8u_C4R( bstart + i*tile_width0*4, 0,
                                                             data + x*4 + img.step*(tile_height - i - 1), 0,
                                                             cvSize(tile_width,1) );
                                    }
                                    else
                                    {
                                        icvCvt_BGRA2BGR_8u_C4C3R( bstart + i*tile_width0*4, 0,
                                                             data + x*3 + img.step*(tile_height - i - 1), 0,
                                                             cvSize(tile_width,1), 2 );
                                    }
                                }
                                else
                                    icvCvt_BGRA2Gray_8u_C4C1R( bstart + i*tile_width0*4, 0,
                                                              data + x + img.step*(tile_height - i - 1), 0,
                                                              cvSize(tile_width,1), 2 );
                            break;
                        }

                        case 16:
                        {
                            if( !is_tiled )
                                ok = (int)TIFFReadEncodedStrip( tif, tileidx, (uint32*)buffer, (tsize_t)-1 ) >= 0;
                            else
                                ok = (int)TIFFReadEncodedTile( tif, tileidx, (uint32*)buffer, (tsize_t)-1 ) >= 0;

                            if( !ok )
                            {
                                close();
                                return false;
                            }

                            for( i = 0; i < tile_height; i++ )
                            {
                                if( color )
                                {
                                    if( ncn == 1 )
                                    {
                                        icvCvt_Gray2BGR_16u_C1C3R(buffer16 + i*tile_width0*ncn, 0,
                                                                  (ushort*)(data + img.step*i) + x*3, 0,
                                                                  cvSize(tile_width,1) );
                                    }
                                    else if( ncn == 3 )
                                    {
                                        icvCvt_RGB2BGR_16u_C3R(buffer16 + i*tile_width0*ncn, 0,
                                                               (ushort*)(data + img.step*i) + x*3, 0,
                                                               cvSize(tile_width,1) );
                                    }
                                    else if (ncn == 4)
                                    {
                                        if (wanted_channels == 4)
                                        {
                                            icvCvt_BGRA2RGBA_16u_C4R(buffer16 + i*tile_width0*ncn, 0,
                                                (ushort*)(data + img.step*i) + x * 4, 0,
                                                cvSize(tile_width, 1));
                                        }
                                        else
                                        {
                                            icvCvt_BGRA2BGR_16u_C4C3R(buffer16 + i*tile_width0*ncn, 0,
                                                (ushort*)(data + img.step*i) + x * 3, 0,
                                                cvSize(tile_width, 1), 2);
                                        }
                                    }
                                    else
                                    {
                                        icvCvt_BGRA2BGR_16u_C4C3R(buffer16 + i*tile_width0*ncn, 0,
                                                               (ushort*)(data + img.step*i) + x*3, 0,
                                                               cvSize(tile_width,1), 2 );
                                    }
                                }
                                else
                                {
                                    if( ncn == 1 )
                                    {
                                        memcpy((ushort*)(data + img.step*i)+x,
                                               buffer16 + i*tile_width0*ncn,
                                               tile_width*sizeof(buffer16[0]));
                                    }
                                    else
                                    {
                                        icvCvt_BGRA2Gray_16u_CnC1R(buffer16 + i*tile_width0*ncn, 0,
                                                               (ushort*)(data + img.step*i) + x, 0,
                                                               cvSize(tile_width,1), ncn, 2 );
                                    }
                                }
                            }
                            break;
                        }

                        case 32:
                        case 64:
                        {
                            if( !is_tiled )
                                ok = (int)TIFFReadEncodedStrip( tif, tileidx, buffer, (tsize_t)-1 ) >= 0;
                            else
                                ok = (int)TIFFReadEncodedTile( tif, tileidx, buffer, (tsize_t)-1 ) >= 0;

                            if( !ok || ncn != 1 )
                            {
                                close();
                                return false;
                            }

                            for( i = 0; i < tile_height; i++ )
                            {
                                if(dst_bpp == 32)
                                {
                                    memcpy((float*)(data + img.step*i)+x,
                                           buffer32 + i*tile_width0*ncn,
                                           tile_width*sizeof(buffer32[0]));
                                }
                                else
                                {
                                    memcpy((double*)(data + img.step*i)+x,
                                         buffer64 + i*tile_width0*ncn,
                                         tile_width*sizeof(buffer64[0]));
                                }
                            }

                            break;
                        }
                        default:
                        {
                            close();
                            return false;
                        }
                    }
                }
            }

            result = true;
        }
    }

    return result;
}

现在发现OpenCV源码真是个好东西,看源码的时候,不仅能够学习到很多优秀思想,优秀的编程技巧,优化方法,还能够帮助你解决一些问题!建议学习OpenCV的朋友,没事多读读OpenCV的源码,绝对对你有好处。

使用libtiff读取tif/tiff图像

标签:tiff

原文地址:http://blog.csdn.net/qianqing13579/article/details/46006737

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!