libTIFF 图像读取与保存

来源:互联网 发布:淘宝加盟代理骗局 编辑:程序博客网 时间:2024/05/28 15:13


本系列文章由 @YhL_Leo 出品,转载请注明出处。
文章链接: http://blog.csdn.net/YhL_Leo/article/details/49848391


1 头文件

libtiff定义一系列C语言类型的数据结构,调用时包含的头文件为:

#include "tiffio.h"

2 文件读写

/* read from an existing TIFF image */void main(){    TIFF* tif = TIFFOpen("foo.tif", "r");    ... do stuff ...    TIFFClose(tif);  // or TIFFFlush(tif);}/* create or overwrite a TIFF image */void main(){    TIFF* tif = TIFFOpen("foo.tif", "w");    ... do stuff ...    TIFFClose(tif);  // or TIFFFlush(tif);}

不同于stdio library对TIFF文件的操作可以同时支持读和写,libtiff对于TIFF文件的操作模式是不可变更的,也就是说对一个指定的TIFF文件,一次只能支持对文件的读或写中的一种操作。

3 多目录文件读写

TIFF格式支持将多个图像文件存储为一个文件的功能,每个图片都有一个对应的数据结构称为一个目录,其中包括全部的信息格式和图像数据内容。图像之间可以是相关的也可以使不相关的。

#include "tiffio.h"int main(int argc, char* argv[]){    TIFF* tif = TIFFOpen(argv[1], "r");    if (tif)     {        int dircount = 0;        do {            dircount++;        } while (TIFFReadDirectory(tif));        printf("%d directories in %s\n", dircount, argv[1]);        TIFFClose(tif);    }    return 0;}// write: TIFFWriteDirectory()

4 标签读取与设置

图像相关的信息例如宽、高、通道数、定向信息、颜色信息等。libtiff中提供了获取和设置标签值的函数:TIFFGetFieldTIFFSetField

/* read the tags */uint32 width, height;uint16 ncn;TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &width);    // image width in pixelsTIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height);  // image height in pixelsTIFFGetField(tif, TIFFTAG_SAMPLESPERPIXEL, &ncn); // samples per pixel -> channelscout << width << " " << height << " " << ncn << endl; /* set the tags */ TIFFSetField( imageWrite, TIFFTAG_IMAGEWIDTH, width );TIFFSetField( imageWrite, TIFFTAG_IMAGELENGTH, height );TIFFSetField( imageWrite, TIFFTAG_BITSPERSAMPLE, 8);    // 8 bits per channelTIFFSetField( imageWrite, TIFFTAG_SAMPLESPERPIXEL, 4);  // 4 channels

下面列出几种常用的TIFF图像信息标签:

#define TIFFTAG_IMAGEWIDTH        256   /* image width in pixels */#define TIFFTAG_IMAGELENGTH       257   /* image height in pixels */#define TIFFTAG_BITSPERSAMPLE     258   /* bits per channel (sample) */#define TIFFTAG_SAMPLESPERPIXEL   277   /* samples per pixel */#define TIFFTAG_COMPRESSION       259   /* data compression technique */#define TIFFTAG_PHOTOMETRIC       262   /* photometric interpretation */#define TIFFTAG_PLANARCONFIG      284   /* storage organization */#define TIFFTAG_XRESOLUTION       282   /* pixels/resolution in x */#define TIFFTAG_YRESOLUTION       283   /* pixels/resolution in y */#define TIFFTAG_RESOLUTIONUNIT    296   /* units of resolutions */

5 RGBA 图像读取与存储

对于4通道的图像,libtiff提供的数据颜色顺序为A B G R,并且整合为32-bit无符号整型数据(每个通道为8 bits),数据读取方法为使用TIFFReadRGBAImage函数:

