contrib/brl/bseg/brip/brip_vil_float_ops.h
Go to the documentation of this file.
00001 // This is brl/bseg/brip/brip_vil_float_ops.h
00002 #ifndef brip_vil_float_ops_h_
00003 #define brip_vil_float_ops_h_
00004 //-----------------------------------------------------------------------------
00005 //:
00006 // \file
00007 // \author J.L. Mundy
00008 // \brief operations on image_view<float> operands
00009 //
00010 // These methods are similar to the VanDuc gevd_float_ops methods. However,
00011 // they use vil_image_view<float> buffers rather than the old bufferxy
00012 // structure. The purpose is to provide efficient foundational
00013 // segmentation routines. They are not meant to be generic.
00014 //
00015 // \verbatim
00016 //  Modifications
00017 //   Feb 15 2003 Initial version
00018 //   Jan 24 2004 Renamed to brip_vil_float_ops, to support moving from vil1 to vil
00019 //   Dec 11 2011 - Peter Vanroose - replaced all unsigned char by vxl_byte
00020 //                                  (before there was a mix of the two)
00021 //                                  and all unsigned short by vxl_uint_16
00022 // \endverbatim
00023 //
00024 //-----------------------------------------------------------------------------
00025 #include <vcl_vector.h>
00026 #include <vcl_complex.h>
00027 #include <vcl_cassert.h>
00028 #include <vnl/vnl_matrix.h>
00029 #include <vbl/vbl_array_2d.h>
00030 #include <vgl/vgl_box_2d.h>
00031 #include <vgl/vgl_polygon.h>
00032 #include <vgl/algo/vgl_h_matrix_2d.h>
00033 #include <vil/vil_image_resource.h>
00034 #include <vil/vil_image_view.h>
00035 #include <vil/vil_math.h>
00036 #include <vil/vil_rgb.h>
00037 #include <vsol/vsol_box_2d_sptr.h>
00038 #include <brip/brip_roi_sptr.h>
00039 #include <vxl_config.h> // for vxl_byte & vxl_uint_16
00040 
00041 class brip_vil_float_ops
00042 {
00043  public:
00044   ~brip_vil_float_ops() {}
00045 
00046   //: convolves with the specified kernel
00047   static vil_image_view<float>
00048     convolve(vil_image_view<float> const& input,
00049              vbl_array_2d<float> const& kernel);
00050 
00051   //: helper to determine processing border required by Gaussian smoothing
00052   static unsigned gaussian_radius(const double sigma, const double fuzz=0.02);
00053 
00054   //: convolves with a Gaussian kernel
00055   static vil_image_view<float> gaussian(vil_image_view<float> const& input,
00056                                         float sigma,
00057                                         float fill = 0.0f);
00058   //: computes absolute value
00059   static vil_image_view<float>
00060     absolute_value(vil_image_view<float> const& input);
00061 
00062 #ifdef VIL_CONVOLVE_WITH_MASK_EXISTS // TODO
00063   //: convolves with a Gaussian kernel and for a given mask
00064   static vil_image_view<float> gaussian(vil_image_view<float> const& input,
00065                                         float sigma,
00066                                         vil_image_view<float> mask);
00067 #endif
00068 
00069   //: non-maximum suppression on a NxN neighborhood, with sub-pixel location
00070   static void non_maximum_suppression(vil_image_view<float> const& input,
00071                                       int n, float thresh,
00072                                       vcl_vector<float>& x_pos,
00073                                       vcl_vector<float>& y_pos,
00074                                       vcl_vector<float>& value);
00075 
00076   //: downsamples the input using the Bert-Adelson algorithm
00077   static vil_image_view<float>
00078     half_resolution(vil_image_view<float> const& input,
00079                     float filter_coef=0.359375f);
00080 
00081   //: interpolates the input using the Bert-Adelson algorithm
00082   static vil_image_view<float>
00083     double_resolution(vil_image_view<float> const& input,
00084                       float filter_coef=0.6f);
00085 
00086   //: sets values greater than \p thresh to specified \p level and the rest to zero
00087   static vil_image_view<float>
00088     threshold(vil_image_view<float> const & image,
00089               const float thresh, const float level = 255.0f);
00090 
00091   template <class T_from,class T_to>
00092   static void normalize_to_interval(const vil_image_view<T_from>& img_inp,
00093                                     vil_image_view<T_to>& img_out,
00094                                     float min,
00095                                     float max);
00096 
00097   //: sets absolute values greater than \p thresh to specified \p level
00098   static vil_image_view<float>
00099     abs_clip_to_level(vil_image_view<float> const & image,
00100                       const float thresh, const float level = 0.0f);
00101 
00102   //: Returns the gradient using a 3x3 kernel
00103   // \verbatim
00104   //         1  |-1  0  1|         1  |-1 -1 -1|
00105   //   Ix = --- |-1  0  1|   Iy = --- | 0  0  0|
00106   //         6  |-1  0  1|         6  | 1  1  1|
00107   // \endverbatim
00108   // Larger masks are computed by pre-convolving with a Gaussian
00109   static void gradient_3x3(vil_image_view<float> const& input,
00110                            vil_image_view<float>& grad_x,
00111                            vil_image_view<float>& grad_y);
00112 
00113   //: Returns the gradient magnitude using a 3x3 kernel
00114   static void gradient_mag_3x3(vil_image_view<float> const& input,
00115                                vil_image_view<float>& mag);
00116 
00117   //: Returns the gradient and its magnitude, using a 3x3 kernel
00118   static void gradient_mag_comp_3x3(vil_image_view<float> const& input,
00119                                     vil_image_view<float>& mag,
00120                                     vil_image_view<float>& grad_x,
00121                                     vil_image_view<float>& grad_y);
00122 
00123   //: Returns the Hessian using a 3x3 kernel
00124   // \verbatim
00125   //          1 | 1  -2  1|          1 |  1  1  1|         1  | 1  0 -1|
00126   //   Ixx = ---| 1  -2  1|   Iyy = ---| -2 -2 -2|  Ixy = --- | 0  0  0|
00127   //          3 | 1  -2  1|          3 |  1  1  1|         4  |-1  0  1|
00128   // \endverbatim
00129   // Larger masks are computed by pre-convolving with a Gaussian
00130   static void hessian_3x3(vil_image_view<float> const& input,
00131                           vil_image_view<float>& Ixx,
00132                           vil_image_view<float>& Ixy,
00133                           vil_image_view<float>& Iyy);
00134 
00135   static vil_image_view<float>
00136     beaudet(vil_image_view<float> const& Ixx,
00137             vil_image_view<float> const& Ixy,
00138             vil_image_view<float> const& Iyy,
00139             bool determinant = true);
00140 
00141   //:
00142   //  \p theta must be given in degrees.
00143   //  Scale invariant means that the response is independent of the
00144   //  \a sigma_y of the unrotated derivative operator, i.e. the direction
00145   //  of the derivative
00146   static void extrema_kernel_mask(float lambda0, float lambda1, float theta,
00147                                   vbl_array_2d<float>& kernel,
00148                                   vbl_array_2d<bool>& mask,
00149                                   float cutoff_percentage = 0.01f,
00150                                   bool scale_invariant = false);
00151 
00152   //: Compute the standard deviation of an operator response, given the image intensity standard deviation at each pixel
00153   static  vil_image_view<float>
00154     std_dev_operator(vil_image_view<float> const& sd_image,
00155                      vbl_array_2d<float> const& kernel);
00156 
00157   //: Compute the standard deviation of an operator response, given the image intensity standard deviation at each pixel
00158   //  Uses a modified formula to compute std_dev
00159   static vil_image_view<float>
00160     std_dev_operator_method2(vil_image_view<float> const& sd_image,
00161                              vbl_array_2d<float> const& kernel);
00162 
00163   //: a helper function for the extrema method: reverts angle to the range [-90, 90]
00164   static float extrema_revert_angle(float angle);
00165 
00166 
00167   //: Find anisotropic intensity extrema (Gaussian 2nd derivative). Theta is in degrees
00168   //  The effect of bright, mag_only and signed response are as follows:
00169   //  bright  mag_only signed_response        result
00170   // ------------------------------------------------
00171   //  false    false      false          dark extrema response
00172   //  false    false      true           signed output(full range)
00173   //  false    true       false          absolute mag output
00174   //  false    true       true           invalid
00175   //  true     false      false          bright extrema output
00176   //  true     false      true           signed output(full range)
00177   //  true     true       false          absolute mag output
00178   //  true     true       true           invalid
00179   //
00180 
00181   static vil_image_view<float> extrema(vil_image_view<float> const& input,
00182                                        float lambda0, float lambda1,
00183                                        float theta, bool bright = true,
00184                                        bool mag_only = false,
00185                                        bool output_response_mask = true,
00186                                        bool signed_response = false,
00187                                        bool scale_invariant = false,
00188                                        bool non_max_suppress = true,
00189                                        float cutoff_per = 0.01f);
00190 
00191   //: Find anisotropic intensity extrema at a range of orientations and return the maximal response at the best orientation.
00192   // \p theta_interval is in degrees
00193   //  If \p lambda0 == \p lambda1 then reduces to the normal extrema operator
00194   static vil_image_view<float> extrema_rotational(vil_image_view<float> const& input,
00195                                                   float lambda0, float lambda1,
00196                                                   float theta_interval,
00197                                                   bool bright = true,
00198                                                   bool mag_only = false,
00199                                                   bool signed_response = false,
00200                                                   bool scale_invariant = false,
00201                                                   bool non_max_suppress = true,
00202                                                   float cutoff_per = 0.01f);
00203 
00204   //: Compute the inscribed rectangle in an ellipse with largest $(1+h)(1+w)$.
00205   //  Needed for fast non-maximal suppression.
00206   //  \p theta is in degrees.
00207   static void max_inscribed_rect(float lambda0, float lambda1, float theta,
00208                                  float& u_rect, float& v_rect);
00209 
00210   //: Find intensity extrema using kernel decomposition.
00211   //  \p theta is in degrees.
00212   //  Image rotation is applied then separated u, v kernels produce the response.
00213   static vil_image_view<float> fast_extrema(vil_image_view<float> const& input,
00214                                             float lambda0, float lambda1,
00215                                             float theta, bool bright = true,
00216                                             bool mag_only = false,
00217                                             bool output_response_mask = true,
00218                                             bool signed_response = false,
00219                                             bool scale_invariant = false,
00220                                             bool non_max_suppress = true,
00221                                             float cutoff= 0.01f);
00222 
00223 
00224   static vil_image_view<float>& resp,
00225     fast_extrema_rotational(vil_image_view<float> const& input,
00226                             float lambda0, float lambda1,
00227                             float theta_interval,
00228                             bool bright =false,
00229                             bool mag_only = false,
00230                             bool signed_response =true,
00231                             bool scale_invariant = true,
00232                             bool non_max_suppress = false,
00233                             float cutoff=0.01f);
00234 
00235   //: Ix.Ix-transpose gradient matrix elements for an NxN region ($N = 2n+1$)
00236   // That is,
00237   // \verbatim
00238   //                        _                           _
00239   //                       | (dI/dx)^2    (dI/dx)(dI/dy) |
00240   //                       |                             |
00241   //  A = Sum(neighborhood)|                             |
00242   //                       |(dI/dx)(dI/dy)   (dI/dx)^2   |
00243   //                       |_                           _|
00244   // \endverbatim
00245   // over a $2n+1 ~\times~ 2n+1$ neighborhood.
00246 
00247   static void grad_matrix_NxN(vil_image_view<float> const& input, unsigned n,
00248                               vil_image_view<float>& IxIx,
00249                               vil_image_view<float>& IxIy,
00250                               vil_image_view<float>& IyIy);
00251 
00252   //: Tr(IxIx.transpose) for a NxN region ($N = 2n+1$)
00253   static  vil_image_view<float>
00254     trace_grad_matrix_NxN(vil_image_view<float> const& input, unsigned n);
00255 
00256   //: Computes the Harris corner measure
00257   static vil_image_view<float> harris(vil_image_view<float> const& IxIx,
00258                                       vil_image_view<float> const& IxIy,
00259                                       vil_image_view<float> const& IyIy,
00260                                       double scale=0.04);
00261 
00262   //: Computes the conditioning of the $2n+1 ~\times~ 2n+1$ gradient neighborhood
00263   // Compute the sqrt of the product of the eigenvalues of the
00264   // gradient matrix over a 2n+1 x 2n+1 neighborhood
00265   // That is,
00266   // \verbatim
00267   //                        _                           _
00268   //                       | (dI/dx)^2    (dI/dx)(dI/dy) |
00269   //                       |                             |
00270   //  A = Sum(neighborhood)|                             |
00271   //                       |(dI/dx)(dI/dy)   (dI/dx)^2   |
00272   //                       |_                           _|
00273   // \endverbatim
00274   // The output image is sqrt(lamba_1*lambda_2) where lambda_i are the eigenvalues
00275   static vil_image_view<float>
00276     sqrt_grad_singular_values(vil_image_view<float>& input, int n);
00277 
00278   //:
00279   // Returns the image with max scale values
00280   static vil_image_view<float> max_scale_trace(vil_image_view<float> input,
00281                                                float min_scale,
00282                                                float max_scale,
00283                                                float scale_inc);
00284 
00285   //:
00286   // Exactly same as max_scale_trace,
00287   // only return the image with actual trace values at max scales instead of the image with max scale values
00288   static vil_image_view<float> max_scale_trace_value(vil_image_view<float> input,
00289                                                      float min_scale,
00290                                                      float max_scale,
00291                                                      float scale_inc);
00292 
00293   //: computes Lucas-Kanade optical flow on a $2n+1$ neighborhood
00294   static void Lucas_KanadeMotion(vil_image_view<float>& current_frame,
00295                                  vil_image_view<float>& previous_frame,
00296                                  int n, double thresh,
00297                                  vil_image_view<float>& vx,
00298                                  vil_image_view<float>& vy);
00299 
00300   //: computes velocity of a region(view) using Lucas Kanade
00301   static void
00302     lucas_kanade_motion_on_view(vil_image_view<float> const& curr_frame,
00303                                 vil_image_view<float> const& prev_frame,
00304                                 const double thresh,
00305                                 float& vx,
00306                                 float& vy);
00307 
00308   //: computes velocity of a region(view) using correlation
00309   static void
00310     velocity_by_correlation(vil_image_view<float> const& curr_image,
00311                             vil_image_view<float> const& prev_region,
00312                             const unsigned start_i, const unsigned end_i,
00313                             const unsigned start_j, const unsigned end_j,
00314                             const unsigned zero_i, const unsigned zero_j,
00315                             float& vx,
00316                             float& vy);
00317 
00318   //: computes optical flow using Horn and Schunck's method
00319   static int Horn_SchunckMotion(vil_image_view<float> const & current_frame,
00320                                 vil_image_view<float> const& previous_frame,
00321                                 vil_image_view<float>& vx,
00322                                 vil_image_view<float>& vy,
00323                                 const float alpha_coef=10000.0f,
00324                                 const int no_of_iterations=5);
00325 
00326   //: fills a border of width \p w on left and right of image with value
00327   static void fill_x_border(vil_image_view<float>& image, unsigned w, float value);
00328 
00329   //: fills a border of height \p h on top and bottom of image with value
00330   static void fill_y_border(vil_image_view<float>& image, unsigned h, float value);
00331 
00332   //: converts a float image to a byte value range
00333   static vil_image_view<vxl_byte>
00334     convert_to_byte(vil_image_view<float> const& image);
00335 
00336   //: converts a float image to a byte value range within a specified range
00337   static vil_image_view<vxl_byte>
00338     convert_to_byte(vil_image_view<float> const& image,
00339                     float min_val, float max_val);
00340 
00341   //: converts an unsigned short (16-bit) image to a byte value range within a specified range
00342   static vil_image_view<vxl_byte>
00343     convert_to_byte(vil_image_view<vxl_uint_16> const& image,
00344                     vxl_uint_16 min_val, vxl_uint_16 max_val);
00345 
00346   //: converts a generic image to a byte image.
00347   // Use this instead of convert_to_grey
00348   static vil_image_view<vxl_byte>
00349     convert_to_byte(vil_image_resource_sptr const& image);
00350 
00351   //: converts a float image to an unsigned short (16-bit) image within a range
00352   // Use this instead of convert_to_grey
00353   static vil_image_view<vxl_uint_16>
00354     convert_to_short(vil_image_view<float> const& image,
00355                      float min_val, float max_val);
00356 
00357   //: converts a float image to an unsigned short (16-bit) image.
00358   // Range is determined automatically
00359   static vil_image_view<vxl_uint_16>
00360     convert_to_short(vil_image_view<float> const& image);
00361 
00362   //: converts a generic image to an unsigned short (16-bit) image
00363   // Use this instead of convert_to_grey
00364   static vil_image_view<vxl_uint_16>
00365     convert_to_short(vil_image_resource_sptr const& image);
00366 
00367   //: converts a vil_image_resource to a float image
00368   static vil_image_view<float>
00369     convert_to_float(vil_image_resource const& image);
00370 
00371   //: converts a vil_image_resource to a float image (preferred interface)
00372   static vil_image_view<float>
00373     convert_to_float(vil_image_resource_sptr const& image)
00374   { return brip_vil_float_ops::convert_to_float(*image); }
00375 
00376   static vil_image_view<float>
00377     convert_to_float(vil_image_view<vxl_byte> const& image);
00378 
00379   static vil_image_view<float>
00380     convert_to_float(vil_image_view<vxl_uint_16> const& image);
00381 
00382   //: converts a byte image to a bool image
00383   static vil_image_view<bool>
00384     convert_to_bool(vil_image_view<vxl_byte> const& image);
00385 
00386   //: converts an RGB image to a float image
00387   static vil_image_view<float>
00388     convert_to_float(vil_image_view<vil_rgb<vxl_byte> > const& image);
00389 
00390   //: convert a single RGB pixel to (I,H,S)
00391   static void rgb_to_ihs(vil_rgb<vxl_byte> const& rgb,
00392                          float& i, float& h, float& s);
00393 
00394   //: convert a single (I,H,S) pixel to RGB
00395   static void ihs_to_rgb(vil_rgb<vxl_byte>& rgb,
00396                          const float i, const float h, const float s);
00397 
00398   //: converts a byte-pixel color image to float (I,H,S) image triple
00399   static void
00400     convert_to_IHS(vil_image_view<vil_rgb<vxl_byte> > const& image,
00401                    vil_image_view<float>& I,
00402                    vil_image_view<float>& H,
00403                    vil_image_view<float>& S);
00404 
00405   //: converts a byte-pixel image to float (I,H,S) image triple
00406   static void
00407     convert_to_IHS(vil_image_view<vxl_byte> const& image,
00408                    vil_image_view<float>& I,
00409                    vil_image_view<float>& H,
00410                    vil_image_view<float>& S);
00411 
00412   //: display (I,H,S) image triple as RGB (no conversion from IHS to RGB!)
00413   static void
00414     display_IHS_as_RGB(vil_image_view<float> const& I,
00415                        vil_image_view<float> const& H,
00416                        vil_image_view<float> const& S,
00417                        vil_image_view<vil_rgb<vxl_byte> >& image);
00418 
00419 #if 0 // TODO ?
00420   //: converting IHS to RGB
00421   static void
00422     convert_IHS_as_RGB(vil_image_view<float> const& I,
00423                        vil_image_view<float> const& H,
00424                        vil_image_view<float> const& S,
00425                        vil_image_view<vil_rgb<vxl_byte> >& image);
00426 #endif // 0
00427 
00428   //: Create a byte-pixel color image from multiple view channels (R,G,B)
00429   // All views have to have the same array dimensions
00430   static vil_image_view<vil_rgb<vxl_byte> >
00431     combine_color_planes(vil_image_view<vxl_byte> const& R,
00432                          vil_image_view<vxl_byte> const& G,
00433                          vil_image_view<vxl_byte> const& B);
00434 
00435   //: Create a byte-pixel color image from multiple resource channels (R,G,B)
00436   // Images do not have to be the same size arrays
00437   static vil_image_view<vil_rgb<vxl_byte> >
00438     combine_color_planes(vil_image_resource_sptr const& R,
00439                          vil_image_resource_sptr const& G,
00440                          vil_image_resource_sptr const& B);
00441 
00442   //: converts a generic (byte-pixel RGB) image to greyscale
00443   static vil_image_view<vxl_byte>
00444     convert_to_grey(vil_image_resource const& img);
00445 
00446   //: loads a $2n+1 ~\times~ 2n+1$ convolution kernel
00447   // Assumes a square kernel with odd dimensions, i.e., $w,h = 2n+1$
00448   // format:
00449   // \verbatim
00450   //     n
00451   //     scale
00452   //     k00  k01  ... k02n
00453   //           ...
00454   //     k2n0 k2n1 ... k2n2n
00455   // \endverbatim
00456   static vbl_array_2d<float> load_kernel(vcl_string const& file);
00457 
00458   //: compute basis images for a set of input images
00459   static void basis_images(vcl_vector<vil_image_view<float> > const& input_images,
00460                            vcl_vector<vil_image_view<float> >& basis);
00461 
00462   //: compute the Fourier transform using the vnl FFT algorithm
00463   static bool fourier_transform(vil_image_view<float> const& input,
00464                                 vil_image_view<float>& mag,
00465                                 vil_image_view<float>& phase);
00466 
00467   //: compute the inverse Fourier transform using the vnl FFT algorithm
00468   static bool inverse_fourier_transform(vil_image_view<float> const& mag,
00469                                         vil_image_view<float> const& phase,
00470                                         vil_image_view<float>& output);
00471 
00472   //: resize to specified dimensions.
00473   //  Fill with zeros if output is larger
00474   static void resize(vil_image_view<float> const& input,
00475                      unsigned width, unsigned height,
00476                      vil_image_view<float>& output);
00477 
00478   //: resize to closest power of two larger dimensions than the input.
00479   //  Fill with zeros if output is larger
00480   static bool
00481     resize_to_power_of_two(vil_image_view<float> const& input,
00482                            vil_image_view<float>& output);
00483 
00484   //: filter the input image with a Gaussian blocking filter
00485   static bool
00486     spatial_frequency_filter(vil_image_view<float> const& input,
00487                              float dir_fx, float dir_fy,
00488                              float f0, float radius,
00489                              bool output_fourier_mag,
00490                              vil_image_view<float>& output);
00491 
00492   //: 2x2 bilinear interpolation of image at specified location
00493   // Neighborhood:
00494   // \verbatim
00495   //      xr
00496   //   yr 0  x
00497   //      x  x
00498   // \endverbatim
00499   static double
00500     bilinear_interpolation(vil_image_view<float> const& input,
00501                            double x, double y);
00502 
00503   //: map the input to the output by a homography.
00504   // \note if the output size is fixed then only the corresponding
00505   // input image space is transformed.
00506   static bool homography(vil_image_view<float> const& input,
00507                          vgl_h_matrix_2d<double> const& H,
00508                          vil_image_view<float>& output,
00509                          bool output_size_fixed = false,
00510                          float output_fill_value = 0.0f);
00511 
00512   //: rotate the input image counter-clockwise about the image origin
00513   static vil_image_view<float> rotate(vil_image_view<float> const& input,
00514                                       double theta_deg);
00515 
00516   //: extract a region of interest.
00517   // If \p roi does not overlap input, return false
00518   static bool chip(vil_image_view<float> const& input,
00519                    vsol_box_2d_sptr const& roi, vil_image_view<float>& chip);
00520 
00521   //: convert image resource to a chip of equivalent pixel type
00522   // If \p roi does not overlap input, return false
00523   static bool chip(vil_image_resource_sptr const& image,
00524                    brip_roi_sptr const& roi,
00525                    vil_image_resource_sptr & chip);
00526 
00527   //: chip multiple images.
00528   // Must be all the same dimensions
00529   // If \p roi does not overlap input, return false
00530   static bool chip(vcl_vector<vil_image_resource_sptr> const& images,
00531                    brip_roi_sptr const& roi,
00532                    vcl_vector<vil_image_resource_sptr>& chips);
00533 
00534   //: compute the average of the image intensity within the specified region
00535   static float average_in_box(vil_image_view<float> const& v,
00536                               vgl_box_2d<double> const& box);
00537 
00538   //: scan a polygon and return the pixel values as well as max min
00539   static vcl_vector<float> scan_region(vil_image_resource_sptr img,
00540                                        vgl_polygon<double> poly,
00541                                        float& min,
00542                                        float& max);
00543   //: cross-correlate two images at a given sub-pixel location
00544   static float cross_correlate(vil_image_view<float> const& image1,
00545                                vil_image_view<float> const& image2,
00546                                float x, float y, int radius = 5,
00547                                float intensity_thresh=25.0f);
00548 
00549   //: cross_correlate two images using running sums
00550   static bool cross_correlate(vil_image_view<float> const& image1,
00551                               vil_image_view<float> const& image2,
00552                               vil_image_view<float>& out,
00553                               int radius = 5, float intensity_thresh=25.0f);
00554 
00555   //: Compute the intensity entropy of a region about the specified pixel
00556   //  No bounds check
00557   static float entropy_i(const unsigned i, const unsigned j,
00558                          const unsigned i_radius,
00559                          const unsigned j_radius,
00560                          vil_image_view<float> const& intensity,
00561                          const float range = 255.0f, const unsigned bins = 16);
00562 
00563   //: Compute the gradient entropy of a region about the specified pixel
00564   //  No bounds check
00565   static float entropy_g(const unsigned i, const unsigned j,
00566                          const unsigned i_radius,
00567                          const unsigned j_radius,
00568                          vil_image_view<float> const& gradx,
00569                          vil_image_view<float> const& grady,
00570                          const float range = 360.0f, const unsigned bins = 8);
00571 
00572   //: Compute the hue and saturation entropy of a region about the specified pixel
00573   //  No bounds check
00574   static float entropy_hs(const unsigned i, const unsigned j,
00575                           const unsigned i_radius,
00576                           const unsigned j_radius,
00577                           vil_image_view<float> const& hue,
00578                           vil_image_view<float> const& sat,
00579                           const float range = 360.0f, const unsigned bins = 8);
00580 
00581   //: Compute the entropy of the specified region about each pixel
00582   static vil_image_view<float> entropy(const unsigned i_radius,
00583                                        const unsigned j_radius,
00584                                        const unsigned step,
00585                                        vil_image_resource_sptr const& img,
00586                                        const float sigma = 1.0f,
00587                                        const bool intensity = true,
00588                                        const bool gradient = true,
00589                                        const bool ihs = false);
00590 
00591   //: Compute the intensity minfo of a region about the specified pixel
00592   //  No bounds check
00593   static float minfo_i(const unsigned i0, const unsigned j0,
00594                        const unsigned i1, const unsigned j1,
00595                        const unsigned i_radius,
00596                        const unsigned j_radius,
00597                        vil_image_view<float> const& intensity0,
00598                        vil_image_view<float> const& intensity1,
00599                        const float range = 255.0f, const unsigned bins = 16);
00600 
00601   //: Compute the gradient minfo of a region about the specified pixel
00602   //  No bounds check
00603   static float minfo_g(const unsigned i0, const unsigned j0,
00604                        const unsigned i1, const unsigned j1,
00605                        const unsigned i_radius,
00606                        const unsigned j_radius,
00607                        vil_image_view<float> const& gradx0,
00608                        vil_image_view<float> const& grady0,
00609                        vil_image_view<float> const& gradx1,
00610                        vil_image_view<float> const& grady1,
00611                        const float range = 360.0f, const unsigned bins = 8);
00612 
00613   //: Compute the hue and saturation minfo of a region about the specified pixel
00614   //  No bounds check
00615   static float minfo_hs(const unsigned i0, const unsigned j0,
00616                         const unsigned i1, const unsigned j1,
00617                         const unsigned i_radius,
00618                         const unsigned j_radius,
00619                         vil_image_view<float> const& hue0,
00620                         vil_image_view<float> const& sat0,
00621                         vil_image_view<float> const& hue1,
00622                         vil_image_view<float> const& sat1,
00623                         const float range = 360.0f, const unsigned bins = 8);
00624 
00625   //: Compute the minfo of the specified region about each pixel
00626   static bool minfo(const unsigned i_radius,
00627                     const unsigned j_radius,
00628                     const unsigned step,
00629                     vil_image_resource_sptr const& img0,
00630                     vil_image_resource_sptr const& img1,
00631                     vil_image_view<float>& MI0,
00632                     vil_image_view<float>& MI1,
00633                     const float sigma = 1.0f,
00634                     const bool intensity = true,
00635                     const bool gradient = true,
00636                     const bool ihs = false);
00637 
00638   //  ===  Arithmetic operations  ===
00639 
00640   //: Blur the image with an NxN averaging filter
00641   static vil_image_view<float> average_NxN(vil_image_view<float> const& img, int N);
00642 
00643   //: Add two images from a general resource (forces types to be the same)
00644   static vil_image_resource_sptr sum(vil_image_resource_sptr const& img0,
00645                                      vil_image_resource_sptr const& img1);
00646 
00647   //: subtracts \p image_1 from \p image_2
00648   static vil_image_view<float> difference(vil_image_view<float> const& image_1,
00649                                           vil_image_view<float> const& image_2);
00650 
00651   //: subtract two generic images, return img0-img1 (forces types to the same)
00652   static vil_image_resource_sptr difference(vil_image_resource_sptr const& img0,
00653                                             vil_image_resource_sptr const& img1);
00654 
00655   //: negate an image returning the same pixel type (only greyscale)
00656   static vil_image_resource_sptr negate(vil_image_resource_sptr const& imgr);
00657 
00658   //: Color order operator, output an index based on RGB intensity order
00659   // It has been observed that color order is somewhat invariant to illumination
00660   // The tolerance determines if two color bands are too close to determine order,
00661   // i.e. they should be considered equal instead
00662   // the two relations being considered  are <, > and =, so the relationship
00663   // graph looks like:
00664   // \verbatim
00665   //         G
00666   //       /   \.
00667   //   > < =   > < =
00668   //    /         \.
00669   //  R  - > < = -  B
00670   // \endverbatim
00671   // Thus, there are three graph edges with each of three possible labels or
00672   // 9 possible order codes. An easy coding scheme is to use the top 6 bits of
00673   // the byte output pixel. The relationship is encoded as states of bit pairs
00674   // \verbatim
00675   // Color relations  R*G  R*B  G*B    * indicates > < = (1,2,3)
00676   // Bit indices      7,6  5,4  3,2
00677   // \endverbatim
00678   static vil_image_view<vxl_byte>
00679     color_order(vil_image_view<float> const& color_image, float eq_tol);
00680 
00681   //  ===  Internals  ===
00682 
00683  private:
00684 
00685   //: find if the center pixel of a neighborhood is the maximum value
00686   static bool local_maximum(vbl_array_2d<float> const& nighborhood,
00687                             int n, float& value);
00688 
00689   //: find the sub-pixel offset to the maximum using a 3x3 quad interpolation
00690   static void interpolate_center(vbl_array_2d<float> const& neighborhood,
00691                                  float& dx, float& dy);
00692 
00693   //: sub-sample a 1-d array using the Bert-Adelson algorithm
00694   static void half_resolution_1d(const float* input, unsigned n,
00695                                  float k0, float k1, float k2, float* output);
00696 
00697   //: interpolate a 1-d array using the Bert-Adelson algorithm
00698   static void double_resolution_1d(const float* input, const unsigned n_input,
00699                                    const float k0, const float k1, const float k2,
00700                                    float* output);
00701 
00702   //: One-dimensional fft
00703   static bool fft_1d(int dir, int m, double* x, double* y);
00704 
00705   //: Two-dimensional fft
00706   static bool fft_2d(vnl_matrix<vcl_complex<double> >& c, int nx,int ny,int dir);
00707 
00708   //: Transform the fft coefficients from/to fft/frequency order(self inverse).
00709   static void ftt_fourier_2d_reorder(vnl_matrix<vcl_complex<double> > const& F1,
00710                                      vnl_matrix<vcl_complex<double> >& F2);
00711 
00712   //: Blocking filter function
00713   static float gaussian_blocking_filter(float dir_fx, float dir_fy,
00714                                         float f0, float radius,
00715                                         float fx, float fy);
00716 
00717   //: u-coordinate of an ellipse defined by lambda0, lambda1 and theta, vs. phi
00718   static float elu(float phi, float lamda0, float lambda1, float theta);
00719   //: v-coordinate of an ellipse defined by lambda0, lambda1 and theta, vs. phi
00720   static float elv(float phi, float lamda0, float lambda1, float theta);
00721 
00722   //: Default constructor is private
00723   brip_vil_float_ops() {}
00724 };
00725 
00726 template <class T_inp,class T_out>
00727 void brip_vil_float_ops::normalize_to_interval(const vil_image_view<T_inp>& img_inp,
00728                                                vil_image_view<T_out>& img_out,
00729                                                float min,
00730                                                float max)
00731 {
00732   assert(min<max);
00733   T_inp min_inp;
00734   T_inp max_inp;
00735   vil_math_value_range<T_inp>(img_inp,min_inp,max_inp);
00736 
00737   if (min_inp >= max_inp) {
00738     img_out.fill(T_out(0));
00739     return;
00740   }
00741 
00742   float min_inp_f = (float)min_inp;
00743   float max_inp_f = (float)max_inp;
00744   float scale = (max-min)/(max_inp_f-min_inp_f);
00745 
00746   img_out.set_size(img_inp.ni(),img_inp.nj(),1);
00747   for (unsigned i=0; i<img_out.ni(); i++) {
00748     for (unsigned j=0; j<img_out.nj(); j++) {
00749       float inp_val = (float)img_inp(i,j);
00750       float out_val = (inp_val-min_inp_f)*scale;
00751       img_out(i,j) = T_out(out_val);
00752     }
00753   }
00754 }
00755 
00756 #endif // brip_vil_float_ops_h_