sinogram_center_of_rotation — TOMOGRAPHY geometry op

데이터 종류: sinogrammeasurement

호출: import tomography; tomography.sinogram_center_of_rotation(sinogram, angles_deg=None, min_condition=0.02)(또는 opstomography.get("sinogram_center_of_rotation"))

사용법

회전축이 실제로 어디에 있는가(중심에서 검출기 빈 몇 개).

> 아래 상세 설명은 원문입니다 —— 요약과 제목은 번역되어 있습니다.

The centre-of-mass identity, which is exact and needs no reconstruction: the

first moment of a projection is the projection of the object's centre of

mass, so::

s_cm(theta) = x0 cos(theta) + y0 sin(theta) + c

with `(x0, y0) the centre of mass in the slice and c` the offset of the

rotation axis from the detector centre. Fitting the three unknowns by least

squares over all views gives *c* directly. Measured on the Shepp-Logan

phantom with 180 views, recovering a deliberately introduced shift, together

with the cost of not correcting it (normalised RMS error of the FBP

reconstruction against the truth):

true shift estimated error uncorrected after this fix

0.00 px +0.0029 px 0.0029 0.0250 0.0249

0.50 px +0.5029 px 0.0029 0.0537 0.0358

1.00 px +1.0029 px 0.0029 0.1016 0.0249

2.00 px +2.0029 px 0.0029 0.1630 0.0249

Three things in that table are worth reading twice. **Half a pixel already

doubles the error** (0.0250 -> 0.0537) and does not look like a mistake — it

looks like a slightly soft reconstruction, which is why this is a measurement

and not an inspection. The estimator's own bias is a constant 0.0029 px

across every shift, so it is a property of the phantom and the detector

sampling, not of the size of the error being measured. And the half-pixel row

is the only one the fix does not fully repair (0.0358 against 0.0249),

because correcting a *fractional* shift means resampling, and the linear

interpolation costs more than the integer shifts do — see

:func:sinogram_center_shift.

Two things this needs, both refused rather than assumed. The object must be

entirely inside the field of view — the identity is about the whole mass,

and a truncated object has a different mass at every angle. And the views must

span enough angle for `[cos, sin, 1]` to be independent: over a narrow

wedge, `cos(theta)` and the constant are nearly the same vector and the fit

puts the object's own offset into *c*. The condition number is checked and a

degenerate design is refused.

:param sinogram: `(n_angles, n_detectors)`, rows = angles.

:param angles_deg: view angles; `None -> uniform [0, 180)`.

:param min_condition: smallest acceptable reciprocal condition number of the

`[cos, sin, 1]` design matrix. The default of 0.02 is calibrated,

not chosen — the reciprocal condition number and the error it lets

through, on a sinogram with a true 1.00-px shift:

span rcond estimate error

180 deg 2.15e-01 +0.9939 0.0061 px

120 deg 8.92e-02 +0.9900 0.0100 px

90 deg 4.85e-02 +0.9485 0.0515 px

60 deg 2.09e-02 +0.8993 0.1007 px <- the default admits this

45 deg 1.17e-02 +0.7041 0.2959 px <- and refuses this

20 deg 2.26e-03 +1.7113 0.7113 px

10 deg 5.54e-04 -6.9765 7.9765 px

The 10-degree row is why the check exists at all: the answer is finite,

the sign is wrong, and the magnitude is eight pixels on a one-pixel

error. Nothing about it looks like a failure.

:returns: `float` — the axis offset in detector bins, positive towards

higher bin indices.

:raises ValueError: on a sinogram whose total mass is zero, on fewer than 3

views, or on an angular span too narrow to separate the offset from the

object's own position.

참고(샘플 데이터·문헌)

• 샘플 데이터 카탈로그(DL URL / 라이선스) —— 2-D 는 skimage.data(BSD/public)+ 합성, 3-D 는 실데이터 소스(Stanford/PDS 등)의 DL URL.

• 연산자의 내력·참고문헌 —— 이 연산자 족의 바탕이 된 연구/기법의 출처.

• 알고리즘의 정전(저자·연도)과 용도는 위의 패밀리 사용 가이드에 적혀 있습니다.

실행 가능한 예제(이 연산자를 실제로 호출하는 검증된 샘플)

ct_reconstructionpy -3.11 examples/ct_reconstruction.py

타입이 이어지는 다음 연산자(measurement 를 입력으로 받는 것)

같은 카테고리(geometry)

sinogram_center_shift


*Provenance: tomography.py — TOMOGRAPHY 연산자 레지스트리. 이 op 노트는 tools/opdocs.py md 가 자동 생성합니다(직접 편집하지 마세요).*

© 2026 Kazufumi Furuse — Fullseye operator documentation. Licensed under Apache-2.0.