LibTIFF 可以与 C++ 一起使用来获取图像的浮点值吗?

Can LibTIFF be used with C++ to get the float values of images?

我读到 here LibTIFF 可以显示浮点 TIFF。但是,我想加载图像,然后将浮点值作为数组获取。

这可以使用 LibTIFF 来实现吗?

Example TIFF

编辑:我正在使用 RHEL 6。

是的,但如果您使用 OpenCV 库,您将更容易处理这个问题。

如果您编译并安装了 OpenCV 库,那么按照您的要求执行操作就像使用 imread() 函数一样简单。这会将其保存到一个名为 cv::Mat(也称为矩阵)的对象中,该对象具有与 tiff 相同的维度和值。

从那里你可以用它做任何你想做的事。

可以用LibTIFF来做,我稍后可能会根据它添加一个答案,但为了便于安装和使用,我会看看CImg 这是一个 C++ header-only 库,非常强大,非常适合您的目的。因为它是 header-only,所以很容易包含(只需一个文件)并且不需要特殊的链接或构建。

以下是您读取 RGB 浮点数 TIFF 的方式:

#define cimg_display 0
#define cimg_use_tiff
#include "CImg.h"
#include <iostream>

using namespace cimg_library;
using namespace std;

int main(){

   // Read in an image
   CImg <float>img("image.tif");

   // Get its width and height and tell user
   int w=img.width();
   int h=img.height();
   cout << "Dimensions: " << w << "x" << h << endl;

   // Get pointer to buffer/array of floats
   float* buffer = img.data();

   cout << buffer[0] << "," << buffer[1] << "," << buffer[2] << endl; 
}

打印前三个红色像素,因为它们排列在平面中 - 即首先是所有红色像素,然后是所有绿色像素,然后是所有蓝色像素。

你会编译它:

g++-6 -std=c++11 read.cpp -I/usr/local/include -L/usr/local/lib -ltiff -o read

如果您愿意,可以像这样以稍微不同的方式访问像素:

#define cimg_display 0
#define cimg_use_tiff
#include "CImg.h"
#include <iostream>

using namespace cimg_library;
using namespace std;

int main(){

   // Read in an image
   CImg <float>img("image.tif");

   // Get its width and height and tell user
   int w=img.width();
   int h=img.height();
   cout << "Dimensions: " << w << "x" << h << endl;

   // Dump the pixels
   for(int y=0;y<h;y++)
      for(int x=0;x<w;x++)
          cout << x << "," << y << ": "
               << img(x,y,0,0) << "/" 
               << img(x,y,0,1) << "/" 
               << img(x,y,0,2) << endl;

}

示例输出

Dimensions: 512x256
0,0: 3.91318e-06/0.232721/128
1,0: 1.06577/0.342173/128
2,0: 2.3778/0.405881/128
3,0: 3.22933/0.137184/128
4,0: 4.26638/0.152943/128
5,0: 5.10948/0.00773837/128
6,0: 6.02352/0.058757/128
7,0: 7.33943/0.02835/128
8,0: 8.33965/0.478541/128
9,0: 9.46735/0.335981/128
10,0: 10.1918/0.340277/128
...
...

为了您的信息,我也用 CImg 制作了测试图像文件 - 基本上每个红色像素都设置为它的 x-coordinate 加上一个小于 0.5 的小随机浮点数。每个绿色像素设置为其 y-coordinate 加上一个小于 0.5 的小随机浮点数,每个蓝色像素设置为 mid-tone.

#define cimg_display 0
#define cimg_use_tiff
#define cimg_use_png
#include "CImg.h"
#include <cstdlib>

using namespace cimg_library;

int main(){
   const int w=512;
   const int h=256;
   const int channels=3;
   float* buffer = new float[w*h*channels];
   float* fp=buffer;
   for(int y=0;y<h;y++){
      for(int x=0;x<w;x++){
         *fp++=x+float(rand())/(2.0*RAND_MAX);    // red
      }
   }
   for(int y=0;y<h;y++){
      for(int x=0;x<w;x++){
         *fp++=y+float(rand())/(2.0*RAND_MAX);    // green
      }
   }
   for(int y=0;y<h;y++){
      for(int x=0;x<w;x++){
         *fp++=128;    // blue
      }
   }

   CImg <float>img(buffer,w,h,1,channels);
   img.save_tiff("result.tif");
}

如果您想使用纯 libTIFF,您的代码可能看起来像这样 - 请注意,我没有做太多错误检查以免混淆 [=代码的 31=] - 但你应该检查图像是否为 float 类型,你应该检查内存分配的结果,你可能不应该像我一样使用 malloc() 而是新的 C++ 方法内存分配 - 但概念很清楚,代码生成的答案与我的 CImg 版本相同...

#include "tiffio.h"
#include <cstdio>
#include <iostream>

using namespace std;

int main()
{

  TIFF* tiff = TIFFOpen("image.tif","r");
  if (!tiff) {
    cerr << "Failed to open image" << endl;
    exit(1);
  }

  uint32 width, height;
  tsize_t scanlength;

  // Read dimensions of image
  if (TIFFGetField(tiff,TIFFTAG_IMAGEWIDTH,&width) != 1) {
    cerr << "Failed to read width" << endl;
    exit(1);
  }
  if (TIFFGetField(tiff,TIFFTAG_IMAGELENGTH, &height) != 1) {
    cerr << "Failed to read height" << endl;
    exit(1);
  }

  scanlength = TIFFScanlineSize(tiff);

  // Make space for image in memory
  float** image= (float**)malloc(sizeof (float*)*height);

  cout << "Dimensions: " << width << "x" << height << endl;
  cout << "Line buffer length (bytes): " << scanlength << endl;

  // Read image data allocating space for each line as we get it
  for (uint32 y = 0; y < height; y++) {
    image[y]=(float*)malloc(scanlength);
    TIFFReadScanline(tiff,image[y],y);
    cout << "Line(" << y << "): " << image[y][0] << "," << image[y][1] << "," << image[y][2] << endl;
  }
  TIFFClose(tiff);

}

示例输出

Dimensions: 512x256
Line buffer length (bytes): 6144
Line(0): 3.91318e-06,0.232721,128
Line(1): 0.24209,1.06866,128
Line(2): 0.185419,2.45852,128
Line(3): 0.141297,3.06488,128
Line(4): 0.346642,4.35358,128
...
...

顺便...

我在终端的命令行中使用 ImageMagick 将您的图像转换为常规 JPEG,如下所示:

convert map.tif[0] -auto-level result.jpg

另一个易于安装的轻量级选项是使用 vips。您可以将 32 位 TIF 转换为 32 位浮点数的原始文件,并将它们直接读入您的 C++ 程序。在命令行中,使用

进行转换
vips rawsave yourImage.tif raw.bin

然后从文件 raw.bin 中读入未压缩、未格式化的浮点数。如果我们现在转储文件 raw.bin,将数据解释为浮点数,您可以看到与我的其他答案中相同的值:

od -f raw.bin

0000000     3.913185e-06    2.327210e-01    1.280000e+02    1.065769e+00
0000020     3.421732e-01    1.280000e+02    2.377803e+00    4.058807e-01
0000040     1.280000e+02    3.229325e+00    1.371841e-01    1.280000e+02

当然,您可以让您的程序通过链接到 libvips 或简单地使用 system() 到 运行 命令行版本进行转换,然后读取其输出文件。