OGS
VtkRaster Class Reference

Detailed Description

Loading raster data such as images or ArcGIS-data into VTK image data structures.

The VtkRaster class enables loading of raster data such as images or ArcGIS-data. Supported image formats are ..... Georeferenced data can be imported via the GeoTIFF- or asc-format.

Definition at line 19 of file VtkRaster.h.

#include <VtkRaster.h>

Static Public Member Functions

static vtkImageImport * loadImageFromArray (double const *const data_array, GeoLib::RasterHeader header)
 Returns a VtkImageAlgorithm from an array of pixel values and some image meta data.
static vtkImageAlgorithm * loadImage (const std::string &fileName)
 Loads an image- or raster-file into an vtkImageAlgorithm-Object.

Static Private Member Functions

static vtkImageAlgorithm * loadImageFromTIFF (const std::string &fileName)
static vtkImageReader2 * loadImageFromFile (const std::string &fileName)
static std::string findWorldFile (const std::string &filename)
static bool readWorldFile (std::string const &filename, vtkImageReader2 *image)

Member Function Documentation

◆ findWorldFile()

std::string VtkRaster::findWorldFile ( const std::string & filename)
staticprivate

Tries to find a world file for the image given by the filename. World files can have a number of extensions depending on the programme used to write the image and this method just cycles through the possibilities, returning the first match it finds.

Definition at line 318 of file VtkRaster.cpp.

319{
320 std::string const no_ext = BaseLib::dropFileExtension(filename);
321
322 constexpr std::array supported_extensions = {
323 ".pgw", ".pngw", ".pgwx", ".jgw", ".jpgw", ".jgwx", ".tfw",
324 ".tifw", ".tfwx", ".bpw", ".bmpw", ".bpwx", ".wld"};
325
326 auto const res =
327 std::find_if(supported_extensions.begin(), supported_extensions.end(),
328 [&no_ext](auto const& ext) -> bool
329 { return BaseLib::IsFileExisting(no_ext + ext); });
330 if (res != supported_extensions.end())
331 {
332 return no_ext + *res;
333 }
334
335 // no world file found
336 return {};
337}
std::string dropFileExtension(std::string const &filename)

References BaseLib::dropFileExtension().

Referenced by readWorldFile().

◆ loadImage()

vtkImageAlgorithm * VtkRaster::loadImage ( const std::string & fileName)
static

Loads an image- or raster-file into an vtkImageAlgorithm-Object.

Public method for loading all data formats. Internally the method automatically differentiates between images and georeferenced files and then calls the appropriate method for reading the file.

Parameters
fileNameFilename of the file that should be loaded.
Returns
The ImageAlgorithm-object.

Definition at line 32 of file VtkRaster.cpp.

