Hacktoberfest 2026:维护者为十月标记出来的 issue,仍然开放、适合新手。 浏览 Hacktoberfest issue

AI-generated: macsima() uses the OME plane positions as pixel padding widths, truncated

未关闭
#419 1 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看

还没有人认领这个 Issue。

评估

难度
4/5
预计耗时
3-5 天
新手友好度
45/100
Issue 类型
缺陷
描述清晰度
基本清楚
活跃度
活跃
技术栈
python
领域
data

调研方向

从 src/spatialdata_io/readers/macsima.py 中的 _get_translations() 开始,然后阅读 MultiChannelImage._pad_images() 和 test_get_translations_returns_correct_values;检查 readers/_utils/_utils.py 中现有的物理尺寸查找逻辑。向维护者确认,或根据真实的 MACSima 数据确认平面位置是像素偏移还是物理长度,然后添加一个回归测试或基于数据的测试,覆盖所选解释以及舍入后的 padding 行为。

由索引模型根据 Issue 内容生成。

描述

[!NOTE]
AI-generated issue, opened from #418 and not verified against real MACSima data. The
code pointers are accurate; the question at the end needs someone who knows what the
MACSima software writes into these fields.

What the code does

_get_translations() reads the position of the first plane of the OME metadata and turns it
into an integer — src/spatialdata_io/readers/macsima.py:

translations = {"translation_x": int(position_x), "translation_y": int(position_y)}

The values end up on ChannelMetadata.translation_x / translation_y and are consumed by
MultiChannelImage._pad_images(), which normalises them against their minimum and uses the
result directly as da.pad widths, i.e. as a number of pixels:

normalized_translations_x = [metadata.translation_x - min_translation_x for metadata in channel_metadata]
...
pad_width = ((0, 0), (pad_y_prepend, pad_y_append), (pad_x_prepend, pad_x_append))
img = da.pad(img, pad_width, mode="constant", constant_values=0)
Two things look off

1. int() truncates towards zero instead of rounding. int(0.9) == 0 and
int(-0.9) == 0, so a plane at x = 10.7 is placed at 10 and the direction of the error
depends on the sign of the position. After the normalisation against the minimum the residual
is below one pixel per channel, so this alone is minor — round() would halve the worst case
and make it sign-symmetric.

2. The positions are physical coordinates, but they are used as pixel counts. In OME,
Plane.position_x comes with a Plane.position_x_unit, and Pixels.physical_size_x gives the
size of a pixel in the same kind of unit (17.0 µm in the OMAP test data). Nothing in the
reader converts between the two, so if a MACSima file writes stage positions in micrometres the
padding is off by the pixel size — a factor of 17 for these datasets — rather than by a fraction
of a pixel. If instead the software writes pixel offsets there (position_x_unit is
REFERENCEFRAME, the OME default, i.e. unspecified, in the files I looked at), the current code
is right and only point 1 applies.

Both small test datasets (OMAP10_small, OMAP23_small) have position_x = None on every
plane, so _get_translations() returns (0, 0) there and this path is exercised by unit tests
only, never by the data-based ones.

What a fix would entail

Depending on the answer to "what unit does MACSima write":

  • if the positions are already in pixels: replace int(...) with round(...) in
    _get_translations() and extend test_get_translations_returns_correct_values with a
    fractional case (e.g. position_x=10.7, position_y=0.9 → {"translation_x": 11, "translation_y": 1});
  • if they are physical lengths: read position_x_unit / position_y_unit and
    Pixels.physical_size_x / physical_size_y alongside the positions, convert to pixels
    (ome_types exposes the unit enums; parse_physical_size() in
    readers/_utils/_utils.py already does this kind of lookup for the physical size), and round
    at the end. _get_translations() currently only receives the OME object, which is enough for
    both. ChannelMetadata.translation_x stays an int, so _pad_images() is unaffected.
  • either way, it would be good to have a data-based test: none of the datasets currently in CI
    has plane positions, so this would need either a file with real positions or a synthetic TIFF
    written with tifffile.imwrite(..., metadata={...}) in the style of
    test_images_with_invalid_ome_metadata_are_excluded.
Context

#418 originally rounded the positions as part of fixing the regressions from #411, but that
changes reader output on a point nobody has confirmed, so it was pulled out of the PR and filed
here instead. The current behaviour on main is unchanged: truncation.

主要语言
Python
星标
103
派生
65
平均合并
1 小时 8 分钟
30 天内合并 PR
3

环境准备

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

scverse/spatialdata-io 的其他 Issue

查看 scverse/spatialdata-io 的全部 Issue

相似的 Issue

更多 Python Issue

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。