C语言中阅读tiff图像或RGB-raw图像中的浮点数

jjjwad0x  于 2023-03-22  发布在  其他
关注(0)|答案(1)|浏览(184)

我正在尝试访问用Rawtherapee生成的tiff文件中的32位浮点数。GIMP可以打开tiff,它看起来很好。
我从ExifTool和tiffdump得到了tif头大小,它们都匹配13,022字节。它们还同意4916宽7370高的宽度和高度以及434,771,040的位图大小。

I wrote a small C program to test reading and decoding the pixel at (0,0):
- Open the file in binary mode
- Seek past the 13022 byte header
- Read the first pixel of 3 floats, 12 bytes into memory
- printf the results with a "%f" format

在RawTherapee中,(0,0)处的像素具有RGB值(22.7%,31.0%和0%)。浮点数应在[0.0.. 1.0]范围内。
解码的浮点数看起来像随机数。所以我用ImageMagick将.tif转换为原始的RGB位图,做了同样的过程,除了寻找0,因为没有标题。结果看起来又是随机的,不匹配tiff像素。
“您的文章似乎包含格式不正确的代码。请使用代码工具栏按钮或CTRL+K键盘快捷键将所有代码缩进4个空格。有关更多编辑帮助,请单击[?]工具栏图标。”这不是代码。
我用ImageMagick将RGB文件转换为JPG,JPG很好,所以RGB文件也一定很好。
浮点tif似乎只有1个条带,并且“StripByteCounts”是标量,而不是数组。StripByteCounts与预期的RGB大小$xres * $yres * 12字节/像素匹配。
RGB文件大小与TIFF StripByteCounts完全匹配:lsr -s pf-274887.edge.f32.tif.rgb -〉434771040 mult 4916 7370 12 434771040
我写了一个小的C程序来尝试访问位图(见下面的代码)。我得到了混乱的数据和tiff和RGB之间的不匹配:

----------
Running:
float.pixel.test
pf-274887.edge.f32.tif: Seek -> 13022, Read 3:  
float:  B -0.000000, G -0.000003, R 0.000000 ->  
UINT32: B 2634654270, G 3059326270, R  457414589

pf-274887.edge.f32.tif.rgb: Seek -> 0, Read 3:  
float:  B 35650027520.000000, G 1450022528.000000, R 0.000000 ->  
UINT32: B 1359269508, G 1319951149, R          0

----
IMAGEMAGICK CONVERSION: ------
convert pf-274887.edge.f32.tif -depth 32 RGB:pf-274887.edge.f32.tif.rgb
convert  -size 4916x7370 -depth 32  RGB:pf-274887.edge.f32.tif.rgb pf-        274887.edge.f32.jpg
The .JPG looks perfect. 

SIZE CHECK: ------
lsr -s pf-274887.edge.f32.tif.rgb  ->  434771040
mult 4916 7370 12                      434771040

EXIFTOOL DATA:  ------
exiftool -s -all pf-274887.edge.f32.tif | \
sort | egrep "^ImageSize|^Strip|SampleFormat"
ImageSize                       : 4916x7370
SampleFormat                    : Float; Float; Float
StripByteCounts                 : 434771040
StripOffsets                    : 13022  << Scalar,not array

TIFFDUMP DATA:  ------
tiffdump pf-274887.edge.f32.tif | \
    egrep "BitsPerSample|ImageLength|ImageWidth|^Strip"
ImageWidth (256) SHORT (3) 1<4916>
ImageLength (257) SHORT (3) 1<7370>
BitsPerSample (258) SHORT (3) 3<32 32 32>
StripOffsets (273) LONG (4) 1<13022>
StripByteCounts (279) LONG (4) 1<434771040>

=========================================================
float.pixel.test  c program:

我期望在没有任何TIFF并发症的情况下阅读RGB文件应该会给予合理的结果。这些值必须以IEEE 754浮点格式存储,与数据存储在内存中的方式相同。
我们的目的是学习如何获取值,而不仅仅是在这种情况下获取值。从RGB获取值将是向前迈出的一大步。
我试着阅读像素(0,0)和(3,3),得到了类似的结果;浮点数不在[0.0.. 1.0]范围内,原始RGB值与tiff值不匹配。
我将tif转换为RGB,然后将RGB转换为JPG,JPG看起来很完美,所以RGB也必须完好无损。
我在所有的seek和fread上使用了size_t。我检查了fread读取的浮点数与请求的数字的错误。我检查了NAN mangling的浮点数。所有的浮点数都是数字,只是不在正确的范围内。
我还期望tiff像素与相应的RGB像素完全匹配,但没有相似之处。我简化了测试程序,不做任何额外的工作。
下面的答案之一是使用“libtiff”,Libtiff对RGB文件阅读问题没有帮助,我不想去Whole Foods买一磅鲑鱼,我想自己抓。
下面是C代码程序,前面有4个空格:

// =============================================================================
// Read and decode a specific pixel in a float32 tiff
/*
 gcc -g -O0 -m64  bln/float.pixel.test.c -lm -lz                                  -o bln/float.pixel.test
 
*/

#include "stdio.h"
#include "stdlib.h"
#include "stdint.h"
#include <math.h>

int osrp(char *ifn, size_t soff, size_t numf);  // Open, Seek, Read, Print

