@@ -59,39 +59,28 @@ FlexibleModelFittingIterativeTask::FlexibleModelFittingIterativeTask(const std::
5959 double deblend_factor,
6060 double meta_iteration_stop,
6161 size_t max_fit_size,
62- WindowType window_type
62+ WindowType window_type,
63+ double ellipse_scale
6364 )
6465 : m_least_squares_engine(least_squares_engine), m_max_iterations(max_iterations),
6566 m_modified_chi_squared_scale(modified_chi_squared_scale), m_scale_factor(scale_factor),
6667 m_meta_iterations(meta_iterations), m_deblend_factor(deblend_factor), m_meta_iteration_stop(meta_iteration_stop),
6768 m_max_fit_size(max_fit_size * max_fit_size), m_parameters(parameters), m_frames(frames), m_priors(priors),
68- m_window_type(window_type) {
69+ m_window_type(window_type), m_ellipse_scale(ellipse_scale) {
6970}
7071
7172FlexibleModelFittingIterativeTask::~FlexibleModelFittingIterativeTask () {
7273}
7374
74- PixelRectangle FlexibleModelFittingIterativeTask::getFittingRect (SourceInterface& source, int frame_index) const {
75- const auto & frame_info = source.getProperty <MeasurementFrameInfo>(frame_index);
75+ PixelRectangle FlexibleModelFittingIterativeTask::getUnclippedFittingRect (SourceInterface& source, int frame_index) const {
7676 auto fitting_rect = source.getProperty <MeasurementFrameRectangle>(frame_index).getRect ();
7777
7878 if (m_window_type == WindowType::ROTATED_ELLIPSE) {
7979 auto ellipse = getFittingEllipse (source, frame_index);
8080
81- ellipse.m_a *= m_ellipse_window_scale;
82- ellipse.m_b *= m_ellipse_window_scale;
83- auto rect = getEllipseRect (ellipse);
84-
85- auto min = rect.getTopLeft ();
86- auto max = rect.getBottomRight ();
87-
88- // clip to image size
89- min.m_x = std::max (min.m_x , 0 );
90- min.m_y = std::max (min.m_y , 0 );
91- max.m_x = std::min (max.m_x , frame_info.getWidth () - 1 );
92- max.m_y = std::min (max.m_y , frame_info.getHeight () - 1 );
93-
94- return PixelRectangle (min, max);
81+ ellipse.m_a *= m_ellipse_scale;
82+ ellipse.m_b *= m_ellipse_scale;
83+ return getEllipseRect (ellipse);
9584 }
9685
9786 if (fitting_rect.getWidth () <= 0 || fitting_rect.getHeight () <= 0 ) {
@@ -135,19 +124,32 @@ PixelRectangle FlexibleModelFittingIterativeTask::getFittingRect(SourceInterface
135124 max.m_y = min.m_y + size;
136125 }
137126
138- // clip to image size
139- min.m_x = std::max (min.m_x , 0 );
140- min.m_y = std::max (min.m_y , 0 );
141- max.m_x = std::min (max.m_x , frame_info.getWidth () - 1 );
142- max.m_y = std::min (max.m_y , frame_info.getHeight () - 1 );
143-
144127 return PixelRectangle (min, max);
145128 }
146129}
147130
131+ PixelRectangle FlexibleModelFittingIterativeTask::clipFittingRect (PixelRectangle fitting_rect,
132+ SourceInterface& source, int frame_index) const {
133+ const auto & frame_info = source.getProperty <MeasurementFrameInfo>(frame_index);
134+
135+ auto min = fitting_rect.getTopLeft ();
136+ auto max = fitting_rect.getBottomRight ();
137+
138+ // clip to image size
139+ min.m_x = std::max (min.m_x , 0 );
140+ min.m_y = std::max (min.m_y , 0 );
141+ max.m_x = std::min (max.m_x , frame_info.getWidth () - 1 );
142+ max.m_y = std::min (max.m_y , frame_info.getHeight () - 1 );
143+
144+ return PixelRectangle (min, max);
145+ }
146+
147+ PixelRectangle FlexibleModelFittingIterativeTask::getFittingRect (SourceInterface& source, int frame_index) const {
148+ return clipFittingRect (getUnclippedFittingRect (source, frame_index), source, frame_index);
149+ }
150+
148151FlexibleModelFittingIterativeTask::FittingEllipse FlexibleModelFittingIterativeTask::getFittingEllipse (SourceInterface& source, int frame_index) const {
149152 auto source_shape = source.getProperty <ShapeParameters>();
150- const auto & frame_info = source.getProperty <MeasurementFrameInfo>(frame_index);
151153 auto centroid = source.getProperty <PixelCentroid>();
152154
153155 // Ellipse in detection frame
@@ -177,8 +179,8 @@ PixelRectangle FlexibleModelFittingIterativeTask::getEllipseRect(FittingEllipse
177179 double b_sin = ellipse.m_b * std::abs (sin_theta);
178180 double b_cos = ellipse.m_b * std::abs (cos_theta);
179181
180- double half_width = a_cos + b_sin;
181- double half_height = a_sin + b_cos;
182+ double half_width = std::sqrt ( a_cos*a_cos + b_sin*b_sin) + 1 ;
183+ double half_height = std::sqrt ( a_sin*a_sin + b_cos*b_cos) + 1 ;
182184
183185 PixelCoordinate min_corner, max_corner;
184186 min_corner.m_x = ellipse.m_x - half_width;
@@ -290,6 +292,9 @@ FrameModel<DownSampledImagePsf, std::shared_ptr<VectorImage<SourceXtractor::SeFl
290292std::shared_ptr<VectorImage<SeFloat>> FlexibleModelFittingIterativeTask::createWeightImage (
291293 SourceInterface& source, int frame_index) const {
292294 const auto & frame_images = source.getProperty <MeasurementFrameImages>(frame_index);
295+ auto frame_coordinates = source.getProperty <MeasurementFrameCoordinates>(frame_index).getCoordinateSystem ();
296+ auto ref_coordinates = source.getProperty <ReferenceCoordinates>().getCoordinateSystem ();
297+
293298 auto frame_image = frame_images.getLockedImage (LayerSubtractedImage);
294299 auto frame_image_thresholded = frame_images.getLockedImage (LayerThresholdedImage);
295300 auto variance_map = frame_images.getLockedImage (LayerVarianceMap);
@@ -298,23 +303,34 @@ std::shared_ptr<VectorImage<SeFloat>> FlexibleModelFittingIterativeTask::createW
298303 SeFloat gain = frame_info.getGain ();
299304 SeFloat saturation = frame_info.getSaturation ();
300305
301- auto rect = getFittingRect (source, frame_index);
306+ auto unclipped_rect = getUnclippedFittingRect (source, frame_index);
307+ auto rect = clipFittingRect (unclipped_rect, source, frame_index);
302308 auto weight = VectorImage<SeFloat>::create (rect.getWidth (), rect.getHeight ());
303309
304-
305310 // Precompute ellipse parameters
306311
307- auto ellipse = getFittingEllipse (source, frame_index);
312+ FittingEllipse ellipse;
313+ auto rad = std::min (unclipped_rect.getWidth () / 2.0 , unclipped_rect.getHeight () / 2.0 ) - 1.0 ;
308314
309- // auto ellipse_rect = getEllipseRect(ellipse);
310- // double ellipse_scale = std::min<double>(rect.getWidth() / ellipse_rect.getWidth()
311- // , rect.getHeight() / ellipse_rect.getHeight());
315+ if (m_window_type == WindowType::ROTATED_ELLIPSE) {
316+ ellipse = getFittingEllipse (source, frame_index);
317+ } else {
318+ // we don't want to require the ShapeParameters property when not using ROTATED_ELLIPSE
319+ auto centroid = source.getProperty <PixelCentroid>();
320+ auto coord = frame_coordinates->worldToImage (
321+ ref_coordinates->imageToWorld (ImageCoordinate (centroid.getCentroidX (),centroid.getCentroidY ())));
322+ ellipse.m_x = coord.m_x ;
323+ ellipse.m_y = coord.m_y ;
324+ ellipse.m_a = rad;
325+ ellipse.m_b = rad;
326+ ellipse.m_theta = 0 ;
327+ }
312328
313329 double cos_theta = std::cos (ellipse.m_theta );
314330 double sin_theta = std::sin (ellipse.m_theta );
315331
316- double a_squared = ellipse.m_a * ellipse.m_a * m_ellipse_window_scale * m_ellipse_window_scale ;
317- double b_squared = ellipse.m_b * ellipse.m_b * m_ellipse_window_scale * m_ellipse_window_scale ;
332+ double a_squared = ellipse.m_a * ellipse.m_a * m_ellipse_scale * m_ellipse_scale ;
333+ double b_squared = ellipse.m_b * ellipse.m_b * m_ellipse_scale * m_ellipse_scale ;
318334
319335 // Precompute components of the ellipse's quadratic form
320336 double A = (cos_theta * cos_theta) / a_squared + (sin_theta * sin_theta) / b_squared;
@@ -326,9 +342,8 @@ std::shared_ptr<VectorImage<SeFloat>> FlexibleModelFittingIterativeTask::createW
326342 auto back_var = variance_map->getValue (rect.getTopLeft ().m_x + x, rect.getTopLeft ().m_y + y);
327343 auto pixel_val = frame_image->getValue (rect.getTopLeft ().m_x + x, rect.getTopLeft ().m_y + y);
328344
329- auto dx = x - rect.getWidth () / 2.0 ;
330- auto dy = y - rect.getHeight () / 2.0 ;
331- auto rad = std::min (rect.getWidth () / 2.0 , rect.getHeight () / 2.0 );
345+ auto dx = x + rect.getTopLeft ().m_x - ellipse.m_x ;
346+ auto dy = y + rect.getTopLeft ().m_y - ellipse.m_y ;
332347
333348 if (saturation > 0 && pixel_val > saturation) {
334349 weight->at (x, y) = 0 ;
@@ -344,15 +359,14 @@ std::shared_ptr<VectorImage<SeFloat>> FlexibleModelFittingIterativeTask::createW
344359 weight->at (x, y) = 0 ;
345360 }
346361 } else if (m_window_type == WindowType::ALIGNED_ELLIPSE) {
347- auto w = rect .getWidth () / 2.0 ;
348- auto h = rect .getHeight () / 2.0 ;
362+ auto w = unclipped_rect .getWidth () / 2.0 ;
363+ auto h = unclipped_rect .getHeight () / 2.0 ;
349364 if (dx / w * dx / w + dy / h * dy / h > 1 ) {
350365 weight->at (x, y) = 0 ;
351366 }
352367 } else if (m_window_type == WindowType::ROTATED_ELLIPSE) {
353368 // Apply the quadratic form of the ellipse equation
354369 double value = A * dx * dx + B * dx * dy + C * dy * dy;
355- // std::cout << value << "\n";
356370 if (value > 1.0 ) {
357371 weight->at (x, y) = 0 ;
358372 }
@@ -483,7 +497,7 @@ std::shared_ptr<VectorImage<SeFloat>> FlexibleModelFittingIterativeTask::createD
483497 int index = 0 ;
484498 for (auto & src : group) {
485499 if (index != source_index) {
486- for (auto parameter : m_parameters) {
500+ for (auto parameter : m_parameters) {
487501 auto free_parameter = std::dynamic_pointer_cast<FlexibleModelFittingFreeParameter>(parameter);
488502
489503 if (free_parameter != nullptr ) {
@@ -494,7 +508,6 @@ std::shared_ptr<VectorImage<SeFloat>> FlexibleModelFittingIterativeTask::createD
494508 free_parameter->create (parameter_manager, engine_parameter_manager, src,
495509 state.source_states [index].parameters_initial_values .at (free_parameter->getId ()),
496510 state.source_states [index].parameters_values .at (free_parameter->getId ())));
497-
498511 } else {
499512 parameter_manager.addParameter (src, parameter,
500513 parameter->create (parameter_manager, engine_parameter_manager, src));
0 commit comments