Я читаю Вот этот LibTIFF может отображать TIFF с плавающей запятой. Тем не менее, я хотел бы загрузить изображение, а затем получить значения с плавающей точкой в виде массива.
Можно ли это сделать с помощью LibTIFF?
РЕДАКТИРОВАТЬ: я использую RHEL 6.
РЕДАКТИРОВАТЬ: https://www.dropbox.com/s/f15fkkj5dg5ojzt/map.tif?dl=0
Извините за неправильную ссылку!
Ссылка на пример TIFF.
Если вы хотите сделать это с чистым LibTIFF, Ваш код может выглядеть примерно так: обратите внимание, что я не провел большую проверку ошибок, чтобы не запутать читателя кода, — но вы должны проверить, что изображение имеет тип 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
...
...
Кстати…
Я преобразовал ваше изображение в обычный JPEG с помощью ImageMagick
в Терминале в командной строке:
convert map.tif[0] -auto-level result.jpg
Вы Можно сделайте это с LibTIFF, и я могу добавить ответ, основанный на этом позже, но для простоты установки и использования я бы посмотрел на CImg
который является C ++ заголовок только библиотека, которая очень мощная и идеально подходит для ваших целей. Поскольку это только заголовок, его просто включить (только один файл) и не нужно никаких специальных ссылок или сборок.
Вот как вы можете прочитать TIFF RGB-поплавков:
#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
вот так — в основном каждый красный пиксель имеет свою координату х плюс небольшое случайное смещение менее 0,5. каждый зеленый пиксель имеет свою координату y плюс небольшое случайное значение с плавающей запятой менее 0,5, а каждый синий пиксель установлен на средний тон.
#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");
}
Да, но вам будет намного легче с этим, если вы используете библиотеку OpenCV.
Если у вас есть библиотека OpenCV, скомпилированная и установленная, выполнить то, что вы просите, так же просто, как использовать imread () функция. Это сохраняет его в объект с именем cv :: Mat (он же матрица) с теми же размерами и значениями, что и tiff.
Оттуда вы можете делать с ней все, что захотите.
Еще один, легко устанавливаемый, легкий вариант будет использовать 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()
запустить версию командной строки, а затем прочитать его выходной файл.