export raw histogram data

This commit is contained in:
Claude Heiland-Allen 2023-12-05 11:18:40 +00:00
parent 6ef145e76e
commit a7b4cc70d6
10 changed files with 122 additions and 6 deletions

View File

@ -1137,6 +1137,25 @@ eRenderStatus Renderer<T, bucketT>::AccumulatorToFinalImage(vector<v4F>& pixels,
return eRenderStatus::RENDER_ERROR;
}
if (RawHistogram())
{
auto p = pixels.data() + finalOffset;
auto q = m_AccumulatorBuckets.data();
auto bytes = sizeof(*p) * FinalRasW();
parallel_for(size_t(0), FinalRasH(), size_t(1), [&](size_t j)
{
auto pixelsRowStart = (m_YAxisUp ? ((FinalRasH() - j) - 1) : j) * FinalRasW();//Pull out of inner loop for optimization.
auto rowStart = j * m_SuperRasW;
memcpy(p + pixelsRowStart, q + rowStart, bytes);
}
#if defined(_WIN32) || defined(__APPLE__)
, tbb::static_partitioner()
#endif
);
LeaveFinalAccum();
return m_Abort ? eRenderStatus::RENDER_ABORT : eRenderStatus::RENDER_OK;
}
//Timing t(4);
const size_t filterWidth = m_SpatialFilter->FinalFilterWidth();
bucketT g, linRange, vibrancy;

View File

@ -374,6 +374,40 @@ void RendererBase::ReclaimOnResize(bool reclaimOnResize)
ChangeVal([&] { m_ReclaimOnResize = reclaimOnResize; }, eProcessAction::FULL_RENDER);
}
/// <summary>
/// Get whether to output raw histogram values instead of gamma corrected
/// colours.
/// Default: false.
/// </summary>
/// <returns>True if raw, else false.</returns>
bool RendererBase::RawHistogram() const { return m_RawHistogram; }
/// <summary>
/// Set whether to output raw histogram values instead of gamma corrected
/// colours.
/// </summary>
/// <param name="rawHistogram">True if raw, else false.</param>
void RendererBase::RawHistogram(bool rawHistogram)
{
ChangeVal([&] { m_RawHistogram = rawHistogram; }, eProcessAction::ACCUM_ONLY);
}
/// <summary>
/// Get whether to output raw histogram values before density filtering.
/// Default: false.
/// </summary>
/// <returns>True if raw, else false.</returns>
bool RendererBase::RawHistogramPreDensity() const { return m_RawHistogramPreDensity; }
/// <summary>
/// Set whether to output raw histogram values before density filtering.
/// </summary>
/// <param name="rawHistogram">True if pre density, else false.</param>
void RendererBase::RawHistogramPreDensity(bool rawHistogramPreDensity)
{
ChangeVal([&] { m_RawHistogramPreDensity = rawHistogramPreDensity; }, eProcessAction::ACCUM_ONLY);
}
/// <summary>
/// Set the callback object.
/// </summary>

View File

@ -156,6 +156,10 @@ public:
void InsertPalette(bool insertPalette);
bool ReclaimOnResize() const;
void ReclaimOnResize(bool reclaimOnResize);
bool RawHistogram() const;
void RawHistogram(bool rawHistogram);
bool RawHistogramPreDensity() const;
void RawHistogramPreDensity(bool rawHistogramPreDensity);
void Callback(RenderCallback* callback);
void ThreadCount(size_t threads, const char* seedString = nullptr);
size_t BytesPerChannel() const;
@ -207,6 +211,8 @@ protected:
bool m_InFinalAccum = false;
bool m_InsertPalette = false;
bool m_ReclaimOnResize = false;
bool m_RawHistogram = false;
bool m_RawHistogramPreDensity = false;
bool m_CurvesSet = false;
volatile bool m_Abort = false;
volatile bool m_Pause = false;

View File

