Follow this link to skip to the main content

camera_image_io.h

Go to the documentation of this file.
00001 // -*-c++-*- 
00002 //---------------------------< /-/ CLARAty /-/ >------------------------------
00003 /** 
00004  * @file  camera_image_io.h
00005  *
00006  * A few, hopefully simple, functions for reading and writing camera images
00007  * (including camera_models, and their framestores) into unknown file types,
00008  * which is figured out using the factory mechanism.
00009  *
00010  * <br>@b Designer(s):  Clay Kunz
00011  * <br>@b Author(s):    Clay Kunz
00012  * <br>@b Date:         March 20, 2003
00013  *
00014  * <b>Software License:</b><br>
00015  * <code>  http://claraty.jpl.nasa.gov/license/open_src.html  or
00016  *         file: ../share/license.txt  </code>
00017  *
00018  * &copy; 2007, Jet Propulsion Laboratory, California Institute of Technology<br>
00019  * &copy; 2007, NASA Ames Research Center
00020  *
00021  * $Revision: 1.3 $
00022  */ 
00023 //-----------------------------------------------------------------------------
00024 
00025 #ifndef _camera_image_io_h_
00026 #define _camera_image_io_h_
00027 
00028 #include "claraty/image_io_factory.h"
00029 #include "claraty/camera_image.h"
00030 #include "claraty/rgb_image.h"
00031 #include "claraty/camera_model.h"
00032 #include "claraty/lock_frame.h"
00033 #include "claraty/string_util.h"
00034 #include "claraty/parse_block.h"
00035 #include "claraty/fdm_parse_tree.h"
00036 
00037 /**
00038  * Saves a camera image, with its camera model and associated
00039  * framestore. Additional header information can be passed in, as well as a
00040  * color image, which will be saved instead of the pixels in the camera_image
00041  * if it is given (so far we don't have a color camera_image type).
00042  *
00043  * @ingroup vision_file_io
00044  * 
00045  */
00046 
00047 template <class T>
00048 bool save_camera_image(const std::string& filename,
00049                        const Camera_Image<T>& img,
00050                        const Parse_Block *extraHeader = NULL,
00051                        const RGB_Image<T> *color_img = NULL)
00052 {
00053   Image_IO_Factory *io =
00054     (*Image_IO_Factory::factory)(string_suffix(filename));
00055   if (io == NULL) {
00056     std::cerr << "Unable to find helper class for saving images of type "
00057               << string_suffix(filename) << std::endl;
00058     return false;
00059   }
00060 
00061   const int image_io_state_version = 2;
00062 
00063   std::auto_ptr<Camera_Model> model(img.get_camera_model_ptr());
00064   std::string mRep = FDM_Parse_Tree::object_to_string(model);
00065   assert(model.get() == img.get_camera_model_ptr());
00066 
00067   std::string fs_rep;
00068   if (model.get() == NULL || model->get_frame().is_empty()) {
00069     Framestore tmp("");
00070     fs_rep = FDM_Parse_Tree::object_to_string(tmp);
00071   } else
00072     fs_rep = FDM_Parse_Tree::object_to_string(model->get_frame().get_store());
00073 
00074   model.release();
00075 
00076   Parse_Block pb;
00077   if (extraHeader != NULL)
00078     pb = *extraHeader;
00079   
00080   pb.add_entry("framestore", fs_rep);
00081   pb.add_entry("model", mRep);
00082   pb.add_entry("image_io_state_version", image_io_state_version);
00083   std::string pbString = pb.write_to_string();
00084 
00085   bool raster_allocated = true;
00086   unsigned char *raster;
00087   int sig_bits;
00088 
00089   if (color_img != NULL) {
00090     sig_bits = Image_IO_Factory::compute_sigbits(color_img->get_red_channel());
00091     raster = Image_IO_Factory::rasterize_image(*color_img);
00092   } else {
00093     sig_bits = Image_IO_Factory::compute_sigbits(img);
00094     raster = Image_IO_Factory::rasterize_image(img, raster_allocated);
00095   }
00096 
00097   bool ok = io->save_image_bytes(filename, raster, img.nrows(), img.ncols(),
00098                                  sizeof(T), sig_bits, pbString,
00099                                  color_img != NULL);
00100   if (raster_allocated)
00101     delete [] raster;
00102 
00103   delete io;
00104 
00105   return ok;
00106 }
00107 
00108 /* Loads the image+annotations stored in the given file into the camera
00109    image. A new framestore is built from information in the image header, as
00110    well as the camera model to be given to the camera image object.
00111    The header information will be returned in the parse block object, if a
00112    non-null pointer is given.
00113    There is not yet any facility for reading color camera images, since no
00114    such type yet exists.
00115 */
00116 template <class T>
00117 bool load_camera_image(const std::string& filename,
00118                        Camera_Image<T> *& img,
00119                        Framestore *& fs,
00120                        Parse_Block *header = NULL)
00121 {
00122   Image_IO_Factory *io =
00123     (*Image_IO_Factory::factory)(string_suffix(filename));
00124   if (io == NULL) {
00125     std::cerr << "Unable to find helper class for reading images of type "
00126               << string_suffix(filename) << std::endl;
00127     return false;
00128   }
00129 
00130   img = NULL;
00131   fs = NULL;
00132 
00133   unsigned char **rows;
00134   unsigned int nr, nc;
00135   std::string comments;
00136   int maxval;
00137   int bytes_per_pixel;
00138   bool color;
00139 
00140   if (!io->load_image_bytes(filename, rows, nr, nc, comments, maxval,
00141                             bytes_per_pixel, color)) {
00142     delete io;
00143     return false;
00144   }
00145   delete io;
00146 
00147   Parse_Block parseBlock;
00148   Parse_Block *pb = header != NULL ? header : &parseBlock;
00149 
00150   img = new Camera_Image<T>(nr, nc, NULL);
00151   img->set_maximum_value(maxval);
00152   Image_IO_Factory::move_raster_to_image(rows, bytes_per_pixel, *img, color);
00153 
00154   // get model_and_framestore, if it's there; otherwise just parse the thing
00155   // and yank out the pieces.
00156   std::string old_header = "model_and_framestore=";
00157   std::string::size_type pos = comments.find(old_header);
00158   if (pos != std::string::npos)
00159     comments = comments.substr(old_header.size());
00160 
00161   if (!pb->read_from_string(comments)) {
00162     std::cerr << "unable to parse image header" << std::endl;
00163     return false;
00164   }
00165   std::string value;
00166 
00167   if (!pb->get_entry("framestore", value)) {
00168     std::cerr << "missed framestore in image header" << std::endl;
00169     return false;
00170   }
00171 
00172   if (pb->check_for_entry("image_io_state_version")) {
00173     fs = new Framestore;
00174     bool ok = FDM_Parse_Tree::string_to_object(*fs, value);
00175     if (!ok) {
00176       std::cerr << "missed framestore (fdm representation expected) "
00177         "in image header" << std::endl;
00178       return false;
00179     }
00180   } else {
00181     Parse_Block fsPb(value);
00182     fs = new Framestore(fsPb);
00183   }
00184 
00185   if (!pb->get_entry("model", value)) {
00186     std::cerr << "missed model in image header" << std::endl;
00187     return false;
00188   }
00189 
00190   std::istringstream mis(value);
00191   Camera_Model *model = Camera_Model::build_from_stream(mis, *fs);
00192 
00193   if (model == NULL) {
00194     std::cerr << "unable to build model from stream" << std::endl;
00195     return false;
00196   } else {
00197     img->set_camera_model(model);
00198     delete model;
00199   }
00200   return true;
00201 }
00202 
00203                        
00204 /* This function is so that two camera images that are a stereo pair can be
00205    loaded with one function call, which merges the framestores loaded into a
00206    single framestore, containing the information for both camera models. */
00207 template <class T>
00208 bool load_stereo_camera_images(const std::string& leftFile,
00209                                const std::string& rightFile,
00210                                Camera_Image<T>*& leftImg,
00211                                Camera_Image<T>*& rightImg,
00212                                Framestore *& fs, Parse_Block *leftHdr = NULL,
00213                                const std::string& refFrame = "")
00214 {
00215   Framestore *fs1;
00216   leftImg = NULL;
00217   rightImg = NULL;
00218   bool ok = load_camera_image(leftFile, leftImg, fs, leftHdr);
00219   ok &= load_camera_image(rightFile, rightImg, fs1);
00220 
00221   if (leftImg == NULL || rightImg == NULL || !ok)
00222     return false;
00223 
00224   // move the right camera into the left camera's framestore
00225   const Camera_Model& rightCM = rightImg->get_camera_model();
00226   Camera_Model *rightCopy = rightCM.clone();
00227   
00228   Frame_l rightFrame = rightCM.get_frame();
00229   Frame_l leftFrame = leftImg->get_camera_model().get_frame();
00230   if (rightFrame.get_name() == leftFrame.get_name() && refFrame != "") {
00231     // The two images have the same camera model frame - we have to be
00232     // careful in case they're in fact the same camera that's moved between
00233     // the two images, instead of two different cameras taking a pair of
00234     // pictures simultaneously.
00235     // In this case, the best we can do is to make a new frame for the
00236     // second camera, and put it in the correct location relative to the
00237     // given reference frame, which must be supplied if this is the case.
00238     Frame_l leftRef = fs->lookup(refFrame);
00239     Frame_l rightRef = fs1->lookup(refFrame);
00240     if (leftRef.is_empty() || rightRef.is_empty()) {
00241       delete rightCopy;
00242       delete fs1;
00243       delete leftImg;
00244       delete rightImg;
00245       delete fs;
00246       leftImg = rightImg = NULL;
00247       fs = NULL;
00248       return false;
00249     }
00250     Location leftCamLoc = leftRef.location_of(leftFrame);
00251     Location rightCamLoc = rightRef.location_of(rightFrame);
00252     if (leftCamLoc.get_translation() !=
00253         rightCamLoc.get_translation() ||
00254         leftCamLoc.get_rotation() !=
00255         rightCamLoc.get_rotation()) {
00256       // The camera models are the same, but in different places in the two
00257       // images. So we have to move the right one into a new frame.
00258       // If the two frames are in the same locations in the two images, then
00259       // there's nothing we can do, except assume that there is additional
00260       // extrinsic information in the camera model, which distinguishes the
00261       // two images.
00262       std::string newRtFrameName = rightFrame.get_name() + ".stereo.right";
00263       Frame_l newRightFrame =
00264         fs->add_frame(newRtFrameName.c_str(), &leftRef, rightCamLoc);
00265       rightCopy->set_frame(newRightFrame);
00266       rightImg->set_camera_model(rightCopy);
00267       delete rightCopy;
00268       delete fs1;
00269       return false;
00270     }
00271   }
00272   // Make sure that the frame information from the right store (regarding the
00273   // camera model, at least) is reflected in the model when we move it into
00274   // the left framestore.
00275   Frame_l lfsrparent = fs->lookup(rightFrame.get_parent().get_name());
00276   Location rcmloc = rightFrame.get_location();
00277   Frame_l lfsrframe = fs->lookup(rightFrame.get_name());
00278   lfsrframe.change_parent(lfsrparent);
00279   lfsrframe.set_location(rcmloc);
00280   rightCopy->set_frame(lfsrframe);
00281   rightImg->set_camera_model(rightCopy); // clones the model
00282 
00283   delete rightCopy;
00284   delete fs1;
00285   return true;
00286 }
00287 
00288 #endif