/* * Copyright (C) 2004-2007 Andrew Mihal * * This file is part of Enblend. * * Enblend is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * Enblend is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Enblend; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __ASSEMBLE_H__ #define __ASSEMBLE_H__ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #ifndef _WIN32 #include #endif #include "common.h" #include "fixmath.h" #include "vigra/copyimage.hxx" #include "vigra/impex.hxx" #include "vigra/inspectimage.hxx" #include "vigra/numerictraits.hxx" #include "vigra/transformimage.hxx" #include "vigra_ext/FunctorAccessor.h" #include "vigra_ext/impexalpha.hxx" using std::cerr; using std::cout; using std::endl; using std::list; using std::pair; using vigra::copyImageIf; using vigra::Diff2D; using vigra::exportImageAlpha; using vigra::FindBoundingRectangle; using vigra::ImageExportInfo; using vigra::ImageImportInfo; using vigra::importImageAlpha; using vigra::inspectImageIf; using vigra::NumericTraits; using vigra::Rect2D; using vigra::Threshold; using vigra::transformImage; using vigra_ext::ReadFunctorAccessor; using vigra_ext::WriteFunctorAccessor; namespace enblend { /** Write output images. */ template void checkpoint(pair &p, ImageExportInfo &outputImageInfo) { typedef typename ImageType::PixelType ImagePixelType; typedef typename EnblendNumericTraits::ImagePixelComponentType ImagePixelComponentType; typedef typename AlphaType::Accessor AlphaAccessor; typedef typename AlphaType::PixelType AlphaPixelType; typedef ReadFunctorAccessor< Threshold, AlphaAccessor> ThresholdingAccessor; ThresholdingAccessor ata( Threshold( NumericTraits::zero(), NumericTraits::zero(), NumericTraits::max(), NumericTraits::zero() ), (p.second)->accessor()); exportImageAlpha(srcImageRange(*(p.first)), srcIter((p.second)->upperLeft(), ata), outputImageInfo); }; template void import(const ImageImportInfo &info, const pair &image, const pair &alpha) { typedef typename DestIterator::PixelType ImagePixelType; typedef typename EnblendNumericTraits::ImagePixelComponentType ImagePixelComponentType; typedef typename AlphaIterator::PixelType AlphaPixelType; // Use a thresholding accessor to write to the alpha image. typedef WriteFunctorAccessor< Threshold, AlphaAccessor> ThresholdingAccessor; // Threshold the alpha mask so that all pixels are either contributing // or not contributing. ThresholdingAccessor ata( Threshold( // FIXME this should really consider pixels only == max NumericTraits::max() / 2, NumericTraits::max(), NumericTraits::zero(), NumericTraits::max() ), alpha.second); importImageAlpha(info, image, destIter(alpha.first, ata)); }; /** Find images that don't overlap and assemble them into one image. * Uses a greedy heuristic. * Removes used images from given list of ImageImportInfos. * Returns an ImageImportInfo for the temporary file. * memory xsection = 2 * (ImageType*inputUnion + AlphaType*inputUnion) */ template pair assemble(list &imageInfoList, Rect2D &inputUnion, Rect2D &bb) { typedef typename AlphaType::traverser AlphaIteratorType; typedef typename AlphaType::Accessor AlphaAccessor; // No more images to assemble? if (imageInfoList.empty()) return pair(NULL, NULL); // Create an image to assemble input images into. ImageType *image = new ImageType(inputUnion.size()); AlphaType *imageA = new AlphaType(inputUnion.size()); if (Verbose > VERBOSE_ASSEMBLE_MESSAGES) { if (OneAtATime) { cout << "Loading next image: " << imageInfoList.front()->getFileName() << endl; } else { cout << "Combining non-overlapping images: " << imageInfoList.front()->getFileName(); cout.flush(); } } Diff2D imagePos = imageInfoList.front()->getPosition(); import(*imageInfoList.front(), destIter(image->upperLeft() + imagePos - inputUnion.upperLeft()), destIter(imageA->upperLeft() + imagePos - inputUnion.upperLeft())); imageInfoList.erase(imageInfoList.begin()); if (!OneAtATime) { // Attempt to assemble additional non-overlapping images. // List of ImageImportInfos we decide to assemble. list::iterator> toBeRemoved; list::iterator i; for (i = imageInfoList.begin(); i != imageInfoList.end(); i++) { ImageImportInfo *info = *i; // Load the next image. ImageType *src = new ImageType(info->size()); AlphaType *srcA = new AlphaType(info->size()); import(*info, destImage(*src), destImage(*srcA)); // Check for overlap. bool overlapFound = false; AlphaIteratorType dy = imageA->upperLeft() - inputUnion.upperLeft() + info->getPosition(); AlphaAccessor da = imageA->accessor(); AlphaIteratorType sy = srcA->upperLeft(); AlphaIteratorType send = srcA->lowerRight(); AlphaAccessor sa = srcA->accessor(); for(; sy.y < send.y; ++sy.y, ++dy.y) { AlphaIteratorType sx = sy; AlphaIteratorType dx = dy; for(; sx.x < send.x; ++sx.x, ++dx.x) { if (sa(sx) && da(dx)) { overlapFound = true; break; } } if (overlapFound) break; } if (!overlapFound) { // Copy src and srcA into image and imageA. if (Verbose > VERBOSE_ASSEMBLE_MESSAGES) { cout << " " << info->getFileName(); cout.flush(); } Diff2D srcPos = info->getPosition(); copyImageIf(srcImageRange(*src), maskImage(*srcA), destIter(image->upperLeft() - inputUnion.upperLeft() + srcPos)); copyImageIf(srcImageRange(*srcA), maskImage(*srcA), destIter(imageA->upperLeft() - inputUnion.upperLeft() + srcPos)); // Remove info from list later. toBeRemoved.push_back(i); } delete src; delete srcA; } // Erase the ImageImportInfos we used. list::iterator>::iterator r; for (r = toBeRemoved.begin(); r != toBeRemoved.end(); r++) { imageInfoList.erase(*r); } } if (Verbose > VERBOSE_ASSEMBLE_MESSAGES && !OneAtATime) cout << endl; // Calculate bounding box of image. FindBoundingRectangle unionRect; inspectImageIf(srcIterRange(Diff2D(), Diff2D() + image->size()), srcImage(*imageA), unionRect); bb = unionRect(); if (Verbose > VERBOSE_ABB_MESSAGES) { cout << "assembled images bounding box: " << unionRect() << endl; } return pair(image, imageA); }; } // namespace enblend #endif /* __ASSEMBLE_H__ */