Skip to content

Commit

Permalink
Several performance improvements with OpenMP.
Browse files Browse the repository at this point in the history
- Faster image load.
- Faster image alignment.
- Faster boxblur.
- Faster result render.
- Faster writing DNG tiles.
  • Loading branch information
jcelaya committed May 17, 2014
1 parent 2a6facd commit 5ef6e32
Show file tree
Hide file tree
Showing 8 changed files with 67 additions and 34 deletions.
6 changes: 3 additions & 3 deletions DngFloatWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -494,12 +494,12 @@ void DngFloatWriter::writeRawData() {
int bytesps = bps >> 3;
uLongf dstLen = tileWidth * tileLength * bytesps;

// #pragma omp parallel
#pragma omp parallel
{
Bytef cBuffer[dstLen];
Bytef uBuffer[dstLen];

// #pragma omp for collapse(2)
#pragma omp for collapse(2) schedule(dynamic)
for (size_t y = 0; y < height; y += tileLength) {
for (size_t x = 0; x < width; x += tileWidth) {
size_t t = (y / tileLength) * tilesAcross + (x / tileWidth);
Expand All @@ -520,7 +520,7 @@ void DngFloatWriter::writeRawData() {
if (err != Z_OK) {
std::cerr << "DNG Deflate: Failed compressing tile " << t << ", with error " << err << std::endl;
} else {
// #pragma omp critical
#pragma omp critical
{
tileOffsets[t] = file.tellp();
file.write((const char *)cBuffer, tileBytes[t]);
Expand Down
2 changes: 2 additions & 0 deletions EditableMask.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ void EditableMask::BoxBlur::boxBlur_4(size_t radius) {

void EditableMask::BoxBlur::boxBlurH_4(size_t r) {
float iarr = 1.0 / (r+r+1);
#pragma omp parallel for schedule(dynamic)
for (size_t i = 0; i < m.height; ++i) {
size_t ti = i * m.width, li = ti, ri = ti + r;
float val = map[li] * (r + 1);
Expand All @@ -198,6 +199,7 @@ void EditableMask::BoxBlur::boxBlurH_4(size_t r) {

void EditableMask::BoxBlur::boxBlurT_4(size_t r) {
float iarr = 1.0 / (r+r+1);
#pragma omp parallel for schedule(dynamic)
for (size_t i = 0; i < m.width; ++i) {
size_t ti = i, li = ti, ri = ti + r*m.width;
float val = map[li] * (r + 1);
Expand Down
4 changes: 0 additions & 4 deletions Image.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -175,10 +175,6 @@ void Image::alignWith(const Image & r) {
dx <<= 1;
dy <<= 1;
}
dx += r.dx;
dy += r.dy;
alignedPixels = &rawPixels[-dy*width - dx];
Log::msg(Log::DEBUG, "Image ", metaData->fileName, " displaced to (", dx, ", ", dy, ")");
}


Expand Down
52 changes: 37 additions & 15 deletions ImageStack.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,18 +52,35 @@ bool ImageStack::addImage(std::unique_ptr<Image> & i) {


int ImageStack::load(const LoadOptions & options, ProgressIndicator & progress) {
int step = 100 / (options.fileNames.size() + 1);
int numImages = options.fileNames.size();
int step = 100 / (numImages + 1);
int p = -step;
for (auto & name : options.fileNames) {
progress.advance(p += step, "Loading %1", name.c_str());
std::unique_ptr<Image> image(measureTime("Load raw", [&] () { return new Image(name.c_str()); }));
if (image.get() == nullptr || !image->good()) {
return 1;
}
if (!addImage(image)) {
return 2;
int error = 0, failedImage = 0;
{
Timer t("Load files");
#pragma omp parallel for schedule(dynamic)
for (int i = 0; i < numImages; ++i) {
if (!error) { // We cannot break from the for loop if we are using OpenMP
string name = options.fileNames[i];
#pragma omp critical
progress.advance(p += step, "Loading %1", name.c_str());
std::unique_ptr<Image> image(new Image(name.c_str()));
#pragma omp critical
if (!error) { // Report on the first image that fails, ignore the rest
if (image.get() == nullptr || !image->good()) {
error = 1;
failedImage = i;
} else if (!addImage(image)) {
error = 2;
failedImage = i;
}
}
}
}
}
if (error) {
return (failedImage << 1) + error - 1;
}
if (options.align) {
Timer t("Align");
progress.advance(p += step, "Aligning");
Expand All @@ -75,7 +92,7 @@ int ImageStack::load(const LoadOptions & options, ProgressIndicator & progress)
computeRelExposures();
mask.generateFrom(*this);
progress.advance(100, "Done loading!");
return 0;
return numImages << 1;
}


Expand All @@ -93,8 +110,12 @@ int ImageStack::save(const SaveOptions & options, ProgressIndicator & progress)

void ImageStack::align() {
if (images.size() > 1) {
for (auto cur = images.rbegin(), next = cur++; cur != images.rend(); next = cur++) {
(*cur)->alignWith(**next);
for (int i = images.size() - 2; i >= 0; --i) {
images[i]->alignWith(*images[i + 1]);
}
for (int i = images.size() - 2; i >= 0; --i) {
images[i]->displace(images[i + 1]->getDeltaX(), images[i + 1]->getDeltaY());
Log::msg(Log::DEBUG, "Image ", i, " displaced to (", images[i]->getDeltaX(), ", ", images[i]->getDeltaY(), ")");
}
for (auto & i : images) {
i->releaseAlignData();
Expand Down Expand Up @@ -134,13 +155,14 @@ double ImageStack::value(size_t x, size_t y) const {


void ImageStack::compose(float * dst) const {
Timer t("Compose");
unique_ptr<float[]> map = measureTime("Blur", [&] () { return mask.blur(); });
Timer t("Compose");
const MetaData & md = images.front()->getMetaData();
int imageMax = images.size() - 1;
float max = 0.0;
for (size_t y = 0, pos = 0; y < height; ++y) {
for (size_t x = 0; x < width; ++x, ++pos) {
#pragma omp parallel for schedule(dynamic)
for (size_t y = 0; y < height; ++y) {
for (size_t x = 0, pos = y*width; x < width; ++x, ++pos) {
int j = map[pos] > imageMax ? imageMax : ceil(map[pos]);
double v = 0.0, vv = 0.0, p;
if (images[j]->contains(x, y)) {
Expand Down
15 changes: 10 additions & 5 deletions Launcher.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,12 +73,17 @@ int Launcher::automaticMerge() {
auto tr = [&] (const char * text) { return QCoreApplication::translate("LoadSave", text); };
CoutProgressIndicator progress;
ImageStack stack;
if (stack.load(options, progress)) {
int i = progress.getPercent() * (options.fileNames.size() + 1) / 100;
if (i) {
cerr << tr("Error loading %1").arg(options.fileNames[i].c_str()) << endl;
return 1;
int numImages = options.fileNames.size();
int result = stack.load(options, progress);
if (result < numImages * 2) {
int format = result & 1;
int i = result >> 1;
if (format) {
cerr << tr("Error loading %1, it has a different format.").arg(options.fileNames[i].c_str()) << endl;
} else {
cerr << tr("Error loading %1, file not found.").arg(options.fileNames[i].c_str()) << endl;
}
return 1;
}
if (!wOptions.fileName.empty()) {
size_t extPos = wOptions.fileName.find_last_of('.');
Expand Down
11 changes: 6 additions & 5 deletions MainWindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -273,11 +273,12 @@ void MainWindow::loadImages(const LoadOptions & options) {
QFuture<int> error = QtConcurrent::run([&] () { return newImages->load(options, progress); });
while (error.isRunning())
QApplication::instance()->processEvents(QEventLoop::ExcludeUserInputEvents);
if (error.result()) {
int i = progress.getPercent() * (numImages + 1) / 100;
QString message = error.result() == 1 ?
tr("Unable to open file %1.").arg(options.fileNames[i].c_str()) :
tr("File %1 has not the same format as the previous ones.").arg(options.fileNames[i].c_str());
int result = error.result();
if (result < numImages * 2) {
int i = result >> 1;
QString message = result & 1 ?
tr("File %1 has not the same format as the previous ones.").arg(options.fileNames[i].c_str()) :
tr("Unable to open file %1.").arg(options.fileNames[i].c_str());
QMessageBox::warning(this, tr("Error opening file"), message);
delete newImages;
return;
Expand Down
3 changes: 3 additions & 0 deletions PreviewWidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ void PreviewWidget::render(int minx, int miny, int maxx, int maxy) {
if (area.isEmpty()) return;
area.getCoords(&minx, &miny, &maxx, &maxy);
QImage image(area.width() - 1, area.height() - 1, QImage::Format_RGB32);
#pragma omp parallel for schedule(dynamic)
for (int row = miny; row < maxy; row++) {
QRgb * scanLine = reinterpret_cast<QRgb *>(image.scanLine(row - miny));
for (int col = minx; col < maxx; col++) {
Expand Down Expand Up @@ -188,6 +189,8 @@ void PreviewWidget::mousePressEvent(QMouseEvent * event) {
} else
event->ignore();
}


void PreviewWidget::mouseMoveEvent(QMouseEvent * event) {
if (addPixels || rmPixels) {
event->accept();
Expand Down
8 changes: 6 additions & 2 deletions hdrmerge_es.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,12 @@
<context>
<name>LoadSave</name>
<message>
<source>Error loading %1</source>
<translation type="finished">Error cargando %1</translation>
<source>Error loading %1, it has a different format.</source>
<translation type="finished">Error cargando %1, tiene un formato diferente.</translation>
</message>
<message>
<source>Error loading %1, file not found.</source>
<translation type="finished">Error cargando %1, no se encontró el fichero.</translation>
</message>
<message>
<source>Writing result to %1</source>
Expand Down

0 comments on commit 5ef6e32

Please sign in to comment.