Skip to content

Fix CircularRegionOfInterest.pixels_in_region omitting boundary pixels - #1895

Open
adityasingh2400 wants to merge 1 commit into
NeuralEnsemble:masterfrom
adityasingh2400:fix-1889
Open

Fix CircularRegionOfInterest.pixels_in_region omitting boundary pixels#1895
adityasingh2400 wants to merge 1 commit into
NeuralEnsemble:masterfrom
adityasingh2400:fix-1889

Conversation

@adityasingh2400

Copy link
Copy Markdown

Fixes #1889.

CircularRegionOfInterest.is_inside() tests a closed disc with <=, so a pixel centre exactly radius away is inside. But pixels_in_region() enumerated range(int(floor(c - r)), int(ceil(c + r))), and range excludes its stop value, so pixels at the +x and +y extremes were never passed to is_inside() at all. They were not rejected, they were never asked about.

The region therefore came out asymmetric about its own centre. For CircularRegionOfInterest(seq, 10, 10, 5) it returned 79 pixels spanning x 5 to 14, while is_inside() accepts 81 spanning 5 to 15.

The fix adds 1 to both upper bounds, so every pixel is_inside() accepts is offered to it.

The repo's own test file contradicted itself on this. Line 11 expected 3 pixels at radius=1 while line 13 expected 5 at radius=1.01. Under a closed disc both radii enclose exactly the same pixel centres, so those two lines could not both be right. Updating the radius=1 expectation to the same 5 pixels is an intentional part of this fix, not an accident. That assertion is what encoded the bug.

I swept the other two ROI classes for the same off-by-one and they are unaffected, so this leaves them alone. RectangularRegionOfInterest.is_inside() uses a half-open interval that exactly matches what its range() bounds enumerate, with 0 disagreements across 11664 centre, width and height combinations. The polygon ray caster excludes its top and right edges to match its bounding box, with 0 disagreements across 400 random polygons.

Tests: the corrected test_result, plus test_pixels_in_region_matches_is_inside, which locks in the real invariant that the enumeration must equal the predicate's accept set, and test_pixels_in_region_is_symmetric_about_centre, which is the issue's exact reproduction.

Restoring neo/core/regionofinterest.py from master makes all three fail, with [[6, 5], [5, 6], [6, 6]] != [[6, 5], [5, 6], [6, 6], [7, 6], [6, 7]]. All five pass after. The core suite is green at 617 passed and 16 skipped, and the circle sweep goes from 486 of 4536 configurations disagreeing to 0 of 4536.

Disclosure: this change was prepared with AI assistance. I have reviewed and tested it.

pixels_in_region enumerated range(floor(c - r), ceil(c + r)). range excludes
its stop value, so pixels at the +x and +y extremes of the disc were never
passed to is_inside at all. is_inside tests a closed disc with <=, so it
accepts those pixels, leaving the region asymmetric about its own centre.

Add 1 to both upper bounds so every pixel is_inside accepts is enumerated.

The existing radius=1 expectation in test_regionofinterest.py contradicted
the radius=1.01 expectation directly below it. Both enclose the same pixel
centres under a closed disc, so the radius=1 case is corrected here.

RectangularRegionOfInterest and PolygonRegionOfInterest were swept for the
same off-by-one and are unaffected: the rectangle's is_inside uses a
half-open interval that matches its range bounds, and the polygon's ray
caster excludes its top and right edges to match.

Fixes NeuralEnsemble#1889
@adityasingh2400

Copy link
Copy Markdown
Author

The readthedocs check here is a builder-side network failure, not something this branch does.

The build dies in doc/source/rawio.rst, whose IPython block calls urlretrieve against web.gin.g-node.org to pull the ephy_testing_data sample files. The traceback bottoms out in ssl.wrap_socket with a ConnectionResetError, so the download was cut off partway rather than the docs failing to build.

This PR only touches neo/core/regionofinterest.py and its test, nothing under doc/ and nothing that runs during the docs build. The same check is green on my other two open PRs against this repo, #1893 and #1894, which is what you would expect if the cause were the fetch rather than the branch.

A rebuild should clear it. I have left it alone rather than pushing an empty commit to force one, but say the word if you would rather I did.

@adityasingh2400

Copy link
Copy Markdown
Author

The Read the Docs check is red here and it is a network failure on the builder rather than anything in this change.

The build dies while sphinx is reading doc/source/rawio.rst, inside the IPython directive that executes a live block:

File .../urllib/request.py:1351, in AbstractHTTPHandler.do_open
    raise URLError(err)
URLError: <urlopen error [Errno 104] Connection reset by peer>
...
RuntimeError: Unexpected exception in `.../doc/source/rawio.rst` line None

This PR touches neo/core/regionofinterest.py and neo/test/coretest/test_regionofinterest.py only, with no documentation changes, so nothing here reaches rawio.rst.

I also checked the version angle before assuming it. The two neo builds earlier the same day, at 12:07 and 12:40, resolved to the same ipython-9.16.1 as this one and both passed, so this is not the IPython regression that has been breaking docs builds elsewhere. It is a connection reset partway through a download.

A rebuild should clear it. I have not pushed an empty commit to force one, since that seemed like the wrong way to retrigger, but I am happy to if that is easier than clicking rebuild.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

CircularRegionOfInterest.pixels_in_region omits boundary pixels that its own is_inside accepts

1 participant