00001
00002
00003
00004
00005
00006
00007
00008
00009 #ifndef ENERGY_MUMFORDSHAH_H
00010 #define ENERGY_MUMFORDSHAH_H
00011
00012 #include <image/Image.hpp>
00013 #include <image/ScalarImage.hpp>
00014 #include <image/utilities.hpp>
00015 #include <shape/BoundaryDiscretizer.hpp>
00016 #include <shape/ShapeStatistics.hpp>
00017 #include <shape/ShapeEnergyInterface.hpp>
00018 #include <minimize/DifferentiableEnergyInterface.hpp>
00019
00020
00021 namespace imaging
00022 {
00049 template <class shape_t>
00050 class MumfordShahEnergy : public DifferentiableEnergyInterface, public ShapeEnergyInterface<shape_t>
00051 {
00052 const static std::size_t N = shape_t::SHAPE_DIMENSION;
00053
00054 Image<N, ublas::fixed_vector<float_t, N> > _contrast_vector_field;
00055 Image<N, ublas::fixed_vector<float_t, N> > _squared_contrast_vector_field;
00056 Image<N, ublas::fixed_vector<float_t, N> > _volume_vector_field;
00057 Image<N, float_t> _image;
00058 float_t _beta;
00059 std::size_t _n_integration_points;
00060
00061 ublas::vector<float_t> _current_argument;
00062 ublas::vector<float_t> _current_gradient;
00063 float_t _current_energy;
00064 shape_t _current_shape;
00065 shape_t _initial_shape;
00066
00067 float_t _image_volume;
00068 float_t _image_contrast;
00069 float_t _squared_image_contrast;
00070
00071 void compute_energy(float_t & u_1, float_t & u_2, float_t & energy);
00072
00073 public:
00074
00076 template <class const_accessor_t>
00077 MumfordShahEnergy(const const_accessor_t & image,
00078 const shape_t & initial_shape,
00079 float_t beta,
00080 std::size_t n_integration_points);
00081
00082 ublas::vector<float_t> & current_argument() { return _current_argument; }
00083 float_t current_energy() const { return _current_energy; }
00084 std::size_t dimension() const { return _initial_shape.dimension(); }
00085 const shape_t & current_shape() const { return _current_shape; }
00086
00087 const ublas::vector<float_t> & current_gradient() const { return _current_gradient; }
00088
00089 void set_argument();
00090 void set_argument_with_gradient();
00091 };
00092
00093 template <class shape_t>
00094 template <class const_accessor_t>
00095 MumfordShahEnergy<shape_t>::MumfordShahEnergy(const const_accessor_t & image,
00096 const shape_t & initial_shape,
00097 float_t beta,
00098 std::size_t n_integration_points) :
00099 _beta(beta),
00100 _initial_shape(initial_shape),
00101 _current_shape(initial_shape),
00102 _n_integration_points(n_integration_points),
00103 _current_argument(ublas::scalar_vector<float_t>(initial_shape.dimension(), 0.0)),
00104 _current_gradient(initial_shape.dimension()),
00105 _contrast_vector_field(image.size()),
00106 _squared_contrast_vector_field(image.size()),
00107 _volume_vector_field(image.size()),
00108 _image(image)
00109 {
00110 Image<N, float_t> squared_image(_image.size());
00111 ublas::fixed_vector<size_t, N> index;
00112 index.assign(0);
00113 do
00114 {
00115 squared_image[index] = square(_image[index]);
00116 }
00117 while(increment_index(_image.size(), index));
00118
00119 compute_divergence_field(image, _contrast_vector_field);
00120 compute_divergence_field(squared_image, _squared_contrast_vector_field);
00121 compute_divergence_field(ScalarImage<N, float_t>(image.size(), 1.0), _volume_vector_field);
00122
00123 _image_volume = 1.0;
00124
00125 for(std::size_t i = 0; i < N; ++i)
00126 _image_volume *= float_t(image.size()(i));
00127
00128 _image_contrast = 0.0;
00129 _squared_image_contrast = 0.0;
00130
00131 index.assign(0);
00132 do
00133 {
00134 _image_contrast += _image[index];
00135 _squared_image_contrast += squared_image[index];
00136 }
00137 while(increment_index(_image.size(), index));
00138
00139 set_argument_with_gradient();
00140 }
00141
00142 template <class shape_t>
00143 void MumfordShahEnergy<shape_t>::set_argument()
00144 {
00145 float_t u_1, u_2;
00146
00147 compute_energy(u_1, u_2, _current_energy);
00148 }
00149
00150
00151 template <class shape_t>
00152 void MumfordShahEnergy<shape_t>::set_argument_with_gradient()
00153 {
00154 shape_t perturbed_shape;
00155 ublas::vector<float_t> perturbed_argument(dimension());
00156 ublas::vector<float_t> statistics_gradient(dimension());
00157 const float_t FINITE_H = 0.001;
00158 ublas::fixed_vector<float_t, shape_t::SHAPE_DIMENSION> point, normal;
00159 float_t u_1, u_2;
00160
00161 perturbed_argument = _current_argument;
00162 _current_gradient = ublas::scalar_vector<float_t>(dimension(), 0.0);
00163
00164 compute_energy(u_1, u_2, _current_energy);
00165
00166 std::auto_ptr< BoundaryDiscretizer<shape_t::SHAPE_DIMENSION> > discretizer = _current_shape.boundary_discretizer(_n_integration_points);
00167
00168 for(std::size_t k = 0; k < dimension(); ++k)
00169 {
00170 perturbed_argument(k) += FINITE_H;
00171
00172 _initial_shape.exponential(perturbed_argument, perturbed_shape);
00173
00174 std::auto_ptr< BoundaryDiscretizer<shape_t::SHAPE_DIMENSION> > perturbed_discretizer = perturbed_shape.boundary_discretizer(_n_integration_points);
00175
00176 ublas::fixed_vector<float_t, shape_t::SHAPE_DIMENSION> perturbed_point, perturbed_normal, shape_derivative, shape_normal_derivative;
00177 float_t image_value;
00178
00179 for(std::size_t j = 0; j < _n_integration_points; ++j)
00180 {
00181 perturbed_point = (*perturbed_discretizer)(j, perturbed_normal);
00182 point = (*discretizer)(j, normal);
00183
00184 shape_derivative = 1.0 / FINITE_H * (perturbed_point - point);
00185 shape_normal_derivative = 1.0 / FINITE_H * (perturbed_normal - normal);
00186
00187
00188 ublas::fixed_vector<size_t, N> pixel_position = ublas::fixed_vector<size_t, N>(point);
00189 bool is_valid_pixel = true;
00190
00191 for(std::size_t i = 0; i < N; ++i)
00192 {
00193 if( ! ( pixel_position(i) < _image.size()(i) ) )
00194 {
00195 is_valid_pixel = false;
00196 break;
00197 }
00198 }
00199
00200 if(is_valid_pixel)
00201 {
00202
00203 image_value = _image[pixel_position];
00204
00205 _current_gradient(k) += ( square(u_1 - image_value) - square(u_2 - image_value) ) *
00206 inner_prod(normal, shape_derivative) * sqrt(norm_2(normal));
00207 }
00208 _current_gradient(k) += 2.0 * _beta * inner_prod(normal, shape_normal_derivative);
00209 }
00210
00211 perturbed_argument(k) -= FINITE_H;
00212 }
00213 }
00214
00215 template <class shape_t>
00216 void MumfordShahEnergy<shape_t>::compute_energy(float_t & u_1, float_t & u_2, float_t & energy)
00217 {
00218 _current_gradient = ublas::scalar_vector<float_t>(dimension(), 0.0);
00219
00220 _initial_shape.exponential(_current_argument, _current_shape);
00221
00222 float_t inner_contrast, outer_contrast;
00223 float_t inner_squared_contrast, outer_squared_contrast;
00224 float_t inner_volume, outer_volume;
00225
00226 std::auto_ptr< BoundaryDiscretizer<shape_t::SHAPE_DIMENSION> > discretizer = _current_shape.boundary_discretizer(_n_integration_points);
00227
00228 inner_contrast = discretizer->integrate_vector_field(_contrast_vector_field);
00229 inner_squared_contrast = discretizer->integrate_vector_field(_squared_contrast_vector_field);
00230 inner_volume = discretizer->integrate_vector_field(_volume_vector_field);
00231
00232 outer_contrast = _image_contrast - inner_contrast;
00233 outer_squared_contrast = _squared_image_contrast - outer_squared_contrast;
00234 outer_volume = _image_volume - inner_volume;
00235
00236 u_1 = inner_contrast / inner_volume;
00237 u_2 = outer_contrast / outer_volume;
00238
00239 float_t shape_boundary_energy = 0.0;
00240 ublas::fixed_vector<float_t, shape_t::SHAPE_DIMENSION> point, normal;
00241 for(std::size_t j = 0; j < _n_integration_points; ++j)
00242 {
00243 point = (*discretizer)(j, normal);
00244 shape_boundary_energy += inner_prod(normal, normal);
00245 }
00246
00247 energy = square(u_1) * inner_volume - 2 * u_1 * inner_contrast + inner_squared_contrast +
00248 square(u_2) * outer_volume - 2 * u_2 * outer_contrast + outer_squared_contrast +
00249 _beta * shape_boundary_energy;
00250
00251 }
00252
00253 }
00254
00255
00256 #endif