Skip to content

Commit 2b428e0

Browse files
committed
Add ISO to dataframe
1 parent 1026ea0 commit 2b428e0

File tree

13 files changed

+370
-256
lines changed

13 files changed

+370
-256
lines changed

src/core/analysis/Analysis.hpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
// --- STRUCTURE DEFINITIONS ---
1515

1616
enum class DataSource { R, G1, G2, B, AVG };
17-
1817
/**
1918
* @struct PointData
2019
* @brief Holds the data for a single plotted point, including its source channel.
@@ -28,6 +27,7 @@ struct PointData {
2827
struct DynamicRangeResult {
2928
std::string filename;
3029
DataSource channel;
30+
float iso_speed = 0.0f;
3131
std::map<double, double> dr_values_ev;
3232
int samples_R = 0;
3333
int samples_G1 = 0;
@@ -57,7 +57,8 @@ struct CurveData {
5757
};
5858

5959
struct SnrCurve {
60-
std::vector<PointData> points; // Replaced separate signal_ev and snr_db vectors
60+
std::vector<PointData> points;
61+
// Replaced separate signal_ev and snr_db vectors
6162
cv::Mat poly_coeffs;
6263
};
6364

src/core/arguments/ArgumentManager.cpp

Lines changed: 99 additions & 96 deletions
Large diffs are not rendered by default.

src/core/arguments/Constants.hpp

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// File: src/core/arguments/Constants.hpp
2+
/**
3+
* @file src/core/arguments/Constants.hpp
4+
* @brief Centralizes all command-line argument name constants.
5+
* @details Using constants for argument names avoids magic strings and ensures
6+
* consistency across the application. A change here propagates everywhere.
7+
*/
8+
#pragma once
9+
10+
namespace DynaRange::Arguments::Constants {
11+
12+
// --- Core Analysis Arguments ---
13+
constexpr const char* BlackLevel = "black-level";
14+
constexpr const char* BlackFile = "black-file";
15+
constexpr const char* SaturationLevel = "saturation-level";
16+
constexpr const char* SaturationFile = "saturation-file";
17+
constexpr const char* InputFiles = "input-files";
18+
constexpr const char* PatchRatio = "patch-ratio";
19+
constexpr const char* SnrThresholdDb = "snrthreshold-db";
20+
constexpr const char* DrNormalizationMpx = "drnormalization-mpx";
21+
constexpr const char* RawChannels = "raw-channels";
22+
constexpr const char* PolyFit = "poly-fit";
23+
24+
// --- Output and Plotting Arguments ---
25+
constexpr const char* OutputFile = "output-file";
26+
constexpr const char* PlotFormat = "plot-format";
27+
constexpr const char* PlotParams = "plot-params";
28+
constexpr const char* PrintPatches = "print-patches";
29+
30+
// --- Chart Generation Arguments ---
31+
constexpr const char* Chart = "chart";
32+
constexpr const char* ChartColour = "chart-colour";
33+
constexpr const char* ChartPatches = "chart-patches";
34+
constexpr const char* ChartCoords = "chart-coords";
35+
36+
// --- Internal Flags (no user-facing CLI equivalent) ---
37+
constexpr const char* GeneratePlot = "generate-plot";
38+
constexpr const char* CreateChartMode = "create-chart-mode";
39+
constexpr const char* SnrThresholdIsDefault = "snr-threshold-is-default";
40+
constexpr const char* BlackLevelIsDefault = "black-level-is-default";
41+
constexpr const char* SaturationLevelIsDefault = "saturation-level-is-default";
42+
43+
} // namespace DynaRange::Arguments::Constants

