• LIBTIFF 图像读取与保存


    1 头文件

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

    #include "tiffio.h"

    2 文件读写

     1 /* read from an existing TIFF image */
     2 void main()
     3 {
     4     TIFF* tif = TIFFOpen("foo.tif", "r");
     5     ... do stuff ...
     6     TIFFClose(tif);  // or TIFFFlush(tif);
     7 }
     8 
     9 /* create or overwrite a TIFF image */
    10 void main()
    11 {
    12     TIFF* tif = TIFFOpen("foo.tif", "w");
    13     ... do stuff ...
    14     TIFFClose(tif);  // or TIFFFlush(tif);
    15 }

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

    3 多目录文件读写

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

     1 #include "tiffio.h"
     2 int main(int argc, char* argv[])
     3 {
     4     TIFF* tif = TIFFOpen(argv[1], "r");
     5     if (tif) 
     6     {
     7         int dircount = 0;
     8         do {
     9             dircount++;
    10         } while (TIFFReadDirectory(tif));
    11 
    12         printf("%d directories in %s
    ", dircount, argv[1]);
    13         TIFFClose(tif);
    14     }
    15     return 0;
    16 }
    17 
    18 // write: TIFFWriteDirectory()

    4 标签读取与设置

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

     1 /* read the tags */
     2 uint32 width, height;
     3 uint16 ncn;
     4 
     5 TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &width);    // image width in pixels
     6 TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height);  // image height in pixels
     7 TIFFGetField(tif, TIFFTAG_SAMPLESPERPIXEL, &ncn); // samples per pixel -> channels
     8 
     9 cout << width << " " << height << " " << ncn << endl; 
    10 
    11 /* set the tags */ 
    12 TIFFSetField( imageWrite, TIFFTAG_IMAGEWIDTH, width );
    13 TIFFSetField( imageWrite, TIFFTAG_IMAGELENGTH, height );
    14 TIFFSetField( imageWrite, TIFFTAG_BITSPERSAMPLE, 8);    // 8 bits per channel
    15 TIFFSetField( imageWrite, TIFFTAG_SAMPLESPERPIXEL, 4);  // 4 channels

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

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

    5 RGBA 图像读取与存储

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

     1 #include "tiffio.h"
     2 
     3 // first method: TIFFReadRGBAImage
     4 int main(int argc, char* argv[])
     5 {
     6     TIFF* tif = TIFFOpen(argv[1], "r");
     7     if (tif) {
     8     uint32 w, h;
     9     size_t npixels;
    10     uint32* raster;
    11 
    12     TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &w);
    13     TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &h);
    14     npixels = w * h;
    15     raster = (uint32*) _TIFFmalloc(npixels * sizeof (uint32));
    16     if (raster != NULL) {
    17         if (TIFFReadRGBAImage(tif, w, h, raster, 0)) {
    18         ...process raster data...
    19         }
    20         _TIFFfree(raster);
    21     }
    22     TIFFClose(tif);
    23     }
    24     return 0;
    25 }
    26 
    27 // second method: TIFFRGBAImageBegin & TIFFRGBAImageGet
    28 int main(int argc, char* argv[])
    29 {
    30     TIFF* tif = TIFFOpen(argv[1], "r");
    31     if (tif) {
    32     TIFFRGBAImage img;
    33     char emsg[1024];
    34 
    35     if (TIFFRGBAImageBegin(&img, tif, 0, emsg)) {
    36         size_t npixels;
    37         uint32* raster;
    38 
    39         npixels = img.width * img.height;
    40         raster = (uint32*) _TIFFmalloc(npixels * sizeof (uint32));
    41         if (raster != NULL) {
    42         if (TIFFRGBAImageGet(&img, raster, img.width, img.height)) {
    43             ...process raster data...
    44         }
    45         _TIFFfree(raster);
    46         }
    47         TIFFRGBAImageEnd(&img);
    48     } else
    49         TIFFError(argv[1], emsg);
    50     TIFFClose(tif);
    51     }
    52     return 0;
    53 }

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

     1 // image channel read order : A B G R
     2 if ( TIFFReadRGBAImage(tif, width, height, raster, 0) )
     3 {
     4     BYTE *imageR = new BYTE[nPixels];
     5     // image pixels are in an inverted order, which is same as bmp format
     6     uint32* rowPoint2Src = raster + (height-1)*width;
     7     BYTE *rowPointerToR  = imageR;
     8 
     9     for ( int rows = height-1; rows >= 0; --rows )
    10     {
    11         uint32 *colPoint2Src = rowPoint2Src;
    12         BYTE* colPoint2R = rowPointerToR;
    13         for ( int cols = 0; cols < width; cols ++ )
    14         {
    15             // read the channel : A
    16             *colPoint2R = (BYTE)TIFFGetA(*colPoint2Src);
    17             // or : colPoint2R[0] = (BYTE)TIFFGetA(colPoint2Src[0]);
    18             colPoint2R++;
    19             colPoint2Src++;
    20         }
    21         rowPoint2Src  -= width;
    22         rowPointerToR += width;
    23     } 
    24     cv::Mat imageR_mat( height, width, CV_8UC1, imageR, width );
    25     imwrite("E:\0-Alpha.jpg", imageR_mat);
    26 
    27     _TIFFfree(imageR);
    28 }

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

     1 /* save as a Mat */
     2 
     3 cv::Mat image(height, width, CV_8UC4, cv::Scalar::all(0));
     4 if ( TIFFReadRGBAImage(tif, width, height, raster, 0) )
     5 {
     6     uchar* imageData = (uchar*)image.data;
     7     uint32* rowPoint2Src = raster + (height-1)*width;
     8 
     9     for ( int rows = height-1; rows >= 0; --rows )
    10     {
    11         uint32 *colPoint2Src = rowPoint2Src;
    12         // image pixels are in an inverted order, which is same as bmp format
    13         uchar* colPoint = image.ptr<uchar>( height - rows - 1 );
    14         for ( int cols = 0; cols < width; cols ++ )
    15         {
    16             *colPoint++ = (uchar)TIFFGetB(*colPoint2Src); // B
    17             *colPoint++ = (uchar)TIFFGetG(*colPoint2Src); // G
    18             *colPoint++ = (uchar)TIFFGetR(*colPoint2Src); // R
    19             *colPoint++ = (uchar)TIFFGetA(*colPoint2Src); // A
    20 
    21             colPoint2Src++;
    22         }
    23         rowPoint2Src  -= width;
    24     } 
    25 }

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

     1 /* creat and write a ABGR tiff image */
     2 #include <iostream>
     3 #include <vector>
     4 
     5 #include "cv.h"
     6 #include "highgui.h"
     7 
     8 #include "tiffio.h"
     9 
    10 using namespace std;
    11 using namespace cv;
    12 
    13 void main()
    14 {
    15     cv::Mat imageGray  = cv::imread( "C:\Users\Leo\Desktop\Test\0.jpg" );
    16     cv::Mat imageAlpha = cv::imread( "C:\Users\Leo\Desktop\Test\0-R.jpg" ); 
    17 
    18     if ( imageGray.channels() == 3 )
    19         cv::cvtColor( imageGray, imageGray, CV_RGB2GRAY );
    20     if ( imageAlpha.channels() == 3 )
    21         cv::cvtColor( imageAlpha, imageAlpha, CV_RGB2GRAY );
    22 
    23     int cols = imageGray.cols;
    24     int rows = imageGray.rows;
    25 
    26     cv::Mat imageMerged(rows, cols, CV_8UC4, cv::Scalar::all(0));
    27 
    28     uchar* data        = (uchar*) imageMerged.data;
    29     uchar* data_gray   = (uchar*) imageGray.data;
    30     uchar* data_alpha  = (uchar*) imageAlpha.data;
    31 
    32     for ( int i=0; i<rows; i++ )
    33     {
    34         for ( int j=0; j<cols; j++ )
    35         {
    36             int index = i*cols + j;
    37             data[index*4]   = data_gray[index];
    38             data[index*4+1] = data_gray[index];
    39             data[index*4+2] = data_gray[index];
    40             data[index*4+3] = data_alpha[index];
    41         }
    42     }
    43 
    44     uint32 width, height;
    45     width  = cols;
    46     height = rows;
    47 
    48     /* save as PNG */
    49     std::vector<int> compression_params;
    50     compression_params.push_back(CV_IMWRITE_PNG_COMPRESSION);
    51     compression_params.push_back(9);
    52     cv::imwrite( "C:\Users\Leo\Desktop\Test\0-1.png", imageMerged, compression_params );
    53 
    54     /* save as TIFF */
    55     TIFF *imageWrite =  TIFFOpen( "C:\Users\Leo\Desktop\Test\0-2.tif", "w" );
    56     if ( imageWrite )
    57     {
    58         TIFFSetField( imageWrite, TIFFTAG_IMAGEWIDTH, width );
    59         TIFFSetField( imageWrite, TIFFTAG_IMAGELENGTH, height );
    60         TIFFSetField( imageWrite, TIFFTAG_COMPRESSION, COMPRESSION_PACKBITS);
    61         TIFFSetField( imageWrite, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
    62         TIFFSetField( imageWrite, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
    63         TIFFSetField( imageWrite, TIFFTAG_BITSPERSAMPLE, 8);
    64         TIFFSetField( imageWrite, TIFFTAG_SAMPLESPERPIXEL, 4);
    65 
    66         uchar *bits = (uchar*) imageMerged.data;
    67 //        uchar* pdst = new uchar[cols*4];
    68 
    69         for ( int i=0; i<rows; i++ )
    70         { 
    71 //             int curidx_bit = i * cols * 4;
    72 //             for ( int idx = 0; idx < cols; idx ++ )
    73 //             {
    74 //                 int curidx_dst  = idx * 4;
    75 //                 int curidx_bit2 = curidx_bit + curidx_dst;
    76 // 
    77 //                 pdst[curidx_dst]   = bits[curidx_bit2];
    78 //                 pdst[curidx_dst+1] = bits[curidx_bit2+1];
    79 //                 pdst[curidx_dst+2] = bits[curidx_bit2+2];
    80 //                 pdst[curidx_dst+3] = bits[curidx_bit2+3];
    81 //             }
    82             TIFFWriteScanline( imageWrite, &bits[i*cols*4], i, 0 );
    83 //            TIFFWriteScanline( imageWrite, pdst, i, 0 );
    84         }
    85         TIFFClose( imageWrite );
    86     }
    87     else
    88     {
    89         std::cout << "Open file error!" << std::endl;
    90         exit(1);
    91     }
    92 }

    这段代码读取了两张图像,一张为灰度图,另一张为对应的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

     

  • 相关阅读:
    jQuery基础之让出$,与其他库共存
    什么是闭包
    绑定repeater时三目运算加特殊结果处理
    将同一张表出来的两部分内容再合成一张表
    后台往前台写弹窗代码不显示
    固定行列转换加分段统计
    js调用后台方法(如果你能容忍执行的后台方法变成一个常量)
    javascript遍历数组
    基于SpringMVC框架使用ECharts3.0实现折线图,柱状图,饼状图,的绘制(上篇)
    echarts
  • 原文地址:https://www.cnblogs.com/ybqjymy/p/13673725.html
Copyright © 2020-2023  润新知