1#include <cgv/base/base.h>
5#include <cgv/utils/file.h>
7#include <cgv/utils/tokenizer.h>
8#include <cgv/media/image/image_reader.h>
9#include <cgv/media/image/image_writer.h>
10#include <cgv/media/video/video_reader.h>
17 volume_info::volume_info() : dimensions(0, 0, 0), extent(1, 1, 1), position(0, 0, 0), type_id(
cgv::type::info::
TI_UINT8), components(
cgv::data::
CF_L)
19 orientation.identity();
21 volume_info::volume_info(
const volume& V,
const std::string& _path)
26 dimensions = V.get_dimensions();
27 type_id = V.get_component_type();
28 components = V.get_format().get_standard_component_format();
29 extent = V.get_box().get_extent();
30 position = V.get_box().get_center();
31 orientation.identity();
33 size_t volume_info::get_data_size()
const
38 bool read_vox(
const std::string& file_name, volume& V, volume_info* info_ptr = 0);
40 bool read_qim_header(
const std::string& file_name, volume_info& info);
41 bool read_qim(
const std::string& file_name, volume& V, volume_info* info_ptr = 0);
43 bool read_tiff(
const std::string& file_name, volume& V, volume_info* info_ptr = 0);
45 bool read_avi(
const std::string& file_name, volume& V, volume_info* info_ptr = 0);
48 bool write_vox(
const std::string& file_name,
const volume& V);
50 bool write_qim_header(
const std::string& file_name,
const volume& V);
51 bool write_qim(
const std::string& file_name,
const volume& V);
53 bool write_tiff(
const std::string& file_name,
const volume& V,
const std::string& options);
56 bool read_header(
const std::string& file_name, volume_info& info,
bool(*unknown_line_callback)(
const std::string& line,
const std::vector<cgv::utils::token>&, volume_info& info))
60 return read_vox_header(file_name, info, unknown_line_callback);
62 return read_qim_header(file_name, info);
66 bool read_volume(
const std::string& file_name, volume& V, volume_info* info_ptr)
69 if (ext ==
"VOX" || ext ==
"HD")
70 return read_vox(file_name, V, info_ptr);
71 if (ext ==
"QIM" || ext ==
"QHA")
72 return read_qim(file_name, V, info_ptr);
73 if (ext ==
"TIF" || ext ==
"TIFF")
74 return read_tiff(file_name, V, info_ptr);
76 return read_avi(file_name, V, info_ptr);
78 std::cerr <<
"unsupported extension " << ext << std::endl;
82 bool write_header(
const std::string& file_name,
const volume& V)
86 return write_vox_header(file_name, V);
88 return write_qim_header(file_name, V);
92 bool write_volume(
const std::string& file_name,
const volume& V,
const std::string& options)
95 if (ext ==
"VOX" || ext ==
"HD")
96 return write_vox(file_name, V);
97 if (ext ==
"QIM" || ext ==
"QHA")
98 return write_qim(file_name, V);
99 if (ext ==
"TIF" || ext ==
"TIFF")
100 return write_tiff(file_name, V, options);
102 std::cerr <<
"unsupported extension " << ext << std::endl;
106 bool read_vox_header(
const std::string& file_name, volume_info& info,
bool (*unknown_line_callback)(
const std::string& line,
const std::vector<cgv::utils::token>&, volume_info& info))
108 std::ifstream is(file_name);
110 std::cerr <<
"could not open vox header " << file_name << std::endl;
115 is.getline(buffer, 500);
116 std::string line(buffer);
118 std::vector<cgv::utils::token> toks;
120 t.set_skip(
"\"'",
"\"'");
122 bool success =
false;
123 if (toks.size() >= 2) {
126 for (c = 1; c < 4; ++c) {
133 if (toks.size() > 4) {
136 if (type_name.substr(0, 13) ==
"UNSIGNED BYTE") {
140 else if (type_name.substr(0, 14) ==
"UNSIGNED SHORT") {
144 else if (type_name.substr(0, 12) ==
"UNSIGNED INT") {
148 else if (type_name.substr(0, 11) ==
"SIGNED BYTE") {
152 else if (type_name.substr(0, 12) ==
"SIGNED SHORT") {
156 else if (type_name.substr(0, 10) ==
"SIGNED INT") {
160 else if (type_name.substr(0, 5) ==
"FLOAT") {
164 else if (type_name.substr(0, 6) ==
"DOUBLE") {
169 std::cerr <<
"unknown voxel type " << type_name << std::endl;
172 if (success && offset < type_name.size()) {
174 if (components.substr(0, 9) ==
"LUMINANCE")
176 else if (components.substr(0, 9) ==
"INTENSITY")
178 else if (components.substr(0, 4) ==
"RGBA")
180 else if (components.substr(0, 3) ==
"RGB")
182 else if (components.substr(0, 2) ==
"RG")
184 else if (components.substr(0, 5) ==
"ALPHA")
192 for (c = 1; c < 4; ++c) {
195 info.position(c - 1) = (float)d;
204 for (c = 1; c < 10; ++c) {
216 for (c = 1; c < 4; ++c) {
219 info.extent(c - 1) = (float)d;
228 for (c = 1; c < 4; ++c) {
231 info.extent(c - 1) = (float)(d * info.dimensions(c - 1));
240 if (info.path.size() >= 2 && info.path.front() == info.path.back() &&
241 (info.path.front() ==
'"' || info.path.front() ==
'\''))
242 info.path = info.path.substr(1, info.path.size() - 2);
247 if (toks.size() > 0) {
248 if (unknown_line_callback && unknown_line_callback(line, toks, info)) {
252 std::cerr <<
"did not understand header line <" << line <<
">!" << std::endl;
260 bool write_vox_header(
const std::string& file_name,
const volume_info& VI)
262 std::ofstream os(file_name);
264 std::cerr <<
"cannot open vox header " << file_name <<
" for writing." << std::endl;
267 os <<
"Size: " << VI.dimensions(0) <<
"x" << VI.dimensions(1) <<
"x" << VI.dimensions(2);
268 switch (VI.type_id) {
278 switch (VI.components) {
287 volume::extent_type scaling = VI.extent;
288 os <<
"Scaling: " << scaling(0)/VI.dimensions(0) <<
"x" << scaling(1)/VI.dimensions(1) <<
"x" << scaling(2)/VI.dimensions(2) << std::endl;
289 if (VI.position.length() > 1e-10)
290 os <<
"Position: " << VI.position(0) <<
", " << VI.position(1) <<
", " << VI.position(2) << std::endl;
294 if ((VI.orientation - I).length() > 1e-10) {
295 os <<
"Orientation: ";
296 for (
int i = 0; i < 9; ++i) {
299 os << reinterpret_cast<const cgv::math::fmat<volume::coord_type, 3, 3>::base_type&>(VI.orientation)(i);
303 if (!VI.path.empty())
304 os <<
"Path: \"" << VI.path <<
"\"" << std::endl;
309 void toggle_volume_endian(volume& V)
311 std::size_t n = V.get_nr_voxels();
312 unsigned c = V.get_nr_components();
315 unsigned char* ptr = V.get_data_ptr<
unsigned char>();
316 for (
unsigned i = 0; i < n; ++i)
317 for (
unsigned j = 0; j < c; ++j) {
318 std::swap(ptr[0], ptr[1]);
323 unsigned char* ptr = V.get_data_ptr<
unsigned char>();
324 for (
unsigned i = 0; i < n; ++i)
325 for (
unsigned j = 0; j < c; ++j) {
326 std::swap(ptr[0], ptr[3]);
327 std::swap(ptr[1], ptr[2]);
333 bool read_volume_binary(
const std::string& file_name,
const volume_info& info, volume& V,
size_t offset)
336 if (V.get_component_type() != info.type_id)
337 V.set_component_type(info.type_id);
338 if (V.get_component_format() != info.components)
339 V.set_component_format(info.components);
340 if (V.get_dimensions() != info.dimensions)
341 V.resize(info.dimensions);
342 if (V.get_extent() != info.extent)
343 V.ref_extent() = info.extent;
346 FILE* fp = fopen(file_name.c_str(),
"rb");
348 std::cerr <<
"cannot open file " << file_name << std::endl;
352 fseek(fp, (
long)offset, SEEK_SET);
356 std::size_t n = V.get_nr_voxels();
357 unsigned N = V.get_voxel_size();
358 std::size_t nr = fread(V.get_data_ptr<
unsigned char>(), N, n, fp);
360 std::cerr <<
"could not read the expected number " << n <<
" of voxels but only " << nr << std::endl;
370 bool read_vox(
const std::string& file_name, volume& V, volume_info* info_ptr)
372 volume_info local_info;
373 volume_info& info = info_ptr ? *info_ptr : local_info;
374 if (!read_vox_header(cgv::utils::file::drop_extension(file_name) +
".hd", info))
376 return read_volume_binary(cgv::utils::file::drop_extension(file_name) +
".vox", info, V);
379 bool read_qim_header(
const std::string& file_name, volume_info& info)
381 std::ifstream is(file_name);
383 std::cerr <<
"could not open qim header " << file_name << std::endl;
387 volume::point_type c, x, y, z;
388 is >> nr_components >> c;
389 is >> info.dimensions(0) >> x;
390 is >> info.dimensions(1) >> y;
391 is >> info.dimensions(2) >> z;
392 info.extent = volume::extent_type(x.length(), y.length(), z.length());
393 if (nr_components != 1) {
394 std::cerr <<
"no support for more than one component in qim file yet" << std::endl;
400 bool read_qim(
const std::string& file_name, volume& V, volume_info* info_ptr)
402 volume_info local_info;
403 volume_info& info = info_ptr ? *info_ptr : local_info;
404 if (!read_qim_header(cgv::utils::file::drop_extension(file_name) +
".qha", info))
406 return read_volume_binary(cgv::utils::file::drop_extension(file_name) +
".qim", info, V);
409 bool read_tiff(
const std::string& file_name, volume& V, volume_info* info_ptr)
413 if (!ir.open(file_name)) {
414 std::cerr <<
"could not open tiff file " << file_name << std::endl;
417 int n = ir.get_nr_images();
425 info_ptr->dimensions = size;
426 info_ptr->position.zeros();
427 info_ptr->orientation.identity();
430 V.ref_extent() = volume::point_type(1, 1, 1) * size / (float)cgv::math::max_value(size);
432 info_ptr->extent = V.get_extent();
433 for (
int i = 0; i < n; ++i) {
435 if (!ir.read_image(dv)) {
436 std::cerr <<
"could not read slice " << i <<
" of file " << file_name << std::endl;
444 bool read_avi(
const std::string& file_name, volume& V, volume_info* info_ptr)
448 if (!
vr.open(file_name)) {
449 std::cerr <<
"could not open avi file " << file_name << std::endl;
452 int nr_frames =
vr.get<
int>(
"nr_frames");
453 if (nr_frames == 0) {
454 std::cerr <<
"could not determine nr frames in avi file " << file_name << std::endl;
459 info_ptr->type_id = V.get_format().get_component_type();
460 info_ptr->components = V.get_format().get_standard_component_format();
464 info_ptr->dimensions = size;
465 info_ptr->position.zeros();
466 info_ptr->orientation.identity();
469 V.ref_extent() = volume::point_type(1, 1, 1) * size / (float)cgv::math::max_value(size);
471 info_ptr->extent = V.get_extent();
473 unsigned char* src_ptr = dv.get_ptr<
unsigned char>();
475 for (
int i = 0; i < nr_frames; ++i) {
476 if (!
vr.read_frame(dv)) {
477 std::cerr <<
"could not read slice " << i <<
" of file " << file_name << std::endl;
480 unsigned char* dst_ptr = V.get_slice_ptr<
unsigned char>(i);
481 for (
size_t j = 0; j < n; ++j)
482 dst_ptr[j] = src_ptr[3 * j];
488 bool write_volume_binary(
const std::string& file_name,
const volume& V,
size_t offset)
490 std::size_t n = V.get_nr_voxels();
491 unsigned N = V.get_voxel_size();
492 FILE* fp = fopen(file_name.c_str(),
"wb");
494 std::cerr <<
"cannot open volume file " << file_name <<
" for write." << std::endl;
498 if (fseek(fp, (
long)offset, SEEK_SET) != 0) {
499 std::cerr <<
"could not seek position " << offset <<
" in file " << file_name << std::endl;
507 std::cerr <<
"could not write the expected number " << n <<
" of voxels but only " << nr << std::endl;
510 std::cout <<
"write volume '" << file_name <<
"' of size " << V.get_dimensions() <<
" and scaling " << V.get_box().get_extent();
512 std::cout <<
" at offset " << offset;
513 std::cout << std::endl;
517 bool write_vox(
const std::string& file_name,
const volume& V)
519 if (!write_vox_header(cgv::utils::file::drop_extension(file_name) +
".hd", volume_info(V)))
521 return write_volume_binary(cgv::utils::file::drop_extension(file_name) +
".vox", V);
524 bool write_qim_header(
const std::string& file_name,
const volume& V)
526 std::ofstream os(file_name);
528 std::cerr <<
"cannot open qim header " << file_name <<
" for writing." << std::endl;
531 os << V.get_nr_components() <<
" 0 0 0" << std::endl;
532 os << V.get_dimensions()(0) <<
" " << V.get_box().get_extent()(0) <<
" 0 0" << std::endl;
533 os << V.get_dimensions()(1) <<
" 0 " << V.get_box().get_extent()(1) <<
" 0" << std::endl;
534 os << V.get_dimensions()(2) <<
" 0 0 " << V.get_box().get_extent()(2) << std::endl;
538 bool write_qim(
const std::string& file_name,
const volume& V)
540 if (!write_vox_header(cgv::utils::file::drop_extension(file_name) +
".qha", V))
542 return write_volume_binary(cgv::utils::file::drop_extension(file_name) +
".qim", V);
545 bool write_tiff(
const std::string& file_name,
const volume& V,
const std::string& options)
552 iw.multi_set(options);
553 for (
unsigned i = 0; i < (unsigned)(V.get_dimensions()(2)); ++i) {
555 if (!iw.write_image(dv)) {
556 std::cerr <<
"could not write slice " << i <<
" to tiff file " << file_name << std::endl;
complete implementation of method actions that only call one method when entering a node
The const_data_view has the functionality of the data_view but uses a const pointer and therefore doe...
the data view gives access to a data array of one, two, three or four dimensions.
matrix of fixed size dimensions
void identity()
set identity matrix
the tokenizer allows to split text into tokens in a convenient way.
ComponentFormat
define standard formats, which should be used to avoid wrong assignment of component names
@ CF_RGBA
color format with components R, G and B
@ CF_I
color format with luminance component L
@ CF_A
blue channel of color format
@ CF_RGB
color format with two components R and G
@ CF_RG
color format with intensity and alpha components: I and A
unsigned int get_type_size(TypeId tid)
function that returns the size of a type specified through TypeId
TypeId
ids for the different types and type constructs
@ TI_INT16
signed integer stored in 8 bits
@ TI_INT32
signed integer stored in 16 bits
@ TI_FLT32
floating point type stored in 16 bits
@ TI_UINT32
unsigned integer stored in 16 bits
@ TI_UINT8
signed integer stored in 64 bits
@ TI_UINT16
unsigned integer stored in 8 bits
@ TI_FLT64
floating point type stored in 32 bits
std::string to_string(const std::string &v, unsigned int w, unsigned int p, bool)
specialization of conversion from string to strings
bool is_integer(const char *begin, const char *end, int &value)
check if the text range (begin,end( defines an integer value. If yes, store the value in the passed r...
char to_upper(char c)
convert char to upper case
bool is_double(const char *begin, const char *end, double &value)
check if the text range (begin,end( defines a double value. If yes, store the value in the passed ref...
the vr namespace for virtual reality support
Helper functions to process strings.
representation of a token in a text by two pointers begin and end, that point to the first character ...