00001 /** 00002 \file Robots/LoBot/io/LoCompositor.H 00003 \brief Quick-and-dirty image stitcher. 00004 00005 This file defines a class to read images from several sources and then 00006 stitch them together into a single image. 00007 */ 00008 00009 // //////////////////////////////////////////////////////////////////// // 00010 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2000-2005 // 00011 // by the University of Southern California (USC) and the iLab at USC. // 00012 // See http://iLab.usc.edu for information about this project. // 00013 // //////////////////////////////////////////////////////////////////// // 00014 // Major portions of the iLab Neuromorphic Vision Toolkit are protected // 00015 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency // 00016 // in Visual Environments, and Applications'' by Christof Koch and // 00017 // Laurent Itti, California Institute of Technology, 2001 (patent // 00018 // pending; application number 09/912,225 filed July 23, 2001; see // 00019 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status). // 00020 // //////////////////////////////////////////////////////////////////// // 00021 // This file is part of the iLab Neuromorphic Vision C++ Toolkit. // 00022 // // 00023 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can // 00024 // redistribute it and/or modify it under the terms of the GNU General // 00025 // Public License as published by the Free Software Foundation; either // 00026 // version 2 of the License, or (at your option) any later version. // 00027 // // 00028 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope // 00029 // that it will be useful, but WITHOUT ANY WARRANTY; without even the // 00030 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // 00031 // PURPOSE. See the GNU General Public License for more details. // 00032 // // 00033 // You should have received a copy of the GNU General Public License // 00034 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write // 00035 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, // 00036 // Boston, MA 02111-1307 USA. // 00037 // //////////////////////////////////////////////////////////////////// // 00038 // 00039 // Primary maintainer for this file: Manu Viswanathan <mviswana at usc dot edu> 00040 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Robots/LoBot/io/LoCompositor.H $ 00041 // $Id: LoCompositor.H 11230 2009-05-27 11:11:23Z mviswana $ 00042 // 00043 00044 #ifndef LOBOT_COMPOSITOR_DOT_H 00045 #define LOBOT_COMPOSITOR_DOT_H 00046 00047 //------------------------------ HEADERS -------------------------------- 00048 00049 // lobot headers 00050 #include "Robots/LoBot/io/LoVideoStream.H" 00051 #include "Robots/LoBot/io/LoImageSource.H" 00052 00053 #include "Robots/LoBot/misc/LoExcept.H" 00054 #include "Robots/LoBot/misc/LoTypes.H" 00055 00056 // INVT image support 00057 #include "Image/CutPaste.H" 00058 #include "Image/ColorOps.H" 00059 #include "Image/Image.H" 00060 #include "Image/Point2D.H" 00061 #include "Image/Dims.H" 00062 00063 // Standard C++ headers 00064 #include <list> 00065 #include <utility> 00066 00067 //----------------------------- NAMESPACE ------------------------------- 00068 00069 namespace lobot { 00070 00071 //------------------------- CLASS DEFINITION ---------------------------- 00072 00073 /** 00074 \class lobot::Compositor 00075 \brief Quick-and-dirty "panaromic" image stitcher. 00076 00077 From Wikipedia: 00078 00079 "Digital compositing is the process of digitally assembling 00080 multiple images to make a final image, typically for print, motion 00081 pictures or screen display. It is the evolution into the digital 00082 realm of optical film compositing." 00083 00084 This class does not actually do any image compositing. No fancy alpha 00085 blending or any other such stuff. But technically, it does assemble 00086 multiple images into a final image and in that sense can be considered 00087 a kind of compositor (albeit a laughably crude one). 00088 00089 Given a number of different video streams, lobot::Compositor reads the 00090 current frame from each and then simply stitches the images together 00091 to create a kind of panaromic image. Of course, it doesn't actually 00092 try to find correspondences between image boundaries and properly 00093 stitch the images to create the final result. Rather, it simply 00094 creates a big image and copies each of the source images into this 00095 final image. 00096 00097 The motivation for this class is as follows: Robolocust is equipped 00098 with three FireWire cameras pointed straight ahead and to the left and 00099 right. We want to take the images from these cameras and create a 00100 single frame from them. Thus this simple-minded "compositor." 00101 */ 00102 template<typename pixel_type> 00103 class Compositor : public ImageSource<pixel_type> { 00104 // Handy type to have around in a derived class 00105 typedef ImageSource<pixel_type> base ; 00106 00107 // Prevent copy and assignment 00108 Compositor(const Compositor&) ; 00109 Compositor& operator=(const Compositor&) ; 00110 00111 /// The compositor needs a number of video sources from which it can 00112 /// draw images to stitch into its final product. 00113 //@{ 00114 typedef std::list<VideoStream*> Streams ; 00115 Streams m_streams ; 00116 //@} 00117 00118 /// We update the dimensions of the output image as new sources are 00119 /// added so that we don't have to compute these dimensions every time 00120 /// the compositor's client requests it to output the compositing 00121 /// result. 00122 int m_output_width, m_output_height ; 00123 00124 public: 00125 Compositor() ; 00126 ~Compositor() ; 00127 00128 /// This method adds a video stream to the compositor's list of input 00129 /// sources. 00130 void push_back(VideoStream*) ; 00131 00132 /// STL compatibility 00133 typedef Streams::const_reference const_reference ; 00134 00135 /// This is the compositor's output routine. When invoked, it reads 00136 /// frames from all its current sources and stitches them together to 00137 /// create the final output image. 00138 void update() ; 00139 00140 /// This method returns the output image's size 00141 Dims getImageSize() const {return Dims(m_output_width, m_output_height) ;} 00142 } ; 00143 00144 //-------------------- INITIALIZATION AND CLEAN-UP ---------------------- 00145 00146 template<typename pixel_type> 00147 Compositor<pixel_type>::Compositor() 00148 : m_output_width(0), m_output_height(0) 00149 {} 00150 00151 template<typename pixel_type> 00152 Compositor<pixel_type>::~Compositor() 00153 {} 00154 00155 //----------------------- ADDING IMAGE SOURCES -------------------------- 00156 00157 // Every time a source is added, we need to update the dimensions of the 00158 // output image. If we don't do this here, in the output routine, we will 00159 // have to walk through the sources list twice: the first pass to 00160 // determine the output image's size and second to do the actual 00161 // compositing. 00162 template<typename pixel_type> 00163 void Compositor<pixel_type>::push_back(VideoStream* V) 00164 { 00165 if (! V) 00166 return ; 00167 m_streams.push_back(V) ; 00168 00169 Dims frame_size = V->frameSize() ; 00170 m_output_width += frame_size.w() ; 00171 m_output_height = std::max(m_output_height, frame_size.h()) ; 00172 } 00173 00174 //------------------------ IMAGE "COMPOSITING" -------------------------- 00175 00176 // The following function object reads the next frame from the specified 00177 // input video source and copies it into the target image. On each 00178 // invocation, it copies the source image into the correct location of 00179 // the target image by maintaining a "cursor" to keep track of the 00180 // insertion point. This cursor only moves along the x-direction, i.e., 00181 // source images are copied to the target flush up against the top. 00182 namespace { 00183 00184 template<typename T> 00185 class paste_into { 00186 mutable Image<T>& target ; 00187 mutable Point2D<int> cursor ; 00188 public: 00189 paste_into(Image<T>&) ; 00190 void operator()(const VideoStream* V) const { 00191 inplacePaste(target, V->readFrame(), cursor) ; 00192 cursor.i += V->frameSize().w() ; 00193 } 00194 } ; 00195 00196 // When the above function object is instantiated, we will use the 00197 // supplied image as the target and initialize the cursor to start 00198 // inserting at the top left corner (0,0) of the target image. 00199 template<typename T> 00200 paste_into<T>::paste_into(Image<T>& I) 00201 : target(I), cursor(0,0) 00202 {} 00203 00204 } // end of local namespace encapsulating above function object 00205 00206 // This is the compositor's output routine. It assembles the output image 00207 // from the frames of each of its input video sources. 00208 template<typename T> 00209 void Compositor<T>::update() 00210 { 00211 if (m_streams.empty()) 00212 throw vstream_error(NO_COMPOSITOR_SOURCES) ; 00213 00214 Image<T> I(m_output_width, m_output_height, NO_INIT) ; 00215 std::for_each(m_streams.begin(), m_streams.end(), paste_into<T>(I)) ; 00216 00217 base::m_image = I ; 00218 base::m_image_gray = GrayImage(luminance(I)) ; 00219 } 00220 00221 //----------------------------------------------------------------------- 00222 00223 } // end of namespace encapsulating this file's definitions 00224 00225 #endif 00226 00227 /* So things look consistent in everyone's emacs... */ 00228 /* Local Variables: */ 00229 /* indent-tabs-mode: nil */ 00230 /* End: */