// =============================================================================
void main(int argc, char *argv[])  {
char tfn[]={ "pf-274887.edge.f32.tif" };      // From RawTherapee
char rfn[]={ "pf-274887.edge.f32.tif.rgb" };  // From ImageMagick
size_t toff=13022ll, roff=0, pixoff=0; // Tif and raw-RGB header Offsets 
int imgx=3, imgy=3, imgw=4916, pix_bytes=12;
    pixoff = (imgy * imgw + imgx) * pix_bytes;  // Byte offet to pixel (3,3)
    pixoff = 0ll;  // Try pixel (0, 0)
    osrp(tfn, toff+pixoff, 3);  // Open, seek, read, print
    osrp(rfn, roff+pixoff, 3);  // FileName, seek_OFFset, #_floats per pixel
    exit(0);                    // 
}  // End Main(). 
// =============================================================================

// =============================================================================
// Open, seek, read, print. Expect floats in (0.0 .. 1.0) range
// Check for errors in number of floats read and NAN on their values
int osrp(char *ifn, size_t soff, size_t numf)  {
union  {  // Overlay floats and 32 bit unsigned ints
    float    fpix[4];  // Holds 1 pixel
    uint32_t ipix[4];  // UI32 and float share same bits    
} fiu;             // Float-Int-Union
FILE *ifp;         // Image_File_Pointer
int ii, numnan=0;  // Number of NANs, Not_A_Numbers
size_t numr;       // uint64_t

    ifp = fopen(ifn, "rb");      // Read Image in Binary mode
    fseek(ifp, soff, SEEK_SET);  // Seek to start of bitmap data
                                 
    // Read numf * 4 bytes from bitmap, store in uint/float union
    numr = fread((void *)fiu.fpix, sizeof(float), numf, ifp);  // 3*4=12B  
    fclose(ifp); 
    if(numr != numf)  {  
        printf("ERROR! NumR %llu != NumF %llu\n", numr, numf);  }

    printf("%s: Seek -> %lld, Read %llu: \nfloat:  B %8.6f, G %8.6f, R %8.6f -> \nUINT32: B %10u, G %10u, R %10u\n",
        ifn, soff, numf, 
        fiu.fpix[0], fiu.fpix[1], fiu.fpix[2],
        fiu.ipix[0], fiu.ipix[1], fiu.ipix[2]);

    for(ii=0; ii < numf; ii++)  {  // Check for Non-Number floats
        if(isnan(fiu.fpix[ii]))  {  numnan++;  }  // Count NANs
    }
    if(numnan == 0)  {  printf("\n");  return(0);  }
    printf("%d floats, %d are NANs!\n\n", numf, numnan);
    return(numnan);
}
bbmckpt7

bbmckpt71#

我不会直接阅读TIFF文件。它是一种复杂的格式,更糟糕的是,非常灵活。TIFF使写作变得容易(您可以将几乎任何数据布局写入TIFF文件),但阅读困难(数据可以以几乎任何方式呈现,您的读者必须潜在地处理所有许多,许多,许多组合)。
没有人(我认为)曾经写过一个TIFF阅读器,可以加载所有可能的TIFF。甚至libtiff本身也会在许多明显的变化中失败。你可能会让它在这个特定的文件中工作,但它会在(可能)任何其他程序编写的float tiff中失败,如果rawtherapee修改他们的tiff编写器,即使是轻微的修改,它也可能会失败。
我会使用libtiff,或者更好,使用一个高级库,可以为您隐藏大部分的丑陋。
例如,libvips支持浮点像素,可以读取和写入浮点TIFF。它将读取所有基准级TIFF和大多数常用的变体。

$ vips colourspace k2.jpg x.tif scrgb
$ tiffinfo x.tif
=== TIFF directory 0 ===
TIFF Directory at offset 0x21fc008 (35635208)
  Image Width: 1450 Image Length: 2048
  Resolution: 72.009, 72.009 pixels/inch
  Bits/Sample: 32
  Sample Format: IEEE floating point
  Compression Scheme: None
  Photometric Interpretation: RGB color
  Orientation: row 0 top, col 0 lhs
  Samples/Pixel: 3
  Rows/Strip: 128
  Planar Configuration: single image plane

这是将常规的8位JPEG转换为scRGB色彩空间,其中像素为线性0 - 1,并保存为TIFF。您可以从tiffinfo输出中看到,它是一个简单的浮点TIFF,可能与您的文件类似。
你可以读出像素,例如:

$ vips getpoint x.tif 10 10
0.00303527 0 0.000303527

检查其价值。
你可以将图像读入大型的C数组,比如:

/* Compile with:
 *
 *      gcc -g -Wall getpoint.c `pkg-config vips --cflags --libs`
 */

#include <vips/vips.h>

int
main( int argc, char **argv )
{
        VipsImage *image;
        int x; 
        int y; 
        float *array;
        size_t size_in_bytes;
        int i;

        if( VIPS_INIT( argv[0] ) )
                vips_error_exit( NULL );

        if( argc != 4 )
                vips_error_exit( "usage:\n\t%s image x y", argv[0] );

        if( !(image = vips_image_new_from_file( argv[1],  
                "access", VIPS_ACCESS_SEQUENTIAL,
                NULL )) )      
                vips_error_exit( NULL );
        if( image->BandFmt != VIPS_FORMAT_FLOAT )
                vips_error_exit( "not a float image" );
        
        x = atoi( argv[2] );
        y = atoi( argv[3] );
        
        if( !(array = vips_image_write_to_memory( image, &size_in_bytes )) )
                vips_error_exit( NULL );
        
        printf( "pixel %d, %d:\n", x, y );
        for( i = 0; i < image->Bands; i++ ) 
                printf( "%d) %g\n", 
                        i,
                        array[image->Bands * (x + y * image->Xsize) + i]);
        
        free( array );
        g_object_unref( image );

        return( 0 );
}

我看到:

$ ./a.out x.tif 10 10
pixel 10, 10:
0) 0.00303527
1) 0
2) 0.000303527

相关问题