LSST Applications g0b6bd0c080+a72a5dd7e6,g1182afd7b4+2a019aa3bb,g17e5ecfddb+2b8207f7de,g1d67935e3f+06cf436103,g38293774b4+ac198e9f13,g396055baef+6a2097e274,g3b44f30a73+6611e0205b,g480783c3b1+98f8679e14,g48ccf36440+89c08d0516,g4b93dc025c+98f8679e14,g5c4744a4d9+a302e8c7f0,g613e996a0d+e1c447f2e0,g6c8d09e9e7+25247a063c,g7271f0639c+98f8679e14,g7a9cd813b8+124095ede6,g9d27549199+a302e8c7f0,ga1cf026fa3+ac198e9f13,ga32aa97882+7403ac30ac,ga786bb30fb+7a139211af,gaa63f70f4e+9994eb9896,gabf319e997+ade567573c,gba47b54d5d+94dc90c3ea,gbec6a3398f+06cf436103,gc6308e37c7+07dd123edb,gc655b1545f+ade567573c,gcc9029db3c+ab229f5caf,gd01420fc67+06cf436103,gd877ba84e5+06cf436103,gdb4cecd868+6f279b5b48,ge2d134c3d5+cc4dbb2e3f,ge448b5faa6+86d1ceac1d,gecc7e12556+98f8679e14,gf3ee170dca+25247a063c,gf4ac96e456+ade567573c,gf9f5ea5b4d+ac198e9f13,gff490e6085+8c2580be5c,w.2022.27
LSST Data Management Base Package
BasisLists.cc
Go to the documentation of this file.
1// -*- lsst-c++ -*-
11#include <cmath>
12#include <limits>
13
14#include "boost/timer.hpp"
15
18#include "lsst/afw/image.h"
19#include "lsst/afw/math.h"
20#include "lsst/geom.h"
21#include "lsst/log/Log.h"
23
25namespace geom = lsst::geom;
26namespace afwImage = lsst::afw::image;
27namespace afwMath = lsst::afw::math;
28
29namespace lsst {
30namespace ip {
31namespace diffim {
32
48 int width,
49 int height
50 ) {
51 if ((width < 1) || (height < 1)) {
52 throw LSST_EXCEPT(pexExcept::Exception, "nRows and nCols must be positive");
53 }
54 const int signedWidth = static_cast<int>(width);
55 const int signedHeight = static_cast<int>(height);
56 afwMath::KernelList kernelBasisList;
57 for (int row = 0; row < signedHeight; ++row) {
58 for (int col = 0; col < signedWidth; ++col) {
60 kernelPtr(new afwMath::DeltaFunctionKernel(width, height, geom::Point2I(col,row)));
61 kernelBasisList.push_back(kernelPtr);
62 }
63 }
64 return kernelBasisList;
65 }
66
79 int halfWidth,
80 int nGauss,
81 std::vector<double> const &sigGauss,
82 std::vector<int> const &degGauss
83 ) {
85 typedef afwImage::Image<Pixel> Image;
86
87 if (halfWidth < 1) {
88 throw LSST_EXCEPT(pexExcept::Exception, "halfWidth must be positive");
89 }
90 if (nGauss != static_cast<int>(sigGauss.size())) {
91 throw LSST_EXCEPT(pexExcept::Exception, "sigGauss does not have enough entries");
92 }
93 if (nGauss != static_cast<int>(degGauss.size())) {
94 throw LSST_EXCEPT(pexExcept::Exception, "degGauss does not have enough entries");
95 }
96 int fullWidth = 2 * halfWidth + 1;
97 Image image(geom::Extent2I(fullWidth, fullWidth));
98
99 afwMath::KernelList kernelBasisList;
100 for (int i = 0; i < nGauss; i++) {
101 /*
102 sigma = FWHM / ( 2 * sqrt(2 * ln(2)) )
103 */
104 double sig = sigGauss[i];
105 int deg = degGauss[i];
106
107 LOGL_DEBUG("TRACE1.ip.diffim.BasisLists.makeAlardLuptonBasisList",
108 "Gaussian %d : sigma %.2f degree %d", i, sig, deg);
109
110 afwMath::GaussianFunction2<Pixel> gaussian(sig, sig);
111 afwMath::AnalyticKernel kernel(fullWidth, fullWidth, gaussian);
113
114 for (int j = 0, n = 0; j <= deg; j++) {
115 for (int k = 0; k <= (deg - j); k++, n++) {
116 /* for 0th order term, skip polynomial */
117 (void)kernel.computeImage(image, true);
118 if (n == 0) {
120 kernelPtr(new afwMath::FixedKernel(image));
121 kernelBasisList.push_back(kernelPtr);
122 continue;
123 }
124
125 /* gaussian to be modified by this term in the polynomial */
126 polynomial.setParameter(n, 1.);
127 (void)kernel.computeImage(image, true);
128 for (int y = 0, v = -halfWidth; y < image.getHeight(); y++, v++) {
129 int u = -halfWidth;
130 for (auto ptr = image.row_begin(y), end = image.row_end(y); ptr != end; ++ptr, ++u) {
131 /* Evaluate from -1 to 1 */
132 *ptr = *ptr * polynomial(u/static_cast<double>(halfWidth),
133 v/static_cast<double>(halfWidth));
134 }
135 }
137 kernelPtr(new afwMath::FixedKernel(image));
138 kernelBasisList.push_back(kernelPtr);
139 polynomial.setParameter(n, 0.);
140 }
141 }
142 }
143 return renormalizeKernelList(kernelBasisList);
144 }
145
146
149 ) {
150
151 /* NOTES
152 *
153 * The 3-point first derivative central difference (Laplacian) yields
154 * diagonal stripes and should not be used.
155
156 coeffs[0][1] = -1. / 2.;
157 coeffs[1][0] = -1. / 2.;
158 coeffs[1][2] = 1. / 2.;
159 coeffs[2][1] = 1. / 2.;
160
161 * The 5-point second derivative central difference (Laplacian) looks great.
162 * For smaller lambdas you need a higher border penalty. In general, if you
163 * decrease the regularization strength you should increase the border
164 * penalty to avoid noise in the border pixels. This has been used to value
165 * 10 and things still look OK.
166
167 * The 9-point second derivative central difference (Laplacian with off
168 * diagonal terms) also looks great. Seems to have slightly higher-valued
169 * border pixels so make boundary larger if using this. E.g. 1.5.
170
171 * The forward finite difference, first derivative term works good
172 *
173 * The forward finite difference, second derivative term is slightly banded
174 * in LLC
175 *
176 * The forward finite difference, third derivative term is highly banded in
177 * LLC and should not be used.
178 *
179 */
180
181 std::string regularizationType = ps.getAsString("regularizationType");
182 int width = ps.getAsInt("kernelSize");
183 int height = ps.getAsInt("kernelSize");
184 float borderPenalty = ps.getAsDouble("regularizationBorderPenalty");
185 bool fitForBackground = ps.getAsBool("fitForBackground");
186
187 Eigen::MatrixXd bMat;
188 if (regularizationType == "centralDifference") {
189 int stencil = ps.getAsInt("centralRegularizationStencil");
190 bMat = makeCentralDifferenceMatrix(width, height, stencil, borderPenalty, fitForBackground);
191 }
192 else if (regularizationType == "forwardDifference") {
193 std::vector<int> orders = ps.getArray<int>("forwardRegularizationOrders");
194 bMat = makeForwardDifferenceMatrix(width, height, orders, borderPenalty, fitForBackground);
195 }
196 else {
197 throw LSST_EXCEPT(pexExcept::Exception, "regularizationType not recognized");
198 }
199
200 Eigen::MatrixXd hMat = bMat.transpose() * bMat;
201 return hMat;
202 }
203
208 int width,
209 int height,
210 int stencil,
211 float borderPenalty,
212 bool fitForBackground
213 ) {
214
215 /* 5- or 9-point stencil to approximate the Laplacian; i.e. this is a second
216 * order central finite difference.
217 *
218 * 5-point approximation ignores off-diagonal elements, and is
219 *
220 * f(x-1,y) + f(x+1,y) + f(x,y-1) + f(x,y+1) - 4 f(x,y)
221 *
222 * 0 1 0
223 * 1 -4 1
224 * 0 1 0
225 *
226 *
227 * 9-point approximation includes diagonals and is
228 *
229 * 1 4 1
230 * 4 -20 4 / 6
231 * 1 4 1
232 *
233 */
234
235 if (borderPenalty < 0)
236 throw LSST_EXCEPT(pexExcept::Exception, "Only border penalty of >= 0 allowed");
237
239 coeffs(3, std::vector<float>(3,0));
240
241 if (stencil == 5) {
242 /* http://www.physics.arizona.edu/~restrepo/475B/Notes/source/node51.html
243 *
244 * This is equivalent to a second order central difference summed along
245 * the x-axis, and then summed along the y-axis.
246 *
247 * http://www.holoborodko.com/pavel/?page_id=239
248 *
249 */
250 coeffs[0][1] = 1.;
251 coeffs[1][0] = 1.;
252 coeffs[1][1] = -4.;
253 coeffs[1][2] = 1.;
254 coeffs[2][1] = 1.;
255 }
256 else if (stencil == 9) {
257 /* http://www.physics.arizona.edu/~restrepo/475B/Notes/source/node52.html */
258 coeffs[0][0] = 1. / 6.;
259 coeffs[0][1] = 4. / 6.;
260 coeffs[0][2] = 1. / 6.;
261 coeffs[1][0] = 4. / 6.;
262 coeffs[1][1] = -20. / 6.;
263 coeffs[1][2] = 4. / 6.;
264 coeffs[2][0] = 1. / 6.;
265 coeffs[2][1] = 4. / 6.;
266 coeffs[2][2] = 1. / 6.;
267 }
268 else {
269 throw LSST_EXCEPT(pexExcept::Exception, "Only 5- or 9-point Laplacian stencils allowed");
270 }
271
272 int nBgTerms = fitForBackground ? 1 : 0;
273 Eigen::MatrixXd bMat = Eigen::MatrixXd::Zero(width * height + nBgTerms, width * height + nBgTerms);
274
275 for (int i = 0; i < width*height; i++) {
276 int const x0 = i % width; // the x coord in the kernel image
277 int const y0 = i / width; // the y coord in the kernel image
278 int const distX = width - x0 - 1; // distance from edge of image
279 int const distY = height - y0 - 1; // distance from edge of image
280
281 if ( (x0 > 0) && (y0 > 0) && (distX > 0) && (distY > 0) ) {
282 for (int dx = -1; dx < 2; dx += 1) {
283 for (int dy = -1; dy < 2; dy += 1) {
284 bMat(i, i + dx + dy * width) += coeffs[dx+1][dy+1];
285 }
286 }
287 }
288 else {
289 bMat(i, i) = borderPenalty;
290 }
291 }
292
293 if (fitForBackground) {
294 /* Last row / col should have no regularization since its the background term */
295 if (bMat.col(width*height).sum() != 0.) {
296 throw LSST_EXCEPT(pexExcept::Exception, "Error 1 in regularization matrix");
297 }
298 if (bMat.row(width*height).sum() != 0.) {
299 throw LSST_EXCEPT(pexExcept::Exception, "Error 2 in regularization matrix");
300 }
301 }
302
303 return bMat;
304 }
305
310 int width,
311 int height,
312 std::vector<int> const& orders,
313 float borderPenalty,
314 bool fitForBackground
315 ) {
316
317 /*
318 Instead of Taylor expanding the forward difference approximation of
319 derivatives (N.R. section 18.5) lets just hard code in the expansion of
320 the 1st through 3rd derivatives, which will try and enforce smoothness of
321 0 through 2nd derivatives.
322
323 A property of the basic "finite difference regularization" is that their
324 rows (column multipliers) sum to 0.
325
326 We taper the order of the constraint as you get close to the boundary.
327 The actual perimeter values are left unconstrained but we might want to
328 consider giving these the same penalties as the other border pixels,
329 which is +1 (since the value gets squared).
330
331 */
332
333 if (borderPenalty < 0)
334 throw LSST_EXCEPT(pexExcept::Exception, "Only border penalty of >= 0 allowed");
335
337 coeffs(4, std::vector<float>(4,0));
338
339 // penalize border? this is along the diagonal and gets squared, so sign does not matter
340 coeffs[0][0] = borderPenalty;
341
342 // penalize zeroth derivative
343 coeffs[1][0] = -1.;
344 coeffs[1][1] = +1.;
345
346 // penalize first derivative
347 coeffs[2][0] = -1.;
348 coeffs[2][1] = +2.;
349 coeffs[2][2] = -1.;
350
351 // penalize second derivative
352 coeffs[3][0] = -1.;
353 coeffs[3][1] = +3.;
354 coeffs[3][2] = -3.;
355 coeffs[3][3] = +1.;
356
357 int nBgTerms = fitForBackground ? 1 : 0;
358 Eigen::MatrixXd bTot = Eigen::MatrixXd::Zero(width * height + nBgTerms, width * height + nBgTerms);
359
361 for (order = orders.begin(); order != orders.end(); order++) {
362 if ((*order < 1) || (*order > 3))
363 throw LSST_EXCEPT(pexExcept::Exception, "Only orders 1..3 allowed");
364
365 Eigen::MatrixXd bMatX = Eigen::MatrixXd::Zero(width * height + nBgTerms,
366 width * height + nBgTerms);
367 Eigen::MatrixXd bMatY = Eigen::MatrixXd::Zero(width * height + nBgTerms,
368 width * height + nBgTerms);
369
370 for (int i = 0; i < width*height; i++) {
371 int const x0 = i % width; // the x coord in the kernel image
372 int const y0 = i / width; // the y coord in the kernel image
373
374 int distX = width - x0 - 1; // distance from edge of image
375 int orderToUseX = std::min(distX, *order);
376 for (int j = 0; j < orderToUseX+1; j++) {
377 bMatX(i, i + j) = coeffs[orderToUseX][j];
378 }
379
380 int distY = height - y0 - 1; // distance from edge of image
381 int orderToUseY = std::min(distY, *order);
382 for (int j = 0; j < orderToUseY+1; j++) {
383 bMatY(i, i + j * width) = coeffs[orderToUseY][j];
384 }
385 }
386 bTot += bMatX;
387 bTot += bMatY;
388 }
389
390 if (fitForBackground) {
391 /* Last row / col should have no regularization since its the background term */
392 if (bTot.col(width*height).sum() != 0.) {
393 throw LSST_EXCEPT(pexExcept::Exception, "Error in regularization matrix");
394 }
395 if (bTot.row(width*height).sum() != 0.) {
396 throw LSST_EXCEPT(pexExcept::Exception, "Error in regularization matrix");
397 }
398 }
399
400 return bTot;
401 }
402
403
413 lsst::afw::math::KernelList const &kernelListIn
414 ) {
416 typedef afwImage::Image<Pixel> Image;
417 double kSum;
418
419 /*
420
421 We want all the bases except for the first to sum to 0.0. This allows
422 us to achieve kernel flux conservation (Ksum) across the image since all
423 the power will be in the first term, which will not vary spatially.
424
425 K(x,y) = Ksum * B_0 + Sum_i : a(x,y) * B_i
426
427 To do this, normalize all Kernels to sum = 1. and subtract B_0 from all
428 subsequent kenrels.
429
430 To get an idea of the relative contribution of each of these basis
431 functions later on down the line, lets also normalize them such that
432
433 Sum(B_i) == 0.0 *and*
434 B_i * B_i == 1.0
435
436 For completeness
437
438 Sum(B_0) == 1.0
439 B_0 * B_0 != 1.0
440
441 */
442 afwMath::KernelList kernelListOut;
443 if (kernelListIn.size() == 0) {
444 return kernelListOut;
445 }
446
447 Image image0(kernelListIn[0]->getDimensions());
448 for (unsigned int i = 0; i < kernelListIn.size(); i++) {
449 if (i == 0) {
450 /* Make sure that it is normalized to kSum 1. */
451 (void)kernelListIn[i]->computeImage(image0, true);
453 kernelPtr(new afwMath::FixedKernel(image0));
454 kernelListOut.push_back(kernelPtr);
455
456 continue;
457 }
458
459 /* Don't normalize here */
460 Image image(kernelListIn[i]->getDimensions());
461 (void)kernelListIn[i]->computeImage(image, false);
462 /* image.writeFits(str(boost::format("in_k%d.fits") % i)); */
463
464 /* Check the kernel sum; if its close to zero don't do anything */
465 kSum = 0.;
466 for (int y = 0; y < image.getHeight(); y++) {
467 for (auto ptr = image.row_begin(y), end = image.row_end(y); ptr != end; ++ptr) {
468 kSum += *ptr;
469 }
470 }
471
472 /* std::numeric_limits<float>::epsilon() ~ e-7
473 std::numeric_limits<double>::epsilon() ~ e-16
474
475 If we end up with 2e-16 kernel sum, this still blows up the kernel values.
476 Even though the kernels are double, use the float limits instead
477 */
478 if (fabs(kSum) > std::numeric_limits<float>::epsilon()) {
479 image /= kSum;
480 image -= image0;
481 }
482
483 /* Finally, rescale such that the inner product is 1 */
484 kSum = 0.;
485 for (int y = 0; y < image.getHeight(); y++) {
486 for (auto ptr = image.row_begin(y), end = image.row_end(y); ptr != end; ++ptr) {
487 kSum += *ptr * *ptr;
488 }
489 }
490 image /= std::sqrt(kSum);
491 /* image.writeFits(str(boost::format("out_k%d.fits") % i)); */
492
494 kernelPtr(new afwMath::FixedKernel(image));
495 kernelListOut.push_back(kernelPtr);
496 }
497 return kernelListOut;
498 }
499
500
501
506 unsigned int width,
507 unsigned int height,
508 unsigned int order,
509 unsigned int boundary_style, // 0 = unwrapped, 1 = wrapped, 2 = order-tapered
510 unsigned int difference_style, // 0 = forward, 1 = central
511 bool printB // a debug flag ... remove when done.
512 ) {
513
514 if (order > 2) throw LSST_EXCEPT(pexExcept::Exception, "Only orders 0..2 allowed");
515
516 if (boundary_style > 2) {
517 throw LSST_EXCEPT(pexExcept::Exception, "Boundary styles 0..2 defined");
518 }
519 if (difference_style > 1) {
520 throw LSST_EXCEPT(pexExcept::Exception, "Only forward(0), and central(1) difference types defined");
521 }
522
523 /* what works, and what doesn't */
524 // == good job ==
525 // - order 0, wrapped, forward
526 // - order 1, wrapped or tapered, central or forward
527 // - order 2, wrapped or tapered, forward
528 // == bad job (usually diagongal stripes) ==
529 // - all others
530
531
532 /*
533 Instead of Taylor expanding the forward difference approximation of
534 derivatives (N.R. section 18.5) lets just hard code in the expansion of
535 the 1st through 3rd derivatives, which will try and enforce smoothness of
536 0 through 2nd derivatives.
537
538 A property of the basic "finite difference regularization" is that their
539 rows (column multipliers) sum to 0.
540
541 Another consideration is to use *multiple* finite difference operators as
542 a constraint.
543
544 */
545
546
547 // ===========================================================================
548 // Get the coeffs for the finite differencing
549 // note: The coeffs are stored 2D although they are essentially 1D entities.
550 // The 2d design was chosen to allow cross-terms to be included,
551 // though they are not yet implemented.
552 //
555 unsigned int x_cen = 0, y_cen = 0; // center of reqested order coeffs
556 unsigned int x_cen1 = 0, y_cen1 = 0; // center of order 1 coeffs
557 unsigned int x_cen2 = 0, y_cen2 = 0; // center of order 2 coeffs
558 unsigned int x_size = 0, y_size = 0;
559
560 // forward difference coefficients
561 if (difference_style == 0) {
562
563 y_cen = x_cen = 0;
564 x_cen1 = y_cen1 = 0;
565 x_cen2 = y_cen2 = 0;
566
567 x_size = y_size = order + 2;
568
569 // default forward difference suggested in NR chap 18
570 // 0th order
571 coeffs[0][0][0] = -2;
572 coeffs[0][0][1] = 1;
573 coeffs[0][1][0] = 1;
574 coeffs[0][1][1] = 0;
575
576 // 1st 2
577 coeffs[1][0][0] = -2;
578 coeffs[1][0][1] = 2;
579 coeffs[1][0][2] = -1;
580 coeffs[1][1][0] = 2;
581 coeffs[1][1][1] = 0;
582 coeffs[1][1][2] = 0;
583 coeffs[1][2][0] = -1;
584 coeffs[1][2][1] = 0;
585 coeffs[1][2][2] = 0;
586
587 // 2nd 2
588 coeffs[2][0][0] = -2;
589 coeffs[2][0][1] = 3;
590 coeffs[2][0][2] = -3;
591 coeffs[2][0][3] = 1;
592 coeffs[2][1][0] = 3;
593 coeffs[2][1][1] = 0;
594 coeffs[2][1][2] = 0;
595 coeffs[2][1][3] = 0;
596 coeffs[2][2][0] = -3;
597 coeffs[2][2][1] = 0;
598 coeffs[2][2][2] = 0;
599 coeffs[2][2][3] = 0;
600 coeffs[2][3][0] = 1;
601 coeffs[2][3][1] = 0;
602 coeffs[2][3][2] = 0;
603 coeffs[2][3][3] = 0;
604 }
605
606 // central difference coefficients
607 if (difference_style == 1) {
608
609 // this is asymmetric and produces diagonal banding in the kernel
610 // from: http://www.holoborodko.com/pavel/?page_id=239
611 if (order == 0) {
612 y_cen = x_cen = 1;
613 x_size = y_size = 3;
614 }
615 coeffs[0][0][0] = 0;
616 coeffs[0][0][1] = -1;
617 coeffs[0][0][2] = 0;
618
619 coeffs[0][1][0] = -1;
620 coeffs[0][1][1] = 0;
621 coeffs[0][1][2] = 1;
622
623 coeffs[0][2][0] = 0;
624 coeffs[0][2][1] = 1;
625 coeffs[0][2][2] = 0;
626
627
628 // this works well and is largely the same as order=1 forward-diff.
629 // from: http://www.holoborodko.com/pavel/?page_id=239
630 if (order == 1) {
631 y_cen = x_cen = 1;
632 x_size = y_size = 3;
633 }
634 y_cen1 = x_cen1 = 1;
635 coeffs[1][0][0] = 0;
636 coeffs[1][0][1] = 1;
637 coeffs[1][0][2] = 0;
638
639 coeffs[1][1][0] = 1;
640 coeffs[1][1][1] = -4;
641 coeffs[1][1][2] = 1;
642
643 coeffs[1][2][0] = 0;
644 coeffs[1][2][1] = 1;
645 coeffs[1][2][2] = 0;
646
647
648 // asymmetric and produces diagonal banding in the kernel
649 // from http://www.holoborodko.com/pavel/?page_id=239
650 if (order == 2) {
651 y_cen = x_cen = 2;
652 x_size = y_size = 5;
653 }
654 y_cen2 = x_cen2 = 2;
655 coeffs[2][0][0] = 0;
656 coeffs[2][0][1] = 0;
657 coeffs[2][0][2] = -1;
658 coeffs[2][0][3] = 0;
659 coeffs[2][0][4] = 0;
660
661 coeffs[2][1][0] = 0;
662 coeffs[2][1][1] = 0;
663 coeffs[2][1][2] = 2;
664 coeffs[2][1][3] = 0;
665 coeffs[2][1][4] = 0;
666
667 coeffs[2][2][0] = -1;
668 coeffs[2][2][1] = 2;
669 coeffs[2][2][2] = 0;
670 coeffs[2][2][3] = -2;
671 coeffs[2][2][4] = 1;
672
673 coeffs[2][3][0] = 0;
674 coeffs[2][3][1] = 0;
675 coeffs[2][3][2] = -2;
676 coeffs[2][3][3] = 0;
677 coeffs[2][3][4] = 0;
678
679 coeffs[2][4][0] = 0;
680 coeffs[2][4][1] = 0;
681 coeffs[2][4][2] = 1;
682 coeffs[2][4][3] = 0;
683 coeffs[2][4][4] = 0;
684 }
685
686
687 /* Note we have to add 1 extra (empty) term here because of the differential
688 * background fitting */
689 Eigen::MatrixXd bMat = Eigen::MatrixXd::Zero(width*height+1, width*height+1);
690
691 /* Forward difference approximation */
692 for (unsigned int i = 0; i < width*height; i++) {
693
694 unsigned int const x0 = i % width; // the x coord in the kernel image
695 unsigned int const y0 = i / width; // the y coord in the kernel image
696
697 unsigned int x_edge_distance = (x0 > (width - x0 - 1)) ? width - x0 - 1 : x0;
698 unsigned int y_edge_distance = (y0 > (height - y0 - 1)) ? height - y0 - 1 : y0;
699 unsigned int edge_distance = (x_edge_distance < y_edge_distance) ? x_edge_distance :
700 y_edge_distance;
701
702 for (unsigned int dx = 0; dx < x_size; dx++) {
703 for (unsigned int dy = 0; dy < y_size; dy++) {
704
705 // determine where to put this coeff
706
707 // handle the boundary condition
708 // note: adding width and height in the sum prevents negatives
709 unsigned int x = 0;
710 unsigned int y = 0;
711 double this_coeff = 0;
712
713 // no-wrapping at edges
714 if (boundary_style == 0) {
715 x = x0 + dx - x_cen;
716 y = y0 + dy - y_cen;
717 if (y > height - 1 || x > width - 1) {
718 continue;
719 }
720 this_coeff = coeffs[order][dx][dy];
721
722 // wrapping at edges
723 } else if (boundary_style == 1) {
724 x = (width + x0 + dx - x_cen) % width;
725 y = (height + y0 + dy - y_cen) % height;
726 this_coeff = coeffs[order][dx][dy];
727
728 // order tapering to the edge (just clone wrapping for now)
729 // - use the lowest order possible
730 } else if (boundary_style == 2) {
731
732 // edge rows and columns ... set to constant
733 if (edge_distance == 0) {
734 x = x0;
735 y = y0;
736 this_coeff = 1;
737 }
738 // in one from edge, use 1st order
739 else if (edge_distance == 1 && order > 0) {
740 x = (width + x0 + dx - x_cen1) % width;
741 y = (height + y0 + dy - y_cen1) % height;
742 if ((dx < 3) && (dy < 3)) { this_coeff = coeffs[1][dx][dy]; }
743 }
744 // in two from edge, use 2st order if order > 1
745 else if (edge_distance == 2 && order > 1){
746 x = (width + x0 + dx - x_cen2) % width;
747 y = (height + y0 + dy - y_cen2) % height;
748 if ((dx < 5) && (dy < 5)) { this_coeff = coeffs[2][dx][dy]; }
749 }
750 // if we're somewhere in the middle
751 else if (edge_distance > order) {
752 x = (width + x0 + dx - x_cen) % width;
753 y = (height + y0 + dy - y_cen) % height;
754 this_coeff = coeffs[order][dx][dy];
755 }
756
757 }
758
759 bMat(i, y*width + x) = this_coeff;
760
761 }
762
763 }
764
765 }
766
767 if (printB) {
768 std::cout << bMat << std::endl;
769 }
770
771 Eigen::MatrixXd hMat = bMat.transpose() * bMat;
772 return hMat;
773 }
774
775}}} // end of namespace lsst::ip::diffim
Subroutines associated with generating, normalising, and regularising Basis functions.
int end
double x
#define LSST_EXCEPT(type,...)
Create an exception with a given type.
Definition: Exception.h:48
afw::table::Key< afw::table::Array< ImagePixelT > > image
LSST DM logging module built on log4cxx.
#define LOGL_DEBUG(logger, message...)
Log a debug-level message using a varargs/printf style interface.
Definition: Log.h:515
uint64_t * ptr
Definition: RangeSet.cc:88
int y
Definition: SpanSet.cc:48
T begin(T... args)
A class to represent a 2-dimensional array of pixels.
Definition: Image.h:51
A kernel described by a function.
Definition: Kernel.h:535
double computeImage(lsst::afw::image::Image< Pixel > &image, bool doNormalize, double x=0.0, double y=0.0) const
Compute an image (pixellized representation of the kernel) in place.
A kernel that has only one non-zero pixel (of value 1)
Definition: Kernel.h:643
A kernel created from an Image.
Definition: Kernel.h:471
void setParameter(unsigned int ind, double newValue)
Set one function parameter without range checking.
Definition: Function.h:143
2-dimensional polynomial function with cross terms
Class for storing generic metadata.
Definition: PropertySet.h:66
std::string getAsString(std::string const &name) const
Get the last value for a string property name (possibly hierarchical).
int getAsInt(std::string const &name) const
Get the last value for a bool/char/short/int property name (possibly hierarchical).
std::vector< T > getArray(std::string const &name) const
Get the vector of values for a property name (possibly hierarchical).
double getAsDouble(std::string const &name) const
Get the last value for any arithmetic property name (possibly hierarchical).
bool getAsBool(std::string const &name) const
Get the last value for a bool property name (possibly hierarchical).
Provides consistent interface for LSST exceptions.
Definition: Exception.h:107
T end(T... args)
T endl(T... args)
T epsilon(T... args)
T min(T... args)
Backwards-compatibility support for depersisting the old Calib (FluxMag0/FluxMag0Err) objects.
lsst::afw::math::KernelList makeDeltaFunctionBasisList(int width, int height)
Build a set of Delta Function basis kernels.
Definition: BasisLists.cc:47
lsst::afw::math::KernelList renormalizeKernelList(lsst::afw::math::KernelList const &kernelListIn)
Renormalize a list of basis kernels.
Definition: BasisLists.cc:412
Eigen::MatrixXd makeFiniteDifferenceRegularizationDeprecated(unsigned int width, unsigned int height, unsigned int order, unsigned int boundary_style, unsigned int difference_style, bool printB)
Generate regularization matrix for delta function kernels.
Definition: BasisLists.cc:505
Eigen::MatrixXd makeRegularizationMatrix(lsst::daf::base::PropertySet const &ps)
Build a regularization matrix for Delta function kernels.
Definition: BasisLists.cc:147
Eigen::MatrixXd makeCentralDifferenceMatrix(int width, int height, int stencil, float borderPenalty, bool fitForBackground)
Build a central difference Laplacian regularization matrix for Delta function kernels.
Definition: BasisLists.cc:207
Eigen::MatrixXd makeForwardDifferenceMatrix(int width, int height, std::vector< int > const &orders, float borderPenalty, bool fitForBackground)
Build a forward difference regularization matrix for Delta function kernels.
Definition: BasisLists.cc:309
lsst::afw::math::KernelList makeAlardLuptonBasisList(int halfWidth, int nGauss, std::vector< double > const &sigGauss, std::vector< int > const &degGauss)
Build a set of Alard/Lupton basis kernels.
Definition: BasisLists.cc:78
float Pixel
Typedefs to be used for pixel values.
Definition: common.h:37
A base class for image defects.
T push_back(T... args)
T size(T... args)
T sqrt(T... args)
int row
Definition: CR.cc:145
int col
Definition: CR.cc:144
table::Key< int > order