15 namespace lsst {
namespace afw {
namespace display {
18 static void getSample(
20 std::size_t
const nSamples,
21 std::vector<T>& vSample
29 vSample.reserve(nSamples);
31 int const initialStride = std::max(
33 static_cast<int>(std::sqrt(width*height/static_cast<double>(nSamples)))
36 for (
int stride = initialStride; stride >= 1; --stride) {
39 for (std::size_t
y = 0;
y <
height;
y += stride) {
40 for (std::size_t
x = 0;
x <
width;
x += stride) {
42 if (std::isfinite(elem)) {
43 vSample.push_back(elem);
49 if (5*vSample.size() > 4*nSamples) {
57 std::vector<double>
const& vFlat,
58 std::vector<int>
const& vBadPix,
59 std::size_t
const nGoodPix
66 double sumz = 0, sumsq = 0;
67 for (
unsigned i = 0; i < vFlat.size(); ++i) {
69 double const z = vFlat[i];
76 double const goodPix = nGoodPix;
77 double const tmp = sumsq/(goodPix - 1) - sumz*sumz/(goodPix*(goodPix - 1));
79 return (tmp > 0) ? std::sqrt(tmp) : 0;
84 static std::pair<double, double>
87 std::vector<T>
const& vSample,
88 double const nSigmaClip,
95 double const xscale = 2.0/(vSample.size() - 1);
96 std::vector<double> xnorm;
97 xnorm.reserve(vSample.size());
98 for (std::size_t i = 0; i < vSample.size(); ++i) {
99 xnorm.push_back(i*xscale - 1.0);
103 std::vector<int> vBadPix(vSample.size(), 0);
105 std::size_t nGoodPix = vSample.size();
106 std::size_t nGoodPixOld = nGoodPix + 1;
109 double intercept = 0;
112 for (
int iteration = 0; iteration < nIter; ++iteration) {
113 if (nGoodPix < minpix || nGoodPix >= nGoodPixOld) {
117 double sum = nGoodPix;
118 double sumx = 0, sumy = 0, sumxx = 0, sumxy = 0;
119 for (std::size_t i = 0; i < vSample.size(); ++i) {
121 double const x = xnorm[i];
122 double const y = vSample[i];
131 double delta = sum * sumxx - sumx * sumx;
134 intercept = (sumxx * sumy - sumx * sumxy) / delta;
135 slope = (sum * sumxy - sumx * sumy) / delta;
138 std::vector<double> vFlat;
139 vFlat.reserve(vSample.size());
140 for (
unsigned i = 0; i < vSample.size(); ++i) {
141 vFlat.push_back(vSample[i] - (xnorm[i]*slope + intercept));
145 double const sigma = computeSigma(vFlat, vBadPix, nGoodPix);
146 double const hcut = sigma*nSigmaClip;
147 double const lcut = -hcut;
150 nGoodPixOld = nGoodPix;
153 for (
unsigned i = 0; i < vSample.size(); ++i) {
154 double val = vFlat[i];
155 if (val < lcut || hcut < val) {
161 std::vector<int>vBadPix_new;
162 vBadPix_new.reserve(vSample.size());
163 for (
unsigned x = 0;
x < vSample.size(); ++
x) {
164 int imin = (
static_cast<int>(
x) > nGrow) ?
x - nGrow : -1;
166 for (
int i =
x; i > imin ; --i) {
169 vBadPix_new.push_back(val ? 1 : 0);
174 vBadPix = vBadPix_new;
178 *nGoodPixOut = nGoodPix;
180 return std::make_pair(intercept - slope, slope*xscale);
184 std::pair<double, double>
187 double const contrast
191 std::vector<T> vSample;
192 getSample(image, nSamples, vSample);
193 int nPix = vSample.size();
195 if (vSample.empty()) {
196 throw LSST_EXCEPT(pex::exceptions::RuntimeError,
"ZScale: No pixel in image is finite");
199 std::sort(vSample.begin(), vSample.end());
205 double const zmin = vSample.front();
206 double const zmax = vSample.back();
207 int const iCenter = nPix/2;
208 T
median = (nPix & 1) ? vSample[iCenter] : (vSample[iCenter] + vSample[iCenter + 1])/2;
211 const int maxRejectionRatio = 2;
212 const int npixelsMin = 5;
214 int minpix = std::max(npixelsMin, nPix/maxRejectionRatio);
215 int nGrow = std::max(1, nPix/100);
217 const double nSigmaClip = 2.5;
218 const int nIterations = 5;
221 std::pair<double, double> ret = fitLine(&nGoodPix, vSample, nSigmaClip, nGrow, minpix, nIterations);
222 #if 0 // unused, but calculated and potentially useful
223 double const zstart = ret.first;
225 double const zslope = ret.second;
228 if (nGoodPix < minpix) {
232 double const slope = zslope/contrast;
234 z1 = std::max(zmin, median - iCenter*slope);
235 z2 = std::min(zmax, median + (nPix - iCenter - 1)*slope);
238 return std::make_pair(z1, z2);
242 #define INSTANTIATE_GETZSCALE(T) \
243 template std::pair<double, double> \
244 getZScale(image::Image<T> const& image, int const nSamples, double const contrast)
std::pair< double, double > getZScale(image::Image< T > const &image, int const nSamples=1000, double const contrast=0.25)
Calculate an IRAF/ds9-style zscaling.
Include files required for standard LSST Exception handling.
#define INSTANTIATE_GETZSCALE(T)
afw::table::Key< double > sigma
table::Key< table::Array< Kernel::Pixel > > image
void ImageT ImageT int float saturatedPixelValue int const width
int getHeight() const
Return the number of rows in the image.
void ImageT ImageT int float saturatedPixelValue int const height
#define LSST_EXCEPT(type,...)
Create an exception with a given type and message and optionally other arguments (dependent on the ty...
int getWidth() const
Return the number of columns in the image.
A class to represent a 2-dimensional array of pixels.