libidx
|
00001 /*************************************************************************** 00002 * Copyright (C) 2008 by Yann LeCun and Pierre Sermanet * 00003 * yann@cs.nyu.edu, pierre.sermanet@gmail.com * 00004 * All rights reserved. 00005 * 00006 * Redistribution and use in source and binary forms, with or without 00007 * modification, are permitted provided that the following conditions are met: 00008 * * Redistributions of source code must retain the above copyright 00009 * notice, this list of conditions and the following disclaimer. 00010 * * Redistributions in binary form must reproduce the above copyright 00011 * notice, this list of conditions and the following disclaimer in the 00012 * documentation and/or other materials provided with the distribution. 00013 * * Redistribution under a license not approved by the Open Source 00014 * Initiative (http://www.opensource.org) must display the 00015 * following acknowledgement in all advertising material: 00016 * This product includes software developed at the Courant 00017 * Institute of Mathematical Sciences (http://cims.nyu.edu). 00018 * * The names of the authors may not be used to endorse or promote products 00019 * derived from this software without specific prior written permission. 00020 * 00021 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED 00022 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 00023 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 00024 * DISCLAIMED. IN NO EVENT SHALL ThE AUTHORS BE LIABLE FOR ANY 00025 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 00026 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 00027 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 00028 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 00029 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 00030 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00031 ***************************************************************************/ 00032 00033 #ifndef IMAGEIO_HPP_ 00034 #define IMAGEIO_HPP_ 00035 00036 #include <math.h> 00037 #include <stdlib.h> 00038 00039 #ifndef __NOSTL__ 00040 #include <fstream> 00041 #include <cstdlib> 00042 #include <cstdio> 00043 #endif 00044 00045 #ifndef __WINDOWS__ 00046 #include <unistd.h> 00047 #endif 00048 00049 #ifdef __MAGICKPP__ 00050 #include <Magick++.h> 00051 #endif 00052 00053 #include <errno.h> 00054 #include "config.h" 00055 #include "idxIO.h" 00056 #include "stl.h" 00057 00058 using namespace std; 00059 00060 namespace ebl { 00061 00063 // I/O: helper functions 00064 00065 template<class T> 00066 idx<T> image_read(const char *fname, idx<T> *out_, int attempts) { 00067 idx<ubyte> tmp; 00068 #ifdef __MAGICKPP__ 00069 // we are under any platform, convert is not available but Magick++ is 00070 try { 00071 Magick::Image im(fname); 00072 tmp = idx<ubyte>(im.rows(), im.columns(), 3); 00073 im.write(0, 0, im.columns(), im.rows(), "RGB", Magick::CharPixel, 00074 tmp.idx_ptr()); 00075 // TODO: handle grayscale? 00076 } catch(Magick::WarningCoder &warning) { 00077 // Process coder warning while loading file (e.g. TIFF warning) 00078 // Maybe the user will be interested in these warnings (or not). 00079 // If a warning is produced while loading an image, the image 00080 // can normally still be used (but not if the warning was about 00081 // something important!) 00082 eblthrow("Coder Warning: " << warning.what()); 00083 } catch(Magick::Warning &warning) { 00084 // Handle any other Magick++ warning. 00085 eblthrow("Warning: " << warning.what()); 00086 } catch(Magick::ErrorBlob &error) { 00087 // Process Magick++ file open error 00088 eblthrow("Error: " << error.what()); 00089 } catch(Magick::ErrorOption &error) { 00090 // Process Magick++ file open error 00091 eblthrow("Error: " << error.what()); 00092 } 00093 #else 00094 #if (defined(__IMAGEMAGICK__) && !defined(__NOIMAGEMAGICK__)) 00095 // we are under linux or mac and convert is available 00096 string cmd; 00097 cmd << IMAGEMAGICK_CONVERT << " -compress lossless -depth 8 \"" 00098 << fname << "\" PPM:-"; 00099 #ifdef __WINDOWS__ 00100 FILE* fp = POPEN(cmd.c_str(), "rb"); 00101 #else 00102 FILE* fp = POPEN(cmd.c_str(), "r"); 00103 #endif 00104 if (!fp) { 00105 std::string err; 00106 err << "conversion of image " << fname << " failed (errno: " 00107 << errno << ", " << strerror(errno) << ")"; 00108 if (attempts > 0) { 00109 cerr << "Warning: " << err << endl; 00110 cerr << "trying again... (remaining attempts: " << attempts << ")" << endl; 00111 return image_read(fname, out_, attempts - 1); 00112 } else 00113 eblthrow(err); 00114 } 00115 try { 00116 // read pnm image 00117 tmp = pnm_read(fp); 00118 } catch (eblexception &err) { 00119 if (PCLOSE(fp) != 0) { 00120 cerr << "Warning: pclose failed (errno: " << errno << ")" << endl; 00121 } 00122 if (attempts > 0) { 00123 cerr << "Warning: " << err << endl; 00124 cerr << "trying again... (remaining attempts: " << attempts << ")" << endl; 00125 return image_read(fname, out_, attempts - 1); 00126 } else 00127 eblthrow(err); 00128 } 00129 if (PCLOSE(fp) != 0) { 00130 cerr << "Warning: pclose failed (errno: " << errno << ")" << endl; 00131 } 00132 #else 00133 // nor Magick++ nor convert are available, error 00134 eblerror("Nor ImageMagick's convert nor Magick++ are available, " 00135 << "please install"); 00136 #endif /* __IMAGEMAGICK__ */ 00137 #endif /* __MAGICK++__ */ 00138 00139 idxdim dims(tmp); 00140 idx<T> out; 00141 idx<T> *pout = &out; 00142 // allocate if not allocated 00143 if (!out_) 00144 out = idx<T>(dims); 00145 else 00146 pout = out_; 00147 // resize if necessary 00148 if (pout->get_idxdim() != dims) 00149 pout->resize(dims); 00150 // copy/cast 00151 idx_copy(tmp, *pout); 00152 return *pout; 00153 } 00154 00156 // I/O: loading 00157 00158 template<class T> 00159 void load_image(const char *fname, idx<T> &out) { 00160 // first try if the image is a mat file 00161 try { 00162 if (out.order() > 3 || out.order() < 2) 00163 eblerror("image has to be 2D or 3D"); 00164 load_matrix<T>(out, fname); 00165 // channels are likely in dim 0 if size 1 or 3 00166 if (((out.dim(0) == 1) || (out.dim(0) == 3)) && (out.order() == 3)) 00167 out = out.shift_dim(0, 2); 00168 return ; 00169 } catch(eblexception &e) { 00170 e = e; 00171 // not a mat file, try regular image 00172 } 00173 image_read(fname, &out); 00174 } 00175 00176 template<class T> 00177 void load_image(const string &fname, idx<T> &out) { 00178 return load_image(fname.c_str(), out); 00179 } 00180 00181 template<class T> 00182 idx<T> load_image(const char *fname) { 00183 // first try if the image is a mat file 00184 try { 00185 idx<T> m = load_matrix<T>(fname); 00186 if (m.order() > 3 || m.order() < 2) 00187 eblerror("image has to be 2D or 3D"); 00188 // channels are likely in dim 0 if size 1 or 3 00189 if (((m.dim(0) == 1) || (m.dim(0) == 3)) && (m.order() == 3)) 00190 m = m.shift_dim(0, 2); 00191 return m; 00192 } catch(eblexception &e) { 00193 e = e; // not a mat file, try regular image 00194 } 00195 return image_read<T>(fname); 00196 } 00197 00198 template<class T> 00199 idx<T> load_image(const string &fname) { 00200 return load_image<T>(fname.c_str()); 00201 } 00202 00204 // I/O: saving 00205 00206 template<class T> 00207 bool save_image_ppm(const string &fname, idx<T> &in) { 00208 return save_image_ppm(fname.c_str(), in); 00209 } 00210 00211 template<class T> 00212 bool save_image_ppm(const char *fname, idx<T> &in) { 00213 // check order 00214 // TODO: support grayscale 00215 if (in.order() != 3) { 00216 cerr << "error: image order (" << in.order() << " not supported." << endl; 00217 return false; 00218 } 00219 // save as ppm 00220 FILE *fp = fopen(fname, "wb"); 00221 if (!fp) { 00222 cerr << "error: failed to open file " << fname << endl; 00223 return false; 00224 } 00225 save_image_ppm(fp, in); 00226 fclose(fp); 00227 return true; 00228 } 00229 00230 template<class T> 00231 bool save_image_ppm(FILE *fp, idx<T> &in) { 00232 // check order 00233 // TODO: support grayscale 00234 if (in.order() != 3) { 00235 cerr << "error: image order (" << in.order() << " not supported." << endl; 00236 return false; 00237 } 00238 if (!fp) { 00239 cerr << "error: NULL fp " << endl; 00240 return false; 00241 } 00242 fprintf(fp,"P6 %d %d 255\n", (int) in.dim(1), (int) in.dim(0)); 00243 if (in.dim(2) == 3) { 00244 idx_bloop1(inn, in, T) { 00245 idx_bloop1(innn, inn, T) { 00246 fputc((ubyte) innn.get(0), fp); 00247 fputc((ubyte) innn.get(1), fp); 00248 fputc((ubyte) innn.get(2), fp); 00249 } 00250 } 00251 } else if (in.dim(2) == 1) { 00252 idx_bloop1(inn, in, T) { 00253 idx_bloop1(innn, inn, T) { 00254 fputc((ubyte) innn.get(0), fp); 00255 fputc((ubyte) innn.get(0), fp); 00256 fputc((ubyte) innn.get(0), fp); 00257 } 00258 } 00259 } else 00260 eblerror("Error saving image " << in << 00261 ", pixel dimension not supported"); 00262 fflush(fp); 00263 return true; 00264 } 00265 00266 template<class T> 00267 bool save_image_jpg(const string &fname, idx<T> &in) { 00268 return save_image(fname, in, "JPG"); 00269 } 00270 00271 template<class T> 00272 bool save_image(const string &fname, idx<T> &in, const char *format) { 00273 if (!strcmp(format, "mat")) { // save as idx 00274 return save_matrix(in, fname); 00275 } 00276 #ifdef __MAGICKPP__ 00277 // we are under any platform, convert is not available but Magick++ is 00278 try { 00279 Magick::Image im; 00280 idx<T> tmp = in;//.shift_dim(0, 1); 00281 idx<ubyte> tmp2(tmp.get_idxdim()); 00282 idx_copy(tmp, tmp2); 00283 switch (tmp2.dim(2)) { 00284 case 1: // grayscale 00285 im.read(tmp2.dim(1), tmp2.dim(0), "I", Magick::CharPixel, tmp2.idx_ptr()); 00286 im.type(Magick::GrayscaleType); 00287 break ; 00288 case 3: // RGB 00289 im.read(tmp2.dim(1), tmp2.dim(0), "RGB", Magick::CharPixel, tmp2.idx_ptr()); 00290 im.type(Magick::TrueColorType); 00291 break ; 00292 default: // unsupported 00293 eblerror("unsupported channels size for saving: " << tmp2); 00294 } 00295 im.write(fname); 00296 // TODO: handle grayscale? 00297 } catch(Magick::WarningCoder &warning) { 00298 // Process coder warning while loading file (e.g. TIFF warning) 00299 // Maybe the user will be interested in these warnings (or not). 00300 // If a warning is produced while loading an image, the image 00301 // can normally still be used (but not if the warning was about 00302 // something important!) 00303 eblthrow("Coder Warning: " << warning.what()); 00304 } catch(Magick::Warning &warning) { 00305 // Handle any other Magick++ warning. 00306 eblthrow("Warning: " << warning.what()); 00307 } catch(Magick::ErrorBlob &error) { 00308 // Process Magick++ file open error 00309 eblthrow("Error: " << error.what()); 00310 } catch(Magick::ErrorOption &error) { 00311 // Process Magick++ file open error 00312 eblthrow("Error: " << error.what()); 00313 } 00314 #else 00315 #if (defined(__IMAGEMAGICK__) && !defined(__NOIMAGEMAGICK__)) 00316 // we are under linux or mac and convert is available 00317 string cmd; 00318 cmd << IMAGEMAGICK_CONVERT << " PPM:- " << format << ":\"" << fname << "\""; 00319 #ifdef __WINDOWS__ 00320 FILE* fp = POPEN(cmd.c_str(), "wb"); 00321 #else 00322 FILE* fp = POPEN(cmd.c_str(), "w"); 00323 #endif 00324 if (!fp) { 00325 cerr << "conversion of image " << fname << " failed (errno: " 00326 << errno << ", " << strerror(errno) << ")"; 00327 return false; 00328 } 00329 try { 00330 // read pnm image 00331 save_image_ppm(fp, in); 00332 } catch (eblexception &err) { 00333 if (PCLOSE(fp) != 0) { 00334 cerr << "Warning: pclose failed (errno: " << errno << ")" << endl; 00335 } 00336 return false; 00337 } 00338 if (PCLOSE(fp) != 0) { 00339 cerr << "Warning: pclose failed (errno: " << errno << ")" << endl; 00340 return false; 00341 } 00342 #else 00343 // nor Magick++ nor convert are available, error 00344 eblerror("Nor ImageMagick's convert nor Magick++ are available, " 00345 << "please install"); 00346 #endif /* __IMAGEMAGICK__ */ 00347 #endif /* __MAGICK++__ */ 00348 return true; 00349 } 00350 00351 } // end namespace ebl 00352 00353 #endif /* IMAGE_HPP_ */