标签:读取数据 ted nal 提取 添加 free off nta 连续
一、TIFF文件结构:
如下图所示为TIFF图像文件基本结构:
文件结构主要分为三个小的描述结构Header+IFD+DE,下面就三个方面对文件基本组成进行讨论。
1.文件头基本组成
第1,2两个字节确定了文件数据的存储格式为大端存储或者小端存储,分为以下两种情况:
- 第一字节和第二字节的内容组成是0x4949则为Little-endian模式。
- 第一字节和第二字节的内容组成是0x4D4D则为Big-endian模式。
第2,3字节存储了TIFF的Magic Number,所有的TIFF文件都是42。
第4~7四个字节用来存储第一个IFD结构的起始位置(所有文件相关参数都要从这里开始查询)。
2.IFD结构的基本组成
第一个IFD的开头保存了当前IFD保存的DE的数量,在图中为B个,每个DE的大小是12Bytes。
如果文件的参数非常多时,就需要使用类似链表的方式扩充IFD结构,在IFD结构的末尾添加下一个IFD结构的Offset。
对于一般的真彩色图像而言,一般包括的DE的数量为:11个,这11个IFD文件结构中主要包括了图像的尺寸,图像色彩深度,图像方向等信息。
实际上IFD的功能是作为DE结构体入口的数据结构,提供了进入DE结构的门,真正的图像参数数据保存在DE结构体当中。
3.DE结构基本组成
DE结构当中是真正存储图像文件相关参数的主体,结构中的每一部分代表的内容如下:
-
Tag:用来表示不同的数据域,例:图像宽度(101.H)、图像高度(100.H)、图像色彩类型(106.H),要获取DE中的内容,首先要检查当前DE中Tag代表的数据类型,然后依次读取数据即可。
-
Types:用来确定当前DE域当中保存数据的格式,1=BYTE、2=ASCII、3=SHORT、4=LONG、5=RATIONAL,通过确定不同的数据格式,在读取后续数据的过程中就可以准确地将数据保存下来。
-
Count:用来记录当前DE的图像参数信息有多少个Types类型的数据保存,在读取文件的过程中读取即可。
-
Value:用来保存小于4Bytes的参数数据(当Count*Sizeof(Types)>4Bytes,就需要将Value当做Offset处理,从而跳转到新的起始地址,完成参数的读取)。
DE是用来保存整个图像文件参数的地方,通过从Header到IFD入口,再到每一个DE结构的入口,最后将整个图像参数提取出来,最后根据参数获取图像Data数据。
如下所示为使用AsTiffTagViewer.exe读取某一图像的结果:
二、相关TIFF文件读写代码实现:
TIFF文件C语言读取(github地址)
有志同道合的朋友可以一起迭代一下这个TIFF的库,可以私聊我!一起进步!
Header结构体展示:
IFD结构体展示:
DE结构体展示:
main.c
#include
#include
#include
#include string.h>
#include
#include "tiff.h"
#include "image_alg.h"
int main(void)
{
unsigned char *PATH = "C:/Users/Administrator/Desktop/mamiao/Alg_Cpp/image/A.tiff";
unsigned char *PATH_1 = "C:/Users/Administrator/Desktop/mamiao/Alg_Cpp/image/A1.bin";
unsigned char *PATH_2 = "C:/Users/Administrator/Desktop/mamiao/Alg_Cpp/image/A1.tiff";
unsigned char *Img=(unsigned char *)malloc(sizeof(unsigned char)*3000000);
// printf("%d\n",mashine_endian());
Tiff_read(Img,PATH);
FILE *fd;
int i,j,k;
fd = fopen(PATH_1,"wb+");
fseek(fd,0,SEEK_SET); // Insert the image data
for(i=0;i1000;i++){
for(j=0;j1000;j++){
for(k=0;k3;k++){
fwrite(Img+i*3000+j*3+k,sizeof(unsigned char),1,fd);
}
}
}
Tiff_write(Img,1000,1000,3,PATH_2);
// printf("%d-%d-%d-%d\n",sizeof(long),sizeof(int),sizeof(char),sizeof(short)); // 4-4-1-2
printf("Finished!\n");
while(1);
return 0;
}
View Code
tiff.c
1 #include "tiff.h"
2 #include 3 #include string.h>
4 #include 5
6 char mashine_endian(void)
7 {
8 int a = 1;
9 int *p = &a;
10 if(*((char *)p) == a){
11 return 1; // little endian
12 }else{
13 return 0; // big endian
14 }
15 }
16
17 char Tiff_read(unsigned char *Image,unsigned char *Path)
18 {
19 FILE *fd;
20 unsigned char tmp[2],buff,dev_endian = mashine_endian(),file_endian,TypeSize,Image_Start_TypeSize;
21 unsigned int DE_n=0,i=0,DE_val_size=0,channel=0,wid,hei,sum,row,clo,dep;
22 unsigned long IFD_Start=0,Image_Start;
23 size_t count;
24 IFH _IFH;
25 IFD _IFD;
26
27 fd = fopen(Path,"rb");
28 count = fread(&(_IFH.endian),short_size,1,fd);
29 if(count != 1) { return -1;}
30 if(_IFH.endian == 0x4d4d){
31 file_endian = 0;
32 }else{
33 file_endian = 1;
34 }
35 count = fread(&(_IFH.magic),short_size,1,fd);
36 if(count != 1) { return -1;}
37 count = fread(&(_IFH.ifd_offset),ulong_size ,1,fd);
38 if(count != 1) { return -1;}
39 if(file_endian != dev_endian) {
40 _IFH.endian = MC_GET_SHORT(_IFH.endian);
41 _IFH.magic = MC_GET_SHORT(_IFH.magic);
42 _IFH.ifd_offset = MC_GET_LONG(_IFH.ifd_offset);
43 }
44
45 IFD_Start = _IFH.ifd_offset;
46
47 printf("Endian,Magic:%x-%x\n",_IFH.endian,_IFH.magic);
48 printf("IFD_Start Offset:%d\n",IFD_Start);
49
50 fseek(fd,IFD_Start,SEEK_SET);
51 count = fread(&(_IFD.n),short_size,1,fd);
52 if(count != 1) { return -1;}
53 if(file_endian != dev_endian) {_IFD.n = MC_GET_SHORT(_IFD.n);}
54 DE_n = _IFD.n;
55 printf("Number Of DE:%d\n",DE_n);
56 _IFD.p = (DE *)malloc(sizeof(DE)*DE_n);
57 for(i=0;i){
58 count = fread(&((_IFD.p+i)->tag),short_size,1,fd);
59 if(count != 1) { return -1;}
60 count = fread(&((_IFD.p+i)->type),short_size,1,fd);
61 if(count != 1) { return -1;}
62 count = fread(&((_IFD.p+i)->size),ulong_size ,1,fd);
63 if(count != 1) { return -1;}
64 count = fread((&(_IFD.p+i)->val_offset),ulong_size ,1,fd);
65 if(count != 1) { return -1;}
66 if(file_endian != dev_endian) {
67 // printf("Ori_Val[Tag-Type-Size]:[%x-%x-%x]\n",(_IFD.p+i)->tag,(_IFD.p+i)->type,(_IFD.p+i)->size);
68 (_IFD.p+i)->tag = MC_GET_SHORT((_IFD.p+i)->tag);
69 (_IFD.p+i)->type = MC_GET_SHORT((_IFD.p+i)->type);
70 (_IFD.p+i)->size = MC_GET_LONG((_IFD.p+i)->size);
71 // printf("Res_Val[Tag-Type-Size]:[%x-%x-%x]\n",(_IFD.p+i)->tag,(_IFD.p+i)->type,(_IFD.p+i)->size);
72 switch((_IFD.p+i)->type){
73 case 1: TypeSize = 1;
74 case 2: DE_val_size = (_IFD.p+i)->size; break;
75 case 3: TypeSize = 2; DE_val_size = (_IFD.p+i)->size * TypeSize; break;
76 case 4: TypeSize = 4; DE_val_size = (_IFD.p+i)->size * TypeSize; break;
77 case 5: TypeSize = 8; DE_val_size = (_IFD.p+i)->size * TypeSize; break;
78 default: TypeSize = 1; break;
79 }
80 if(DE_val_size == 1){
81 (_IFD.p+i)->val_offset = MC_GET_CHAR((_IFD.p+i)->val_offset);
82 }else if(DE_val_size == 2){
83 (_IFD.p+i)->val_offset = MC_GET_SHORT((_IFD.p+i)->val_offset);
84 }else if(DE_val_size >= 4){
85 (_IFD.p+i)->val_offset = MC_GET_LONG((_IFD.p+i)->val_offset);
86 }
87 }
88 // printf("Tag Value:%d\n",(_IFD.p+i)->tag);
89 if(256 == (_IFD.p+i)->tag){ // 图像宽度存储位置
90 wid = (_IFD.p+i)->val_offset;
91 printf("DE-Width of Img-[Tag:%d Type:%d Size:%d Offset:%d]\n",(_IFD.p+i)->tag,(_IFD.p+i)->type,(_IFD.p+i)->size,(_IFD.p+i)->val_offset);
92 continue;
93 }
94 if(257 == (_IFD.p+i)->tag){ // 图像高度存储位置
95 hei = (_IFD.p+i)->val_offset;
96 printf("DE-Height of Img-[Tag:%d Type:%d Size:%d Offset:%d]\n",(_IFD.p+i)->tag,(_IFD.p+i)->type,(_IFD.p+i)->size,(_IFD.p+i)->val_offset);
97 continue;
98 }
99 if(258 == (_IFD.p+i)->tag){ // 图像每个通道灰度等级 eg:RGB[8,8,8]
100 printf("DE-BitsPerSample of Img-[Tag:%d Type:%d Size:%d Offset:%d]\n",(_IFD.p+i)->tag,(_IFD.p+i)->type,(_IFD.p+i)->size,(_IFD.p+i)->val_offset);
101 continue;
102 }
103 if(259 == (_IFD.p+i)->tag){ // 图像采用的压缩算法 1-NoCompression 2-CCITT ...
104 printf("DE-Compression of Img-[Tag:%d Type:%d Size:%d Offset:%d]\n",(_IFD.p+i)->tag,(_IFD.p+i)->type,(_IFD.p+i)->size,(_IFD.p+i)->val_offset);
105 continue;
106 }
107 if(262 == (_IFD.p+i)->tag){ // 表示图像的种类: 0-WhiteisZero 1-BlackisZero 2-RGBImg 3-PaletteColor ...
108 if((_IFD.p+i)->val_offset == 2){
109 channel = 3;
110 }else{
111 channel = 1;
112 }
113 printf("DE-PhotometricInyerpretation of Img-[Tag:%d Type:%d Size:%d Offset:%d]\n",(_IFD.p+i)->tag,(_IFD.p+i)->type,(_IFD.p+i)->size,(_IFD.p+i)->val_offset);
114 continue;
115 }
116 if(273 == (_IFD.p+i)->tag){ // 图像数据起始地址存储位置相对于文件开始的位置val的保存位置
117 Image_Start = (_IFD.p+i)->val_offset;
118 Image_Start_TypeSize = TypeSize;
119 printf("DE-StripOffsets of Img-[Tag:%d Type:%d Size:%d Offset:%d]\n",(_IFD.p+i)->tag,(_IFD.p+i)->type,(_IFD.p+i)->size,(_IFD.p+i)->val_offset);
120 continue;
121 }
122 if(274 == (_IFD.p+i)->tag){ // 图像坐标系方式: 1[left top] 2[right top] 3[bottom right] ...
123 printf("DE-Orientation of Img-[Tag:%d Type:%d Size:%d Offset:%d]\n",(_IFD.p+i)->tag,(_IFD.p+i)->type,(_IFD.p+i)->size,(_IFD.p+i)->val_offset);
124 continue;
125 }
126 if(277 == (_IFD.p+i)->tag){ // 表示图像的格式为3[RGB]或1[bilevel,grayscale,palette-color] image
127 printf("DE-SamplePerPixel of Img-[Tag:%d Type:%d Size:%d Offset:%d]\n",(_IFD.p+i)->tag,(_IFD.p+i)->type,(_IFD.p+i)->size,(_IFD.p+i)->val_offset);
128 continue;
129 }
130 if(278 == (_IFD.p+i)->tag){ // 表示每一个Strip内包含的图像的行数 eg:Img[w][h][w] --> RowsPerStrip=1
131 printf("DE-RowsPerStrip of Img-[Tag:%d Type:%d Size:%d Offset:%d]\n",(_IFD.p+i)->tag,(_IFD.p+i)->type,(_IFD.p+i)->size,(_IFD.p+i)->val_offset);
132 continue;
133 }
134 if(279 == (_IFD.p+i)->tag){ // 表示每一个Strip的Bytes大小 eg:Img[w][h][d] --> StripByteCounts=w*d
135 printf("DE-StripByteCounts of Img-[Tag:%d Type:%d Size:%d Offset:%d]\n",(_IFD.p+i)->tag,(_IFD.p+i)->type,(_IFD.p+i)->size,(_IFD.p+i)->val_offset);
136 continue;
137 }
138 if(284 == (_IFD.p+i)->tag){ // 全彩图像每一个像素点排列方式: 1[RGB...RGB]-交叉 2[[R...R],[G...G],[B...B]]-平铺
139 printf("DE-PlanarConfiguration of Img-[Tag:%d Type:%d Size:%d Offset:%d]\n",(_IFD.p+i)->tag,(_IFD.p+i)->type,(_IFD.p+i)->size,(_IFD.p+i)->val_offset);
140 continue;
141 }
142 }
143
144 fseek(fd,Image_Start,SEEK_SET);
145 fread(&Image_Start,Image_Start_TypeSize,1,fd); // Image_Start:图像数据起始地址存储位置相对于文件开始的位置
146 if(Image_Start_TypeSize == 2){
147 Image_Start = MC_GET_SHORT(Image_Start);
148 }else if(Image_Start_TypeSize == 4){
149 Image_Start = MC_GET_LONG(Image_Start);
150 }
151 printf("The image data start address:%d\n",Image_Start);
152 fseek(fd,Image_Start,SEEK_SET);
153 for(row=0;row){
154 for(clo=0;clo){
155 for(dep=0;dep3;dep++){
156 count = fread(&buff,sizeof(unsigned char),1,fd);
157 if(count != 1) { return -1;}
158 *(Image + row*wid*channel + clo*channel + dep) = buff;
159 }
160 }
161 }
162 free(_IFD.p);
163 fclose(fd);
164 return 0;
165 }
166
167 char Tiff_write(unsigned char const *Image,unsigned int w,unsigned int h,unsigned char channel, unsigned char *Path)
168 {
169 IFH _IFH;
170 IFD _IFD;
171 FILE * fd;
172 fd = fopen(Path,"wb+");
173 unsigned long block_size = w*channel, sum = h*block_size;
174 unsigned long i,j,k;
175 // Offset=w*h*d + 8(eg:Img[1000][1000][3] --> 3000008)
176 // RGB Full Color:W H BitsPerSample Compression Photometric StripOffset Orientation SamplePerPixle RowsPerStrip StripByteCounts PlanarConfiguration
177 short DE_tag[DE_N]={256,257,258,259,262,273,274,277,278,279,284};
178 short DE_type[DE_N]={3, 3, 3, 3, 3, 4, 3, 3, 3, 4, 3};
179 unsigned long DE_size[DE_N]={1,1,3,1,1,h,1,1,1,h,1};
180 unsigned long DE_val_offset[DE_N]={w,h,sum+146,1,2,sum+4152,1,3,1,sum+152,1};
181 short RGB_Scale[3] = {8,8,8};
182 unsigned long StripOffset = 8;
183
184
185 _IFH.endian = 0x4949;
186 _IFH.magic = 42;
187 _IFH.ifd_offset = sum + 8;
188
189 _IFD.n = DE_N;
190 _IFD.p = (DE *)malloc(sizeof(DE)*_IFD.n);
191 _IFD.next_ifd_offset = 0;
192 for(i=0;i){
193 (_IFD.p+i)->tag = DE_tag[i];
194 (_IFD.p+i)->type = DE_type[i];
195 (_IFD.p+i)->size = DE_size[i];
196 (_IFD.p+i)->val_offset = DE_val_offset[i];
197 }
198
199 fseek(fd,0,SEEK_SET);
200 fwrite(&(_IFH.endian),short_size,1,fd);
201 fwrite(&(_IFH.magic),short_size,1,fd);
202 fwrite(&(_IFH.ifd_offset),ulong_size,1,fd);
203
204 fseek(fd,_IFH.ifd_offset,SEEK_SET);
205 fwrite(&(_IFD.n),short_size,1,fd);
206 for(i=0;i<_ifd.n>){
207 fwrite(&((_IFD.p+i)->tag),short_size,1,fd);
208 fwrite(&((_IFD.p+i)->type),short_size,1,fd);
209 fwrite(&((_IFD.p+i)->size),ulong_size,1,fd);
210 fwrite(&((_IFD.p+i)->val_offset),ulong_size,1,fd);
211 }
212 fwrite(&(_IFD.next_ifd_offset),ulong_size,1,fd);
213
214 printf("%d-%d\n",(_IFD.p+2)->val_offset,(_IFD.p+2)->size); // 3000146-3
215 fseek(fd,(_IFD.p+2)->val_offset,SEEK_SET); // Setup the RGB grayscale for RGB image[8,8,8]
216 for(i=0;i2)->size;i++){
217 fwrite(RGB_Scale+i,short_size,1,fd);
218 }
219
220 fseek(fd,(_IFD.p+5)->val_offset,SEEK_SET);
221 printf("%d-%d\n",(_IFD.p+5)->val_offset,(_IFD.p+5)->size); // 3004152-1000
222 for(i=0;i5)->size;i++){
223 fwrite(&StripOffset,ulong_size,1,fd); // For Small TIFF Need to change the data-type to short.
224 // printf("%d-%d-%d-%d\n",StripOffset,block_size,(_IFD.p+5)->size,i);
225 StripOffset += block_size;
226 }
227
228 printf("%d-%d\n",(_IFD.p+9)->val_offset,(_IFD.p+9)->size);
229 fseek(fd,(_IFD.p+9)->val_offset,SEEK_SET); // Insert the block_size for every StripOffset
230 for(i=0;i9)->size;i++){
231 fwrite(&block_size,ulong_size,1,fd);
232 }
233 fseek(fd,8,SEEK_SET); // Insert the image data
234 for(i=0;i){
235 for(j=0;j){
236 for(k=0;k){
237 fwrite(Image+i*block_size+j*channel+k,sizeof(unsigned char),1,fd);
238 }
239 }
240 }
241 }
View Code
tiff.h
1 #ifndef _TIFF_H_
2 #define _TIFF_H_
3 #include 4
5 #define MC_GET_CHAR(__data__) __data__
6 #define MC_GET_SHORT(__data__) ((__data__ & 0xFF) > 8)
7 #define MC_GET_LONG(__data__) ((__data__ & 0xFF) > 8) | ((__data__ & 0xFF000000) >> 24)
8
9 #define DE_N 11
10 #define short_size sizeof(short)
11 #define ulong_size sizeof(unsigned long)
12
13 typedef struct
14 {
15 short endian; // 字节顺序标志位,值为II或者MM:II表示小字节在前,又称为little-endian,MM表示大字节在前,又称为big-endian
16 short magic; // TIFF的标志位,一般都是42
17 unsigned long ifd_offset; // 第一个IFD的偏移量,可以在任意位置,但必须是在一个字的边界,也就是说必须是2的整数倍
18 }IFH;
19
20 typedef struct
21 {
22 short tag; // 此TAG的唯一标识
23 short type; // 数据类型
24 unsigned long size; // 数量,通过类型和数量可以确定存储此TAG的数据需要占据的字节数
25 unsigned long val_offset;
26 }DE;
27
28 typedef struct
29 {
30 short n; // 表示此IFD包含了多少个DE,假设数目为n
31 DE *p; // n个DE
32 unsigned long next_ifd_offset; // 下一个IFD的偏移量,如果没有则置为0
33 }IFD;
34
35 char mashine_endian(void);
36 char Tiff_read(unsigned char *Image,unsigned char *Path); // 以平铺platted方式来排布RGB数据,每一个像素点对应三个连续的数据(RGB)
37 char Tiff_write(unsigned char const *Image,unsigned int w,unsigned int h,unsigned char channel, unsigned char *Path);
38 #endif
View Code
三、JPEG/PNG到TIFF文件转换以及TIFF读写函数验证:
1.Matlab验证TIFF读取正确性
1 %%
2 % C:\Users\Administrator\Desktop\mamiao\Alg_Cpp\image
3 I = imread(‘C:/Users/Administrator/Desktop/mamiao/Alg_Cpp/image/A.tiff‘);
4 f = fopen(‘C:/Users/Administrator/Desktop/mamiao/Alg_Cpp/image/A1.bin‘,‘r‘);
5 [height, width, depth] = size(I);
6 for i = 1 : width
7 for j = 1 : height
8 for k = 1 : depth
9 tmp = fread(f,1);
10 if (I(i,j,k) - tmp) ~= 0
11 i,j,k
12 end
13 end
14 end
15 end
16 fclose(f);
2.Matlab转换图像格式:
1 I=imread(‘C:\Users\Administrator\Desktop\ImgB.‘);
2 imwrite(I,‘C:\Users\Administrator\Desktop\CImgB.tiff‘,‘Compression‘,‘none‘);
Reference:
下载已经整理好的资源:TIFF白皮书&Code&Software
TIFF图像文件格式详解:https://www.cnblogs.com/WangGuiHandsome/p/10024243.html
TIFF文件C语言读取(嵌入式平台摆脱Opencv束缚)
标签:读取数据 ted nal 提取 添加 free off nta 连续
原文地址:https://www.cnblogs.com/uestc-mm/p/12504851.html