zoukankan      html  css  js  c++  java
  • TIFF文件C语言读取(嵌入式平台摆脱Opencv束缚)

    一、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 <stdio.h>
    #include <stdlib.h>
    #include <stdfix.h>
    #include <string.h>
    #include <math.h>
    #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
    ",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;i<1000;i++){
            for(j=0;j<1000;j++){
                for(k=0;k<3;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
    ",sizeof(long),sizeof(int),sizeof(char),sizeof(short)); // 4-4-1-2
        printf("Finished!
    ");
        while(1);
        return 0;
    }
    View Code

    tiff.c

      1 #include "tiff.h"
      2 #include <stdlib.h>
      3 #include <string.h>
      4 #include <math.h>
      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
    ",_IFH.endian,_IFH.magic);
     48     printf("IFD_Start Offset:%d
    ",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
    ",DE_n);
     56     _IFD.p = (DE *)malloc(sizeof(DE)*DE_n);
     57     for(i=0;i<DE_n;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]
    ",(_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]
    ",(_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
    ",(_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]
    ",(_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]
    ",(_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]
    ",(_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]
    ",(_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]
    ",(_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]
    ",(_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]
    ",(_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]
    ",(_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]
    ",(_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]
    ",(_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]
    ",(_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
    ",Image_Start);
    152     fseek(fd,Image_Start,SEEK_SET);
    153     for(row=0;row<hei;row++){
    154         for(clo=0;clo<wid;clo++){
    155             for(dep=0;dep<3;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<DE_N;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;i++){
    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
    ",(_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;i<(_IFD.p+2)->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
    ",(_IFD.p+5)->val_offset,(_IFD.p+5)->size); // 3004152-1000
    222     for(i=0;i<(_IFD.p+5)->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
    ",StripOffset,block_size,(_IFD.p+5)->size,i);
    225         StripOffset += block_size;
    226     }
    227 
    228     printf("%d-%d
    ",(_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;i<(_IFD.p+9)->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<h;i++){
    235         for(j=0;j<w;j++){
    236             for(k=0;k<channel;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 <stdio.h>
     4 
     5 #define MC_GET_CHAR(__data__) __data__
     6 #define MC_GET_SHORT(__data__) ((__data__ & 0xFF) << 8) | (__data__ >> 8)
     7 #define MC_GET_LONG(__data__) ((__data__ & 0xFF) << 24) | ((__data__ & 0xFF00) << 8) | ((__data__ & 0xFF0000) >> 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:UsersAdministratorDesktopmamiaoAlg_Cppimage
     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:UsersAdministratorDesktopImgB.');
    2 imwrite(I,'C:UsersAdministratorDesktopCImgB.tiff','Compression','none');

     Reference:

    下载已经整理好的资源:TIFF白皮书&Code&Software 

    TIFF图像文件格式详解:https://www.cnblogs.com/WangGuiHandsome/p/10024243.html

  • 相关阅读:
    django关闭调试信息,打开内置错误视图
    django 配置URLconf和获取值
    django模版中配置和使用静态文件方法
    django的模型类管理器-----------数据库操作的封装
    美团校招的算法题:灯泡游戏
    ccTouchBegan
    特效effects(二)
    特效effects
    CCProgressTo和CCProgressTimer
    TransitionsTest
  • 原文地址:https://www.cnblogs.com/uestc-mm/p/12504851.html
Copyright © 2011-2022 走看看