Repository navigation
Calibrate only the analysed pixels and stack the search areas in step 3 - #179
Merged
Merged
Conversation
…-fff0f0' into claude/image-reading-performance-3a725f
Once every image was decoded once for all channels, half of the time of step 3 was still spent outside the decoding. The black level, the white level and the read noise were applied to the whole frame, and the quantities of every LED were taken one LED at a time, about 15 numpy calls per LED and channel on arrays of a few hundred pixels. ImageChannels keeps the stored values of a RAW image and applies the calibration to the pixels it is asked for. Step 3 asks for its search areas and side bands, about 7 % of a 24 MP frame, in one selection, so that they are calibrated once for all channels. The whole frame can still be asked for as before. generate_analysis_data stacks the search areas and takes every quantity along the axes of the stack: sum, mean, maximum, the median and mean of the border ring, the noise and the side band mean, which reduceat takes over the side band pixels of all LEDs at once. A search area at the border of the image is cut short as the slicing did, and stacked with those of its shape. Only the fits are still made LED by LED. _generate_led_analysis_data, used by the debug path and the tests, is built on the same code. On the demo_2 CR2s, step 3 for three channels takes 375 ms per image instead of 621 ms on one core, and analyses 13.5 instead of 3.5 images per second on eight. The analysis of the three channels takes 39 ms instead of about 300 ms; the rest is the decoding. Every value and every CSV line of 24 images is the same as before, with and without fits. Unit tests pass, 403; the acceptance tests pass, 32. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…g-performance-3a725f
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What changed
Once every image is decoded only once for all channels (#178), half of the time of step 3 was still spent outside the decoding. The black level, the white level and the read noise were applied to the whole 24 MP frame, and the quantities of every LED were taken one LED at a time, about 15 numpy calls per LED and channel on arrays of a few hundred pixels.
ledsa/core/image_reading.py:ImageChannelskeeps the stored values of a RAW image and applies the calibration only to the pixels it is asked for.channel_data_mask_and_noise(channel, pixels)takes an optional selection of row and column indices. The calibrated selection does not depend on the channel and is kept for the next call with the same selection, so the three channels of an image calibrate it once. Without a selection the whole frame is returned as before._read_img_array_and_noise_from_raw_fileis gone; nothing used it any more.ledsa/data_extraction/step_3_functions.py:generate_analysis_dataasks for the pixels of its search areas and side bands only, about 7 % of the frame, in one selection that is cached per process like the side band geometry. It stacks the search areas and takes every quantity along the axes of the stack (_analyse_search_areas,_estimate_ring_backgrounds). Only the fits are still made LED by LED. A search area at the border of the image is cut short exactly asdata[row - R:row + R, col - R:col + R]cut it, and stacked with those of its shape._generate_led_analysis_data, used by the debug path and the tests, runs on the same code.ledsa/data_extraction/sideband_background.py:estimate_sideband_backgroundstakes the side band mean of all LEDs at once withreduceat.estimate_sideband_backgrounduses it for a single LED.Why
Step 3 for three channels on 24 MP CR2s of
demo_2, 981 LEDs, without fits (-s3_fast), warm file cache, M3 Pro:On one core, ~335 ms of the 375 ms is reading the file, almost all of it LibRaw's decode; the analysis of the three channels takes 39 ms instead of about 300 ms. Decoding alone tops out at about 21 images/s with 8 processes on this machine, so step 3 is now close to that limit. With #178, 8 cores gave only 2.2× of one core; now they give 5×, probably because each worker no longer moves several full-frame float arrays through memory per image.
For the reviewer
process_image_datawrites for 24 images match those of Read every image once for all channels in step 3 #178 and of master byte for byte below the header, on 1 and on 8 cores.uint16frame and its Bayer colors, a worker holds the calibrated selection (about 1.7 M pixels) instead of full-framefloat32arrays for the data, the noise and the per-channel copies._estimate_local_backgroundand_estimate_local_background_meanare replaced by the stacked_estimate_ring_backgrounds; their tests now call it through a single-box helper.search_area_radiusto the top or left edge of the image gives an empty search area, and step 3 raises on it.Tests
test_stacked_search_areas.pycompares the stacked analysis with the definitions applied LED by LED on the whole image, for all channels, upright and turned sideways, with a search area cut short at the border, an LED without side bands and skipped LEDs, and checks that only the analysed pixels are calibrated, once for three channels. New tests intest_image_channels.pycover selected pixels of RAW and PNG images and when the calibration is kept.🤖 Generated with Claude Code