#include "tiffio.h"// first method: TIFFReadRGBAImageint main(int argc, char* argv[]){    TIFF* tif = TIFFOpen(argv[1], "r");    if (tif) {    uint32 w, h;    size_t npixels;    uint32* raster;    TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &w);    TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &h);    npixels = w * h;    raster = (uint32*) _TIFFmalloc(npixels * sizeof (uint32));    if (raster != NULL) {        if (TIFFReadRGBAImage(tif, w, h, raster, 0)) {        ...process raster data...        }        _TIFFfree(raster);    }    TIFFClose(tif);    }    return 0;}// second method: TIFFRGBAImageBegin & TIFFRGBAImageGetint main(int argc, char* argv[]){    TIFF* tif = TIFFOpen(argv[1], "r");    if (tif) {    TIFFRGBAImage img;    char emsg[1024];    if (TIFFRGBAImageBegin(&img, tif, 0, emsg)) {        size_t npixels;        uint32* raster;        npixels = img.width * img.height;        raster = (uint32*) _TIFFmalloc(npixels * sizeof (uint32));        if (raster != NULL) {        if (TIFFRGBAImageGet(&img, raster, img.width, img.height)) {            ...process raster data...        }        _TIFFfree(raster);        }        TIFFRGBAImageEnd(&img);    } else        TIFFError(argv[1], emsg);    TIFFClose(tif);    }    return 0;}

TIFFReadRGBAImage为例,读取图像后,获得其某一通道的结果,可使用:

// image channel read order : A B G Rif ( TIFFReadRGBAImage(tif, width, height, raster, 0) ){    BYTE *imageR = new BYTE[nPixels];    // image pixels are in an inverted order, which is same as bmp format    uint32* rowPoint2Src = raster + (height-1)*width;    BYTE *rowPointerToR  = imageR;    for ( int rows = height-1; rows >= 0; --rows )    {        uint32 *colPoint2Src = rowPoint2Src;        BYTE* colPoint2R = rowPointerToR;        for ( int cols = 0; cols < width; cols ++ )        {            // read the channel : A            *colPoint2R = (BYTE)TIFFGetA(*colPoint2Src);            // or : colPoint2R[0] = (BYTE)TIFFGetA(colPoint2Src[0]);            colPoint2R++;            colPoint2Src++;        }        rowPoint2Src  -= width;        rowPointerToR += width;    }     cv::Mat imageR_mat( height, width, CV_8UC1, imageR, width );    imwrite("E:\\0-Alpha.jpg", imageR_mat);    _TIFFfree(imageR);}

如果想把4通道TIFF文件,读入内存后转为Mat格式,可以这么做:

