lsst.afw
g3a5ebb7d8a+28b83bf6a5
Toggle main menu visibility
Loading...
Searching...
No Matches
src
detection
FootprintMerge.cc
Go to the documentation of this file.
1
/*
2
* LSST Data Management System
3
* Copyright 2008-2014 LSST Corporation.
4
*
5
* This product includes software developed by the
6
* LSST Project (http://www.lsst.org/).
7
*
8
* This program is free software: you can redistribute it and/or modify
9
* it under the terms of the GNU General Public License as published by
10
* the Free Software Foundation, either version 3 of the License, or
11
* (at your option) any later version.
12
*
13
* This program is distributed in the hope that it will be useful,
14
* but WITHOUT ANY WARRANTY; without even the implied warranty of
15
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
* GNU General Public License for more details.
17
*
18
* You should have received a copy of the LSST License Statement and
19
* the GNU General Public License along with this program. If not,
20
* see <http://www.lsstcorp.org/LegalNotices/>.
21
*/
22
#include <cstdint>
23
24
#include "
lsst/afw/detection/FootprintMerge.h
"
25
#include "
lsst/afw/table/IdFactory.h
"
26
27
namespace
lsst
{
28
namespace
afw
{
29
namespace
detection
{
30
31
class
FootprintMerge
{
32
public
:
33
using
KeyTuple
= FootprintMergeList::KeyTuple;
34
using
FilterMap
= FootprintMergeList::FilterMap;
35
36
explicit
FootprintMerge
(
std::shared_ptr<Footprint>
footprint,
37
std::shared_ptr<afw::table::SourceTable>
sourceTable,
38
std::shared_ptr<PeakTable>
peakTable,
39
afw::table::SchemaMapper
const
&peakSchemaMapper,
KeyTuple
const
&keys)
40
: _footprints(1, footprint), _source(sourceTable->makeRecord()) {
41
std::shared_ptr<Footprint>
newFootprint =
std::make_shared<Footprint>
(*footprint);
42
43
_source->set(keys.footprint,
true
);
44
// Replace all the Peaks in the merged Footprint with new ones that include the origin flags
45
newFootprint->getPeaks() =
PeakCatalog
(peakTable);
46
for
(
PeakCatalog::iterator
iter = footprint->getPeaks().begin(); iter != footprint->getPeaks().end();
47
++iter) {
48
std::shared_ptr<PeakRecord>
newPeak = peakTable->copyRecord(*iter, peakSchemaMapper);
49
newPeak->set(keys.peak,
true
);
50
newPeak->setId((*newFootprint->getPeaks().getTable()->getIdFactory())());
51
newFootprint->getPeaks().push_back(newPeak);
52
}
53
_source->setFootprint(newFootprint);
54
}
55
56
~FootprintMerge
() =
default
;
57
FootprintMerge
(
FootprintMerge
const
&) =
default
;
58
FootprintMerge
(
FootprintMerge
&&) =
default
;
59
FootprintMerge
&
operator=
(
FootprintMerge
const
&) =
default
;
60
FootprintMerge
&
operator=
(
FootprintMerge
&&) =
default
;
61
62
/*
63
* Does this Footprint overlap the merged Footprint.
64
*
65
* The current implementation just builds an image from the two Footprints and
66
* detects the number of peaks. This is not very efficient and will be changed
67
* within the Footprint class in the future.
68
*/
69
bool
overlaps
(
Footprint
const
&rhs)
const
{
70
return
getMergedFootprint
()->getSpans()->overlaps(*(rhs.
getSpans
()));
71
}
72
73
/*
74
* Add this Footprint to the merge.
75
*
76
* If minNewPeakDist >= 0, it will add all peaks from the footprint to the merged Footprint
77
* that are greater than minNewPeakDist away from the closest peak in the existing list.
78
* If minNewPeakDist < 0, no peaks will be added from the footprint.
79
*
80
* If maxSamePeakDist >= 0, it will find the closest peak in the existing list for every peak
81
* in the footprint. If the closest peak is less than maxSamePeakDist, the peak will not
82
* be added and the closest peak will be flagged as detected by the filter defined in keys.
83
*
84
* If the footprint does not overlap it will do nothing.
85
*/
86
void
add
(
std::shared_ptr<Footprint>
footprint,
afw::table::SchemaMapper
const
&peakSchemaMapper,
87
KeyTuple
const
&keys,
float
minNewPeakDist = -1.,
float
maxSamePeakDist = -1.) {
88
if
(
addSpans
(footprint)) {
89
_footprints.push_back(footprint);
90
_source->set(keys.footprint,
true
);
91
_addPeaks(footprint->getPeaks(), &peakSchemaMapper, &keys, minNewPeakDist, maxSamePeakDist,
nullptr
);
92
}
93
}
94
95
/*
96
* Merge an already-merged clump of Footprints into this
97
*
98
* If minNewPeakDist >= 0, it will add all peaks from the footprint to the merged Footprint
99
* that are greater than minNewPeakDist away from the closest peak in the existing list.
100
* If minNewPeakDist < 0, no peaks will be added from the footprint.
101
*
102
* If maxSamePeakDist >= 0, it will find the closest peak in the existing list for every peak
103
* in the footprint. If the closest peak is less than maxSamePeakDist, the peak will not
104
* be added to the list and the flags from the closest peak will be set to the OR of the two.
105
*
106
* If the FootprintMerge does not overlap it will do nothing.
107
*/
108
void
add
(
FootprintMerge
const
&other,
FilterMap
const
&keys,
float
minNewPeakDist = -1.,
109
float
maxSamePeakDist = -1.) {
110
if
(
addSpans
(other.
getMergedFootprint
())) {
111
_footprints.insert(_footprints.end(), other._footprints.
begin
(), other._footprints.
end
());
112
// Set source flags to the OR of the flags of the two inputs
113
for
(
auto
const
&key : keys) {
114
afw::table::Key<afw::table::Flag>
const
&flagKey = key.second.footprint;
115
_source->set(flagKey, _source->get(flagKey) || other._source->get(flagKey));
116
}
117
_addPeaks(other.
getMergedFootprint
()->getPeaks(),
nullptr
,
nullptr
, minNewPeakDist, maxSamePeakDist,
118
&keys);
119
}
120
}
121
122
// Get the bounding box of the merge
123
lsst::geom::Box2I
getBBox
()
const
{
return
getMergedFootprint
()->getBBox(); }
124
125
std::shared_ptr<Footprint>
getMergedFootprint
()
const
{
return
_source->getFootprint(); }
126
127
std::shared_ptr<afw::table::SourceRecord>
getSource
()
const
{
return
_source; }
128
129
// Implementation helper for add() methods; returns true if the Footprint actually overlapped
130
// and was merged, and false otherwise.
131
bool
addSpans
(
std::shared_ptr<Footprint>
footprint) {
132
if
(!
getMergedFootprint
()->getSpans()->
overlaps
(*(footprint->getSpans())))
return
false
;
133
getMergedFootprint
()->setSpans(
getMergedFootprint
()->getSpans()->union_(*(footprint->getSpans())));
134
return
true
;
135
}
136
137
private
:
138
/*
139
* Add new peaks to the list of peaks of the merged footprint.
140
* This function handles two different cases:
141
* - The peaks come from a single footprint. In this case, the peakSchemaMapper
142
* and keys should be defined so that it can create a new peak, copy the appropriate
143
* data, and set the peak flag defined in keys.
144
* - The peaks come from another FootprintMerge. In this case, filterMap should
145
* be defined so that the information from the other peaks can be propagated.
146
*/
147
void
_addPeaks(
PeakCatalog
const
&otherPeaks,
afw::table::SchemaMapper
const
*peakSchemaMapper,
148
KeyTuple
const
*keys,
float
minNewPeakDist,
float
maxSamePeakDist,
149
FilterMap
const
*filterMap) {
150
if
(minNewPeakDist < 0 && maxSamePeakDist < 0)
return
;
151
152
assert(peakSchemaMapper || filterMap);
153
154
PeakCatalog
¤tPeaks =
getMergedFootprint
()->getPeaks();
155
std::shared_ptr<PeakRecord>
nearestPeak;
156
// Create new list of peaks
157
PeakCatalog
newPeaks(currentPeaks.
getTable
());
158
float
minNewPeakDist2 = minNewPeakDist * minNewPeakDist;
159
float
maxSamePeakDist2 = maxSamePeakDist * maxSamePeakDist;
160
for
(
PeakCatalog::const_iterator
otherIter = otherPeaks.
begin
(); otherIter != otherPeaks.
end
();
161
++otherIter) {
162
float
minDist2 =
std::numeric_limits<float>::infinity
();
163
164
for
(
PeakCatalog::const_iterator
currentIter = currentPeaks.
begin
();
165
currentIter != currentPeaks.
end
(); ++currentIter) {
166
float
dist2 = otherIter->getI().distanceSquared(currentIter->getI());
167
168
if
(dist2 < minDist2) {
169
minDist2 = dist2;
170
nearestPeak = currentIter;
171
}
172
}
173
174
if
(minDist2 < maxSamePeakDist2 && nearestPeak && maxSamePeakDist > 0) {
175
if
(peakSchemaMapper) {
176
nearestPeak->set(keys->peak,
true
);
177
}
else
{
178
for
(
auto
const
&i : *filterMap) {
179
afw::table::Key<afw::table::Flag>
const
&flagKey = i.second.peak;
180
nearestPeak->set(flagKey, nearestPeak->
get
(flagKey) || otherIter->get(flagKey));
181
}
182
}
183
}
else
if
(minDist2 > minNewPeakDist2 && !(minNewPeakDist < 0)) {
184
if
(peakSchemaMapper) {
185
std::shared_ptr<PeakRecord> newPeak = newPeaks.addNew();
186
newPeak->assign(*otherIter, *peakSchemaMapper);
187
newPeak->set(
keys
->peak,
true
);
188
newPeak->setId((*currentPeaks.
getTable
()->getIdFactory())());
189
}
else
{
190
newPeaks.push_back(otherIter);
191
}
192
}
193
}
194
195
getMergedFootprint
()->getPeaks().insert(
getMergedFootprint
()->getPeaks().
end
(), newPeaks.begin(),
196
newPeaks.end(),
197
true
// deep-copy
198
);
199
}
200
201
std::vector<std::shared_ptr<Footprint>> _footprints;
202
std::shared_ptr<afw::table::SourceRecord> _source;
203
};
204
205
FootprintMergeList::FootprintMergeList
(
afw::table::Schema
&sourceSchema,
206
std::vector<std::string>
const
&filterList,
207
afw::table::Schema
const
&initialPeakSchema)
208
: _peakSchemaMapper(initialPeakSchema) {
209
_initialize(sourceSchema, filterList);
210
}
211
212
FootprintMergeList::FootprintMergeList
(
afw::table::Schema
&sourceSchema,
213
std::vector<std::string>
const
&filterList)
214
: _peakSchemaMapper(
PeakTable
::makeMinimalSchema()) {
215
_initialize(sourceSchema, filterList);
216
}
217
218
FootprintMergeList::~FootprintMergeList
() =
default
;
219
FootprintMergeList::FootprintMergeList
(
FootprintMergeList
const
&) =
default
;
220
FootprintMergeList::FootprintMergeList
(
FootprintMergeList
&&) =
default
;
221
FootprintMergeList
&
FootprintMergeList::operator=
(
FootprintMergeList
const
&) =
default
;
222
FootprintMergeList
&
FootprintMergeList::operator=
(
FootprintMergeList
&&) =
default
;
223
224
void
FootprintMergeList::_initialize(
afw::table::Schema
&sourceSchema,
225
std::vector<std::string>
const
&filterList) {
226
_peakSchemaMapper.
addMinimalSchema
(_peakSchemaMapper.
getInputSchema
(),
true
);
227
// Add Flags for the filters
228
for
(
auto
const
&iter : filterList) {
229
KeyTuple &keys = _filterMap[iter];
230
keys.footprint = sourceSchema.
addField
(
231
table::Field<afw::table::Flag>
(
232
"merge_footprint_"
+ iter,
233
"Detection footprint overlapped with a detection from filter "
+ iter),
234
/*doReplace=*/
true
);
235
keys.peak = _peakSchemaMapper.
editOutputSchema
().
addField
<afw::table::Flag>(
236
"merge_peak_"
+ iter,
"Peak detected in filter "
+ iter);
237
}
238
_peakTable =
PeakTable::make
(_peakSchemaMapper.
getOutputSchema
());
239
}
240
241
void
FootprintMergeList::addCatalog
(
std::shared_ptr<afw::table::SourceTable>
sourceTable,
242
afw::table::SourceCatalog
const
&inputCat,
std::string
const
&filter,
243
float
minNewPeakDist,
bool
doMerge,
float
maxSamePeakDist) {
244
FilterMap::const_iterator keyIter = _filterMap.find(filter);
245
if
(keyIter == _filterMap.end()) {
246
throw
LSST_EXCEPT
(
pex::exceptions::LogicError
,
247
(boost::format(
"Filter %s not in original list"
) % filter).str());
248
}
249
250
// If list is empty or merging not requested, don't check for any matches, just add all the objects
251
bool
checkForMatches = !_mergeList.empty() && doMerge;
252
253
for
(
afw::table::SourceCatalog::const_iterator
srcIter = inputCat.begin(); srcIter != inputCat.end();
254
++srcIter) {
255
// Only consider unblended objects
256
if
(srcIter->getParent() != 0)
continue
;
257
258
std::shared_ptr<Footprint>
foot = srcIter->getFootprint();
259
260
// Empty pointer to account for the first match in the catalog. If there is more than one
261
// match, subsequent matches will be merged with this one
262
std::shared_ptr<FootprintMerge>
first =
std::shared_ptr<FootprintMerge>
();
263
264
if
(checkForMatches) {
265
FootprintMergeVec::iterator iter = _mergeList.begin();
266
while
(iter != _mergeList.end()) {
267
// Grow by one pixel to allow for touching
268
lsst::geom::Box2I
box((**iter).getBBox());
269
box.
grow
(
lsst::geom::Extent2I
(1, 1));
270
if
(box.
overlaps
(foot->getBBox()) && (**iter).overlaps(*foot)) {
271
if
(!first) {
272
first = *iter;
273
// Spatially extend existing FootprintMerge in order to connect subsequent,
274
// now-overlapping FootprintMerges. If a subsequent FootprintMerge overlaps with
275
// the new footprint, it's now guaranteed to overlap with this first FootprintMerge.
276
// Hold off adding foot's lower-priority footprints and peaks until the
277
// higher-priority existing peaks are merged into this first FootprintMerge.
278
first->addSpans(foot);
279
}
else
{
280
// Add existing merged Footprint to first
281
first->add(**iter, _filterMap, minNewPeakDist, maxSamePeakDist);
282
iter = _mergeList.erase(iter);
283
continue
;
284
}
285
}
286
++iter;
287
}
// while mergeList
288
}
// if checkForMatches
289
290
if
(first) {
291
// Now merge footprint including peaks into the newly-connected, higher-priority FootprintMerge
292
first->add(foot, _peakSchemaMapper, keyIter->second, minNewPeakDist, maxSamePeakDist);
293
}
else
{
294
// Footprint did not overlap with any existing FootprintMerges. Add to MergeList
295
_mergeList.push_back(
std::make_shared<FootprintMerge>
(foot, sourceTable, _peakTable,
296
_peakSchemaMapper, keyIter->second));
297
}
298
}
299
}
300
301
void
FootprintMergeList::getFinalSources
(
afw::table::SourceCatalog
&outputCat) {
302
// Now set the merged footprint as the footprint of the SourceRecord
303
for
(
auto
const
&iter : _mergeList) {
304
outputCat.push_back((*iter).getSource());
305
}
306
}
307
}
// namespace detection
308
}
// namespace afw
309
}
// namespace lsst
LSST_EXCEPT
#define LSST_EXCEPT(type,...)
FootprintMerge.h
IdFactory.h
std::string
std::vector::begin
T begin(T... args)
lsst::afw::detection::Footprint
Class to describe the properties of a detected object from an image.
Definition
Footprint.h:63
lsst::afw::detection::Footprint::getSpans
std::shared_ptr< geom::SpanSet > getSpans() const
Return a shared pointer to the SpanSet.
Definition
Footprint.h:115
lsst::afw::detection::FootprintMerge::overlaps
bool overlaps(Footprint const &rhs) const
Definition
FootprintMerge.cc:69
lsst::afw::detection::FootprintMerge::addSpans
bool addSpans(std::shared_ptr< Footprint > footprint)
Definition
FootprintMerge.cc:131
lsst::afw::detection::FootprintMerge::~FootprintMerge
~FootprintMerge()=default
lsst::afw::detection::FootprintMerge::getSource
std::shared_ptr< afw::table::SourceRecord > getSource() const
Definition
FootprintMerge.cc:127
lsst::afw::detection::FootprintMerge::FilterMap
FootprintMergeList::FilterMap FilterMap
Definition
FootprintMerge.cc:34
lsst::afw::detection::FootprintMerge::operator=
FootprintMerge & operator=(FootprintMerge &&)=default
lsst::afw::detection::FootprintMerge::FootprintMerge
FootprintMerge(FootprintMerge &&)=default
lsst::afw::detection::FootprintMerge::getMergedFootprint
std::shared_ptr< Footprint > getMergedFootprint() const
Definition
FootprintMerge.cc:125
lsst::afw::detection::FootprintMerge::KeyTuple
FootprintMergeList::KeyTuple KeyTuple
Definition
FootprintMerge.cc:33
lsst::afw::detection::FootprintMerge::FootprintMerge
FootprintMerge(std::shared_ptr< Footprint > footprint, std::shared_ptr< afw::table::SourceTable > sourceTable, std::shared_ptr< PeakTable > peakTable, afw::table::SchemaMapper const &peakSchemaMapper, KeyTuple const &keys)
Definition
FootprintMerge.cc:36
lsst::afw::detection::FootprintMerge::operator=
FootprintMerge & operator=(FootprintMerge const &)=default
lsst::afw::detection::FootprintMerge::add
void add(std::shared_ptr< Footprint > footprint, afw::table::SchemaMapper const &peakSchemaMapper, KeyTuple const &keys, float minNewPeakDist=-1., float maxSamePeakDist=-1.)
Definition
FootprintMerge.cc:86
lsst::afw::detection::FootprintMerge::getBBox
lsst::geom::Box2I getBBox() const
Definition
FootprintMerge.cc:123
lsst::afw::detection::FootprintMerge::FootprintMerge
FootprintMerge(FootprintMerge const &)=default
lsst::afw::detection::FootprintMerge::add
void add(FootprintMerge const &other, FilterMap const &keys, float minNewPeakDist=-1., float maxSamePeakDist=-1.)
Definition
FootprintMerge.cc:108
lsst::afw::detection::FootprintMergeList
List of Merged Footprints.
Definition
FootprintMerge.h:56
lsst::afw::detection::FootprintMergeList::FootprintMergeList
FootprintMergeList(afw::table::Schema &sourceSchema, std::vector< std::string > const &filterList, afw::table::Schema const &initialPeakSchema)
Initialize the merge with a custom initial peak schema.
Definition
FootprintMerge.cc:205
lsst::afw::detection::FootprintMergeList::getFinalSources
void getFinalSources(afw::table::SourceCatalog &outputCat)
Get SourceCatalog with entries that contain the final Footprint and SourceRecord for each entry.
Definition
FootprintMerge.cc:301
lsst::afw::detection::FootprintMergeList::operator=
FootprintMergeList & operator=(FootprintMergeList const &)
lsst::afw::detection::FootprintMergeList::addCatalog
void addCatalog(std::shared_ptr< afw::table::SourceTable > sourceTable, afw::table::SourceCatalog const &inputCat, std::string const &filter, float minNewPeakDist=-1., bool doMerge=true, float maxSamePeakDist=-1.)
Add objects from a SourceCatalog in the specified filter.
Definition
FootprintMerge.cc:241
lsst::afw::detection::FootprintMergeList::~FootprintMergeList
~FootprintMergeList()
lsst::afw::detection::PeakTable
Table class for Peaks in Footprints.
Definition
Peak.h:102
lsst::afw::detection::PeakTable::make
static std::shared_ptr< PeakTable > make(afw::table::Schema const &schema, bool forceNew=false)
Obtain a table that can be used to create records with given schema.
Definition
Peak.cc:96
lsst::afw::table._source.SourceCatalog
Definition
_source.py:33
lsst::afw::table::CatalogT< PeakRecord >::iterator
CatalogIterator< typename Internal::iterator > iterator
Definition
Catalog.h:110
lsst::afw::table::CatalogT::begin
iterator begin()
Iterator access.
Definition
Catalog.h:401
lsst::afw::table::CatalogT< PeakRecord >::const_iterator
CatalogIterator< typename Internal::const_iterator > const_iterator
Definition
Catalog.h:111
lsst::afw::table::CatalogT::end
iterator end()
Definition
Catalog.h:402
lsst::afw::table::CatalogT::getTable
std::shared_ptr< Table > getTable() const
Return the table associated with the catalog.
Definition
Catalog.h:114
lsst::afw::table::Key
A class used as a handle to a particular field in a table.
Definition
Key.h:53
lsst::afw::table::Schema
Defines the fields and offsets for a table.
Definition
Schema.h:51
lsst::afw::table::Schema::addField
Key< T > addField(Field< T > const &field, bool doReplace=false)
Add a new field to the Schema, and return the associated Key.
Definition
Schema.cc:479
lsst::afw::table::SchemaMapper
A mapping between the keys of two Schemas, used to copy data between them.
Definition
SchemaMapper.h:21
lsst::afw::table::SchemaMapper::getOutputSchema
Schema const getOutputSchema() const
Return the output schema (copy-on-write).
Definition
SchemaMapper.h:27
lsst::afw::table::SchemaMapper::editOutputSchema
Schema & editOutputSchema()
Return a reference to the output schema that allows it to be modified in place.
Definition
SchemaMapper.h:30
lsst::afw::table::SchemaMapper::addMinimalSchema
void addMinimalSchema(Schema const &minimal, bool doMap=true)
Add the given minimal schema to the output schema.
Definition
SchemaMapper.cc:179
lsst::afw::table::SchemaMapper::getInputSchema
Schema const getInputSchema() const
Return the input schema (copy-on-write).
Definition
SchemaMapper.h:24
lsst::afw::table::SortedCatalogT< SourceRecord >::const_iterator
typename Base::const_iterator const_iterator
Definition
SortedCatalog.h:50
lsst::geom::Box2I
lsst::geom::Box2I::overlaps
bool overlaps(Box2I const &other) const noexcept
lsst::geom::Box2I::grow
void grow(int buffer)
lsst::pex::exceptions::LogicError
std::vector::end
T end(T... args)
std::shared_ptr::get
T get(T... args)
std::numeric_limits::infinity
T infinity(T... args)
std::make_shared
T make_shared(T... args)
astshim::keyMap::keyMapContinued::keys
keys
lsst::afw::detection
Definition
Footprint.h:50
lsst::afw::detection::PeakCatalog
afw::table::CatalogT< PeakRecord > PeakCatalog
Definition
Peak.h:244
lsst::afw
Definition
imageAlgorithm.dox:1
lsst::geom::Extent2I
Extent< int, 2 > Extent2I
lsst
std::shared_ptr
lsst::afw::table::Field
A description of a field in a table.
Definition
Field.h:24
std::vector
Generated on
for lsst.afw by
1.17.0