Basic Image AlgorithmS Library  2.8.0
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
ExampleImageDri.cpp

Creates a DRI image (dynamic range increase) out of three input images: normal exposure, under-exposed and over-exposed. THE INPUT IMAGES MUST BE GIVEN IN THIS ORDER!This algorithm is fairly simple: Iterate over all pixel of the normal exposed image. If the mean color value is below a threshold, take the pixel from the over-exposed image. If it is over a certain threshold, take it from the under-exposed image. To avoid sharp edges, a weighted sum is used. The weight results from the distance to the threshold. Both thresholds can be set, as well as the blending range.

Author
rwulff
/*
This file is part of the BIAS library (Basic ImageAlgorithmS).
Copyright (C) 2003-2009 (see file CONTACT for details)
Multimediale Systeme der Informationsverarbeitung
Institut fuer Informatik
Christian-Albrechts-Universitaet Kiel
BIAS is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
BIAS 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with BIAS; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/**
* @example ExampleImageDri.cpp
@relates Image
@brief Creates a DRI image (dynamic range increase) out of three input images:
* normal exposure, under-exposed and over-exposed. THE INPUT IMAGES MUST
* BE GIVEN IN THIS ORDER!
*
* This algorithm is fairly simple:
* Iterate over all pixel of the normal exposed image. If the mean color value
* is below a threshold, take the pixel from the over-exposed image. If it is
* over a certain threshold, take it from the under-exposed image. To avoid
* sharp edges, a weighted sum is used. The weight results from the distance
* to the threshold.
* Both thresholds can be set, as well as the blending range.
*
* @author rwulff
*/
#include <Base/Image/Image.hh>
#include <Base/Image/ImageIO.hh>
#include <Base/ImageUtils/ImageDraw.hh>
using namespace BIAS;
using namespace std;
int main(int argc, char *argv[]) {
const unsigned char LO_THRESHOLD = (unsigned char)100;
const unsigned char HI_THRESHOLD = (unsigned char)230;
// blend over a certain range:
// 1.0 = whole range
// 2.0 = 1/2 range
// 3.0 = 1/3 range and so on...
// e.g. if LO_THRESHOLD = 50 and BLENDING_RANGE = 2.0, intensities between
// 25 (= 50 * 1/2.0) and 50 will be blended linearly
const float BLENDING_RANGE = 1.0f;
// check params
if (argc < 4) {
cout << "wrong parameter count!!" << endl << endl;
cout << "usage:" << endl;
cout << argv[0] << " " << "<normal_image> <darker_image> <brighter_image>" << endl;
return -1;
}
// load images
Image<unsigned char> imNorm, imDark, imBright;
if (ImageIO::Load(argv[1], imNorm) != 0) {
cout << "normal image could not be loaded!" << endl;
return -1;
}
else {
cout << "normal image loaded!" << endl;
}
if (ImageIO::Load(argv[2], imDark) != 0) {
cout << "darker image could not be loaded!" << endl;
return -1;
}
else {
cout << "darker image loaded!" << endl;
}
if (ImageIO::Load(argv[3], imBright) != 0) {
cout << "brighter image could not be loaded!" << endl;
return -1;
}
else {
cout << "brighter image loaded!" << endl;
}
cout << "images loaded" << endl;
// ensure that input images have same size and RGB color model and init diffImage
BIASASSERT(imNorm.GetWidth() == imDark.GetWidth() && imNorm.GetHeight() == imDark.GetHeight());
BIASASSERT(imDark.GetWidth() == imBright.GetWidth() && imDark.GetHeight() == imBright.GetHeight());
BIASASSERT(imNorm.GetColorModel() == ImageBase::CM_RGB);
BIASASSERT(imDark.GetColorModel() == ImageBase::CM_RGB);
BIASASSERT(imBright.GetColorModel() == ImageBase::CM_RGB);
Image<unsigned char> imDri(imNorm);
// get image data
unsigned char *imNormData = imNorm.GetImageData();
unsigned char *imDarkData = imDark.GetImageData();
unsigned char *imBrightData = imBright.GetImageData();
unsigned char *imDriData = imDri.GetImageData();
unsigned int offset = 0;
unsigned char mean = 0;
float weight = 0.0f;
cout << "starting iteration..." << endl;
// iterate over pixels and draw difference image
for (unsigned int y = 0; y < imNorm.GetHeight(); y++) {
for (unsigned int x = 0; x < imNorm.GetWidth(); x++) {
offset = y*imNorm.GetWidth()*imNorm.GetChannelCount() + x*imNorm.GetChannelCount();
mean = (imNormData[offset] + imNormData[offset+1] + imNormData[offset+2]) / 3;
if (mean < LO_THRESHOLD) {
weight = ((float)(LO_THRESHOLD - mean)) / (float)(LO_THRESHOLD);
weight *= BLENDING_RANGE; // blend over a certain range
weight = weight > 1.0f ? 1.0f : weight;
imDriData[offset] = (unsigned char)(weight*(float)imBrightData[offset] + (1.0f-weight)*(float)imNormData[offset]);
imDriData[offset+1] = (unsigned char)(weight*(float)imBrightData[offset+1] + (1.0f-weight)*(float)imNormData[offset+1]);
imDriData[offset+2] = (unsigned char)(weight*(float)imBrightData[offset+2] + (1.0f-weight)*(float)imNormData[offset+2]);
}
else if (mean > HI_THRESHOLD) {
weight = ((float)(mean - HI_THRESHOLD)) / (float)(255 - HI_THRESHOLD);
weight *= BLENDING_RANGE; // blend over a certain range
weight = weight > 1.0f ? 1.0f : weight;
imDriData[offset] = (unsigned char)(weight*(float)imDarkData[offset] + (1.0f-weight)*(float)imNormData[offset]);
imDriData[offset+1] = (unsigned char)(weight*(float)imDarkData[offset+1] + (1.0f-weight)*(float)imNormData[offset+1]);
imDriData[offset+2] = (unsigned char)(weight*(float)imDarkData[offset+2] + (1.0f-weight)*(float)imNormData[offset+2]);
}
else {
imDriData[offset] = imNormData[offset];
imDriData[offset+1] = imNormData[offset+1];
imDriData[offset+2] = imNormData[offset+2];
}
}
}
ImageIO::Save("dri.mip", imDri);
cout << "done!" << endl;
return 0;
}