void WindowAdapterTest::testWindowAdapter() { debug(LOG_DEBUG, DEBUG_LOG, 0, "window adapter test"); // create an image Image<unsigned char> image(16, 16); for (unsigned int x = 0; x < 16; x++) { for (unsigned int y = 0; y < 16; y++) { image.pixel(x, y) = x * y; } } // create the subframe ImageRectangle frame(ImagePoint(4, 4), ImageSize(8, 8)); debug(LOG_DEBUG, DEBUG_LOG, 0, "frame: %s", frame.toString().c_str()); // create an adapter for a subframe WindowAdapter<unsigned char> adapter(image, frame); // access the subframe ImageSize size = adapter.getSize(); debug(LOG_DEBUG, DEBUG_LOG, 0, "adapter size: %s", size.toString().c_str()); for (int x = 0; x < size.width(); x++) { for (int y = 0; y < size.height(); y++) { unsigned char value = adapter.pixel(x, y); unsigned char v = (frame.origin().x() + x) * (frame.origin().y() + y); if (v != value) { debug(LOG_DEBUG, DEBUG_LOG, 0, "expected %d != %d found", (int)v, (int)value); } CPPUNIT_ASSERT(value == v); } } debug(LOG_DEBUG, DEBUG_LOG, 0, "window adapter test complete"); }
std::string ImageSize:: String(ImageSize imageSize) { std::ostringstream out; out << imageSize.width(); out << "x"; out << imageSize.height(); return out.str(); }
/** * \brief Compute size of the complex fourier transform image * * We are using the real data DFTs from the fftw3 library, which uses a layout * different from what you would expect from our image types. When going * through a pixel array In our image types, the quickly increasing * coordinate is the horizontal coordinate, which we usually call the * x coordinate, and which is also the first coordinate. In FFTW3, the slowly * increasing coordinate when going through the FFT array is the second * coordinate. So if an image has width w and height h, then we have * treat it as a data array with n0 = h and n1 = w. The corresponding * fourier transform array for the real data transforms then has dimensions * n0 and (n1/2 + 1). But since again the second coordinate is the one that * increases quickly, we have to create an image of width (n1/2 + 1) and * height n0. * * All this is unimportant as long as we don't look at the fourier transform * as an image in its own right. Only then does it become important how we * interpret the coordinates. * * \param size size of the image to be fourier transformed */ ImageSize FourierImage::fsize(const ImageSize& size) { int w = size.width(); int h = size.height(); int n0 = h; int n1 = w; ImageSize result(2 * (1 + n1 / 2), n0); debug(LOG_DEBUG, DEBUG_LOG, 0, "fourier image size %s -> %s", size.toString().c_str(), result.toString().c_str()); return result; }
std::vector<Residual> Analyzer::operator()(const ConstImageAdapter<double>& image) const { // first find out whether the patch size fits inside the image if ((patchsize > image.getSize().width()) || (patchsize > image.getSize().height())) { throw std::runtime_error("patch size does not fit into image"); } // build a set of patches ImageSize size = image.getSize(); int hsteps = (size.width() - patchsize) / spacing; int xoffset = (size.width() - hsteps * spacing) / 2; int vsteps = (size.height() - patchsize) / spacing; int yoffset = (size.height() - vsteps * spacing) / 2; std::vector<ImagePoint> points; for (int h = 0; h <= hsteps; h++) { for (int v = 0; v <= vsteps; v++) { ImagePoint point(xoffset + h * spacing, yoffset + v * spacing); points.push_back(point); } } // now compute the shift for each point std::vector<Residual> result; for (auto pt = points.begin(); pt != points.end(); pt++) { Residual residual = translation(image, *pt, patchsize); if (residual.valid()) { result.push_back(residual); } } // display resulting residuals if in debug mode if (debuglevel >= LOG_DEBUG) { for (std::vector<Residual>::size_type i = 0; i < result.size(); i++) { debug(LOG_DEBUG, DEBUG_LOG, 0, "residual[%d] %s", i, std::string(result[i]).c_str()); } } return result; }
void QsiCcd::startExposure(const Exposure& exposure) { std::unique_lock<std::recursive_mutex> lock(_camera.mutex); Ccd::startExposure(exposure); debug(LOG_DEBUG, DEBUG_LOG, 0, "start QSI exposure"); try { // set the binning mode _camera.camera().put_BinX(exposure.mode().x()); _camera.camera().put_BinY(exposure.mode().y()); // compute the frame size in binned pixels, as this is what // the QSI camera expects ImagePoint origin = exposure.frame().origin() / exposure.mode(); ImageSize size = exposure.frame().size() / exposure.mode(); ImageRectangle frame(origin, size); debug(LOG_DEBUG, DEBUG_LOG, 0, "requesting %s image", frame.toString().c_str()); // set the subframe _camera.camera().put_NumX(size.width()); _camera.camera().put_NumY(size.height()); _camera.camera().put_StartX(origin.x()); _camera.camera().put_StartY(origin.y()); // turn off the led debug(LOG_DEBUG, DEBUG_LOG, 0, "turn LED off"); _camera.camera().put_LEDEnabled(false); // get shutter info bool light = (exposure.shutter() == Shutter::OPEN); _camera.camera().StartExposure(exposure.exposuretime(), light); debug(LOG_DEBUG, DEBUG_LOG, 0, "%fsec %s exposure started", exposure.exposuretime(), (light) ? "light" : "dark"); } catch (const std::exception& x) { debug(LOG_ERR, DEBUG_LOG, 0, "bad exposure parameters: %s", x.what()); cancelExposure(); throw BadParameter(x.what()); } // check the current state of the camera exposureStatus(); }
/** * \brief Write a processed image to a file */ void Viewer::writeimage(const std::string& filename) { ImageSize size = image->size(); Image<RGB<unsigned char> > *outimage = new Image<RGB<unsigned char> >(size); unsigned int width = size.width(); unsigned int height = size.height(); uint32_t *i = imagedata(); for (unsigned int x = 0; x < width; x++) { for (unsigned int y = 0; y < height; y++) { uint32_t v = i[size.offset(x, y)]; unsigned char R = (v & 0xff0000) >> 16; unsigned char G = (v & 0x00ff00) >> 8; unsigned char B = (v & 0x0000ff); //debug(LOG_DEBUG, DEBUG_LOG, 0, "%d,%d,%d", R, G, B); outimage->pixel(x, y) = RGB<unsigned char>(R, G, B); } } FITSout out(filename); out.setPrecious(false); out.write(ImagePtr(outimage)); }
size_t subdark(const ImageSequence&, ImageMean<T>& im, const Subgrid grid, unsigned int k = 3) { debug(LOG_DEBUG, DEBUG_LOG, 0, "processing subgrid %s", grid.toString().c_str()); // we also need the mean of the image to decide which pixels are // too far off to consider them "sane" pixels T mean = im.mean(grid); T var = im.variance(grid); // now find out which pixels are bad, and mark them using NaNs. // we consider pixels bad if the deviate from the mean by more // than three standard deviations T stddevk = k * sqrt(var); debug(LOG_DEBUG, DEBUG_LOG, 0, "found mean: %f, variance: %f, " "stddev%u = %f", mean, var, k, stddevk); size_t badpixelcount = 0; SubgridAdapter<T> sga(*im.image, grid); ImageSize size = sga.getSize(); for (int x = 0; x < size.width(); x++) { for (int y = 0; y < size.height(); y++) { T v = sga.pixel(x, y); // skip NaNs if (v != v) { break; } if (fabs(v - mean) > stddevk) { sga.writablepixel(x, y) = std::numeric_limits<T>::quiet_NaN(); badpixelcount++; } } } debug(LOG_DEBUG, DEBUG_LOG, 0, "found %u bad pixels", badpixelcount); return badpixelcount; }
/** * \brief Compare two size objects: inequality * * Two size objects are unequal if width or height are unequal */ bool ImageSize::operator!=(const ImageSize& other) const { return (_width != other.width()) || (_height != other.height()); }
/** * \brief Compare two size objects: equality * * Two size objects are equal if width and height are identical */ bool ImageSize::operator==(const ImageSize& other) const { return (_width == other.width()) && (_height == other.height()); }
/** * \brief Create a new Viewer * * This constructor converts the image to an RGB<float> image, and * then sets up the image processing pipeline on this image. * For the pipeline, some objects have to computed, like the white * balance, the background gradients. */ Viewer::Viewer(const std::string& filename) { debug(LOG_DEBUG, DEBUG_LOG, 0, "create viewer for file %s", filename.c_str()); // read the FITS image FITSin in(filename); ImagePtr rawimage = in.read(); // image size ImageSize size = rawimage->size(); _displaysize = size; // allocate an image with float pixels Image<RGB<float> > *imagep = new Image<RGB<float> >(size); image = ImagePtr(imagep); // create an array uint32_t *p = new uint32_t[size.getPixels()]; _imagedata = imagedataptr(p); // copy the data from the image to the imagep convert_mono<unsigned char>(*imagep, rawimage); convert_mono<unsigned short>(*imagep, rawimage); convert_mono<unsigned int>(*imagep, rawimage); convert_mono<unsigned long>(*imagep, rawimage); convert_mono<float>(*imagep, rawimage); convert_mono<double>(*imagep, rawimage); // copy the data from the image to the luminanceimagep, *imagep convert_rgb<unsigned char>(*imagep, rawimage); convert_rgb<unsigned short>(*imagep, rawimage); convert_rgb<unsigned int>(*imagep, rawimage); convert_rgb<unsigned long>(*imagep, rawimage); convert_rgb<float>(*imagep, rawimage); convert_rgb<double>(*imagep, rawimage); // create the viewer pipeline pipeline = new ViewerPipeline(imagep); pipelineptr = std::shared_ptr<ViewerPipeline>(pipeline); // compute the white balance vector filter::WhiteBalance<float> wb; RGB<double> rgb = wb.filter(*imagep); ImagePoint center = rawimage->center(); // background stuff BackgroundExtractor be(100); Background<float> bg = be(center, false, BackgroundExtractor::LINEAR, *imagep); background(bg); backgroundEnabled(true); gradientEnabled(true); // set parameters pipeline->colorcorrection(RGB<float>(rgb.R, rgb.G, rgb.B)); pipeline->setRange(0, 10000); // Histogram debug(LOG_DEBUG, DEBUG_LOG, 0, "computing histogram"); _histograms = HistogramSet(image, 350); // set up the preview size previewwidth(300); // set up the background preview debug(LOG_DEBUG, DEBUG_LOG, 0, "computing background size"); unsigned int width = 100; unsigned int height = (size.height() * width) / size.width(); debug(LOG_DEBUG, DEBUG_LOG, 0, "background %u x %u", width, height); backgroundsize(ImageSize(width, height)); // copy the data to the update(); previewupdate(); }
void Viewer::previewwidth(unsigned int width) { debug(LOG_DEBUG, DEBUG_LOG, 0, "set width to %u", width); ImageSize size = image->size(); unsigned int height = (size.height() * width) / size.width(); previewsize(ImageSize(width, height)); }
ImageSize operator/(const ImageSize& size, const Binning& binning) { return ImageSize(size.width() / binning.x(), size.height() / binning.y()); }
/** * \brief Main function of the Focusing process */ void VCurveFocusWork::main(astro::thread::Thread<FocusWork>& /* thread */) { debug(LOG_DEBUG, DEBUG_LOG, 0, "start focusing work"); if (!complete()) { focusingstatus(Focusing::FAILED); throw std::runtime_error("focuser not completely specified"); } FocusCompute fc; // determine how many intermediate steps we want to access if (min() < focuser()->min()) { throw std::runtime_error("minimum too small"); } // based on the exposure specification, build an evaluator ImageSize size = exposure().size(); int radius = std::min(size.width(), size.height()) / 2; FWHM2Evaluator evaluator(size.center(), radius); unsigned long delta = max() - min(); for (int i = 0; i < steps(); i++) { // compute new position unsigned short position = min() + (i * delta) / (steps() - 1); debug(LOG_DEBUG, DEBUG_LOG, 0, "measuring position %hu", position); // move to new position moveto(position); // get an image from the Ccd focusingstatus(Focusing::MEASURING); ccd()->startExposure(exposure()); usleep(1000000 * exposure().exposuretime()); ccd()->wait(); ImagePtr image = ccd()->getImage(); // turn the image into a value FWHMInfo fwhminfo = focusFWHM2_extended(image, size.center(), radius); double value = fwhminfo.radius; // add the new value fc.insert(std::pair<unsigned short, double>(position, value)); // send the callback data callback(combine(image, fwhminfo), position, value); } // compute the best focus position double focusposition = 0; try { focusposition = fc.focus(); } catch (std::exception& x) { debug(LOG_DEBUG, DEBUG_LOG, 0, "no optimal focus position: %s", x.what()); focusingstatus(Focusing::FAILED); return; } debug(LOG_DEBUG, DEBUG_LOG, 0, "optimal focus position: %f", focusposition); // plausibility check for the position if (!((focusposition >= min()) && (focusposition <= max()))) { focusingstatus(Focusing::FAILED); debug(LOG_DEBUG, DEBUG_LOG, 0, "focusing failed"); return; } // move to the focus position unsigned short targetposition = focusposition; moveto(targetposition); focusingstatus(Focusing::FOCUSED); debug(LOG_DEBUG, DEBUG_LOG, 0, "target position reached"); }