src/core/engine/Processing.cpp

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,6 @@ std::vector<SingleFileResult> AnalyzeSingleRawFile(
9999
}
100100
const double strict_min_snr_db = -10.0 - norm_adjustment;
101101
const double permissive_min_snr_db = DynaRange::Analysis::Constants::MIN_SNR_DB_THRESHOLD - norm_adjustment;
102-
103102
// Find the highest SNR threshold requested by the user for the validation check.
104103
double max_requested_threshold = 0.0;
105104
if (!opts.snr_thresholds_db.empty()) {
@@ -126,10 +125,8 @@ std::vector<SingleFileResult> AnalyzeSingleRawFile(
126125
}
127126

128127
bool should_draw_overlay = generate_debug_image && (channel == DataSource::R);
129-
130128
// --- Pass 1: Analyze with the strict threshold ---
131129
PatchAnalysisResult patch_data = AnalyzePatches(img_prepared, chart.GetGridCols(), chart.GetGridRows(), opts.patch_ratio, should_draw_overlay, strict_min_snr_db);
132-
133130
// --- Validation Step ---
134131
bool needs_reanalysis = false;
135132
if (!patch_data.signal.empty()) {
@@ -151,7 +148,8 @@ std::vector<SingleFileResult> AnalyzeSingleRawFile(
151148
// --- Pass 2 (Conditional): Re-analyze with the permissive threshold ---
152149
if (needs_reanalysis) {
153150
log_stream << " - Info: Re-analyzing channel " << Formatters::DataSourceToString(channel)
154-
<< " with permissive threshold to find low-SNR data." << std::endl;
151+
<< " with permissive threshold to find low-SNR data."
152+
<< std::endl;
155153
patch_data = AnalyzePatches(img_prepared, chart.GetGridCols(), chart.GetGridRows(), opts.patch_ratio, should_draw_overlay, permissive_min_snr_db);
156154
}
157155

@@ -187,14 +185,16 @@ std::vector<SingleFileResult> AnalyzeSingleRawFile(
187185
}
188186

189187
if (final_patch_data.signal.empty()) continue;
190-
188+
191189
auto [dr_result, curve_data] = CalculateResultsFromPatches(final_patch_data, opts, raw_file.GetFilename(), camera_resolution_mpx, final_channel);
192190

191+
dr_result.iso_speed = raw_file.GetIsoSpeed(); // Populate the new ISO field
193192
dr_result.samples_R = individual_channel_patches.count(DataSource::R) ? individual_channel_patches.at(DataSource::R).signal.size() : 0;
194-
dr_result.samples_G1 = individual_channel_patches.count(DataSource::G1) ? individual_channel_patches.at(DataSource::G1).signal.size() : 0;
193+
dr_result.samples_G1 = individual_channel_patches.count(DataSource::G1) ?
194+
individual_channel_patches.at(DataSource::G1).signal.size() : 0;
195195
dr_result.samples_G2 = individual_channel_patches.count(DataSource::G2) ? individual_channel_patches.at(DataSource::G2).signal.size() : 0;
196196
dr_result.samples_B = individual_channel_patches.count(DataSource::B) ? individual_channel_patches.at(DataSource::B).signal.size() : 0;
197-
197+
198198
if(opts.plot_labels.count(raw_file.GetFilename())) {
199199
curve_data.plot_label = opts.plot_labels.at(raw_file.GetFilename());
200200
} else {

src/core/engine/Reporting.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,13 +46,16 @@ ReportOutput FinalizeAndReport(
4646
PathManager paths(opts);
4747
ReportOutput output;
4848

49+
// Flatten and sort the results before any output is generated.
50+
auto sorted_rows = Formatters::FlattenAndSortResults(results.dr_results);
51+
4952
output.final_csv_path = paths.GetCsvOutputPath().string();
5053
output.individual_plot_paths = GenerateIndividualPlots(results.curve_data, results.dr_results, opts, paths, log_stream);
5154

5255
log_stream << "\n--- " << _("Dynamic Range Results") << " ---" << std::endl;
53-
log_stream << Formatters::FormatResultsTable(results.dr_results, opts);
56+
log_stream << Formatters::FormatResultsTable(sorted_rows);
5457

55-
OutputWriter::WriteCsv(results.dr_results, opts, paths.GetCsvOutputPath(), log_stream);
58+
OutputWriter::WriteCsv(sorted_rows, paths.GetCsvOutputPath(), log_stream);
5659

5760
output.summary_plot_path = GenerateSummaryPlotReport(results.curve_data, results.dr_results, opts, paths, log_stream);
5861

src/core/io/OutputWriter.cpp

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,7 @@ bool WritePng(cairo_surface_t* surface, const fs::path& path, std::ostream& log_
2828
}
2929

3030
bool WriteCsv(
31-
const std::vector<DynamicRangeResult>& all_results,
32-
const ProgramOptions& opts,
31+
const std::vector<Formatters::FlatResultRow>& sorted_rows,
3332
const fs::path& path,
3433
std::ostream& log_stream)
3534
{
@@ -42,9 +41,9 @@ bool WriteCsv(
4241
// Write the new, fixed header
4342
csv_file << Formatters::FormatCsvHeader() << std::endl;
4443

45-
// Iterate through results and write the multiple rows that each may generate
46-
for (const auto& res : all_results) {
47-
csv_file << Formatters::FormatCsvRows(res);
44+
// Iterate through the pre-sorted rows and write each one.
45+
for (const auto& row : sorted_rows) {
46+
csv_file << Formatters::FormatCsvRow(row);
4847
}
4948

5049
csv_file.close();

src/core/io/OutputWriter.hpp

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,11 @@
77
*/
88
#pragma once
99

10-
#include <vector>
1110
#include <ostream>
1211
#include <filesystem>
1312
#include <cairo/cairo.h>
1413
#include <opencv2/core.hpp>
15-
#include "../analysis/Analysis.hpp"
16-
#include "../arguments/ArgumentsOptions.hpp"
14+
#include "../utils/Formatters.hpp"
1715

1816
namespace fs = std::filesystem;
1917

@@ -41,16 +39,13 @@ bool WriteDebugImage(const cv::Mat& image, const fs::path& path, std::ostream& l
4139

4240
/**
4341
* @brief Writes the analysis results to a CSV file.
44-
* @param all_results The vector of DynamicRangeResult structs to write.
45-
* @param opts The program options, used to get the SNR thresholds for the header.
42+
* @param sorted_rows The flattened and sorted vector of result rows to write.
4643
* @param path The full filesystem path for the output CSV.
4744
* @param log_stream A stream for logging success or error messages.
4845
* @return true on success, false on failure.
4946
*/
5047
bool WriteCsv(
51-
const std::vector<DynamicRangeResult>& all_results,
52-
const ProgramOptions& opts,
48+
const std::vector<Formatters::FlatResultRow>& sorted_rows,
5349
const fs::path& path,
5450
std::ostream& log_stream);
55-
5651
} // namespace OutputWriter

src/core/utils/CommandGenerator.cpp

Lines changed: 40 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,22 @@
55
*/
66
#include "CommandGenerator.hpp"
77
#include "../arguments/ArgumentManager.hpp"
8+
#include "../arguments/Constants.hpp"
89
#include "Constants.hpp"
910
#include <filesystem>
1011
#include <iomanip>
1112
#include <libintl.h>
1213
#include <sstream>
1314

1415
#define _(string) gettext(string)
16+
1517
namespace fs = std::filesystem;
1618

1719
namespace CommandGenerator {
1820

1921
std::string GenerateCommand(CommandFormat format)
2022
{
23+
using namespace DynaRange::Arguments::Constants;
2124
std::stringstream command_ss;
2225
command_ss << DynaRange::Utils::Constants::CLI_EXECUTABLE_NAME;
2326
auto& mgr = ArgumentManager::Instance();
@@ -28,104 +31,103 @@ std::string GenerateCommand(CommandFormat format)
2831
command_ss << " --" << name;
2932
return;
3033
}
31-
// Map long names to short names for the short command format
34+
3235
static const std::map<std::string, std::string> short_map
33-
= { { "black-level", " -B" }, { "black-file", " -b" }, { "saturation-level", " -S" }, { "saturation-file", " -s" }, { "input-files", " -i" }, { "patch-ratio", " -r" },
34-
{ "snrthreshold-db", " -d" }, { "drnormalization-mpx", " -m" }, { "poly-fit", " -f" }, { "output-file", " -o" }, { "plot-format", " -p" }, { "plot-params", " -P" },
35-
{ "print-patches", " -g" }, { "raw-channel", " -w" }, { "chart", " -c" }, { "chart-colour", " -C" }, { "chart-coords", " -x" }, { "chart-patches", " -M" } };
36+
= { { BlackLevel, " -B" }, { BlackFile, " -b" }, { SaturationLevel, " -S" }, { SaturationFile, " -s" }, { InputFiles, " -i" }, { PatchRatio, " -r" },
37+
{ SnrThresholdDb, " -d" }, { DrNormalizationMpx, " -m" }, { PolyFit, " -f" }, { OutputFile, " -o" }, { PlotFormat, " -p" }, { PlotParams, " -P" },
38+
{ PrintPatches, " -g" }, { RawChannels, " -w" }, { Chart, " -c" }, { ChartColour, " -C" }, { ChartCoords, " -x" }, { ChartPatches, " -M" } };
3639
auto it = short_map.find(name);
3740
if (it != short_map.end()) {
3841
command_ss << it->second;
3942
} else {
40-
command_ss << " --" << name; // Fallback for args without a short version
43+
command_ss << " --" << name;
4144
}
4245
};
4346

44-
std::string black_file = mgr.Get<std::string>("black-file");
47+
std::string black_file = mgr.Get<std::string>(BlackFile);
4548
if (!black_file.empty()) {
46-
add_arg("black-file");
49+
add_arg(BlackFile);
4750
if (format == CommandFormat::GuiPreview || format == CommandFormat::Full) {
4851
command_ss << " \"" << black_file << "\"";
4952
} else {
5053
command_ss << " \"" << fs::path(black_file).filename().string() << "\"";
5154
}
5255
} else {
53-
add_arg("black-level");
54-
command_ss << " " << std::fixed << std::setprecision(2) << mgr.Get<double>("black-level");
56+
add_arg(BlackLevel);
57+
command_ss << " " << std::fixed << std::setprecision(2) << mgr.Get<double>(BlackLevel);
5558
}
5659

57-
std::string sat_file = mgr.Get<std::string>("saturation-file");
60+
std::string sat_file = mgr.Get<std::string>(SaturationFile);
5861
if (!sat_file.empty()) {
59-
add_arg("saturation-file");
62+
add_arg(SaturationFile);
6063
if (format == CommandFormat::GuiPreview || format == CommandFormat::Full) {
6164
command_ss << " \"" << sat_file << "\"";
6265
} else {
6366
command_ss << " \"" << fs::path(sat_file).filename().string() << "\"";
6467
}
6568
} else {
66-
add_arg("saturation-level");
67-
command_ss << " " << std::fixed << std::setprecision(2) << mgr.Get<double>("saturation-level");
69+
add_arg(SaturationLevel);
70+
command_ss << " " << std::fixed << std::setprecision(2) << mgr.Get<double>(SaturationLevel);
6871
}
6972

7073
if (format == CommandFormat::Full) {
71-
add_arg("output-file");
72-
command_ss << " \"" << mgr.Get<std::string>("output-file") << "\"";
74+
add_arg(OutputFile);
75+
command_ss << " \"" << mgr.Get<std::string>(OutputFile) << "\"";
7376
}
7477

75-
if (!mgr.Get<bool>("snr-threshold-is-default")) {
76-
add_arg("snrthreshold-db");
77-
const auto& thresholds = mgr.Get<std::vector<double>>("snrthreshold-db");
78+
if (!mgr.Get<bool>(SnrThresholdIsDefault)) {
79+
add_arg(SnrThresholdDb);
80+
const auto& thresholds = mgr.Get<std::vector<double>>(SnrThresholdDb);
7881
for (const auto& threshold : thresholds) {
7982
command_ss << " " << threshold;
8083
}
8184
}
8285

83-
add_arg("drnormalization-mpx");
84-
command_ss << " " << mgr.Get<double>("drnormalization-mpx");
85-
add_arg("poly-fit");
86-
command_ss << " " << mgr.Get<int>("poly-fit");
87-
add_arg("patch-ratio");
88-
command_ss << " " << mgr.Get<double>("patch-ratio");
86+
add_arg(DrNormalizationMpx);
87+
command_ss << " " << mgr.Get<double>(DrNormalizationMpx);
88+
add_arg(PolyFit);
89+
command_ss << " " << mgr.Get<int>(PolyFit);
90+
add_arg(PatchRatio);
91+
command_ss << " " << mgr.Get<double>(PatchRatio);
8992

90-
if (mgr.Get<bool>("generate-plot")) {
91-
add_arg("plot-format");
92-
command_ss << " " << mgr.Get<std::string>("plot-format");
93+
if (mgr.Get<bool>(GeneratePlot)) {
94+
add_arg(PlotFormat);
95+
command_ss << " " << mgr.Get<std::string>(PlotFormat);
9396

94-
add_arg("plot-params");
95-
const auto& plot_params = mgr.Get<std::vector<int>>("plot-params");
97+
add_arg(PlotParams);
98+
const auto& plot_params = mgr.Get<std::vector<int>>(PlotParams);
9699
for (const auto& val : plot_params) {
97100
command_ss << " " << val;
98101
}
99102
}
100103

101-
const auto& chart_coords = mgr.Get<std::vector<double>>("chart-coords");
104+
const auto& chart_coords = mgr.Get<std::vector<double>>(ChartCoords);
102105
if (!chart_coords.empty()) {
103-
add_arg("chart-coords");
106+
add_arg(ChartCoords);
104107
for (const auto& coord : chart_coords)
105108
command_ss << " " << coord;
106109
}
107110

108-
const auto& chart_patches = mgr.Get<std::vector<int>>("chart-patches");
111+
const auto& chart_patches = mgr.Get<std::vector<int>>(ChartPatches);
109112
if (!chart_patches.empty()) {
110-
add_arg("chart-patches");
113+
add_arg(ChartPatches);
111114
for (const auto& val : chart_patches)
112115
command_ss << " " << val;
113116
}
114117

115-
// Add --raw-channel to the command string if it's not the default.
116-
const auto& raw_channels_vec = mgr.Get<std::vector<int>>("raw-channel");
118+
const auto& raw_channels_vec = mgr.Get<std::vector<int>>(RawChannels);
117119
const std::vector<int> default_channels = { 0, 0, 0, 0, 1 };
118120
if (raw_channels_vec != default_channels) {
119-
add_arg("raw-channel");
121+
add_arg(RawChannels);
120122
for (const auto& val : raw_channels_vec) {
121123
command_ss << " " << val;
122124
}
123125
}
124126

125127
if (format == CommandFormat::Full || format == CommandFormat::GuiPreview) {
126-
const auto& input_files = mgr.Get<std::vector<std::string>>("input-files");
128+
const auto& input_files = mgr.Get<std::vector<std::string>>(InputFiles);
127129
if (!input_files.empty()) {
128-
add_arg("input-files");
130+
add_arg(InputFiles);
129131
for (const auto& file : input_files) {
130132
command_ss << " \"" << file << "\"";
131133
}

0 commit comments

Comments
 (0)