MPIopenvision.C

Go to the documentation of this file.
00001 /*!@file INVT/MPIopenvision.C  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/MPIopenvision.C $
00035 // $Id: MPIopenvision.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 <cmath>
00051 #include <fstream>
00052 #ifdef HAVE_MPI_H
00053 #include <mpi.h>
00054 #endif
00055 
00056 #define ITMAX 200
00057 #define FTOL 0.00000001f
00058 #define NBCOEFFS 144
00059 #define MASTER 0
00060 #define MSG_DATA 1000
00061 #define MSG_RESULT 2000
00062 #define PATH "/tmphpc-01/itti/openvision"
00063 #define NB_PIC 14
00064 #define NB_FILTERS 3
00065 
00066 #define NB_EVALS 1
00067 
00068 #define NB_PROC (NBCOEFFS * NB_EVALS + 1)
00069 
00070 
00071 int main(int argc, char **argv)
00072 {
00073 #ifndef HAVE_MPI_H
00074 
00075   LFATAL("<mpi.h> must be installed to use this program");
00076 
00077 #else
00078 
00079   // Set verbosity:
00080   int loglev = LOG_ERR;
00081   MYLOGVERB = loglev;
00082 
00083   // Number of coefficients:
00084   int n = 4;
00085   int m = n * n * NB_FILTERS * 3;
00086 
00087   // Initialize the MPI system and get the number of processes:
00088   int myrank, size;
00089   MPI_Init(&argc, &argv);
00090   MPI_Comm_size(MPI_COMM_WORLD, &size);
00091 
00092   // Check for proper number of processes:
00093   if(size < NB_PROC)
00094     {
00095       LERROR("*** Error: %d Processes needed. ***", NB_PROC);
00096       MPI_Finalize();
00097       return 1;
00098     }
00099 
00100   // Get the rank of the process:
00101   MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
00102 
00103   if (myrank == MASTER)
00104     {
00105       // ################ MASTER PROCESS ################
00106 
00107       // **************** INITIALIZATION ****************
00108 
00109       MPI_Status status;
00110 
00111       // Generate the starting point, directions and function value:
00112       float p[m];
00113       float xi[m][m];
00114       for(int i = 0; i < m; i++)
00115         {
00116           p[i] = 0.0f;
00117           for(int j = 0; j < m; j++)
00118             xi[j][i] = 0.0f;
00119           xi[i][i] = 1.0f;
00120         }
00121       p[0] = 0.1f;
00122       float fp = 10.0f;
00123 
00124       // **************** OPTIMIZATION ****************
00125 
00126       for (int iter = 0; ; iter++)
00127         {
00128           LERROR("### ITERATION %i ###", iter);
00129           int stop = 0;
00130           float del1 = 0.0f;
00131           float fp1 = fp;
00132           int ibig1 = 0;
00133           float p1[m];
00134           for (int part = 0; part < 2; part++)
00135             {
00136               // Sent data to slave processes:
00137               for (int i = 0; i < m; i++)
00138                 for (int mu = 1; mu <= NB_EVALS; mu++)
00139                   {
00140                     int proc = (i * NB_EVALS) + mu;
00141                     float pt[m];
00142                     for (int j = 0; j < m; j++)
00143                       if (part == 0)
00144                         pt[j] = p[j] + (mu * 0.1f * xi[j][i]);
00145                       else
00146                         pt[j] = p[j] - (mu * 0.1f * xi[j][i]);
00147                     MPI_Send(&stop, 1, MPI_INT, proc,
00148                              4 * iter + part,
00149                              MPI_COMM_WORLD);
00150                     MPI_Send(pt, m, MPI_FLOAT, proc,
00151                              MSG_DATA + 4 * iter + part,
00152                              MPI_COMM_WORLD);
00153                   }
00154               LERROR("*** PART %i : data sent to slaves.",
00155                      part + 1);
00156               // Receive results and keep the best:
00157               for (int i = 0; i < m; i++)
00158                 for (int mu = 1; mu <= NB_EVALS; mu++)
00159                   {
00160                     int proc = (i * NB_EVALS) + mu;
00161                     float fpt;
00162                     MPI_Recv(&fpt, 1, MPI_FLOAT, proc,
00163                              MSG_RESULT + 4 * iter + part,
00164                              MPI_COMM_WORLD, &status);
00165                     if (fp - fpt > del1)
00166                       {
00167                         del1 = fp - fpt;
00168                         ibig1 = i;
00169                         for (int j = 0; j < m; j++)
00170                           if (part == 0)
00171                             p1[j] = p[j] + (mu * 0.1f * xi[j][i]);
00172                           else
00173                             p1[j] = p[j] - (mu * 0.1f * xi[j][i]);
00174                         fp1 = fpt;
00175                       }
00176                   }
00177               LERROR("*** PART %i : result received from slaves.",
00178                      part + 1);
00179             }
00180           float del2 = 0.0f;
00181           float fp2 = fp1;
00182           float p2[m];
00183           int ibig2 = 0;
00184           for (int part = 0; part < 2; part++)
00185             {
00186               // Sent data to slave processes:
00187               for (int i = 0; i < m; i++)
00188                 for (int mu = 1; mu <= NB_EVALS; mu++)
00189                   {
00190                     int proc = (i * NB_EVALS) + mu;
00191                     float pt[m];
00192                     for (int j = 0; j < m; j++)
00193                           if (part == 0)
00194                             pt[j] = p1[j] + (mu * 0.1f * xi[j][i]);
00195                           else
00196                             pt[j] = p1[j] - (mu * 0.1f * xi[j][i]);
00197                     MPI_Send(&stop, 1, MPI_INT, proc,
00198                              4 * iter + 2 + part,
00199                              MPI_COMM_WORLD);
00200                     MPI_Send(pt, m, MPI_FLOAT, proc,
00201                              MSG_DATA + 4 * iter + 2 + part,
00202                              MPI_COMM_WORLD);
00203                   }
00204               LERROR("*** PART %i : data sent to slaves",
00205                      part + 3);
00206               // Receive results and keep the best:
00207               for (int i = 0; i < m; i++)
00208                 for (int mu = 1; mu <= NB_EVALS; mu++)
00209                   {
00210                     int proc = (i * NB_EVALS) + mu;
00211                     float fpt;
00212                     MPI_Recv(&fpt, 1, MPI_FLOAT, proc,
00213                              MSG_RESULT + 4 * iter + 2 + part,
00214                              MPI_COMM_WORLD, &status);
00215                     if (fp1 - fpt > del2)
00216                       {
00217                         del2 = fp1 - fpt;
00218                         ibig2 = i;
00219                         for (int j = 0; j < m; j++)
00220                           if (part == 0)
00221                             p2[j] = p1[j] + (mu * 0.1f * xi[j][i]);
00222                           else
00223                             p2[j] = p1[j] - (mu * 0.1f * xi[j][i]);
00224                         fp2 = fpt;
00225                       }
00226                   }
00227               LERROR("*** PART %i : result received from slaves.",
00228                      part + 3);
00229             }
00230 
00231           LERROR("old value = %f *** new value = %f.", fp, fp2);
00232 
00233           // Exit the loop if ITMAX is reach or if the decrease is too low:
00234           if (2.0 * fabs(fp - fp2) <= FTOL * (fabs(fp) + fabs(fp2)))
00235             {
00236               stop = 1;
00237               for (int i = 1; i < NB_PROC; i++)
00238                 {
00239                   MPI_Send(&stop, 1, MPI_INT, i,
00240                            4 * iter + 4, MPI_COMM_WORLD);
00241                 }
00242               LERROR("### Low decrease ! ###");
00243               MPI_Finalize();
00244               return 0;
00245             }
00246           if (iter == ITMAX)
00247             {
00248               stop = 1;
00249               for (int i = 1; i < NB_PROC; i++)
00250                 {
00251                   MPI_Send(&stop, 1, MPI_INT, i,
00252                            4 * iter + 4, MPI_COMM_WORLD);
00253                 }
00254               LERROR("### Maximum iterations exceeded ! ###");
00255               MPI_Finalize();
00256               return 0;
00257             }
00258 
00259           // Update data:
00260           float xit[m];
00261           float norm = 0;
00262           int ibig;
00263           if (del1 > del2)
00264             ibig = ibig1;
00265           else
00266             ibig = ibig2;
00267           for (int j = 0; j < m; j++)
00268             {
00269               xit[j] = p2[j] - p[j];
00270               norm += xit[j] * xit[j];
00271               p[j] = p2[j]; // Current position updated
00272             }
00273 
00274           const std::string filename =
00275             sformat("%s/results/step%03i.txt", PATH, iter);
00276           std::ofstream resultfile (filename.c_str());
00277           if (resultfile.is_open())
00278             {
00279               for (int j = 0; j < m; j++)
00280                 resultfile << p[j] << "\n";
00281               resultfile.close();
00282             }
00283 
00284           norm = sqrt(norm);
00285           for (int j = 0; j < m; j++)
00286             {
00287               xi[j][ibig] = xit[j] / norm; // Current directions updated
00288             }
00289           fp = fp2; // Current value updated
00290         }
00291     }
00292   else
00293     {
00294       // ################ SLAVES PROCESS ################
00295 
00296       // **************** INITIALIZATION ****************
00297 
00298       MPI_Status status;
00299 
00300       // Generate the haar transform matrix:
00301       Image<float> hmat(n, n, NO_INIT);
00302       for(int i = 0; i < n; i++)
00303         {
00304           hmat.setVal(i, 0, 1.0f);
00305         }
00306       for(int i = 0; i < n / 2; i++)
00307         {
00308           hmat.setVal(i, 1, 1.0f);
00309           hmat.setVal(i + n / 2, 1, -1.0f);
00310           hmat.setVal(2 * i, i + n / 2, 1.0f);
00311           hmat.setVal(2 * i + 1, i + n / 2, -1.0f);
00312         }
00313 
00314       // Load the input images and masks:
00315       ImageSet< PixRGB<byte> > input(NB_PIC);
00316       ImageSet<byte> mask(NB_PIC);
00317       for (int i = 0; i < NB_PIC; i++)
00318         {
00319           input[i] =
00320             Raster::ReadRGB(sformat("%s/pictures/PIC_%03i.PPM", PATH, i));
00321           mask[i] =
00322             Raster::ReadGray(sformat("%s/pictures/PIC_%03i.PGM", PATH, i));
00323         }
00324 
00325       LERROR("### SLAVE %i INITIALIZED SUCCESFULLY ! ###", myrank);
00326 
00327       // **************** OPTIMIZATION ****************
00328 
00329       for (int iter = 0; ; ++iter)
00330         {
00331           // Receive the stop message:
00332           int stop;
00333           MPI_Recv(&stop, 1, MPI_INT, MASTER,
00334                    iter, MPI_COMM_WORLD, &status);
00335           if (stop == 1)
00336             {
00337               MPI_Finalize();
00338               return 0;
00339             }
00340 
00341           // Receive data from master:
00342           float data[m];
00343           MPI_Recv(data, m, MPI_FLOAT, MASTER,
00344                    MSG_DATA + iter, MPI_COMM_WORLD, &status);
00345 
00346           // Convert data into filters:
00347           ImageSet<float> trans(NB_FILTERS * 3);
00348           for (int i = 0; i < NB_FILTERS * 3; i++)
00349             trans[i] = Image<float>(data + (n * n * i), n, n);
00350           ImageSet<float> filter(NB_FILTERS * 3);
00351           Dims filterdim(8, 8);
00352           for (int i = 0; i < NB_FILTERS * 3; i++)
00353             filter[i] = scaleBlock(matrixMult(hmat,
00354                                               matrixMult(trans[i],
00355                                                          transpose(hmat))),
00356                                    filterdim);
00357 
00358           // Compute the dot product of the filters:
00359           Image<float> prod1(8, 8, ZEROS);
00360           Image<float> prod2(8, 8, ZEROS);
00361           Image<float> prod3(8, 8, ZEROS);
00362           for (int i = 0; i < NB_FILTERS; i++)
00363             {
00364               prod1 += filter[3 * i] * filter[3 * i + 1];
00365               prod2 += filter[3 * i] * filter[3 * i + 2];
00366               prod3 += filter[3 * i + 2] * filter[3 * i + 1];
00367             }
00368           float dotprod = sum(prod1) + sum(prod2) + sum(prod3);
00369 
00370           // Init resut:
00371           float result = 0.0f;
00372 
00373           // Compute the error for each image:
00374           for (int p = 0; p < NB_PIC; p++)
00375             {
00376               // Instantiate a ModelManager:
00377               ModelManager manager("Open Attention Model");
00378 
00379               // Instantiate our various ModelComponents:
00380               nub::soft_ref<RawVisualCortex> vcx(new RawVisualCortex(manager));
00381               manager.addSubComponent(vcx);
00382 
00383               for (int i = 0; i < 1; i++)
00384                 {
00385                   // Create a channel attached to each filter:
00386                   nub::soft_ref<RGBConvolveChannel>
00387                     channel(new RGBConvolveChannel(manager));
00388                   channel->setDescriptiveName(sformat("RGBConvolve%d", i));
00389                   channel->setTagName(sformat("rgbconv%d", i));
00390 
00391                   // Assign the 3 filters to the channel:
00392                   channel->setFilters(filter[3 * i], filter[3 * i + 1],
00393                                       filter[3 * i + 2],
00394                                       CONV_BOUNDARY_ZERO);
00395 
00396                   // Attach the channel to our visual cortex:
00397                   vcx->addSubChan(channel);
00398                 }
00399 
00400               // Let's get all our ModelComponent instances started:
00401               manager.exportOptions(MC_RECURSE);
00402               manager.setModelParamString("UsingFPE", "false");
00403               manager.setModelParamString("TestMode", "true");
00404 
00405               // reduce amount of log messages:
00406               MYLOGVERB = loglev;
00407 
00408               manager.start();
00409 
00410               // Process the image through the visual cortex:
00411               vcx->input(InputFrame::fromRgb(&input[p]));
00412 
00413               // Get the resulting saliency map:
00414               Image<float> sm = vcx->getOutput();
00415 
00416               // Normalize the saliency map:
00417               inplaceNormalize(sm, 0.0f, 255.0f);
00418               Image<byte> smb = sm;
00419 
00420               // Blur and resize the binary mask:
00421               Dims smbdim = smb.getDims();
00422               Image<byte> blur_mask = binaryReverse(chamfer34(mask[p],
00423                                                               (byte) 255),
00424                                                     (byte) 255);
00425               inplaceLowThresh(blur_mask, (byte) 200);
00426               Image<byte> mask_in = scaleBlock(blur_mask, smbdim);
00427               Image<byte> mask_out = binaryReverse(mask_in, (byte) 255);
00428 
00429               // Weight the saliency map using the in and out masks:
00430               Image<float> smb_in = (mask_in * (1.0f / 255.0f)) * smb;
00431               Image<float> smb_out = (mask_out * (1.0f / 255.0f)) * smb;
00432 
00433               // Get the max_in and max_out values:
00434               float max_in, max_out, min;
00435               getMinMax(smb_in, min, max_in);
00436               getMinMax(smb_out, min, max_out);
00437 
00438               // Compute the error:
00439               float detect_coeff = 1.0f - ((max_in - max_out) / 255.0f);
00440               result += detect_coeff * detect_coeff;
00441 
00442               // Stop all our ModelComponents
00443               manager.stop();
00444             }
00445 
00446           // Send the result to the master :
00447           result /= NB_PIC;
00448           result += fabs(dotprod) * 0.001f;
00449           MPI_Send(&result, 1, MPI_FLOAT, MASTER,
00450                    MSG_RESULT + iter, MPI_COMM_WORLD);
00451         }
00452     }
00453 
00454 #endif // HAVE_MPI_H
00455 
00456 }
00457 
00458 // ######################################################################
00459 /* So things look consistent in everyone's emacs... */
00460 /* Local Variables: */
00461 /* indent-tabs-mode: nil */
00462 /* End: */
Generated on Sun May 8 08:05:16 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3