grid scan: the five lanes become one, with a single home for the crystal type and its settings
Integration of the per-image detection scores, the analysis mode, the grid-scan crystal search, its rugnux entry point and the viewer display. GridScanCrystal/GridScanResult had two definitions - a placeholder in common/ and the real one in image_analysis/ - which is a redefinition in any translation unit reaching both, and tests/RasterReportTest.cpp reaches both. Unified into common/GridScanResult.h, beside ScanResult where the data type belongs, leaving the algorithm in image_analysis/. Same reason UnitCell lives in common while the indexers do not. GridScanAnalysisSettings is now the only home for the search parameters, replacing the loose GridScanAnalysisParameters struct the raster lane carried while the class did not yet exist. Three values changed with the move: - decisive_single_cell_score 0.9 -> 0.6. 0.9 drops a real two-cell crystal peaking at 0.751 and costs a loop on the labelled corpus. 0.6 is the middle of a measured gap: over 67 rasters no water raster peaks above 0.15 and no ice raster above 0.50, while the weakest confirmed-protein raster peaks at 0.67. - max_crystals is std::optional, unset meaning no cap. 0 as a sentinel for "unlimited" reads as "find nothing", which is the opposite of what it did. - grow_score_threshold was missing from the class entirely. The viewer reads protein_score, ice_score and the crystal list from the reader rather than a local stub, and asks the broker for ice_ring_ratio rather than the retired ice_ring_score spelling. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EFEJG6WBQv8th4UJFNe53N
This commit is contained in:
@@ -17,7 +17,7 @@ GridScanResult AnalyzeGridScan(const ScanResult &scan,
|
||||
const GridScanSettings &grid,
|
||||
float beam_size_x_um,
|
||||
float beam_size_y_um,
|
||||
const GridScanAnalysisParameters ¶ms) {
|
||||
const GridScanAnalysisSettings &settings) {
|
||||
const int64_t nx = grid.GetGridSizeX_step();
|
||||
const int64_t ny = grid.GetGridSizeY_step();
|
||||
const float step_x = fabsf(grid.GetGridStepX_um());
|
||||
@@ -47,7 +47,7 @@ GridScanResult AnalyzeGridScan(const ScanResult &scan,
|
||||
// background that never reaches the seed level produces nothing.
|
||||
std::vector<uint8_t> grown(nx * ny);
|
||||
for (int64_t i = 0; i < nx * ny; i++)
|
||||
grown[i] = (protein[i] > params.grow_score_threshold) ? 1 : 0;
|
||||
grown[i] = (protein[i] > settings.GetGrowScoreThreshold()) ? 1 : 0;
|
||||
|
||||
// Labelled with no size cut of its own: whether a patch is big enough is no longer a plain
|
||||
// floor - a small patch survives on the strength of its diffraction - and that test needs the
|
||||
@@ -72,7 +72,7 @@ GridScanResult AnalyzeGridScan(const ScanResult &scan,
|
||||
// whatever its shape, so nothing about it is worth measuring.
|
||||
bool has_seed = false;
|
||||
for (int64_t i: cell)
|
||||
has_seed = has_seed || protein[i] > params.protein_score_threshold;
|
||||
has_seed = has_seed || protein[i] > settings.GetProteinScoreThreshold();
|
||||
if (!has_seed)
|
||||
continue;
|
||||
|
||||
@@ -176,8 +176,8 @@ GridScanResult AnalyzeGridScan(const ScanResult &scan,
|
||||
// patch no seed would have admitted, because the patch has already been discarded above
|
||||
// unless it holds a seed cell - and a seed cell is by definition the strongest kind there
|
||||
// is, so the peak of a grown patch is the peak of its seeds.
|
||||
if (static_cast<int64_t>(cell.size()) < params.min_blob_cells
|
||||
&& peak_protein < params.decisive_protein_score)
|
||||
if (static_cast<int64_t>(cell.size()) < settings.GetMinBlobCells()
|
||||
&& peak_protein < settings.GetDecisiveSingleCellScore())
|
||||
continue;
|
||||
|
||||
GridScanCrystal crystal;
|
||||
@@ -228,9 +228,10 @@ GridScanResult AnalyzeGridScan(const ScanResult &scan,
|
||||
|
||||
// Kept to the best few only where a caller asked for that; the sort above is what makes the
|
||||
// ones it keeps the right ones.
|
||||
if (params.max_crystals > 0
|
||||
&& result.crystals.size() > static_cast<size_t>(params.max_crystals))
|
||||
result.crystals.resize(params.max_crystals);
|
||||
// Unset means no cap: a crystal found and then dropped is information the caller cannot recover.
|
||||
if (const auto cap = settings.GetMaxCrystals();
|
||||
cap.has_value() && result.crystals.size() > static_cast<size_t>(*cap))
|
||||
result.crystals.resize(*cap);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user