int ExtractSubImageWithBoundary( const vector<float> &im_input, const ImageSize &imSize_input, const ImageSize &imSize_output, const size_t &h_offset, const size_t &w_offset, const size_t &boundary_length, vector<float> *im_output ) { im_output->resize(imSize_output.whc); for(int c=0; c<imSize_output.nChannels; ++c) { for(int w=0; w<imSize_output.width; ++w) { for(int h=0; h<imSize_output.height; ++h) { im_output->at(imSize_output.at(h,w,c)) = im_input[imSize_input.symmetrise_at(h-boundary_length+h_offset, w-boundary_length+w_offset, c)]; } } } return EXIT_SUCCESS; }
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"); }
int PartialRecomposeImageWithBoundaries( const vector<float> &im_subdivide, const ImageSize &imSize_subdivide, const ImageSize &imSize_output, const int &h_offset, const int &w_offset, const int &boundary_length, const int &boundary_w_length, const int &boundary_h_length, vector<float> *im_output ) { //! Compute the image for(int c=0; c<imSize_output.nChannels; ++c) { for(int w=0; w<imSize_subdivide.width-boundary_w_length; ++w) //X { if(w+w_offset >= imSize_output.width) continue; for(int h=0; h<imSize_subdivide.height-boundary_h_length; ++h) //X { if(h+h_offset >= imSize_output.height) continue; im_output->at(imSize_output.at(h+h_offset, w+w_offset, c)) = im_subdivide[imSize_subdivide.at(h+boundary_length, w+boundary_length, c)]; } } } return EXIT_SUCCESS; }
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; }
vector<float> ExtractPatches( const vector<float> &im_input, const ImageSize &imSize, const int length ) { const int dim_patch = length*length*imSize.nChannels; const int im_height = imSize.height-length; const int im_width = imSize.width-length; const int number_patch = im_height*im_width; vector<float> patches(number_patch*dim_patch); for(int c=0; c<imSize.nChannels; ++c) { for(int w=0; w<im_width; ++w) { for(int h=0; h<im_height; ++h) { for(int j=0; j<length; ++j) { for(int i=0; i<length; ++i) { size_t pos_patch = i + j*length + c*length*length; size_t pos_pixel = h + w*im_height; patches[pos_pixel*dim_patch + pos_patch] = im_input[imSize.at(h+i, w+j, c)]; } } } } } return patches; }
vector<float> ExtractCenteredPatches( const vector<float> &im_input, const ImageSize &imSize, const int l ) { const int length = 2*l+1; const int dim_patch = length*length; const int im_height = imSize.height-2*l; const int im_width = imSize.width-2*l; const int im_wh = im_height*im_width; const int number_patch = im_height*im_width*imSize.nChannels; vector<float> patches(number_patch*dim_patch); int c=0; for(int w=l; w<imSize.width-l; ++w) { for(int h=l; h<imSize.height-l; ++h) { for(int j=-l; j<=l; ++j) { for(int i=-l; i<=l; ++i) { size_t pos_patch = i+l + (j+l)*length; size_t pos_pixel = (h-l) + (w-l)*im_height + c*im_wh; patches[pos_pixel*dim_patch + pos_patch] = im_input[imSize.at(h+i, w+j, c)]; } } } } return patches; }
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(); }
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; }
virtual double operator()(const transform::EuclideanDisplacement& d) const { if ((d.angle() < -0.1) || (d.angle() > 0.1)) { return 0; } if (!size.contains(floor(d.translation().x()), floor(d.translation().y()))) { return 0; } return 1; }
/** * \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)); }
void ImageSizeTest::testBounds() { debug(LOG_DEBUG, DEBUG_LOG, 0, "testBounds() begin"); CPPUNIT_ASSERT(i1->bounds(ImagePoint(0, 0))); CPPUNIT_ASSERT(i1->bounds(ImagePoint(6, 0))); CPPUNIT_ASSERT(i1->bounds(ImagePoint(0, 10))); CPPUNIT_ASSERT(i1->bounds(ImagePoint(6, 10))); CPPUNIT_ASSERT(!i1->bounds(ImagePoint(0, -1))); CPPUNIT_ASSERT(!i1->bounds(ImagePoint(6, -1))); CPPUNIT_ASSERT(!i1->bounds(ImagePoint(0, 11))); CPPUNIT_ASSERT(!i1->bounds(ImagePoint(6, 11))); CPPUNIT_ASSERT(!i1->bounds(ImagePoint(-1, 0))); CPPUNIT_ASSERT(!i1->bounds(ImagePoint(-1, 10))); CPPUNIT_ASSERT(!i1->bounds(ImagePoint(7, 0))); CPPUNIT_ASSERT(!i1->bounds(ImagePoint(7, 10))); debug(LOG_DEBUG, DEBUG_LOG, 0, "testBounds() end"); }
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; }
int saveImage( const char *p_name, const vector<float> &i_im, const ImageSize &p_imSize, const float &p_min, const float &p_max ) { float* imTmp = new float[p_imSize.whc]; for(int _c=0; _c<p_imSize.nChannels; ++_c) { for(int _h=0; _h<p_imSize.height; ++_h) { for(int _w=0; _w<p_imSize.width; ++_w) { imTmp[_c*p_imSize.wh + _h*p_imSize.width + _w] = i_im[p_imSize.at(_h,_w,_c) ]; } } } //! Check for boundary problems for (int k = 0; k < p_imSize.whc; k++) { imTmp[k] = imTmp[k] < p_min ? p_min : (imTmp[k] > p_max ? p_max : imTmp[k]); } if (write_png_f32(p_name, imTmp, p_imSize.width, p_imSize.height, p_imSize.nChannels) != 0) { cout << "... failed to save png image :'" << p_name << "'" << endl; return EXIT_FAILURE; } delete[] imTmp; return EXIT_SUCCESS; }
/** * \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 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"); }
/** * \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()); }
ImageSize operator/(const ImageSize& size, const Binning& binning) { return ImageSize(size.width() / binning.x(), size.height() / binning.y()); }
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)); }
/** * \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 ImageSizeTest::testPixels() { debug(LOG_DEBUG, DEBUG_LOG, 0, "testPixels() begin"); CPPUNIT_ASSERT(i1->getPixels() == 77); CPPUNIT_ASSERT(i2->getPixels() == 15); debug(LOG_DEBUG, DEBUG_LOG, 0, "testPixels() end"); }
int loadImage( const char* p_name, vector<float> &o_im, ImageSize &o_imSize, const bool p_verbose ) { if (p_verbose) { cout << endl << "Read input image '" << p_name << "'..."; } size_t w, h, c; float *imTmp = read_png_f32(p_name, &w, &h, &c); if (!imTmp) { cout << "error :: " << p_name << " not found or not a correct png image" << endl; return EXIT_FAILURE; } if (p_verbose) { cout << "done." << endl; } //! test if image is really a color image and exclude the alpha channel if (c == 2) { cout << "The gray image has a alpha channel. We will remove it." << endl; c = 1; } else if(c >= 3) { cout << "Parigi does not work with color images." << endl; exit(-1); } if (p_verbose) { cout << "image size :" << endl; cout << " - width = " << w << endl; cout << " - height = " << h << endl; cout << " - nb of channels = " << c << endl; } o_imSize.width = w; o_imSize.height = h; o_imSize.nChannels = c; o_imSize.wh = w * h; o_imSize.whc = w * h * c; o_im.resize(w * h * c); for(size_t _c=0; _c<c; ++_c) { for(size_t _h=0; _h<h; ++_h) { for(size_t _w=0; _w<w; ++_w) { o_im[o_imSize.at(_h,_w,_c)] = imTmp[_c*w*h + _h*w + _w]; } } } delete[] imTmp; return EXIT_SUCCESS; }