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
中提供了获取和设置标签值的函数:TIFFGetField
和TIFFSetField
:
/* 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
图像。代码里给出了TIFFWriteScanline
写TIFF
的两种方法,其中注释掉的部分即为另一种方法。
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
- libTIFF 图像读取与保存
- 使用libtiff读取tif/tiff图像
- HighGUI读取与保存图像
- BMP图像的读取与保存
- Opencv 图像读取与保存问题
- 图像的读取,显示与保存
- 【python图像处理】图像的读取、显示与保存
- 读取、修改、保存图像
- Python+OpenCV学习(1)---图像的读取与保存
- 读取、修改、保存图像---opencv
- OpenCV读取、复制、保存图像
- OpenCV 读取、修改、保存图像
- opencv读取、显示、保存图像
- OpenCV2 图像读取、显示、保存
- Opencv-Python:图像尺寸、图像的读取、显示、保存与复制
- 图像显示与保存
- XML读取与保存
- RichEdit保存与读取
- (java)Remove Duplicates from Sorted List
- 使用jQuery的validation插件来完成表单的验证
- 有人爱、有事做、有所期待(老俞)
- ALM
- 基础树状数组
- libTIFF 图像读取与保存
- 我的个人博客
- 第127讲:Hadoop集群管理之安全模式解析及动手实战学习笔记
- Linux安装MySQL的两种方法
- 如何理解协议-网络编程
- JavaScript学习随记——Function
- Java集合框架之小结
- mobile Web 星星打分 实践
- LeetCode:Majority Element