@ -332,6 +332,8 @@ bool EmberAnimate(int argc, _TCHAR* argv[], EmberOptions& opt)
r->EarlyClip(opt.EarlyClip());
r->YAxisUp(opt.YAxisUp());
r->LockAccum(opt.LockAccum());
r->RawHistogram(opt.RawHistogram());
r->RawHistogramPreDensity(opt.RawHistogramPreDensity());
r->PixelAspectRatio(T(opt.AspectRatio()));
r->Priority(eThreadPriority(Clamp<intmax_t>(intmax_t(opt.Priority()), intmax_t(eThreadPriority::LOWEST), intmax_t(eThreadPriority::HIGHEST))));
}
@ -471,7 +473,7 @@ bool EmberAnimate(int argc, _TCHAR* argv[], EmberOptions& opt)
vector<float> g(size);
vector<float> b(size);
vector<float> a(size);
Rgba32ToRgba32Exr(finalImagep, r.data(), g.data(), b.data(), a.data(), w, h, opt.Transparency());
Rgba32ToRgba32Exr(finalImagep, r.data(), g.data(), b.data(), a.data(), w, h, opt.Transparency(), ! opt.RawHistogram());
const auto writeSuccess = WriteExr32(fn.c_str(),
r.data(),
g.data(),

View File

@ -433,8 +433,36 @@ template <typename T, typename bucketT>
bool RendererCL<T, bucketT>::ReadFinal(v4F* pixels)
{
if (pixels && !m_Devices.empty())
return m_Devices[0]->m_Wrapper.ReadImage(m_FinalImageName, FinalRasW(), FinalRasH(), 0, m_Devices[0]->m_Wrapper.Shared(), pixels);
{
if (RawHistogram())
{
if (RawHistogramPreDensity() ? ReadHist(0) : ReadAccum())
{
auto p = pixels;
auto q = RawHistogramPreDensity() ? HistBuckets() : AccumulatorBuckets();
auto bytes = sizeof(*p) * FinalRasW();
parallel_for(size_t(0), FinalRasH(), size_t(1), [&](size_t j)
{
auto pixelsRowStart = (m_YAxisUp ? ((FinalRasH() - j) - 1) : j) * FinalRasW();//Pull out of inner loop for optimization.
auto rowStart = j * SuperRasW();
memcpy(p + pixelsRowStart, q + rowStart, bytes);
}
#if defined(_WIN32) || defined(__APPLE__)
, tbb::static_partitioner()
#endif
);
return true;
}
else
{
return false;
}
}
else
{
return m_Devices[0]->m_Wrapper.ReadImage(m_FinalImageName, FinalRasW(), FinalRasH(), 0, m_Devices[0]->m_Wrapper.Shared(), pixels);
}
}
return false;
}

View File

@ -310,10 +310,13 @@ static void Rgba32ToRgbaExr(const v4F* rgba, Rgba* ilmfRgba, size_t width, size_
/// <param name="width">The width of the image in pixels</param>
/// <param name="height">The height of the image in pixels</param>
/// <param name="doAlpha">True to use alpha transparency, false to assign the max alpha value to make each pixel fully visible</param>
static void Rgba32ToRgba32Exr(const v4F* rgba, float* r, float* g, float* b, float* a, size_t width, size_t height, bool doAlpha)
/// <param name="doClamp">True to clamp output to 0..1, false to use full high dynamic range</param>
static void Rgba32ToRgba32Exr(const v4F* rgba, float* r, float* g, float* b, float* a, size_t width, size_t height, bool doAlpha, bool doClamp)
{
if (rgba != nullptr && r != nullptr && g != nullptr && b != nullptr && a != nullptr)
{
if (doClamp)
{
for (size_t i = 0; i < (width * height); i++)
{
r[i] = Clamp<float>(Sqr(rgba[i].r), 0.0f, 1.0f);
@ -321,6 +324,17 @@ static void Rgba32ToRgba32Exr(const v4F* rgba, float* r, float* g, float* b, flo
b[i] = Clamp<float>(Sqr(rgba[i].b), 0.0f, 1.0f);
a[i] = doAlpha ? Clamp<float>(rgba[i].a * 1.0f, 0.0f, 1.0f) : 1.0f;
}
}
else
{
for (size_t i = 0; i < (width * height); i++)
{
r[i] = rgba[i].r;
g[i] = rgba[i].g;
b[i] = rgba[i].b;
a[i] = rgba[i].a;
}
}
}
}

View File

@ -70,6 +70,8 @@ enum class eOptionIDs : et
OPT_DUMP_KERNEL,
OPT_FLAM3_COMPAT,
OPT_IGNORE_EXISTING,
OPT_RAW_HISTOGRAM,
OPT_RAW_HISTOGRAM_PRE_DENSITY,
//Value args.
OPT_NTHREADS,//Int value args.
@ -378,6 +380,8 @@ public:
INITBOOLOPTION(DumpKernel, Eob(eOptionUse::OPT_USE_RENDER, eOptionIDs::OPT_DUMP_KERNEL, _T("--dump_kernel"), false, SO_NONE, " --dump_kernel Print the iteration kernel string when using OpenCL (ignored for CPU) [default: false].\n"));
INITBOOLOPTION(Flam3Compat, Eob(eOptionUse::OPT_USE_ALL, eOptionIDs::OPT_FLAM3_COMPAT, _T("--flam3_compat"), false, SO_NONE, " --flam3_compat The behavior of the cos, cosh, cot, coth, csc, csch, sec, sech, sin, sinh, tan and tanh variations are different in flam3/Apophysis versus Chaotica. True for flam3/Apophysis behavior, false for Chaotica behavior [default: true].\n"));
INITBOOLOPTION(IgnoreExisting, Eob(eOptionUse::OPT_USE_ANIMATE, eOptionIDs::OPT_IGNORE_EXISTING, _T("--ignore-existing"), false, SO_NONE, " --ignore-existing Skip animating a frame if the output images for all of the specified file output types already exist in the output folder [default: false].\n"));
INITBOOLOPTION(RawHistogram, Eob(eOptionUse::OPT_USE_ALL, eOptionIDs::OPT_RAW_HISTOGRAM, _T("--raw_histogram"), false, SO_NONE, " --raw_histogram Output raw histogram values (after density filter, before gamma correction). For best results, use EXR 32-bit float and set supersampling to 1x. [default: false].\n"));
INITBOOLOPTION(RawHistogramPreDensity, Eob(eOptionUse::OPT_USE_ALL, eOptionIDs::OPT_RAW_HISTOGRAM_PRE_DENSITY, _T("--raw_histogram_pre_density"), false, SO_NONE, " --raw_histogram_pre_density Output raw histogram values before density filter instead of afterwards. Requires --raw_histogram. [default: false].\n"));
//Int.
INITINTOPTION(Symmetry, Eoi(eOptionUse::OPT_USE_GENOME, eOptionIDs::OPT_SYMMETRY, _T("--symmetry"), 0, SO_REQ_SEP, " --symmetry=<val> Set symmetry of result [default: 0].\n"));
INITINTOPTION(SheepGen, Eoi(eOptionUse::OPT_USE_GENOME, eOptionIDs::OPT_SHEEP_GEN, _T("--sheep_gen"), -1, SO_REQ_SEP, " --sheep_gen=<val> Sheep generation of this flame [default: -1].\n"));
@ -541,6 +545,8 @@ public:
PARSEBOOLOPTION(eOptionIDs::OPT_DUMP_KERNEL, DumpKernel);
PARSEBOOLOPTION(eOptionIDs::OPT_FLAM3_COMPAT, Flam3Compat);
PARSEBOOLOPTION(eOptionIDs::OPT_IGNORE_EXISTING, IgnoreExisting);
PARSEBOOLOPTION(eOptionIDs::OPT_RAW_HISTOGRAM, RawHistogram);
PARSEBOOLOPTION(eOptionIDs::OPT_RAW_HISTOGRAM_PRE_DENSITY, RawHistogramPreDensity);
PARSEOPTION(eOptionIDs::OPT_SYMMETRY, Symmetry);//Int args
PARSEOPTION(eOptionIDs::OPT_SHEEP_GEN, SheepGen);
PARSEOPTION(eOptionIDs::OPT_SHEEP_ID, SheepId);
@ -833,6 +839,8 @@ public:
Eob DumpKernel;
Eob Flam3Compat;
Eob IgnoreExisting;
Eob RawHistogram;
Eob RawHistogramPreDensity;
Eoi Symmetry;//Value int.
Eoi SheepGen;

View File

@ -603,6 +603,8 @@ bool EmberGenome(int argc, _TCHAR* argv[], EmberOptions& opt)
renderer->EarlyClip(opt.EarlyClip());
renderer->YAxisUp(opt.YAxisUp());
renderer->LockAccum(opt.LockAccum());
renderer->RawHistogram(opt.RawHistogram());
renderer->RawHistogramPreDensity(opt.RawHistogramPreDensity());
renderer->PixelAspectRatio(T(opt.AspectRatio()));
if (opt.Repeat() == 0)

View File

@ -153,6 +153,8 @@ bool EmberRender(int argc, _TCHAR* argv[], EmberOptions& opt)
renderer->EarlyClip(opt.EarlyClip());
renderer->YAxisUp(opt.YAxisUp());
renderer->LockAccum(opt.LockAccum());
renderer->RawHistogram(opt.RawHistogram());
renderer->RawHistogramPreDensity(opt.RawHistogramPreDensity());
renderer->InsertPalette(opt.InsertPalette());
renderer->PixelAspectRatio(T(opt.AspectRatio()));
renderer->Priority(eThreadPriority(Clamp<intmax_t>(intmax_t(opt.Priority()), intmax_t(eThreadPriority::LOWEST), intmax_t(eThreadPriority::HIGHEST))));
@ -447,7 +449,7 @@ bool EmberRender(int argc, _TCHAR* argv[], EmberOptions& opt)
vector<float> g(size);
vector<float> b(size);
vector<float> a(size);
Rgba32ToRgba32Exr(finalImagep, r.data(), g.data(), b.data(), a.data(), finalEmber.m_FinalRasW, finalEmber.m_FinalRasH, opt.Transparency());
Rgba32ToRgba32Exr(finalImagep, r.data(), g.data(), b.data(), a.data(), finalEmber.m_FinalRasW, finalEmber.m_FinalRasH, opt.Transparency(), ! opt.RawHistogram());
const auto writeSuccess = WriteExr32(filename.c_str(),
r.data(),
g.data(),

View File

@ -183,7 +183,8 @@ bool FractoriumEmberControllerBase::SaveCurrentRender(const QString& filename, c
vector<float> g(size);
vector<float> b(size);
vector<float> a(size);
Rgba32ToRgba32Exr(data, r.data(), g.data(), b.data(), a.data(), width, height, transparency);
bool raw_histogram = false;
Rgba32ToRgba32Exr(data, r.data(), g.data(), b.data(), a.data(), width, height, transparency, ! raw_histogram);
ret = WriteExr32(s.c_str(), r.data(), g.data(), b.data(), a.data(), width, height, true, comments, id, url, nick);
}
}