49 namespace algorithms {
53 inline double min4(
double a,
double b,
double c,
double d) {
57 inline double max4(
double a,
double b,
double c,
double d) {
65 int nx = im.getWidth();
66 int ny = im.getHeight();
68 auto out = std::make_shared<afw::detection::Psf::Image>(nx + 2 * xPad, ny + 2 * yPad);
69 out->setXY0(im.getX0() - xPad, im.getY0() - yPad);
77 geom::Box2I computeBBoxFromTransform(geom::Box2I
const bbox, geom::AffineTransform
const &t) {
78 static const int dst_padding = 0;
84 static const double maxTransformCoeff = 200.0;
86 if (t.getLinear().getMatrix().lpNorm<Eigen::Infinity>() > maxTransformCoeff) {
87 throw LSST_EXCEPT(pex::exceptions::RangeError,
"Unexpectedly large transform passed to WarpedPsf");
105 int out_xlo = floor(min4(c00.getX(), c01.getX(), c10.getX(), c11.getX())) - dst_padding;
106 int out_ylo = floor(min4(c00.getY(), c01.getY(), c10.getY(), c11.getY())) - dst_padding;
107 int out_xhi = ceil(max4(c00.getX(), c01.getX(), c10.getX(), c11.getX())) + dst_padding;
108 int out_yhi = ceil(max4(c00.getY(), c01.getY(), c10.getY(), c11.getY())) + dst_padding;
110 geom::Box2I ret = geom::Box2I(
geom::Point2I(out_xlo, out_ylo),
129 geom::AffineTransform
const &srcToDest,
130 afw::math::WarpingControl
const &wc) {
134 afw::math::SeparableKernel
const &kernel = *wc.getWarpingKernel();
136 int const xPad =
std::max(center.getX(), kernel.getWidth() - center.getX());
137 int const yPad =
std::max(center.getY(), kernel.getHeight() - center.getY());
140 geom::Box2I
bbox = computeBBoxFromTransform(im.getBBox(), srcToDest);
141 auto ret = std::make_shared<afw::detection::Psf::Image>(
bbox);
157 _undistortedPsf(undistortedPsf),
158 _distortion(distortion),
159 _warpingControl(control) {
167 _undistortedPsf(undistortedPsf),
168 _distortion(distortion),
169 _warpingControl(new afw::math::WarpingControl(kernelName,
"", cache)) {
173 void WarpedPsf::_init() {
176 "Undistorted Psf passed to WarpedPsf must not be None/NULL");
181 if (!_warpingControl) {
183 "WarpingControl passed to WarpedPsf must not be None/NULL");
213 double normFactor = 1.0;
219 for (
int y = 0;
y != ret->getHeight(); ++
y) {
222 normFactor += *imPtr;
225 if (normFactor == 0.0) {
243 struct PersistenceHelper {
249 static PersistenceHelper
const &get() {
250 static PersistenceHelper
const instance;
257 psfIndex(
schema.addField<int>(
"psfIndex",
"archive ID of nested Psf object")),
258 transformIndex(
schema.addField<int>(
"transformIndex",
"archive ID of nested Transform object")),
260 schema.addField<int>(
"controlIndex",
"archive ID of nested WarpingControl object")) {}
263 std::string _getPersistenceName() {
return "WarpedPsf"; }
265 class :
public afw::table::io::PersistableFactory {
268 afw::table::io::InputArchive
const &archive,
269 afw::table::io::CatalogVector
const &catalogs)
const {
270 static PersistenceHelper
const &
keys = PersistenceHelper::get();
273 afw::table::BaseRecord
const &record = catalogs.front().front();
275 return std::make_shared<WarpedPsf>(
276 archive.get<afw::detection::Psf>(record.get(
keys.psfIndex)),
278 archive.get<afw::math::WarpingControl>(record.get(
keys.controlIndex)));
282 } warpedPsfFactory(_getPersistenceName());
290 static PersistenceHelper
const &
keys = PersistenceHelper::get();
296 record->set(
keys.controlIndex, handle.put(_warpingControl));
298 handle.saveCatalog(catalog);
afw::table::Key< double > b
#define LSST_EXCEPT(type,...)
#define LSST_ARCHIVE_ASSERT(EXPR)
afw::table::Key< int > controlIndex
afw::table::Key< int > transformIndex
afw::table::Key< int > psfIndex
afw::table::Schema schema
virtual std::shared_ptr< afw::table::io::Persistable > read(afw::table::io::InputArchive const &archive, afw::table::io::CatalogVector const &catalogs) const
image::Image< Pixel > Image
_view_t::x_iterator x_iterator
std::shared_ptr< BaseRecord > addNew()
static std::shared_ptr< T > dynamicCast(std::shared_ptr< Persistable > const &ptr)
PersistableFactory(std::string const &name)
io::OutputArchiveHandle OutputArchiveHandle
double getMinY() const noexcept
double getWidth() const noexcept
double getMinX() const noexcept
double getHeight() const noexcept
An intermediate base class for Psfs that use an image representation.
void write(OutputArchiveHandle &handle) const override
std::shared_ptr< afw::detection::Psf > resized(int width, int height) const override
Return a clone with specified kernel dimensions.
geom::Point2D getAveragePosition() const override
Return the average of the positions of the stars that went into this Psf.
std::shared_ptr< afw::detection::Psf::Image > doComputeKernelImage(geom::Point2D const &position, afw::image::Color const &color) const override
std::shared_ptr< afw::geom::TransformPoint2ToPoint2 const > _distortion
std::shared_ptr< afw::detection::Psf const > _undistortedPsf
WarpedPsf(std::shared_ptr< afw::detection::Psf const > undistortedPsf, std::shared_ptr< afw::geom::TransformPoint2ToPoint2 const > distortion, std::shared_ptr< afw::math::WarpingControl const > control)
Construct WarpedPsf from unwarped psf and distortion.
std::string getPersistenceName() const override
std::shared_ptr< afw::detection::Psf > clone() const override
Polymorphic deep copy. Usually unnecessary, as Psfs are immutable.
std::string getPythonModule() const override
std::shared_ptr< TransformPoint2ToPoint2 > makeTransform(lsst::geom::AffineTransform const &affine)
Transform< Point2Endpoint, Point2Endpoint > TransformPoint2ToPoint2
lsst::geom::AffineTransform linearizeTransform(TransformPoint2ToPoint2 const &original, lsst::geom::Point2D const &inPoint)
int warpImage(DestImageT &destImage, geom::SkyWcs const &destWcs, SrcImageT const &srcImage, geom::SkyWcs const &srcWcs, WarpingControl const &control, typename DestImageT::SinglePixel padValue=lsst::afw::math::edgePixel< DestImageT >(typename lsst::afw::image::detail::image_traits< DestImageT >::image_category()))
Point< double, 2 > Point2D
Extent< int, 2 > Extent2I