使用libtiff读取tif/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的源码,绝对对你有好处。

时间: 2024-10-12 22:49:19

使用libtiff读取tif/tiff图像的相关文章

TIFF图像文件格式详解

1 什么是TIFF?TIFF是Tagged Image File Format的缩写.在现在的标准中,只有TIFF存在, 其他的提法已经舍弃不用了.做为一种标记语言,TIFF与其他文件格式最大的不同在于除了图像数据,它还可以记录很多图像的其他信息.它记录图像数据的方式也比较灵活, 理论上来说, 任何其他的图像格式都能为TIFF所用, 嵌入到TIFF里面.比如JPEG, Lossless JPEG, JPEG2000和任意数据宽度的原始无压缩数据都可以方便的嵌入到TIFF中去.由于它的可扩展性,

任务5 图像的读取及表示 图像的特征 图片特征的降维

任务目的: 知道图像的表示以及读取方法 了解图像的特征 对图像特征进行降维 一.图像的读取及表示 图像要进行处理才能进行模型输入. python自带的库将图像存在矩阵或者张量里面. 图像由像素组成,一个像素点一般油RGB三维数组构成. 二.图像的特征 图像的识别should环境因素约束. 常见的图像颜色特征有:SIFT尺度不变特征变换 和 HOG方向梯度直方图 颜色特征就是对RGB做一个统计,统计有各颜色的分布百分比. 前者具有尺度不变性,即使改变旋转角度,图像亮度或拍摄视角依然能够很好地识别.

&lt;转&gt;Matlab读写TIFF格式文件

1.简介 通常情况下,使用MATLAB做图像处理后,使用下面的命令就可以保存处理结果为图片. imwrite(im,'im.bmp'); 而如果需要保存的图像为single或者double类型,或保存的图像超过RGB三个通道时,则不能使用imwrite来直接进行,此时需要将矩阵保存为TIFF格式的图片. matlab支持LibTIFF库作为TIFF图像读写的工具,因此只要学习如果使用LibTIFF提供的matlab接口就可以完成TIFF图像的读写任务. 使用TIFF保存图像时使用的详细的TAG信

tiff或tif文件的读取

以下是VC下读取TIFF文件的代码 char* szFileName = "K:\\地图\\fujian-DEM\\fujian1.tif"; TIFF* tiff = TIFFOpen(szFileName, "r");//打开Tiff文件,得到指针,以后所有的操作都通过指针进行 int nTotalFrame = TIFFNumberOfDirectories(tiff); //得到图像的总帧数 //TIFFSetDirectory(tiff,0); //我们打

Python读取TIFF多通道图像

1.PIL from PIL import Image im = Image.open("filename") 支持单通道及多通道Uint8 TIFF图像读取,读取单通道Uint16 TIFF图像转为Uint8处理,直接读取Uint16 TIFF多通道图像出错,错误信息: 2.OpenCV import cv2 cv2.imread("filename",flags) 对于cv2,imread的关于通道数和位深的flags有四种选择: IMREAD_UNCHANGE

Opencv 图像读取与保存问题

本系列文章由 @yhl_leo 出品,转载请注明出处. 文章链接: http://blog.csdn.net/yhl_leo/article/details/49737357 本文仅对 Opencv图像读取与保存进行阐述,重在探讨图像读取与保存过程中应注意的细节问题. 1 图像读取 首先看一下,imread函数的声明: // C++: Mat based Mat imread(const string& filename, int flags=1 ); // C: IplImage based

Python爬虫新手进阶版:怎样读取非结构化、图像、视频、语音数据

通过open读取之后会返回一个图像文件对象,后续所有的图像处理都基于该对象进行.上述代码执行后,通过 img.show() 会调用系统默认的图像浏览器查看打开图像进行查看.如图所示. 该对象包含了很多方法可以用来打印输出文件的属性,例如尺寸.格式.色彩模式等. print ('img format: ', img.format) # 打印图像格式 print ('img size: ', img.size) # 打印图像尺寸 print ('img mode: ', img.mode) # 打印

C/C++ 图像二进制存储与读取

本系列文章由 @yhl_leo 出品,转载请注明出处. 文章链接: http://blog.csdn.net/yhl_leo/article/details/50782792 在深度学习时,制作样本数据集时,须要产生和读取一些二进制图像的数据集,如MNIST,CIFAR-10等都提供了适合C语言的二进制版本号. 以CIFAR-10的数据集为例.官网上有两段关键的介绍: 二进制版本号数据集格式为(图像大小为32x32): <1 x label><3072 x pixel> ... &

VTK序列图像的读取[转][改]

医学图像处理的应用程序中,经常会碰到读取一个序列图像的操作.比如CT.MR等所成的图像都是一个切面一个切面地存储的,医学图像处理程序要处理这些数据,第一步当然是把这些数据从磁盘等外部存储介质中导入内存. 利用VTK可以读取多种格式的图像文件,支持读取单个的二维图像(比如*.BMP.*.JPEG.*.PNG等)或者三维图像文件(*.VTK.*.mhd.*.mha等),也支持序列图像文件的导入.下面我们详细地讲解如何在VTK里实现序列图像文件的读取(我们以美国可视人的数据做为测试数据,数据可以从这里