73static inline void checkWarpingKernelParameter(
const SeparableKernel *p,
unsigned int ind,
double value) {
76 "bad ind argument in WarpingKernel::setKernelParameter()");
78 int ctr =
p->getCtr()[ind];
79 int size =
p->getDimensions()[ind];
81 if (ctr == (size - 1) / 2) {
82 if (value < -1e-6 || value > 1 + 1e-6) {
84 "bad coordinate in WarpingKernel::setKernelParameter()");
86 }
else if (ctr == (size + 1) / 2) {
87 if (value < -1 - 1e-6 || value > 1e-6) {
89 "bad coordinate in WarpingKernel::setKernelParameter()");
93 "bad ctr value in WarpingKernel::setKernelParameter()");
104 checkWarpingKernelParameter(
this, ind, value);
125 return 0.5 + (1.0 - (2.0 * fabs(this->
_params[0]))) * (0.5 - fabs(x));
129 checkWarpingKernelParameter(
this, ind, value);
135 os <<
"_BilinearFunction1: ";
136 os << Function1<Kernel::Pixel>::toString(prefix);
146 return static_cast<double>((fabs(this->
_params[0]) < 0.5) == (fabs(x) < 0.5));
150 checkWarpingKernelParameter(
this, ind, value);
156 os <<
"_NearestFunction1: ";
157 os << Function1<Kernel::Pixel>::toString(prefix);
163struct LanczosKernelPersistenceHelper {
167 static LanczosKernelPersistenceHelper
const &get() {
168 static LanczosKernelPersistenceHelper
const instance;
172 LanczosKernelPersistenceHelper(LanczosKernelPersistenceHelper
const &) =
delete;
173 LanczosKernelPersistenceHelper(LanczosKernelPersistenceHelper &&) =
delete;
174 LanczosKernelPersistenceHelper &operator=(LanczosKernelPersistenceHelper
const &) =
delete;
175 LanczosKernelPersistenceHelper &operator=(LanczosKernelPersistenceHelper &&) =
delete;
178 LanczosKernelPersistenceHelper()
179 : schema(), order(schema.addField<int>(
"order",
"order of Lanczos function")) {}
182class :
public table::io::PersistableFactory {
184 table::io::CatalogVector
const &catalogs)
const override {
185 auto const &keys = LanczosKernelPersistenceHelper::get();
194} lanczosFactory(
"LanczosWarpingKernel");
197class DefaultPersistableFactory :
public table::io::PersistableFactory {
198 std::shared_ptr<table::io::Persistable>
read(table::io::InputArchive
const &archive,
199 table::io::CatalogVector
const &catalogs)
const override {
204 using table::io::PersistableFactory::PersistableFactory;
207DefaultPersistableFactory<BilinearWarpingKernel> bilinearFactory(
"BilinearWarpingKernel");
208DefaultPersistableFactory<NearestWarpingKernel> nearestFactory(
"NearestWarpingKernel");
213 auto const &keys = LanczosKernelPersistenceHelper::get();
216 record->set(keys.order,
getOrder());
227 static const std::regex LanczosRE(
"lanczos(\\d+)");
228 if (name ==
"bilinear") {
231 std::string orderStr(matches[1].first, matches[1].second);
234 }
else if (name ==
"nearest") {
237 throw LSST_EXCEPT(pexExcept::InvalidParameterError,
"unknown warping kernel name: \"" + name +
"\"");
242 if (_warpingKernelPtr->getCacheSize() != _cacheSize) {
243 _warpingKernelPtr->computeCache(_cacheSize);
245 return _warpingKernelPtr;
254 if (_maskWarpingKernelPtr) {
255 _testWarpingKernels(warpingKernel, *_maskWarpingKernelPtr);
259 _warpingKernelPtr = warpingKernelPtr;
263 if (_maskWarpingKernelPtr) {
264 if (_maskWarpingKernelPtr->getCacheSize() != _cacheSize) {
265 _maskWarpingKernelPtr->computeCache(_cacheSize);
268 return _maskWarpingKernelPtr;
272 if (!maskWarpingKernelName.
empty()) {
276 _maskWarpingKernelPtr.reset();
281 _testWarpingKernels(*_warpingKernelPtr, maskWarpingKernel);
285void WarpingControl::_testWarpingKernels(
SeparableKernel const &warpingKernel,
293 if (!kernelBBox.
contains(maskKernelBBox)) {
295 "warping kernel is smaller than mask warping kernel");
301struct WarpingControlPersistenceHelper {
302 table::Schema schema;
303 table::Key<int> warpingKernelIndex;
304 table::Key<table::Flag> hasMaskKernel;
305 table::Key<int> maskKernelIndex;
306 table::Key<int> cacheSize;
307 table::Key<int> interpLength;
308 table::Key<image::MaskPixel> growFullMask;
310 static WarpingControlPersistenceHelper
const &get() {
311 static WarpingControlPersistenceHelper
const instance;
315 WarpingControlPersistenceHelper(WarpingControlPersistenceHelper
const &) =
delete;
316 WarpingControlPersistenceHelper(WarpingControlPersistenceHelper &&) =
delete;
317 WarpingControlPersistenceHelper &operator=(WarpingControlPersistenceHelper
const &) =
delete;
318 WarpingControlPersistenceHelper &operator=(WarpingControlPersistenceHelper &&) =
delete;
321 WarpingControlPersistenceHelper()
324 schema.addField<int>(
"warpingKernelIndex",
"archive ID of nested warping kernel")),
325 hasMaskKernel(schema.addField<table::Flag>(
"hasMaskKernel",
"whether a mask kernel is stored")),
326 maskKernelIndex(schema.addField<int>(
"maskKernelIndex",
327 "archive ID of nested mask kernel. "
328 "Valid only if hasMaskKernel")),
329 cacheSize(schema.addField<int>(
"cacheSize",
"Cache size for warping kernel(s)")),
330 interpLength(schema.addField<int>(
"interpLength",
331 "Distance over which WCS can be linearly interpolated")),
332 growFullMask(schema.addField<
image::MaskPixel>(
333 "growFullMask",
"bits to grow to full width of image/variance kernel")) {}
336std::string _getWarpingControlPersistenceName() {
return "WarpingControl"; }
338class :
public table::io::PersistableFactory {
339 std::shared_ptr<table::io::Persistable>
read(table::io::InputArchive
const &archive,
340 table::io::CatalogVector
const &catalogs)
const override {
341 auto const &
keys = WarpingControlPersistenceHelper::get();
344 afw::table::BaseRecord
const &record =
catalogs.front().front();
349 record.get(
keys.interpLength),
350 record.get(
keys.growFullMask));
354 control->setWarpingKernel(*archive.get<
SeparableKernel>(record.get(
keys.warpingKernelIndex)));
355 if (record.get(
keys.hasMaskKernel)) {
356 control->setMaskWarpingKernel(*archive.get<
SeparableKernel>(record.get(
keys.maskKernelIndex)));
362} controlFactory(_getWarpingControlPersistenceName());
371 return _warpingKernelPtr->isPersistable() &&
376 auto const &keys = WarpingControlPersistenceHelper::get();
380 record->set(keys.warpingKernelIndex, handle.
put(_warpingKernelPtr));
383 record->set(keys.maskKernelIndex, handle.
put(_maskWarpingKernelPtr));
385 record->set(keys.cacheSize, _cacheSize);
386 record->set(keys.interpLength, _interpLength);
387 record->set(keys.growFullMask, _growFullMask);
392template <
typename DestExposureT,
typename SrcExposureT>
394 typename DestExposureT::MaskedImageT::SinglePixel padValue) {
395 if (!destExposure.hasWcs()) {
396 throw LSST_EXCEPT(pexExcept::InvalidParameterError,
"destExposure has no Wcs");
398 if (!srcExposure.hasWcs()) {
399 throw LSST_EXCEPT(pexExcept::InvalidParameterError,
"srcExposure has no Wcs");
401 typename DestExposureT::MaskedImageT mi = destExposure.getMaskedImage();
402 if (srcExposure.getInfo()->hasId()) {
403 destExposure.getInfo()->setId(srcExposure.getInfo()->getId());
405 destExposure.setPhotoCalib(srcExposure.getPhotoCalib());
406 destExposure.setFilter(srcExposure.getFilter());
407 destExposure.getInfo()->setVisitInfo(srcExposure.getInfo()->getVisitInfo());
408 return warpImage(mi, *destExposure.getWcs(), srcExposure.getMaskedImage(), *srcExposure.getWcs(), control,
418 geom::SkyWcs
const &destWcs,
419 geom::SkyWcs
const &srcWcs)
423 return srcWcs.skyToPixel(destWcs.pixelToSky(destPix));
426inline double computeRelativeArea(
435 return std::abs(dSrcA.getX() * dSrcB.getY() - dSrcA.getY() * dSrcB.getX());
440template <
typename DestImageT,
typename SrcImageT>
441int warpImage(DestImageT &destImage, geom::SkyWcs
const &destWcs, SrcImageT
const &srcImage,
443 typename DestImageT::SinglePixel padValue) {
444 auto srcToDest = geom::makeWcsPairTransform(srcWcs, destWcs);
445 return warpImage(destImage, srcImage, *srcToDest, control, padValue);
448template <
typename DestImageT,
typename SrcImageT>
449int warpImage(DestImageT &destImage, SrcImageT
const &srcImage,
450 geom::TransformPoint2ToPoint2
const &srcToDest,
WarpingControl const &control,
451 typename DestImageT::SinglePixel padValue) {
452 if (imagesOverlap(destImage, srcImage)) {
453 throw LSST_EXCEPT(pexExcept::InvalidParameterError,
"destImage overlaps srcImage; cannot warp");
461 warpingKernelPtr->shrinkBBox(srcImage.getBBox(
image::LOCAL));
463 for (
int y = 0, height = destImage.getHeight(); y < height; ++y) {
464 for (
typename DestImageT::x_iterator destPtr = destImage.row_begin(y), end = destImage.row_end(y);
465 destPtr != end; ++destPtr) {
476 int numGoodPixels = 0;
479 auto const parentDestToParentSrc = srcToDest.inverted();
480 std::vector<double> const localDestToParentDestVec = {
static_cast<double>(destImage.getX0()),
481 static_cast<double>(destImage.getY0())};
482 auto const localDestToParentDest = geom::TransformPoint2ToPoint2(
ast::ShiftMap(localDestToParentDestVec));
483 auto const localDestToParentSrc = localDestToParentDest.then(*parentDestToParentSrc);
486 int const srcWidth = srcImage.getWidth();
487 int const srcHeight = srcImage.getHeight();
488 LOGL_DEBUG(
"TRACE2.lsst.afw.math.warp",
"source image width=%d; height=%d", srcWidth, srcHeight);
490 int const destWidth = destImage.getWidth();
491 int const destHeight = destImage.getHeight();
492 LOGL_DEBUG(
"TRACE2.lsst.afw.math.warp",
"remap image width=%d; height=%d", destWidth, destHeight);
495 LOGL_DEBUG(
"TRACE3.lsst.afw.math.warp",
"Remapping masked image");
497 int const maxCol = destWidth - 1;
498 int const maxRow = destHeight - 1;
502 if (interpLength > 0) {
507 int const numColEdges = 2 + ((destWidth - 1) / interpLength);
512 edgeColList.
reserve(numColEdges);
517 invWidthList.
reserve(numColEdges);
522 for (
int prevEndCol = -1; prevEndCol < maxCol; prevEndCol += interpLength) {
523 int endCol = prevEndCol + interpLength;
524 if (endCol > maxCol) {
528 assert(endCol - prevEndCol > 0);
529 invWidthList.
push_back(1.0 /
static_cast<double>(endCol - prevEndCol));
531 assert(edgeColList.
back() == maxCol);
543 std::vector<lsst::geom::Point2D>::iterator
const srcPosView = srcPosList.
begin() + 1;
546 endColPosList.
reserve(numColEdges);
549 for (
int endCol : edgeColList) {
552 auto rightSrcPosList = localDestToParentSrc->applyForward(endColPosList);
553 srcPosView[-1] = rightSrcPosList[0];
554 for (
int colBand = 1, endBand = edgeColList.
size(); colBand < endBand; ++colBand) {
555 int const prevEndCol = edgeColList[colBand - 1];
556 int const endCol = edgeColList[colBand];
560 (rightSrcPosList[colBand] - leftSrcPos) * invWidthList[colBand];
562 for (
int col = prevEndCol + 1; col <= endCol; ++col) {
563 srcPosView[col] = srcPosView[col - 1] + xDeltaSrcPos;
568 while (endRow < maxRow) {
571 int prevEndRow = endRow;
572 endRow = prevEndRow + interpLength;
573 if (endRow > maxRow) {
576 assert(endRow - prevEndRow > 0);
577 double interpInvHeight = 1.0 /
static_cast<double>(endRow - prevEndRow);
582 for (
int endCol : edgeColList) {
585 auto bottomSrcPosList = localDestToParentSrc->applyForward(destRowPosList);
586 for (
int colBand = 0, endBand = edgeColList.size(); colBand < endBand; ++colBand) {
587 int endCol = edgeColList[colBand];
588 yDeltaSrcPosList[colBand] =
589 (bottomSrcPosList[colBand] - srcPosView[endCol]) * interpInvHeight;
592 for (
int row = prevEndRow + 1; row <= endRow; ++row) {
593 typename DestImageT::x_iterator destXIter = destImage.row_begin(row);
594 srcPosView[-1] += yDeltaSrcPosList[0];
595 for (
int colBand = 1, endBand = edgeColList.size(); colBand < endBand; ++colBand) {
598 int const prevEndCol = edgeColList[colBand - 1];
599 int const endCol = edgeColList[colBand];
608 for (
int col = prevEndCol + 1; col <= endCol; ++col, ++destXIter) {
615 srcPos = bottomSrcPosList[colBand];
620 srcPos = rightSrcPos;
624 srcPos = leftSrcPos + xDeltaSrcPos;
626 double relativeArea = computeRelativeArea(srcPos, leftSrcPos, srcPosView[col]);
628 srcPosView[col] = srcPos;
631 destXIter, srcPos, relativeArea,
646 destPosList.
reserve(1 + destWidth);
647 for (
int col = -1; col < destWidth; ++col) {
650 auto prevSrcPosList = localDestToParentSrc->applyForward(destPosList);
652 for (
int row = 0; row < destHeight; ++row) {
654 for (
int col = -1; col < destWidth; ++col) {
657 auto srcPosList = localDestToParentSrc->applyForward(destPosList);
659 typename DestImageT::x_iterator destXIter = destImage.row_begin(row);
660 for (
int col = 0; col < destWidth; ++col, ++destXIter) {
662 auto srcPos = srcPosList[col + 1];
663 double relativeArea =
664 computeRelativeArea(srcPos, prevSrcPosList[col], prevSrcPosList[col + 1]);
666 if (warpAtOnePoint(destXIter, srcPos, relativeArea,
673 swap(srcPosList, prevSrcPosList);
677 return numGoodPixels;
680template <
typename DestImageT,
typename SrcImageT>
684 typename DestImageT::SinglePixel padValue) {
686 if ((destImage.getWidth() != srcImage.getWidth()) || (destImage.getHeight() != srcImage.getHeight()) ||
687 (destImage.getXY0() != srcImage.getXY0())) {
689 errStream <<
"src and dest images must have same size and xy0.";
690 throw LSST_EXCEPT(pexExcept::InvalidParameterError, errStream.
str());
694 SrcImageT srcImageCopy(srcImage,
true);
695 srcImageCopy.setXY0(0, 0);
696 destImage.setXY0(0, 0);
708 static float t = 0.0;
709 float t_before = 1.0*clock()/CLOCKS_PER_SEC;
710 int n =
warpImage(destImage, srcImageCopy, affTran, control, padValue);
711 float t_after = 1.0*clock()/CLOCKS_PER_SEC;
712 float dt = t_after - t_before;
714 std::cout <<srcImage.getWidth()<<
"x"<<srcImage.getHeight()<<
": "<< dt <<
" "<< t <<
std::endl;
716 int n =
warpImage(destImage, srcImageCopy, *affineTransform22, control, padValue);
720 destImage.setXY0(srcImage.getXY0());
730#define EXPOSURE(PIXTYPE) image::Exposure<PIXTYPE, image::MaskPixel, image::VariancePixel>
731#define MASKEDIMAGE(PIXTYPE) image::MaskedImage<PIXTYPE, image::MaskPixel, image::VariancePixel>
732#define IMAGE(PIXTYPE) image::Image<PIXTYPE>
735#define INSTANTIATE(DESTIMAGEPIXELT, SRCIMAGEPIXELT) \
736 template int warpCenteredImage( \
737 IMAGE(DESTIMAGEPIXELT) & destImage, IMAGE(SRCIMAGEPIXELT) const &srcImage, \
738 lsst::geom::LinearTransform const &linearTransform, lsst::geom::Point2D const ¢erPosition, \
739 WarpingControl const &control, IMAGE(DESTIMAGEPIXELT)::SinglePixel padValue); \
740 NL template int warpCenteredImage( \
741 MASKEDIMAGE(DESTIMAGEPIXELT) & destImage, MASKEDIMAGE(SRCIMAGEPIXELT) const &srcImage, \
742 lsst::geom::LinearTransform const &linearTransform, lsst::geom::Point2D const ¢erPosition, \
743 WarpingControl const &control, MASKEDIMAGE(DESTIMAGEPIXELT)::SinglePixel padValue); \
744 NL template int warpImage(IMAGE(DESTIMAGEPIXELT) & destImage, IMAGE(SRCIMAGEPIXELT) const &srcImage, \
745 geom::TransformPoint2ToPoint2 const &srcToDest, WarpingControl const &control, \
746 IMAGE(DESTIMAGEPIXELT)::SinglePixel padValue); \
747 NL template int warpImage(MASKEDIMAGE(DESTIMAGEPIXELT) & destImage, \
748 MASKEDIMAGE(SRCIMAGEPIXELT) const &srcImage, \
749 geom::TransformPoint2ToPoint2 const &srcToDest, WarpingControl const &control, \
750 MASKEDIMAGE(DESTIMAGEPIXELT)::SinglePixel padValue); \
751 NL template int warpImage(IMAGE(DESTIMAGEPIXELT) & destImage, geom::SkyWcs const &destWcs, \
752 IMAGE(SRCIMAGEPIXELT) const &srcImage, geom::SkyWcs const &srcWcs, \
753 WarpingControl const &control, IMAGE(DESTIMAGEPIXELT)::SinglePixel padValue); \
754 NL template int warpImage(MASKEDIMAGE(DESTIMAGEPIXELT) & destImage, geom::SkyWcs const &destWcs, \
755 MASKEDIMAGE(SRCIMAGEPIXELT) const &srcImage, geom::SkyWcs const &srcWcs, \
756 WarpingControl const &control, \
757 MASKEDIMAGE(DESTIMAGEPIXELT)::SinglePixel padValue); \
758 NL template int warpExposure(EXPOSURE(DESTIMAGEPIXELT) & destExposure, \
759 EXPOSURE(SRCIMAGEPIXELT) const &srcExposure, WarpingControl const &control, \
760 EXPOSURE(DESTIMAGEPIXELT)::MaskedImageT::SinglePixel padValue);
#define INSTANTIATE(FROMSYS, TOSYS)
#define LSST_EXCEPT(type,...)
Create an exception with a given type.
LSST DM logging module built on log4cxx.
#define LOGL_DEBUG(logger, message...)
Log a debug-level message using a varargs/printf style interface.
Implementation of the Photometric Calibration class.
#define LSST_ARCHIVE_ASSERT(EXPR)
An assertion macro used to validate the structure of an InputArchive.
ShiftMap is a linear Mapping which shifts each axis by a specified constant value.
std::string toString(std::string const &="") const override
Return string representation.
Kernel::Pixel operator()(double x) const override
Solve bilinear equation.
void write(OutputArchiveHandle &handle) const override
Write the object to one or more catalogs.
std::shared_ptr< Kernel > clone() const override
Return a pointer to a deep copy of this kernel.
void setKernelParameter(unsigned int ind, double value) const override
Set one kernel parameter.
std::vector< double > _params
lsst::geom::Extent2I const getDimensions() const
Return the Kernel's dimensions (width, height)
lsst::geom::Point2I getCtr() const
Return index of kernel's center.
int getWidth() const
Return the Kernel's width.
Lanczos warping: accurate but slow and can introduce ringing artifacts.
int getOrder() const
get the order of the kernel
LanczosWarpingKernel(int order)
void setKernelParameter(unsigned int ind, double value) const override
Set one kernel parameter.
std::shared_ptr< Kernel > clone() const override
Return a pointer to a deep copy of this kernel.
void write(OutputArchiveHandle &handle) const override
Write the object to one or more catalogs.
Kernel::Pixel operator()(double x) const override
Solve nearest neighbor equation.
std::string toString(std::string const &="") const override
Return string representation.
Nearest neighbor warping: fast; good for undersampled data.
std::shared_ptr< Kernel > clone() const override
Return a pointer to a deep copy of this kernel.
void write(OutputArchiveHandle &handle) const override
Write the object to one or more catalogs.
void setKernelParameter(unsigned int ind, double value) const override
Set one kernel parameter.
A kernel described by a pair of functions: func(x, y) = colFunc(x) * rowFunc(y)
std::shared_ptr< Kernel > clone() const override
Return a pointer to a deep copy of this kernel.
void setKernelParameter(unsigned int ind, double value) const override
Set one kernel parameter.
SeparableKernel()
Construct an empty spatially invariant SeparableKernel of size 0x0.
Parameters to control convolution.
bool hasMaskWarpingKernel() const
return true if there is a mask kernel
void setWarpingKernel(SeparableKernel const &warpingKernel)
set the warping kernel
int getInterpLength() const
get the interpolation length (pixels)
std::string getPythonModule() const override
Return the fully-qualified Python module that should be imported to guarantee that its factory is reg...
void setWarpingKernelName(std::string const &warpingKernelName)
set the warping kernel by name
void setMaskWarpingKernelName(std::string const &maskWarpingKernelName)
set or clear the mask warping kernel by name
std::string getPersistenceName() const override
Return the unique name used to persist this object and look up its factory.
void setMaskWarpingKernel(SeparableKernel const &maskWarpingKernel)
set the mask warping kernel
std::shared_ptr< SeparableKernel > getWarpingKernel() const
get the warping kernel
void write(OutputArchiveHandle &handle) const override
Write the object to one or more catalogs.
std::shared_ptr< SeparableKernel > getMaskWarpingKernel() const
get the mask warping kernel
bool isPersistable() const noexcept override
Return true if this particular object can be persisted using afw::table::io.
A functor that computes one warped pixel.
Base class for all records.
Field< T >::Value get(Key< T > const &key) const
Return the value of a field for the given key.
Schema getSchema() const
Return the Schema that holds this record's fields and keys.
A class used as a handle to a particular field in a table.
Defines the fields and offsets for a table.
void saveCatalog(BaseCatalog const &catalog)
Save a catalog in the archive.
void saveEmpty()
Indicate that the object being persisted has no state, and hence will never call makeCatalog() or sav...
BaseCatalog makeCatalog(Schema const &schema)
Return a new, empty catalog with the given schema.
int put(Persistable const *obj, bool permissive=false)
Save an object to the archive and return a unique ID that can be used to retrieve it from an InputArc...
PersistableFactory(std::string const &name)
Constructor for the factory.
io::OutputArchiveHandle OutputArchiveHandle
An integer coordinate rectangle.
bool contains(Point2I const &point) const noexcept
Return true if the box contains the point.
Reports invalid arguments.
T emplace_back(T... args)
double indexToPosition(double ind)
Convert image index to image position.
std::shared_ptr< SeparableKernel > makeWarpingKernel(std::string name)
Return a warping kernel given its name.
int warpCenteredImage(DestImageT &destImage, SrcImageT const &srcImage, lsst::geom::LinearTransform const &linearTransform, lsst::geom::Point2D const ¢erPosition, WarpingControl const &control, typename DestImageT::SinglePixel padValue=lsst::afw::math::edgePixel< DestImageT >(typename lsst::afw::image::detail::image_traits< DestImageT >::image_category()))
Warp an image with a LinearTranform about a specified point.
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()))
Warp an Image or MaskedImage to a new Wcs.
int warpExposure(DestExposureT &destExposure, SrcExposureT const &srcExposure, WarpingControl const &control, typename DestExposureT::MaskedImageT::SinglePixel padValue=lsst::afw::math::edgePixel< typename DestExposureT::MaskedImageT >(typename lsst::afw::image::detail::image_traits< typename DestExposureT::MaskedImageT >::image_category()))
Warp (remap) one exposure to another.
CatalogT< BaseRecord > BaseCatalog
Extent< double, 2 > Extent2D
Point< double, 2 > Point2D
Extent< int, 2 > Extent2I
T static_pointer_cast(T... args)
typename ImageT::image_category image_category
std::shared_ptr< table::io::Persistable > read(table::io::InputArchive const &archive, table::io::CatalogVector const &catalogs) const override