Allow reading more than 6 sub-frames

This allows all images to be read from a Canon burst raw file.

Refactor raw image source to use unique_ptr.
This commit is contained in:
Lawrence Lee 2024-10-06 18:01:40 -07:00
parent 00360a6dbb
commit 860306dc35
No known key found for this signature in database
GPG Key ID: 048FF2B76A63895F
3 changed files with 37 additions and 33 deletions

View File

@ -505,14 +505,6 @@ RawImageSource::~RawImageSource()
delete greenCache; delete greenCache;
delete blueCache; delete blueCache;
for (size_t i = 0; i < numFrames; ++i) {
delete riFrames[i];
}
for (size_t i = 0; i + 1 < numFrames; ++i) {
delete rawDataBuffer[i];
}
if (camProfile) { if (camProfile) {
cmsCloseProfile(camProfile); cmsCloseProfile(camProfile);
} }
@ -1219,11 +1211,13 @@ int RawImageSource::load(const Glib::ustring &fname, bool firstFrameOnly)
return errCode; return errCode;
} }
numFrames = firstFrameOnly ? (numFrames < 7 ? 1 : ri->getFrameCount()) : ri->getFrameCount(); const bool isHasselblad = ri->get_maker() == "Hasselblad";
numFrames = firstFrameOnly && (numFrames < 7 || !isHasselblad) ? 1 : ri->getFrameCount();
errCode = 0; errCode = 0;
if (numFrames >= 7) { if (numFrames >= 7 && isHasselblad) {
// special case to avoid crash when loading Hasselblad H6D-100cMS pixelshift files // special case to avoid crash when loading Hasselblad H6D-100cMS pixelshift files
// limit to 6 frames and skip first frame, as first frame is not bayer // limit to 6 frames and skip first frame, as first frame is not bayer
if (firstFrameOnly) { if (firstFrameOnly) {
@ -1232,6 +1226,9 @@ int RawImageSource::load(const Glib::ustring &fname, bool firstFrameOnly)
numFrames = 6; numFrames = 6;
} }
riFrames.clear();
riFrames.resize(numFrames);
#ifdef _OPENMP #ifdef _OPENMP
#pragma omp parallel #pragma omp parallel
#endif #endif
@ -1243,10 +1240,10 @@ int RawImageSource::load(const Glib::ustring &fname, bool firstFrameOnly)
for (unsigned int i = 0; i < numFrames; ++i) { for (unsigned int i = 0; i < numFrames; ++i) {
if (i == 0) { if (i == 0) {
riFrames[i] = ri; riFrames[i].reset(ri);
errCodeThr = riFrames[i]->loadRaw(true, i + 1, true, plistener, 0.8); errCodeThr = riFrames[i]->loadRaw(true, i + 1, true, plistener, 0.8);
} else { } else {
riFrames[i] = new RawImage(fname); riFrames[i].reset(new RawImage(fname));
errCodeThr = riFrames[i]->loadRaw(true, i + 1); errCodeThr = riFrames[i]->loadRaw(true, i + 1);
} }
} }
@ -1259,6 +1256,9 @@ int RawImageSource::load(const Glib::ustring &fname, bool firstFrameOnly)
} }
} }
} else if (numFrames > 1) { } else if (numFrames > 1) {
riFrames.clear();
riFrames.resize(numFrames);
#ifdef _OPENMP #ifdef _OPENMP
#pragma omp parallel #pragma omp parallel
#endif #endif
@ -1271,10 +1271,10 @@ int RawImageSource::load(const Glib::ustring &fname, bool firstFrameOnly)
for (unsigned int i = 0; i < numFrames; ++i) for (unsigned int i = 0; i < numFrames; ++i)
{ {
if (i == 0) { if (i == 0) {
riFrames[i] = ri; riFrames[i].reset(ri);
errCodeThr = riFrames[i]->loadRaw(true, i, true, plistener, 0.8); errCodeThr = riFrames[i]->loadRaw(true, i, true, plistener, 0.8);
} else { } else {
riFrames[i] = new RawImage(fname); riFrames[i].reset(new RawImage(fname));
errCodeThr = riFrames[i]->loadRaw(true, i); errCodeThr = riFrames[i]->loadRaw(true, i);
} }
} }
@ -1287,9 +1287,13 @@ int RawImageSource::load(const Glib::ustring &fname, bool firstFrameOnly)
} }
} }
} else { } else {
riFrames[0] = ri; riFrames.clear();
errCode = riFrames[0]->loadRaw(true, 0, true, plistener, 0.8); riFrames.emplace_back(ri);
errCode = riFrames.back()->loadRaw(true, 0, true, plistener, 0.8);
} }
rawDataFrames.resize(riFrames.size());
rawDataBuffer.clear();
rawDataBuffer.resize(riFrames.size() - 1);
if (!errCode) { if (!errCode) {
for (unsigned int i = 0; i < numFrames; ++i) { for (unsigned int i = 0; i < numFrames; ++i) {
@ -1514,21 +1518,21 @@ void RawImageSource::preprocess(const RAWParams &raw, const LensProfParams &lens
rawDataFrames[i] = &rawData; rawDataFrames[i] = &rawData;
} else { } else {
if (!rawDataBuffer[bufferNumber]) { if (!rawDataBuffer[bufferNumber]) {
rawDataBuffer[bufferNumber] = new array2D<float>; rawDataBuffer[bufferNumber].reset(new array2D<float>);
} }
rawDataFrames[i] = rawDataBuffer[bufferNumber]; rawDataFrames[i] = rawDataBuffer[bufferNumber].get();
++bufferNumber; ++bufferNumber;
copyOriginalPixels(raw, riFrames[i], rid, rif, *rawDataFrames[i], reddeha, greendeha, bluedeha); copyOriginalPixels(raw, riFrames[i].get(), rid, rif, *rawDataFrames[i], reddeha, greendeha, bluedeha);
} }
} }
} else if (numFrames == 2 && currFrame == 2) { // average the frames } else if (numFrames == 2 && currFrame == 2) { // average the frames
if (!rawDataBuffer[0]) { if (!rawDataBuffer[0]) {
rawDataBuffer[0] = new array2D<float>; rawDataBuffer[0].reset(new array2D<float>);
} }
rawDataFrames[1] = rawDataBuffer[0]; rawDataFrames[1] = rawDataBuffer[0].get();
copyOriginalPixels(raw, riFrames[1], rid, rif, *rawDataFrames[1], reddeha, greendeha, bluedeha); copyOriginalPixels(raw, riFrames[1].get(), rid, rif, *rawDataFrames[1], reddeha, greendeha, bluedeha);
copyOriginalPixels(raw, ri, rid, rif, rawData, reddeha, greendeha, bluedeha); copyOriginalPixels(raw, ri, rid, rif, rawData, reddeha, greendeha, bluedeha);
for (int i = 0; i < H; ++i) { for (int i = 0; i < H; ++i) {
@ -2581,9 +2585,8 @@ void RawImageSource::retinex(const ColorManagementParams& cmp, const RetinexPara
void RawImageSource::flush() void RawImageSource::flush()
{ {
for (size_t i = 0; i + 1 < numFrames; ++i) { for (auto &buffer : rawDataBuffer) {
delete rawDataBuffer[i]; buffer.reset();
rawDataBuffer[i] = nullptr;
} }
if (rawData) { if (rawData) {

View File

@ -21,6 +21,7 @@
#include <array> #include <array>
#include <iostream> #include <iostream>
#include <memory> #include <memory>
#include <vector>
#include "array2D.h" #include "array2D.h"
#include "colortemp.h" #include "colortemp.h"
@ -78,13 +79,13 @@ protected:
bool rgbSourceModified; bool rgbSourceModified;
RawImage* ri; // Copy of raw pixels, NOT corrected for initial gain, blackpoint etc. RawImage* ri; // Copy of raw pixels, NOT corrected for initial gain, blackpoint etc.
RawImage* riFrames[6] = {nullptr}; std::vector<std::unique_ptr<RawImage>> riFrames;
unsigned int currFrame = 0; unsigned int currFrame = 0;
unsigned int numFrames = 0; unsigned int numFrames = 0;
int flatFieldAutoClipValue = 0; int flatFieldAutoClipValue = 0;
array2D<float> rawData; // holds preprocessed pixel values, rowData[i][j] corresponds to the ith row and jth column array2D<float> rawData; // holds preprocessed pixel values, rowData[i][j] corresponds to the ith row and jth column
array2D<float> *rawDataFrames[6] = {nullptr}; std::vector<array2D<float> *> rawDataFrames;
array2D<float> *rawDataBuffer[5] = {nullptr}; std::vector<std::unique_ptr<array2D<float>>> rawDataBuffer;
// the interpolated green plane: // the interpolated green plane:
array2D<float> green; array2D<float> green;
@ -204,12 +205,12 @@ public:
static void init (); static void init ();
static void cleanup (); static void cleanup ();
void setCurrentFrame(unsigned int frameNum) override { void setCurrentFrame(unsigned int frameNum) override {
if (numFrames == 2 && frameNum == 2) { // special case for averaging of two frames if (numFrames == 2 && frameNum == 2 && riFrames.size() >= 1) { // special case for averaging of two frames
currFrame = frameNum; currFrame = frameNum;
ri = riFrames[0]; ri = riFrames[0].get();
} else { } else if (riFrames.size() > std::min(numFrames - 1, frameNum)) {
currFrame = std::min(numFrames - 1, frameNum); currFrame = std::min(numFrames - 1, frameNum);
ri = riFrames[currFrame]; ri = riFrames[currFrame].get();
} }
} }
int getFrameCount() override {return numFrames;} int getFrameCount() override {return numFrames;}

View File

@ -745,7 +745,7 @@ void BayerProcess::FrameCountChanged(int n, int frameNum)
imageNumber->remove_all(); imageNumber->remove_all();
imageNumber->append("1"); imageNumber->append("1");
for (int i = 2; i <= std::min(n, 6); ++i) { for (int i = 2; i <= n; ++i) {
std::ostringstream entry; std::ostringstream entry;
entry << i; entry << i;
imageNumber->append(entry.str()); imageNumber->append(entry.str());