// Read 3D image data unsigned char * // (OUTPUT) buffer containing the read image data iomanager::tiff3D::readData( std::string img_path, // (INPUT) image filepath int & img_width, // (INPUT/OUTPUT) image width (in pixels) int & img_height, // (INPUT/OUTPUT) image height (in pixels) int & img_depth, // (INPUT/OUTPUT) image depth (in pixels) int & img_bytes_x_chan, // (INPUT/OUTPUT) number of bytes per channel int & img_chans, // (INPUT/OUTPUT) number of channels to be read unsigned char *data, // (INPUT) image data int z0, // (INPUT) region of interest [x0,x1)[y0,y1)[z0,z1) to be set on the image int z1, // (INPUT) region of interest [x0,x1)[y0,y1)[z0,z1) to be set on the image const std::string & params) // (INPUT) additional parameters <param1=val, param2=val, ...> throw (iom::exception) { //throw iom::exception(iom::strprintf("not implemented yet"), __iom__current__function__); /**/iom::debug(iom::LEV3, iom::strprintf("img_path = %s, img_width = %d, img_height = %d, img_depth = %d, img_bytes_x_chan = %d, img_chans = %d, data = %p, z0 = %d, z1 = %d, params = \"%s\"", img_path.c_str(), img_width, img_height, img_depth, img_bytes_x_chan, img_chans, data, z0, z1, params.c_str()).c_str(), __iom__current__function__); //disable warning handler to avoid messages on unrecognized tags TIFFSetWarningHandler(0); unsigned int _width; unsigned int _height; unsigned int _depth; int _bytes_x_chan; unsigned int _chans; int b_swap; void *fhandle; int header_len; char *err_Tiff3Dfmt; if ( !data ) { // recover the metadata, allocate the buffer and set parameters if ( (err_Tiff3Dfmt = loadTiff3D2Metadata((char *)img_path.c_str(),_width,_height,_depth,_chans,_bytes_x_chan,b_swap,fhandle,header_len)) != 0 ) { throw iom::exception(iom::strprintf("(%s) unable to read meta data of tiff file %s",err_Tiff3Dfmt,img_path.c_str()), __iom__current__function__); } closeTiff3DFile(fhandle); data = new unsigned char[_width * _height * _depth * _chans * _bytes_x_chan]; img_width = _width; img_height = _height; img_depth = _depth; img_bytes_x_chan = _bytes_x_chan; img_chans = _chans; } // set the ROI z0 = (z0 < 0) ? 0: z0; z1 = (z1 < 0) ? img_depth : z1; if ( z0 >= z1 ) throw iom::exception(iom::strprintf("wrong slice indices (z0 = %d, z1 = %d)",z0, z1), __iom__current__function__); // get the image if ( (err_Tiff3Dfmt = readTiff3DFile2Buffer((char *)img_path.c_str(),data,img_width,img_height,z0,z1-1)) != 0 ) { throw iom::exception(iom::strprintf("(%s) unable to read tiff file %s in page range [%d,%d]",err_Tiff3Dfmt,img_path.c_str(),z0,z1-1), __iom__current__function__); } return data; }
// Read 2D image data unsigned char * // (OUTPUT) a buffer storing the 2D image iomanager::tiff2D::readData( std::string img_path, // (INPUT) image filepath int & img_width, // (INPUT/OUTPUT) image width (in pixels) int & img_height, // (INPUT/OUTPUT) image height (in pixels) int & img_bytes_x_chan, // (INPUT/OUTPUT) number of bytes per channel int & img_chans, // (INPUT/OUTPUT) number of channels to be read unsigned char *data, // (INPUT) image data const std::string & params) // (INPUT) additional parameters <param1=val, param2=val, ...> throw (iom::exception) { //throw iom::exception(iom::strprintf("not implemented yet"), __iom__current__function__); /**/iom::debug(iom::LEV3, iom::strprintf("img_path = %s, img_width 0 %d, img_height 0 %d, img_bytes_x_chan = %d, img_chans = %d, params = \"%s\"", img_path.c_str(), img_width, img_height, img_bytes_x_chan, img_chans, params.c_str()).c_str(), __iom__current__function__); char *err_Tiff3Dfmt; //disable warning handler to avoid messages on unrecognized tags TIFFSetWarningHandler(0); if ( !data ) { // recover the metadata, allocate the buffer and set parameters unsigned int _width; unsigned int _height; unsigned int _depth; int _bytes_x_chan; unsigned int _chans; int b_swap; void *fhandle; int header_len; if ( (err_Tiff3Dfmt = loadTiff3D2Metadata((char *)img_path.c_str(),_width,_height,_depth,_chans,_bytes_x_chan,b_swap,fhandle,header_len)) != 0 ) { throw iom::exception(iom::strprintf("(%s) unable to read meta data of tiff file %s",err_Tiff3Dfmt,img_path.c_str()), __iom__current__function__); } closeTiff3DFile(fhandle); data = new unsigned char[_width * _height * _chans * _bytes_x_chan]; img_width = _width; img_height = _height; img_bytes_x_chan = _bytes_x_chan; img_chans = _chans; } // load 2D image if ( (err_Tiff3Dfmt = readTiff3DFile2Buffer((char *)img_path.c_str(),data,img_width,img_height,0,0)) != 0 ) { throw iom::exception(iom::strprintf("(%s) unable to read tiff file %s",err_Tiff3Dfmt,img_path.c_str()), __iom__current__function__); } return data; }
// read 3D image data from a stack of (2D) image files iom::real_t* // (OUTPUT) a [0.0,1.0]-valued array storing the 3D image in channel->slice->row order iomanager::tiff2D::readData( char **files, // (INPUT) array of C-strings storing image filenames int files_size, // (INPUT) size of 'files' const char *path /*= 0*/, // (INPUT) path to be concatenated to the i-th entry of 'files' int first /*= -1*/, // (INPUT) selects a range [first, last] of files to be loaded int last /*= -1*/, // (INPUT) selects a range [first, last] of files to be loaded bool is_sparse /*= false*/, // (INPUT) if true, 'files' is a sparse array and null entries should be treated as empty (black) images iom::channel chan, // (INPUT) channel selection { ALL, R, G, B }. const std::string & params) // (INPUT) additional parameters <param1=val, param2=val, ...> throw (iom::exception) { throw iom::exception(iom::strprintf("no more available"), __iom__current__function__); /**/iom::debug(iom::LEV3, iom::strprintf("files_size = %d, path = %s, first = %d, last = %d, is_sparse = %s, chan = %d, params = \"%s\"", files_size, path ? path : "null", first, last, is_sparse ? "true" : "false", chan, params.c_str()).c_str(), __iom__current__function__); char *err_Tiff3Dfmt; unsigned int rows; unsigned int cols; unsigned int n_slices; unsigned int channels; int depth; int swap; void *dummy; int dummy_len; unsigned char *data; iom::real_t *raw_data; iom::real_t *image_stack = 0; uint64 image_stack_width=0, image_stack_height=0, z=0; // check for valid file list if(!files || files_size <= 0) throw iom::exception("invalid file list (null pointer or 0-sized)", __iom__current__function__); // check and adjust file selection first = (first == -1 ? 0 : first); last = (last == -1 ? files_size - 1 : last ); first = min(first, files_size-1); last = min(last, files_size-1); //disable warning handler to avoid messages on unrecognized tags TIFFSetWarningHandler(0); // build absolute image path of first file in the stack int i = 0; while ( is_sparse && i<files_size && files[i]==0 ) // look for existing file i++; if ( i == files_size ) throw iom::exception("stack is entirely empty: cannot recover slice dimension", __iom__current__function__); std::string image_path = path ? std::string(path) + "/" + files[i] : files[i]; // load metadata //iomanager::tiff2D::readMetadata(image_path,cols,rows,depth,channels,params); if ( (err_Tiff3Dfmt = loadTiff3D2Metadata((char *)image_path.c_str(),cols,rows,n_slices,channels,depth,swap,dummy,dummy_len)) != 0 ) { throw iom::exception(iom::strprintf("unable to read tiff file (%s)",err_Tiff3Dfmt), __iom__current__function__); } closeTiff3DFile(dummy); // allocate buffer data = new unsigned char[cols * rows * depth * channels]; // loop over files for(int file_i = first; file_i <= last; file_i++, z++) { // skip missing slices if stack is sparse if(is_sparse && !files[file_i]) continue; // if stack is not sparse, a missing slice must throw an iom::exception if(!files[file_i]) throw iom::exception("invalid slice filename in non-sparse tile", __iom__current__function__); // build absolute image path std::string image_path = path ? std::string(path) + "/" + files[file_i] : files[file_i]; // load 2D image if ( (err_Tiff3Dfmt = readTiff3DFile2Buffer((char *)image_path.c_str(),data,cols,rows,0,0)) != 0 ) { throw iom::exception(iom::strprintf("unable to read tiff file (%s)",err_Tiff3Dfmt), __iom__current__function__); } double proctime = -TIME(0); // if(chan == iom::ALL) // image = cv::imread(image_path, CV_LOAD_IMAGE_GRAYSCALE | CV_LOAD_IMAGE_ANYDEPTH); // pack all channels into grayscale // else // image = cv::imread(image_path, CV_LOAD_IMAGE_ANYCOLOR); // load individual channels // if(!image.data) // throw iom::exception(iom::strprintf("unable to open image \"%s\". Possible unsupported format or it isn't an image.\nSupported formats are BMP, DIB, JPEG, JPG, JPE, PNG, PBM, PGM, PPM, SR, RAS, TIFF, TIF", image_path.c_str()), __iom__current__function__); // select channel (if requested) // if(image.channels() == 3 && chan != iom::ALL) // { // cv::Mat imageChannels[3]; // cv::split(image, imageChannels); // image = imageChannels[3-CHANS]; // OpenCV uses BGR ! // } // update time if(TIME_CALC) { proctime += TIME(0); time_IO+=proctime; proctime = -TIME(0); } // initialize output data and image dimensions if(!image_stack) { image_stack_height = (uint64) rows; image_stack_width = (uint64) cols; uint64 image_stack_size = image_stack_width * image_stack_height * (last-first+1); image_stack = new iom::real_t[image_stack_size]; for(uint64 j=0; j < image_stack_size; j++) image_stack[j] = 0; // default is 0 (black) } else if(image_stack_width != (uint64)cols || image_stack_height != (uint64)rows) throw iom::exception("images in stack have not the same dimensions", __iom__current__function__); // iom::real_t *raw_data = &image_stack[z*image.rows*image.cols]; // if(image.depth == CV_8U) // { // for(int i=0; i<image.rows; i++) // { // uint8* img_data = image.ptr<uint8>(i); // for(int j=0; j<image.cols; j++, raw_data++) // *raw_data = img_data[j]/255.0f; // } // } // else if (image.depth() == CV_16U) // { // for(int i=0; i<image.rows; i++) // { // uint16* img_data = image.ptr<uint16>(i); // for(int j=0; j<image.cols; j++, raw_data++) // *raw_data = img_data[j]/65535.0f; // } // } // else // throw iom::exception("unsupported image depth", __iom__current__function__); int offset; // convert image to [0.0,1.0]-valued array if ( channels == 1 ) { raw_data = &image_stack[z*rows*cols]; if ( depth == 1 ) { for(int i = 0; i < (rows * cols); i++) raw_data[i] = (iom::real_t) data[i]/255.0f; } else { // depth == 2 for(int i = 0; i < (rows * cols); i++) raw_data[i] = (iom::real_t) ((uint16 *)data)[i]/65535.0f; // data must be interpreted as a uint16 array } } else { // conversion to an intensity image if ( chan == iom::ALL ) { throw iom::exception("conversion from multi-channel to intensity images not supported.", __iom__current__function__); } else if ( chan == iom::R ) { offset = 0; } else if ( chan == iom::G ) { offset = 1; } else if ( chan == iom::B ) { offset = 2; } else { throw iom::exception("wrong value for parameter iom::CHANNEL_SELECTION.", __iom__current__function__); } raw_data = &image_stack[z*rows*cols]; if ( depth == 1 ) for(int i = 0; i < (rows * cols); i++) raw_data[i] = (iom::real_t) data[3*i + offset]/255.0f; else // depth == 2 for(int i = 0; i < (rows * cols); i++) raw_data[i] = (iom::real_t) ((uint16 *)data)[3*i + offset]/65535.0f; // data must be interpreted as a uint16 array } // update time if(TIME_CALC) { proctime += TIME(0); time_conversions+=proctime; } } delete []data; // cannot load any data from this stack if(!image_stack) throw iom::exception(iom::strprintf("stack (%s) does not contain loadable data in [%d,%d]", path ? path : "0", first, last), __iom__current__function__); return image_stack; }