/* save as a Mat */cv::Mat image(height, width, CV_8UC4, cv::Scalar::all(0));if ( TIFFReadRGBAImage(tif, width, height, raster, 0) ){    uchar* imageData = (uchar*)image.data;    uint32* rowPoint2Src = raster + (height-1)*width;    for ( int rows = height-1; rows >= 0; --rows )    {        uint32 *colPoint2Src = rowPoint2Src;        // image pixels are in an inverted order, which is same as bmp format        uchar* colPoint = image.ptr<uchar>( height - rows - 1 );        for ( int cols = 0; cols < width; cols ++ )        {            *colPoint++ = (uchar)TIFFGetB(*colPoint2Src); // B            *colPoint++ = (uchar)TIFFGetG(*colPoint2Src); // G            *colPoint++ = (uchar)TIFFGetR(*colPoint2Src); // R            *colPoint++ = (uchar)TIFFGetA(*colPoint2Src); // A            colPoint2Src++;        }        rowPoint2Src  -= width;    } }

创建并保存4通道TIFF图像可以按照下面的方法:

/* creat and write a ABGR tiff image */#include <iostream>#include <vector>#include "cv.h"#include "highgui.h"#include "tiffio.h"using namespace std;using namespace cv;void main(){    cv::Mat imageGray  = cv::imread( "C:\\Users\\Leo\\Desktop\\Test\\0.jpg" );    cv::Mat imageAlpha = cv::imread( "C:\\Users\\Leo\\Desktop\\Test\\0-R.jpg" );     if ( imageGray.channels() == 3 )        cv::cvtColor( imageGray, imageGray, CV_RGB2GRAY );    if ( imageAlpha.channels() == 3 )        cv::cvtColor( imageAlpha, imageAlpha, CV_RGB2GRAY );    int cols = imageGray.cols;    int rows = imageGray.rows;    cv::Mat imageMerged(rows, cols, CV_8UC4, cv::Scalar::all(0));    uchar* data        = (uchar*) imageMerged.data;    uchar* data_gray   = (uchar*) imageGray.data;    uchar* data_alpha  = (uchar*) imageAlpha.data;    for ( int i=0; i<rows; i++ )    {        for ( int j=0; j<cols; j++ )        {            int index = i*cols + j;            data[index*4]   = data_gray[index];            data[index*4+1] = data_gray[index];            data[index*4+2] = data_gray[index];            data[index*4+3] = data_alpha[index];        }    }    uint32 width, height;    width  = cols;    height = rows;    /* save as PNG */    std::vector<int> compression_params;    compression_params.push_back(CV_IMWRITE_PNG_COMPRESSION);    compression_params.push_back(9);    cv::imwrite( "C:\\Users\\Leo\\Desktop\\Test\\0-1.png", imageMerged, compression_params );    /* save as TIFF */    TIFF *imageWrite =  TIFFOpen( "C:\\Users\\Leo\\Desktop\\Test\\0-2.tif", "w" );    if ( imageWrite )    {        TIFFSetField( imageWrite, TIFFTAG_IMAGEWIDTH, width );        TIFFSetField( imageWrite, TIFFTAG_IMAGELENGTH, height );        TIFFSetField( imageWrite, TIFFTAG_COMPRESSION, COMPRESSION_PACKBITS);        TIFFSetField( imageWrite, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);        TIFFSetField( imageWrite, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);        TIFFSetField( imageWrite, TIFFTAG_BITSPERSAMPLE, 8);        TIFFSetField( imageWrite, TIFFTAG_SAMPLESPERPIXEL, 4);        uchar *bits = (uchar*) imageMerged.data;//        uchar* pdst = new uchar[cols*4];        for ( int i=0; i<rows; i++ )        { //             int curidx_bit = i * cols * 4;//             for ( int idx = 0; idx < cols; idx ++ )//             {//                 int curidx_dst  = idx * 4;//                 int curidx_bit2 = curidx_bit + curidx_dst;// //                 pdst[curidx_dst]   = bits[curidx_bit2];//                 pdst[curidx_dst+1] = bits[curidx_bit2+1];//                 pdst[curidx_dst+2] = bits[curidx_bit2+2];//                 pdst[curidx_dst+3] = bits[curidx_bit2+3];//             }            TIFFWriteScanline( imageWrite, &bits[i*cols*4], i, 0 );//            TIFFWriteScanline( imageWrite, pdst, i, 0 );        }        TIFFClose( imageWrite );    }    else    {        std::cout << "Open file error!" << std::endl;        exit(1);    }}

这段代码读取了两张图像,一张为灰度图,另一张为对应的Alpha通道图像,然后将其转换为RGBA图像。代码里给出了TIFFWriteScanlineTIFF的两种方法,其中注释掉的部分即为另一种方法。

6 三种图像I/O读写方法

libTIFF中提供了三种文件读写方式:

  • Scanline-based
  • Strip-oriented
  • Tile-oriented

此处不做过的介绍,详情请阅读 Using The TIFF Library~

Opencv中也有对TIFF文件的操作,也是基于libTIFF库,详情参考文件:grfmt_tiff.cpp


PS:

  • LibTIFF (libtiff.org)
  • LibTIFF (remotesensing.org)
  • TIFF Documentation
1 0
原创粉丝点击