33{
34 QFileInfo fileInfo(QString::fromStdString(fileName));
35
36 std::unique_ptr<GeoLib::Raster> raster(nullptr);
37 if (fileInfo.suffix().toLower() == "asc")
38 {
39 raster.reset(
41 }
42 else if (fileInfo.suffix().toLower() == "grd")
43 {
44 raster.reset(
46 }
47 else if (fileInfo.suffix().toLower() == "xyz")
48 {
49 raster.reset(
51 }
52 if (raster)
53 {
54 return VtkRaster::loadImageFromArray(raster->data(),
55 raster->getHeader());
56 }
57 if ((fileInfo.suffix().toLower() == "tif") ||
58 (fileInfo.suffix().toLower() == "tiff"))
59 {
60#ifdef GEOTIFF_FOUND
61 return loadImageFromTIFF(fileName);
62#else
63 ERR("VtkRaster::loadImage(): GeoTiff file format not supported in this "
64 "version! Trying to parse as Tiff-file.");
65 return loadImageFromFile(fileName);
66#endif
67 }
68
69 return loadImageFromFile(fileName);
70}
void ERR(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:40
static GeoLib::Raster * getRasterFromXyzFile(std::string const &fname)
Reads a XYZ raster file.
static GeoLib::Raster * getRasterFromSurferFile(std::string const &fname)
Reads a Surfer GRD raster file.
static GeoLib::Raster * getRasterFromASCFile(std::string const &fname)
Reads an ArcGis ASC raster file.
static vtkImageAlgorithm * loadImageFromTIFF(const std::string &fileName)
static vtkImageReader2 * loadImageFromFile(const std::string &fileName)
static vtkImageImport * loadImageFromArray(double const *const data_array, GeoLib::RasterHeader header)
Returns a VtkImageAlgorithm from an array of pixel values and some image meta data.
Definition VtkRaster.cpp:71

References ERR(), FileIO::AsciiRasterInterface::getRasterFromASCFile(), FileIO::AsciiRasterInterface::getRasterFromSurferFile(), FileIO::AsciiRasterInterface::getRasterFromXyzFile(), loadImageFromArray(), loadImageFromFile(), and loadImageFromTIFF().

Referenced by VtkCompositeTextureOnSurfaceFilter::init(), MainWindow::loadFile(), and VtkGeoImageSource::readImage().

◆ loadImageFromArray()

vtkImageImport * VtkRaster::loadImageFromArray ( double const *const data_array,
GeoLib::RasterHeader header )
static

Returns a VtkImageAlgorithm from an array of pixel values and some image meta data.

Definition at line 71 of file VtkRaster.cpp.

73{
74 const unsigned length = header.n_rows * header.n_cols * header.n_depth;
75 auto* data = new float[length * 2];
76 float max_val =
77 static_cast<float>(*std::max_element(data_array, data_array + length));
78 for (unsigned j = 0; j < length; ++j)
79 {
80 data[j * 2] = static_cast<float>(data_array[j]);
81 if (fabs(data[j * 2] - header.no_data) <
82 std::numeric_limits<double>::epsilon())
83 {
84 data[j * 2] = max_val;
85 data[j * 2 + 1] = 0;
86 }
87 else
88 {
89 data[j * 2 + 1] = max_val;
90 }
91 }
92
93 vtkImageImport* image = vtkImageImport::New();
94 image->SetDataSpacing(header.cell_size, header.cell_size, header.cell_size);
95 image->SetDataOrigin(header.origin[0] + (header.cell_size / 2.0),
96 header.origin[1] + (header.cell_size / 2.0),
97 0); // translate whole mesh by half a pixel in x and y
98 image->SetWholeExtent(0, header.n_cols - 1, 0, header.n_rows - 1, 0,
99 header.n_depth - 1);
100 image->SetDataExtent(0, header.n_cols - 1, 0, header.n_rows - 1, 0,
101 header.n_depth - 1);
102 image->SetDataExtentToWholeExtent();
103 image->SetDataScalarTypeToFloat();
104 image->SetNumberOfScalarComponents(2);
105 image->SetImportVoidPointer(data, 0);
106 image->Update();
107
108 return image;
109}
std::size_t n_depth
Definition Raster.h:21
MathLib::Point3d origin
Definition Raster.h:22
std::size_t n_cols
Definition Raster.h:19
std::size_t n_rows
Definition Raster.h:20

References GeoLib::RasterHeader::cell_size, GeoLib::RasterHeader::n_cols, GeoLib::RasterHeader::n_depth, GeoLib::RasterHeader::n_rows, GeoLib::RasterHeader::no_data, and GeoLib::RasterHeader::origin.

Referenced by NetCdfConfigureDialog::createDataObject(), and loadImage().

◆ loadImageFromFile()

vtkImageReader2 * VtkRaster::loadImageFromFile ( const std::string & fileName)
staticprivate

Loads image files into a QPixmap object. Since images are not geo-referenced no origin point will be returned.

Parameters
fileNameFilename of the file that should be loaded.
Returns
vtkImageReader2-object containing the image data.

Definition at line 280 of file VtkRaster.cpp.

281{
282 QString file_name(QString::fromStdString(fileName));
283 QFileInfo fi(file_name);
284 vtkImageReader2* image(nullptr);
285
286 if (fi.suffix().toLower() == "png")
287 {
288 image = vtkPNGReader::New();
289 }
290 else if ((fi.suffix().toLower() == "tif") ||
291 (fi.suffix().toLower() == "tiff"))
292 {
293 image = vtkTIFFReader::New();
294 }
295 else if ((fi.suffix().toLower() == "jpg") ||
296 (fi.suffix().toLower() == "jpeg"))
297 {
298 image = vtkJPEGReader::New();
299 }
300 else if (fi.suffix().toLower() == "bmp")
301 {
302 image = vtkBMPReader::New();
303 }
304 else
305 {
306 ERR("VtkRaster::readImageFromFile(): File format not supported, please "
307 "convert to BMP, JPG, PNG or TIFF.");
308 return nullptr;
309 }
310
311 image->SetFileName(fileName.c_str());
312 image->GetOutput()->AllocateScalars(VTK_FLOAT, 1);
313 image->Update();
314 readWorldFile(fileName, image);
315 return image;
316}
static bool readWorldFile(std::string const &filename, vtkImageReader2 *image)

References ERR(), and readWorldFile().

Referenced by loadImage().

◆ loadImageFromTIFF()

vtkImageAlgorithm * VtkRaster::loadImageFromTIFF ( const std::string & fileName)
staticprivate

Loads ArcGIS asc-files to a QPixmap object and automatically does a contrast stretching to adjust values to 8 bit greyscale images.

Parameters
fileNameFilename of the file that should be loaded.
Returns
A vtkImageImport-object (derived from vtkImageAlgorithm).

Definition at line 112 of file VtkRaster.cpp.

113{
114 TIFF* tiff = XTIFFOpen(fileName.c_str(), "r");
115
116 if (tiff)
117 {
118 GTIF* geoTiff = GTIFNew(tiff);
119
120 int version[3];
121 int count(0);
122 GTIFDirectoryInfo(geoTiff, version, &count);
123
124 if (count == 0)
125 WARN("VtkRaster::loadImageFromTIFF - file is not georeferenced.");
126
127 if (geoTiff)
128 {
129 double x0 = 0.0;
130 double y0 = 0.0;
131 double cellsize = 1.0;
132 int imgWidth = 0;
133 int imgHeight = 0;
134 int nImages = 0;
135 int pntCount = 0;
136 double* pnts = nullptr;
137
138 // get actual number of images in the tiff file
139 do
140 {
141 ++nImages;
142 } while (TIFFReadDirectory(tiff));
143 if (nImages > 1)
144 INFO(
145 "VtkRaster::loadImageFromTIFF() - File contains {:d} "
146 "images. This method is not tested for this case.",
147 nImages);
148
149 // get image size
150 TIFFGetField(tiff, TIFFTAG_IMAGEWIDTH, &imgWidth);
151 TIFFGetField(tiff, TIFFTAG_IMAGELENGTH, &imgHeight);
152
153 // get cellsize
154 // Note: GeoTiff allows anisotropic pixels. This is not supported
155 // here and equilateral pixels are assumed.
156 if (TIFFGetField(tiff, GTIFF_PIXELSCALE, &pntCount, &pnts))
157 {
158 if (pnts[0] != pnts[1])
159 WARN(
160 "VtkRaster::loadImageFromTIFF(): Original raster data "
161 "has anisotrop pixel size!");
162 cellsize = pnts[0];
163 }
164
165 // get upper left point / origin
166 if (TIFFGetField(tiff, GTIFF_TIEPOINTS, &pntCount, &pnts))
167 {
168 x0 = pnts[3];
169 y0 = pnts[4] -
170 (imgHeight * cellsize); // the origin should be the lower
171 // left corner of the img
172 }
173
174 // read pixel values
175 auto* pixVal = static_cast<uint32*>(
176 _TIFFmalloc(imgWidth * imgHeight * sizeof(uint32)));
177 if ((imgWidth > 0) && (imgHeight > 0))
178 {
179 if (!TIFFReadRGBAImage(tiff, imgWidth, imgHeight, pixVal, 0))
180 {
181 ERR("VtkRaster::loadImageFromTIFF(): reading GeoTIFF "
182 "file.");
183 _TIFFfree(pixVal);
184 GTIFFree(geoTiff);
185 XTIFFClose(tiff);
186 return nullptr;
187 }
188 }
189
190 // check for colormap
191 uint16 photometric;
192 TIFFGetField(tiff, TIFFTAG_PHOTOMETRIC, &photometric);
193 // read colormap
194 uint16 *cmap_red = nullptr, *cmap_green = nullptr,
195 *cmap_blue = nullptr;
196 int colormap_used = TIFFGetField(tiff, TIFFTAG_COLORMAP, &cmap_red,
197 &cmap_green, &cmap_blue);
198
199 auto* data = new float[imgWidth * imgHeight * 4];
200 auto* pxl(new int[4]);
201 for (int j = 0; j < imgHeight; ++j)
202 {
203 int lineindex = j * imgWidth;
204 for (int i = 0; i < imgWidth; ++i)
205 { // scale intensities and set nodata values to white (i.e. the
206 // background colour)
207 unsigned pxl_idx(lineindex + i);
208 unsigned pos = 4 * (pxl_idx);
209 if (photometric == 1 && colormap_used == 1)
210 {
211 int idx = TIFFGetR(pixVal[pxl_idx]);
212 data[pos] = static_cast<float>(cmap_red[idx] >> 8);
213 data[pos + 1] =
214 static_cast<float>(cmap_green[idx] >> 8);
215 data[pos + 2] = static_cast<float>(cmap_blue[idx] >> 8);
216 data[pos + 3] = 1;
217 }
218 else
219 {
220 data[pos] =
221 static_cast<float>(TIFFGetR(pixVal[pxl_idx]));
222 data[pos + 1] =
223 static_cast<float>(TIFFGetG(pixVal[pxl_idx]));
224 data[pos + 2] =
225 static_cast<float>(TIFFGetB(pixVal[pxl_idx]));
226 data[pos + 3] =
227 static_cast<float>(TIFFGetA(pixVal[pxl_idx]));
228 }
229 }
230 }
231 delete[] pxl;
232
233 // set transparency values according to maximum pixel value
234 if (photometric == 1)
235 {
236 float max_val(0);
237 unsigned nPixels = 4 * imgWidth * imgHeight;
238 for (unsigned j = 0; j < nPixels; ++j)
239 {
240 if (data[j] > max_val)
241 {
242 max_val = data[j];
243 }
244 }
245
246 for (unsigned j = 0; j < nPixels; j += 4)
247 {
248 data[j + 3] = max_val;
249 }
250 }
251
252 vtkImageImport* image = vtkImageImport::New();
253 image->SetDataOrigin(x0, y0, 0);
254 image->SetDataSpacing(cellsize, cellsize, cellsize);
255 image->SetWholeExtent(0, imgWidth - 1, 0, imgHeight - 1, 0, 0);
256 image->SetDataExtent(0, imgWidth - 1, 0, imgHeight - 1, 0, 0);
257 image->SetDataExtentToWholeExtent();
258 image->SetDataScalarTypeToFloat();
259 image->SetNumberOfScalarComponents(4);
260 image->SetImportVoidPointer(data, 0);
261 image->Update();
262
263 _TIFFfree(pixVal);
264 GTIFFree(geoTiff);
265 XTIFFClose(tiff);
266 return image;
267 }
268
269 XTIFFClose(tiff);
270 ERR("VtkRaster::loadImageFromTIFF() - File not recognised as "
271 "GeoTIFF-Image.");
272 return nullptr;
273 }
274
275 ERR("VtkRaster::loadImageFromTIFF() - File not recognised as TIFF-Image.");
276 return nullptr;
277}
void INFO(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:28
void WARN(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:34

References ERR(), INFO(), uint32, and WARN().

Referenced by loadImage().

◆ readWorldFile()

bool VtkRaster::readWorldFile ( std::string const & filename,
vtkImageReader2 * image )
staticprivate

Tries to find and load the world file associated with a BMP/JPG/PNG-file and create a RasterHeader for the image.

Definition at line 339 of file VtkRaster.cpp.

341{
342 std::string const world_file = findWorldFile(filename);
343 if (world_file.empty())
344 {
345 WARN("No world file found. Image is not georeferenced.");
346 return false;
347 }
348
349 std::ifstream in(world_file.c_str());
350 if (!in.is_open())
351 {
352 ERR("VtkRaster::readWorldFile(): Could not open file {:s}.", filename);
353 return false;
354 }
355
356 std::string line;
357 // x-scaling
358 if (!std::getline(in, line))
359 {
360 return false;
361 }
362 double const delta_x = BaseLib::str2number<double>(line);
363 // 2x rotation (ignored)
364 if (!(std::getline(in, line) && std::getline(in, line)))
365 {
366 return false;
367 }
368 // negative y-scaling
369 if (!std::getline(in, line))
370 {
371 return false;
372 }
373 double const delta_y = BaseLib::str2number<double>(line);
374 if (delta_x != -delta_y)
375 WARN(
376 "Anisotropic pixel size detected ({:f} vs {:f}). An isotropic "
377 "spacing of {:f} is assumed, be aware results may be wrong.",
378 delta_x, delta_y, delta_x);
379 // x-translation
380 if (!std::getline(in, line))
381 {
382 return false;
383 }
384 double const x0 = BaseLib::str2number<double>(line);
385 // y-translation
386 if (!std::getline(in, line))
387 {
388 return false;
389 }
390 double const y0 = BaseLib::str2number<double>(line);
391
392 int extent[3];
393 image->GetOutput()->GetDimensions(extent);
394 image->SetDataSpacing(delta_x, delta_x, delta_x);
395 // for GIS the origin is on the lower left, for VTK it is on the upper left
396 double const vtk_y0 = y0 + (extent[1] * delta_y);
397 image->SetDataOrigin(x0, vtk_y0, 0);
398 return true;
399}
static std::string findWorldFile(const std::string &filename)
T str2number(const std::string &str)
Definition StringTools.h:53

References ERR(), findWorldFile(), BaseLib::str2number(), and WARN().

Referenced by loadImageFromFile().


The documentation for this class was generated from the following files: