Skip to content

Commit ffeb0af

Browse files
committed
added ellipse_scale config option, fixed windows on the borders
1 parent c6994dd commit ffeb0af

File tree

9 files changed

+85
-49
lines changed

9 files changed

+85
-49
lines changed

SEImplementation/SEImplementation/Configuration/ModelFittingConfig.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ class ModelFittingConfig : public Euclid::Configuration::Configuration {
6565
double getDeblendFactor() const { return m_deblend_factor; }
6666
double getMetaIterationStop() const { return m_meta_iteration_stop; }
6767
FlexibleModelFittingIterativeTask::WindowType getWindowType() const { return m_window_type; }
68+
double getEllipseScale() const { return m_ellipse_scale; }
6869

6970
private:
7071
std::string m_least_squares_engine;
@@ -76,6 +77,7 @@ class ModelFittingConfig : public Euclid::Configuration::Configuration {
7677
double m_meta_iteration_stop { 0.0001 };
7778
FlexibleModelFittingIterativeTask::WindowType m_window_type
7879
{ FlexibleModelFittingIterativeTask::WindowType::RECTANGLE };
80+
double m_ellipse_scale { 3.0 };
7981

8082
std::map<int, std::shared_ptr<FlexibleModelFittingParameter>> m_parameters;
8183
std::map<int, std::shared_ptr<FlexibleModelFittingModel>> m_models;

SEImplementation/SEImplementation/Plugin/FlexibleModelFitting/FlexibleModelFittingIterativeTask.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,8 @@ class FlexibleModelFittingIterativeTask : public GroupTask {
5959
double deblend_factor=1.0,
6060
double meta_iteration_stop=0.0001,
6161
size_t max_fit_size=100,
62-
WindowType window_type = WindowType::RECTANGLE
62+
WindowType window_type = WindowType::RECTANGLE,
63+
double ellipse_scale=3.0
6364
);
6465

6566
virtual ~FlexibleModelFittingIterativeTask();
@@ -125,6 +126,8 @@ class FlexibleModelFittingIterativeTask : public GroupTask {
125126
PixelRectangle getEllipseRect(FittingEllipse ellipse) const;
126127
FlexibleModelFittingIterativeTask::FittingEllipse transformEllipse(
127128
FittingEllipse ellipse, SourceInterface& source, int frame_index) const;
129+
PixelRectangle clipFittingRect(PixelRectangle fitting_rect, SourceInterface& source, int frame_index) const;
130+
PixelRectangle getUnclippedFittingRect(SourceInterface& source, int frame_index) const;
128131

129132
// Task configuration
130133
std::string m_least_squares_engine;
@@ -141,7 +144,7 @@ class FlexibleModelFittingIterativeTask : public GroupTask {
141144
std::vector<std::shared_ptr<FlexibleModelFittingPrior>> m_priors;
142145

143146
WindowType m_window_type { WindowType::RECTANGLE };
144-
double m_ellipse_window_scale = 3.0;
147+
double m_ellipse_scale = 3.0;
145148
};
146149

147150
}

SEImplementation/SEImplementation/Plugin/FlexibleModelFitting/FlexibleModelFittingTaskFactory.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ class FlexibleModelFittingTaskFactory : public TaskFactory {
5353
double m_deblend_factor { 1.0 };
5454
double m_meta_iteration_stop { 0.0001 };
5555
FlexibleModelFittingIterativeTask::WindowType m_window_type { FlexibleModelFittingIterativeTask::WindowType::RECTANGLE };
56+
double m_ellipse_scale { 3.0 };
5657

5758
std::vector<std::shared_ptr<FlexibleModelFittingParameter>> m_parameters;
5859
std::vector<std::shared_ptr<FlexibleModelFittingFrame>> m_frames;

SEImplementation/python/sourcextractor/config/compat.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,4 +125,8 @@ def use_iterative_fitting(use):
125125
def set_window_type(window_type):
126126
global_measurement_config.model_fitting.set_window_type(window_type)
127127

128+
@_compat_doc_helper(copy_doc_from=ModelFitting.set_ellipse_scale)
129+
def set_ellipse_scale(ellipse_scale):
130+
global_measurement_config.model_fitting.set_ellipse_scale(ellipse_scale)
131+
128132

SEImplementation/python/sourcextractor/config/model_fitting.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1061,7 +1061,7 @@ def __init__(self):
10611061
self.params_dict = {"max_iterations": 200, "modified_chi_squared_scale": 10, "engine": "",
10621062
"use_iterative_fitting": True, "meta_iterations": 5,
10631063
"deblend_factor": 0.95, "meta_iteration_stop": 0.0001,
1064-
"window_type": WindowType.RECTANGLE
1064+
"window_type": WindowType.RECTANGLE, "ellipse_scale": 3.0
10651065
}
10661066

10671067
def _set_model_to_frames(self, group, model):
@@ -1244,6 +1244,17 @@ def set_window_type(self, window_type):
12441244

12451245
self.params_dict["window_type"] = window_type
12461246

1247+
def set_ellipse_scale(self, ellipse_scale):
1248+
"""
1249+
Parameters
1250+
----------
1251+
1252+
ellipse_scale : double
1253+
specify scaling of elliptic footprints
1254+
1255+
"""
1256+
self.params_dict["ellipse_scale"] = ellipse_scale
1257+
12471258

12481259
def print_model_fitting_info(group, show_params=False, prefix='', file=sys.stderr):
12491260
"""

SEImplementation/src/lib/Configuration/ModelFittingConfig.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,7 @@ void ModelFittingConfig::initializeInner() {
386386
m_meta_iteration_stop = py::extract<double>(parameters["meta_iteration_stop"]);
387387
m_window_type = static_cast<FlexibleModelFittingIterativeTask::WindowType>(
388388
py::extract<int>(parameters["window_type"].attr("value"))());
389+
m_ellipse_scale = py::extract<double>(parameters["ellipse_scale"]);
389390
}
390391

391392
const std::map<int, std::shared_ptr<FlexibleModelFittingParameter>>& ModelFittingConfig::getParameters() const {

SEImplementation/src/lib/Plugin/AssocMode/AssocModeConfig.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ std::vector<int> parseColumnList(const std::string& arg) {
106106

107107
AssocModeConfig::AssocModeConfig(long manager_id) : Configuration(manager_id), m_assoc_mode(AssocMode::UNKNOWN),
108108
m_assoc_radius(0.), m_default_pixel_size(10), m_pixel_width_column(-1), m_pixel_height_column(-1),
109-
m_group_id_column(-1) {
109+
m_group_id_column(-1), m_assoc_coord_type(AssocCoordType::PIXEL) {
110110
declareDependency<DetectionImageConfig>();
111111
declareDependency<PartitionStepConfig>();
112112

@@ -388,7 +388,7 @@ std::vector<AssocModeConfig::CatalogEntry> AssocModeConfig::readTable(
388388
world_coord = coordinate_system->imageToWorld(coord);
389389
}
390390
}
391-
catalog.emplace_back(CatalogEntry { coord, world_coord, 1.0, {}, 1.0, 0 });
391+
catalog.emplace_back(CatalogEntry { coord, world_coord, 1.0, {}, 1.0, 1.0, 0 });
392392
if (columns.size() == 3 && columns.at(2) >= 0) {
393393
catalog.back().weight = boost::apply_visitor(CastVisitor<double>{}, row[columns.at(2)]);
394394
}

SEImplementation/src/lib/Plugin/FlexibleModelFitting/FlexibleModelFittingIterativeTask.cpp

Lines changed: 56 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -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

7172
FlexibleModelFittingIterativeTask::~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+
148151
FlexibleModelFittingIterativeTask::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
290292
std::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));

SEImplementation/src/lib/Plugin/FlexibleModelFitting/FlexibleModelFittingTaskFactory.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ std::shared_ptr<Task> FlexibleModelFittingTaskFactory::createTask(const Property
4040
if (m_use_iterative_fitting) {
4141
return std::make_shared<FlexibleModelFittingIterativeTask>(m_least_squares_engine, m_max_iterations,
4242
m_modified_chi_squared_scale, m_parameters, m_frames, m_priors, m_scale_factor,
43-
m_meta_iterations, m_deblend_factor, m_meta_iteration_stop, m_max_fit_size, m_window_type);
43+
m_meta_iterations, m_deblend_factor, m_meta_iteration_stop, m_max_fit_size, m_window_type, m_ellipse_scale);
4444
} else {
4545
return std::make_shared<FlexibleModelFittingTask>(m_least_squares_engine, m_max_iterations,
4646
m_modified_chi_squared_scale, m_parameters, m_frames, m_priors, m_scale_factor);
@@ -76,6 +76,7 @@ void FlexibleModelFittingTaskFactory::configure(Euclid::Configuration::ConfigMan
7676
m_deblend_factor = model_fitting_config.getDeblendFactor();
7777
m_meta_iteration_stop = model_fitting_config.getMetaIterationStop();
7878
m_window_type = model_fitting_config.getWindowType();
79+
m_ellipse_scale = model_fitting_config.getEllipseScale();
7980

8081
std::string approach;
8182
if (m_use_iterative_fitting) {

0 commit comments

Comments
 (0)