ThreeB 1.1
multispot5_jni.cc
Go to the documentation of this file.
00001 /*
00002     This file is part of B-cubed.
00003 
00004     Copyright (C) 2009, 2010, 2011, Edward Rosten and Susan Cox
00005 
00006     B-cubed is free software; you can redistribute it and/or
00007     modify it under the terms of the GNU Lesser General Public
00008     License as published by the Free Software Foundation; either
00009     version 3.0 of the License, or (at your option) any later version.
00010 
00011     This library is distributed in the hope that it will be useful,
00012     but WITHOUT ANY WARRANTY; without even the implied warranty of
00013     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014     Lesser General Public License for more details.
00015 
00016     You should have received a copy of the GNU General Public License     
00017     along with this program.  If not, see <http://www.gnu.org/licenses/>
00018 */
00019 
00020 #include <sstream>
00021 #include <algorithm>
00022 #include <cvd/image.h>
00023 #include <cvd/image_convert.h>
00024 
00025 #include "ThreeBRunner.h"
00026 #include "storm_imagery.h"
00027 #include "multispot5.h"
00028 #include "multispot5_place_choice.h"
00029 #include "utility.h"
00030 #include <gvars3/instances.h>
00031 
00032 #include <tag/printf.h>
00033 #undef make_tuple
00034 #include <tr1/tuple>
00035 
00036 using namespace std;
00037 using namespace std::tr1;
00038 using namespace CVD;
00039 using namespace GVars3;
00040 using namespace tag;
00041 using namespace TooN;
00042 
00043 
00044 /**
00045 3B User interface for the Java plugin.
00046 
00047 This particular UI ferries various messages between Java and C++
00048 via callbacks and polling.
00049 
00050 @ingroup gPlugin
00051 */
00052 class JNIUserInterface: public UserInterfaceCallback
00053 {
00054     private:
00055         JNIEnv *env;
00056         jobject ThreeBRunner_this;
00057         jmethodID send_message_string;
00058         jmethodID die;
00059         jmethodID should_stop;
00060         jmethodID send_new_points;
00061         int passes;
00062 
00063     public:
00064         JNIUserInterface(JNIEnv* env_, jobject jthis)
00065         :env(env_),ThreeBRunner_this(jthis)
00066         {
00067             jclass cls = env->GetObjectClass(jthis);
00068             
00069             send_message_string  = env->GetMethodID(cls, "send_message_string", "(Ljava/lang/String;)V");
00070             die  = env->GetMethodID(cls, "die", "(Ljava/lang/String;)V");
00071 
00072             should_stop  = env->GetMethodID(cls, "should_stop", "()Z");
00073 
00074             send_new_points = env->GetMethodID(cls, "send_new_points", "([F)V");
00075 
00076             passes = GV3::get<int>("main.passes");
00077         }
00078 
00079 
00080         virtual void per_spot(int iteration, int pass, int spot_num, int total_spots)
00081         {
00082             send_message(sPrintf("Iteration %i, optimizing  %4i%%", iteration*passes+pass, 100 *spot_num / total_spots));
00083         }
00084 
00085         virtual void per_modification(int iteration, int spot_num, int total_spots)
00086         {
00087             send_message(sPrintf("Iteration %i, modifying  %4i%%", iteration*passes+passes-1, 100 *spot_num / total_spots));
00088         }
00089 
00090         virtual void per_pass(int , int , const std::vector<TooN::Vector<4> >& spots)
00091         {
00092             //Copy data into the correct format
00093             vector<jfloat> pts_data;
00094             for(unsigned int i=0; i < spots.size(); i++)
00095             {
00096                 pts_data.push_back(spots[i][2]);
00097                 pts_data.push_back(spots[i][3]);
00098             }
00099             
00100             //Allocate a java array and copy data into it
00101             jfloatArray pts = env->NewFloatArray(pts_data.size());
00102             env->SetFloatArrayRegion(pts, 0, pts_data.size(), pts_data.data());
00103             
00104             //Make the call...
00105             jvalue pts_obj;
00106             pts_obj.l = pts;
00107 
00108             env->CallVoidMethod(ThreeBRunner_this, send_new_points, pts_obj);
00109             
00110             //Free the object
00111             env->DeleteLocalRef(pts);
00112         }
00113 
00114         virtual void perhaps_stop()
00115         {
00116             bool stop = env->CallBooleanMethod(ThreeBRunner_this, should_stop);
00117             if(stop)
00118                 throw UserIssuedStop();
00119         }
00120 
00121 
00122         void send_message(const string& s)
00123         {
00124             jvalue message_string;
00125             message_string.l = env->NewStringUTF(s.c_str());
00126             env->CallVoidMethod(ThreeBRunner_this, send_message_string, message_string);
00127             env->DeleteLocalRef(message_string.l);
00128         }
00129 
00130         void fatal(const string& s)
00131         {
00132             jvalue message_string;
00133             message_string.l = env->NewStringUTF(s.c_str());
00134             env->CallVoidMethod(ThreeBRunner_this, die, message_string);
00135             env->DeleteLocalRef(message_string.l);
00136         }
00137 };
00138 
00139 ///Get a local C++ copy of a java string.
00140 ///@ingroup gPlugin
00141 string get_string(JNIEnv *env, jstring js)
00142 {
00143     const char* str;
00144 
00145     //Covert the config into a string
00146     str = env->GetStringUTFChars(js, NULL);
00147 
00148     string stdstring(str);
00149     env->ReleaseStringUTFChars(js, str);
00150 
00151 
00152     return stdstring;
00153 }
00154 
00155 ///Get a local C++ copy of an image from a jbyteArray coming from the guts of ImageJ
00156 ///@ingroup gPlugin
00157 Image<jbyte> get_local_copy_of_image(JNIEnv* env, jbyteArray data, int rows, int cols)
00158 {
00159     //This takes a copy of the pixels (perhaps)
00160     jbyte* pix = env->GetByteArrayElements(data, NULL);
00161 
00162     BasicImage<jbyte> pix_im(pix, ImageRef(cols, rows));
00163 
00164     Image<jbyte> im;
00165     im.copy_from(pix_im);
00166     
00167     //This frees the pixels if copied, or releases a reference
00168     env->ReleaseByteArrayElements(data,pix, JNI_ABORT);
00169     
00170     return im;
00171 }
00172 
00173 ///Get a local C++ copy of an image from a jfloatArray coming from the guts of ImageJ
00174 ///@ingroup gPlugin
00175 Image<float> get_local_copy_of_image(JNIEnv* env, jfloatArray data, int rows, int cols)
00176 {
00177     //This takes a copy of the pixels (perhaps)
00178     float* pix = env->GetFloatArrayElements(data, NULL);
00179 
00180     BasicImage<float> pix_im(pix, ImageRef(cols, rows));
00181 
00182     Image<float> im;
00183     im.copy_from(pix_im);
00184     
00185     //This frees the pixels if copied, or releases a reference
00186     env->ReleaseFloatArrayElements(data,pix, JNI_ABORT);
00187     
00188     return im;
00189 }
00190 
00191 
00192 ///Run the 3B code.
00193 ///@ingroup gPlugin
00194 JNIEXPORT void JNICALL Java_ThreeBRunner_call
00195   (JNIEnv *env, jobject jthis, jstring cfg, jobjectArray images, jbyteArray mask_data, jint n_images, jint rows, jint cols, jstring file)
00196 {
00197     istringstream config(get_string(env, cfg));
00198     GUI.ParseStream(config);
00199 
00200     JNIUserInterface ui(env, jthis);
00201     ui.send_message("Initializing...");
00202     
00203     string filename = get_string(env, file);
00204 
00205     //Attmpt to open the file
00206     ofstream save_spots;
00207     save_spots.open(filename.c_str());
00208     int err = errno;
00209 
00210     if(!save_spots.good())
00211     {
00212         ui.fatal("failed to open " + filename + ": " + strerror(err));
00213         return;
00214     }
00215 
00216     vector<ImageRef> maskir;
00217     Image<double> maskd;
00218     {
00219         Image<jbyte> mask = get_local_copy_of_image(env, mask_data, rows, cols);
00220         maskd = convert_image(mask);
00221         for(ImageRef p(-1, 0); p.next(mask.size()); )
00222             if(mask[p])
00223                 maskir.push_back(p);
00224     }   
00225 
00226 
00227     vector<Image<float> > ims;
00228 
00229     for(int i=0; i < n_images; i++)
00230     {
00231         jfloatArray f = static_cast<jfloatArray>(env->GetObjectArrayElement(images, i));
00232         ims.push_back(preprocess_image(get_local_copy_of_image(env, f, rows, cols)));
00233         env->DeleteLocalRef(f);
00234     }
00235 
00236     double mean, variance;
00237     tie(mean, variance) = mean_and_variance(ims);
00238 
00239     for(unsigned int i=0; i < ims.size(); i++)
00240             transform(ims[i].begin(), ims[i].end(), ims[i].begin(), bind1st(multiplies<double>(), 1/ sqrt(variance)));
00241      
00242     tie(mean, variance) = mean_and_variance(ims);
00243 
00244     //A sanity check.
00245     cerr << "Rescaled:\n";
00246     cerr << "mean = " << mean << endl;
00247     cerr << "std  = " << sqrt(variance) << endl;
00248     cerr << "Version 1.1" << endl;
00249 
00250 
00251     auto_ptr<FitSpotsGraphics> gr = null_graphics();
00252 
00253     place_and_fit_spots(ims, maskir, maskd, save_spots, *gr, ui);
00254 }
00255