00001 /*!@file INVT/MPIopenvision2.C another MPI version of openvision.C */ 00002 00003 // //////////////////////////////////////////////////////////////////// // 00004 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2001 by the // 00005 // University of Southern California (USC) and the iLab at USC. // 00006 // See http://iLab.usc.edu for information about this project. // 00007 // //////////////////////////////////////////////////////////////////// // 00008 // Major portions of the iLab Neuromorphic Vision Toolkit are protected // 00009 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency // 00010 // in Visual Environments, and Applications'' by Christof Koch and // 00011 // Laurent Itti, California Institute of Technology, 2001 (patent // 00012 // pending; application number 09/912,225 filed July 23, 2001; see // 00013 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status). // 00014 // //////////////////////////////////////////////////////////////////// // 00015 // This file is part of the iLab Neuromorphic Vision C++ Toolkit. // 00016 // // 00017 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can // 00018 // redistribute it and/or modify it under the terms of the GNU General // 00019 // Public License as published by the Free Software Foundation; either // 00020 // version 2 of the License, or (at your option) any later version. // 00021 // // 00022 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope // 00023 // that it will be useful, but WITHOUT ANY WARRANTY; without even the // 00024 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // 00025 // PURPOSE. See the GNU General Public License for more details. // 00026 // // 00027 // You should have received a copy of the GNU General Public License // 00028 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write // 00029 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, // 00030 // Boston, MA 02111-1307 USA. // 00031 // //////////////////////////////////////////////////////////////////// // 00032 // 00033 // Primary maintainer for this file: Laurent Itti <itti@usc.edu> 00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/INVT/MPIopenvision2.C $ 00035 // $Id: MPIopenvision2.C 10845 2009-02-13 08:49:12Z itti $ 00036 // 00037 00038 #include "Channels/RGBConvolveChannel.H" 00039 #include "Component/ModelManager.H" 00040 #include "Image/MathOps.H" 00041 #include "Image/MatrixOps.H" 00042 #include "Image/Pixels.H" 00043 #include "Image/Transforms.H" 00044 #include "Media/FrameSeries.H" 00045 #include "Neuro/NeuroOpts.H" 00046 #include "Channels/RawVisualCortex.H" 00047 #include "Raster/Raster.H" 00048 #include "Util/sformat.H" 00049 00050 #include <fstream> 00051 #ifdef HAVE_MPI_H 00052 #include <mpi.h> 00053 #endif 00054 00055 #define ITMAX 200 00056 #define FTOL 0.000001f 00057 #define MASTER 0 00058 #define MSG_STOP 10 00059 #define MSG_PIC 1 00060 #define MSG_DATA 2 00061 #define MSG_RESULT 200 00062 #define PATH "/tmphpc-01/itti/openvision" 00063 #define INPUTFILE "/tmphpc-01/itti/openvision/start.txt" 00064 #define NB_PICS 14 00065 #define NB_FILTERS 3 00066 #define NCOEFFS 8 00067 #define MCOEFFS NCOEFFS * NCOEFFS * NB_FILTERS * 3 00068 #define NB_EVALS 10 00069 #define NB_WAVES 5 00070 #define NB_PROCS NB_PICS * NB_EVALS * 2 + 1 00071 00072 int main(int argc, char **argv) 00073 { 00074 #ifndef HAVE_MPI_H 00075 00076 LFATAL("<mpi.h> must be installed to use this program"); 00077 00078 #else 00079 00080 // Set verbosity: 00081 int loglev = LOG_ERR; 00082 MYLOGVERB = loglev; 00083 00084 // Number of coefficients: 00085 int n = NCOEFFS; 00086 int m = MCOEFFS; 00087 00088 // Initialize the MPI system and get the number of processes: 00089 int myrank, size; 00090 MPI_Init(&argc, &argv); 00091 MPI_Comm_size(MPI_COMM_WORLD, &size); 00092 00093 // Check for proper number of processes: 00094 if(size < NB_PROCS) 00095 { 00096 LERROR("*** Error: %i Processes needed. ***", NB_PROCS); 00097 MPI_Finalize(); 00098 return 1; 00099 } 00100 00101 // Get the rank of the process: 00102 MPI_Comm_rank(MPI_COMM_WORLD, &myrank); 00103 00104 if (myrank == MASTER) 00105 { 00106 // ################ MASTER PROCESS ################ 00107 00108 // **************** INITIALIZATION **************** 00109 00110 MPI_Status status; 00111 00112 // Load start coefficients: 00113 float p[m]; 00114 std::ifstream inputfile (INPUTFILE); 00115 if (inputfile.is_open()) 00116 { 00117 for (int j = 0; j < m; j++) 00118 inputfile >> p[j]; 00119 inputfile.close(); 00120 } 00121 else 00122 { 00123 LERROR("*** Cannot open input file !"); 00124 return 1; 00125 } 00126 00127 // Generate the starting point, directions and function value: 00128 float xi[m][m]; 00129 for(int i = 0; i < m; i++) 00130 { 00131 for(int j = 0; j < m; j++) 00132 xi[j][i] = 0.0f; 00133 xi[i][i] = 1.0f; 00134 } 00135 float fp = 10.0f; 00136 00137 // **************** OPTIMIZATION **************** 00138 00139 for (int iter = 0; ; iter++) 00140 { 00141 LERROR("### ITERATION %i ###", iter); 00142 00143 int stop = 0; 00144 float del = 0.0f; 00145 int ibig = 0; 00146 float fstart = fp; 00147 float start[m]; 00148 for (int i = 0; i < m; i++) 00149 start[m] = p[m]; 00150 float fpt = fp; 00151 int mubig = 0; 00152 00153 // Loop over all directions: 00154 for (int i = 0; i < m; i++) 00155 { 00156 mubig = 0; 00157 for (int wave = 0; wave < NB_WAVES; wave++) 00158 { 00159 int muplus = NB_EVALS * wave; 00160 // Send data to slaves: 00161 for (int part = 0; part < 2; part++) 00162 for (int mu = 1; mu <= NB_EVALS; mu++) 00163 { 00164 int mu2 = (1 - 2 * part) * (mu + muplus); 00165 float ptry[m]; 00166 for (int j = 0; j < m; j++) 00167 ptry[j] = p[j] + (mu2 * 0.02f * xi[j][i]); 00168 for (int pic = 0; pic < NB_PICS; pic++) 00169 { 00170 int proc = (NB_EVALS * NB_PICS * part); 00171 proc += (NB_PICS * (mu - 1)) + pic + 1; 00172 MPI_Send(&stop, 1, MPI_INT, proc, 00173 MSG_STOP, MPI_COMM_WORLD); 00174 MPI_Send(&pic, 1, MPI_INT, proc, 00175 MSG_PIC, MPI_COMM_WORLD); 00176 MPI_Send(ptry, m, MPI_FLOAT, proc, 00177 MSG_DATA, MPI_COMM_WORLD); 00178 00179 } 00180 } 00181 LERROR("*** Data sent to slaves"); 00182 00183 // Receive result from slaves and keep best decrease: 00184 for (int part = 0; part < 2; part++) 00185 for (int mu = 1; mu <= NB_EVALS; mu++) 00186 { 00187 float fptry = 0.0f; 00188 for (int pic = 0; pic < NB_PICS; pic++) 00189 { 00190 float value; 00191 int proc = (NB_EVALS * NB_PICS * part); 00192 proc += (NB_PICS * (mu - 1)) + pic + 1; 00193 MPI_Recv(&value, 1, MPI_FLOAT, proc, 00194 MSG_RESULT, MPI_COMM_WORLD, 00195 &status); 00196 fptry += value; 00197 } 00198 fptry /= NB_PICS; 00199 if (fptry < fpt) 00200 { 00201 fpt = fptry; 00202 mubig = (1 - 2 * part) * (mu + muplus); 00203 } 00204 } 00205 } 00206 00207 LERROR("*** Result received"); 00208 // Keep the greatest decrease: 00209 if (fp - fpt > del) 00210 { 00211 del = fp - fpt; 00212 ibig = i; 00213 } 00214 fp = fpt; 00215 for (int j = 0; j < m; j++) 00216 p[j] += mubig * 0.02f * xi[j][i]; 00217 00218 LERROR("*** Direction %i : mu = %i", i, mubig); 00219 LERROR("*** New value : %f", fp); 00220 00221 // float maxcoeff1 = 0; 00222 // float maxcoeff2 = 0; 00223 // float maxcoeff3 = 0; 00224 // for (int j = 0; j < m / 3; j++) 00225 // { 00226 // if (fabs(p[j]) > maxcoeff1) 00227 // maxcoeff1 = fabs(p[j]); 00228 // if (fabs(p[j + m / 3]) > maxcoeff2) 00229 // maxcoeff2 = fabs(p[j + m / 3]); 00230 // if (fabs(p[j + 2 * m / 3]) > maxcoeff3) 00231 // maxcoeff3 = fabs(p[j + 2 * m / 3]); 00232 // } 00233 // for (int j = 0; j < m / 3; j++) 00234 // { 00235 // p[j] /= maxcoeff1; 00236 // p[j + m / 3] /= maxcoeff2; 00237 // p[j + 2 * m / 3] /= maxcoeff3; 00238 // } 00239 } 00240 00241 LERROR("### Total decrease for iteration : %f", fstart - fp); 00242 00243 // Save current coefficients: 00244 const std::string filename = 00245 sformat("%s/results/step%03i.txt", PATH, iter); 00246 std::ofstream resultfile (filename.c_str()); 00247 if (resultfile.is_open()) 00248 { 00249 for (int j = 0; j < m; j++) 00250 resultfile << p[j] << "\n"; 00251 resultfile.close(); 00252 } 00253 LERROR("### Current result saved in %s", filename.c_str()); 00254 00255 // Exit the loop if ITMAX is reach or if the decrease is too low: 00256 if (2.0 * fabs(fstart - fp) <= FTOL * (fabs(fstart) + fabs(fp))) 00257 { 00258 stop = 1; 00259 for (int i = 1; i < NB_PROCS; i++) 00260 MPI_Send(&stop, 1, MPI_INT, i, 00261 MSG_STOP, MPI_COMM_WORLD); 00262 LERROR("### Low decrease ! ###"); 00263 sleep(10); 00264 // MPI_Finalize(); 00265 return 0; 00266 } 00267 if (iter == ITMAX) 00268 { 00269 stop = 1; 00270 for (int i = 1; i < NB_PROCS; i++) 00271 MPI_Send(&stop, 1, MPI_INT, i, 00272 MSG_STOP, MPI_COMM_WORLD); 00273 LERROR("### Maximum iterations exceeded ! ###"); 00274 sleep(10); 00275 // MPI_Finalize(); 00276 return 1; 00277 } 00278 00279 // Update data: 00280 float xit[m]; 00281 float norm = 0; 00282 for (int j = 0; j < m; j++) 00283 { 00284 xit[j] = p[j] - start[j]; 00285 norm += xit[j] * xit[j]; 00286 } 00287 norm = sqrt(norm); 00288 for (int j = 0; j < m; j++) 00289 { 00290 xi[j][ibig] = xit[j] / norm; 00291 } 00292 } 00293 } 00294 else 00295 { 00296 // ################ SLAVES PROCESS ################ 00297 00298 // **************** INITIALIZATION **************** 00299 00300 MPI_Status status; 00301 00302 // Generate the haar transform matrix: 00303 Image<float> hmat(n, n, ZEROS); 00304 for(int i = 0; i < n; i++) 00305 { 00306 hmat.setVal(i, 0, 1.0f); 00307 } 00308 for(int i = 0; i < n / 2; i++) 00309 { 00310 hmat.setVal(i, 1, 1.0f); 00311 hmat.setVal(i + n / 2, 1, -1.0f); 00312 if (i - 2 < 0) 00313 { 00314 hmat.setVal(i, 2, 1.0f); 00315 hmat.setVal(i + 2, 2, -1.0f); 00316 } 00317 else 00318 { 00319 hmat.setVal(i + 2, 3, 1.0f); 00320 hmat.setVal(i + 4, 3, -1.0f); 00321 } 00322 hmat.setVal(2 * i, i + n / 2, 1.0f); 00323 hmat.setVal(2 * i + 1, i + n / 2, -1.0f); 00324 } 00325 00326 // Load the input images and masks: 00327 ImageSet< PixRGB<byte> > input(NB_PICS); 00328 ImageSet<byte> mask(NB_PICS); 00329 for (int i = 0; i < NB_PICS; i++) 00330 { 00331 input[i] = 00332 Raster::ReadRGB(sformat("%s/pictures/PIC_%03i.PPM", PATH, i)); 00333 mask[i] = 00334 Raster::ReadGray(sformat("%s/pictures/PIC_%03i.PGM", PATH, i)); 00335 } 00336 00337 LERROR("### SLAVE %i INITIALIZED SUCCESFULLY ! ###", myrank); 00338 00339 // **************** OPTIMIZATION **************** 00340 00341 for (int iter = 0; ; ++iter) 00342 { 00343 // Receive the stop message: 00344 int stop; 00345 MPI_Recv(&stop, 1, MPI_INT, MASTER, 00346 MSG_STOP, MPI_COMM_WORLD, &status); 00347 if (stop == 1) 00348 { 00349 // MPI_Finalize(); 00350 return 0; 00351 } 00352 00353 // Receive data from master: 00354 int pic; 00355 MPI_Recv(&pic, 1, MPI_INT, MASTER, 00356 MSG_PIC, MPI_COMM_WORLD, &status); 00357 float data[m]; 00358 MPI_Recv(data, m, MPI_FLOAT, MASTER, 00359 MSG_DATA, MPI_COMM_WORLD, &status); 00360 00361 // Convert data into filters: 00362 ImageSet<float> trans(NB_FILTERS * 3); 00363 for (int i = 0; i < NB_FILTERS * 3; i++) 00364 trans[i] = Image<float>(data + (n * n * i), n, n); 00365 ImageSet<float> filter(NB_FILTERS * 3); 00366 for (int i = 0; i < NB_FILTERS * 3; i++) 00367 filter[i] = matrixMult(transpose(hmat), 00368 matrixMult(trans[i], hmat)); 00369 00370 // Compute the dot product of the filters: 00371 Image<float> prod1(8, 8, ZEROS); 00372 Image<float> prod2(8, 8, ZEROS); 00373 Image<float> prod3(8, 8, ZEROS); 00374 for (int i = 0; i < NB_FILTERS; i++) 00375 { 00376 prod1 += filter[3 * i] * filter[3 * i + 1]; 00377 prod2 += filter[3 * i] * filter[3 * i + 2]; 00378 prod3 += filter[3 * i + 2] * filter[3 * i + 1]; 00379 } 00380 float dotprod = sum(prod1) + sum(prod2) + sum(prod3); 00381 00382 // Instantiate a ModelManager: 00383 ModelManager manager("Open Attention Model"); 00384 00385 // Instantiate our various ModelComponents: 00386 nub::soft_ref<RawVisualCortex> vcx(new RawVisualCortex(manager)); 00387 manager.addSubComponent(vcx); 00388 00389 for (int i = 0; i < NB_FILTERS; i++) 00390 { 00391 // Create a channel attached to each filter: 00392 nub::soft_ref<RGBConvolveChannel> 00393 channel(new RGBConvolveChannel(manager)); 00394 channel->setDescriptiveName(sformat("RGBConvolve%d", i)); 00395 channel->setTagName(sformat("rgbconv%d", i)); 00396 00397 // Assign the 3 filters to the channel: 00398 channel->setFilters(filter[3 * i], filter[3 * i + 1], 00399 filter[3 * i + 2], 00400 CONV_BOUNDARY_ZERO); 00401 00402 // Attach the channel to our visual cortex: 00403 vcx->addSubChan(channel); 00404 } 00405 00406 // Let's get all our ModelComponent instances started: 00407 manager.exportOptions(MC_RECURSE); 00408 manager.setModelParamString("UsingFPE", "false"); 00409 manager.setModelParamString("TestMode", "true"); 00410 00411 // reduce amount of log messages: 00412 MYLOGVERB = loglev; 00413 00414 manager.start(); 00415 00416 // Process the image through the visual cortex: 00417 vcx->input(InputFrame::fromRgb(&input[pic])); 00418 00419 // Get the resulting saliency map: 00420 Image<float> sm = vcx->getOutput(); 00421 00422 // Normalize the saliency map: 00423 inplaceNormalize(sm, 0.0f, 255.0f); 00424 Image<byte> smb = sm; 00425 00426 // Blur and resize the binary mask: 00427 Dims smbdim = smb.getDims(); 00428 Image<byte> blur_mask = binaryReverse(chamfer34(mask[pic], 00429 (byte) 255), 00430 (byte) 255); 00431 inplaceLowThresh(blur_mask, (byte) 200); 00432 Image<byte> mask_in = scaleBlock(blur_mask, smbdim); 00433 Image<byte> mask_out = binaryReverse(mask_in, (byte) 255); 00434 00435 // Weight the saliency map using the in and out masks: 00436 Image<float> smb_in = (mask_in * (1.0f / 255.0f)) * smb; 00437 Image<float> smb_out = (mask_out * (1.0f / 255.0f)) * smb; 00438 00439 // Get the max_in and max_out values: 00440 float max_in, max_out, min; 00441 getMinMax(smb_in, min, max_in); 00442 getMinMax(smb_out, min, max_out); 00443 00444 // Compute the error: 00445 float error = 1.0f - ((max_in - max_out) / 255.0f); 00446 float result = error * error + 0.001f * fabs(dotprod); 00447 00448 // Stop all our ModelComponents 00449 manager.stop(); 00450 00451 // Send the result to the master : 00452 MPI_Send(&result, 1, MPI_FLOAT, MASTER, 00453 MSG_RESULT, MPI_COMM_WORLD); 00454 } 00455 } 00456 00457 #endif // HAVE_MPI_H 00458 00459 } 00460 00461 // ###################################################################### 00462 /* So things look consistent in everyone's emacs... */ 00463 /* Local Variables: */ 00464 /* indent-tabs-mode: nil */ 00465 /* End: */ 00466