nanofractal
High-performance fiducial-marker detection for Python. nanofractal wraps two
compact, header-only C++ detectors with nanobind:
- ArUco Nano v6 — square markers: all standard OpenCV ArUco dictionaries
(4×4, 5×5, 6×6, 7×7) plus
ARUCO_MIP_36h12and AprilTag36h11. - Fractal markers — nested markers that stay detectable under heavy occlusion and expose many inner corner correspondences for accurate, long-range pose.
It is built for speed: zero-copy NumPy ↔ cv::Mat, the GIL is released
during detection, and a parallel batch API scales across cores.
single-frame detect(): ~0.43 ms @ 640×480 ~1.0 ms @ 1280×720 ~3.1 ms @ 1920×1080
detection_scale=0.5: ~4× faster on the threshold/contour stage (corners refined at full res)
batch detect_batch(): ~3.2× throughput on 4 threads
Measured on a desktop CPU with
max_attempts=1; your numbers will vary.
Installation
pip install nanofractal
Wheels are available for x86_64 and aarch64 Linux (manylinux). They bundle a minimal OpenCV, so no system OpenCV is required at runtime.
Build from source
You need a C++17 compiler, CMake ≥ 3.18 and a development OpenCV
(core, imgproc, calib3d, features2d):
# Debian/Ubuntu
sudo apt-get install -y build-essential cmake libopencv-dev
pip install .
Local dev build with CPU tuning
# Enable -march=native + -ffast-math for maximum local performance:
NF_NATIVE=1 pip install -e . --no-build-isolation
Quick start
Inputs are plain NumPy uint8 arrays — either (H, W) grayscale, (H, W, 1)
grayscale, or (H, W, 3) BGR, and C-contiguous (use np.ascontiguousarray
if unsure). Any image loader works; the examples use OpenCV.
Generate ArUco markers
import nanofractal as nf
# Generate a single 4×4 marker (id=7, 200×200 pixels, grayscale uint8)
marker = nf.generate_aruco(marker_id=7, size_px=200,
dictionary=nf.Dict.DICT_4X4_50, border_bits=1)
# Generate the external level of a fractal marker
config = "FRACTAL_5L_6"
fractal = nf.generate_fractal(config, size_px=400) # uint8 grayscale
Detect ArUco markers
import cv2
import nanofractal as nf
image = cv2.imread("scene.png") # (H, W, 3) uint8 BGR
# Standard 4×4 dictionary (50 unique markers)
det = nf.ArucoDetector(nf.Dict.DICT_4X4_50)
# Or the legacy / AprilTag dictionaries:
# det = nf.ArucoDetector(nf.Dict.ARUCO_MIP_36h12)
# det = nf.ArucoDetector(nf.Dict.APRILTAG_36h11)
res = det.detect(image)
print(len(res)) # number of detected markers
print(res.ids) # int32 (N,) e.g. [ 7 42]
print(res.corners) # float32 (N, 4, 2) clockwise corners, subpixel
# Iterate over results
for marker_id, corners in res:
print(f"Marker {marker_id}: {corners}")
Tune detection parameters
params = nf.DetectorParams()
params.min_contour_size = 30 # detect smaller markers (default: 50)
params.adaptive_block_size = 11 # adaptive threshold window (must be odd, ≥3)
params.adaptive_c = 7.0 # threshold constant (default: 7)
params.approx_poly_rate = 0.05 # polygon approx rate (default: 0.05)
det = nf.ArucoDetector(nf.Dict.DICT_5X5_100, params=params)
# Or change params after creation:
det.params.min_contour_size = 80
For high-resolution input with reasonably large markers, detection_scale is the
single biggest speed lever — the dominant cost (adaptiveThreshold + findContours)
is already SIMD-optimized inside OpenCV, so the win comes from feeding it fewer
pixels. Corners are still refined at full resolution, and it works for both
ArucoDetector and FractalDetector:
params = nf.DetectorParams()
params.detection_scale = 0.5 # ~4x faster threshold/contour stage @1080p
det = nf.ArucoDetector(nf.Dict.DICT_4X4_50, params=params)
fdet = nf.FractalDetector("FRACTAL_5L_6", params=params)
FractalDetector also supports all the same parameters plus two extras:
fparams = nf.DetectorParams()
fparams.subpix_win_size = 4 # corner sub-pixel half-window (0 = off)
fparams.kfilter_min_dist = 10.0 # min pixel distance between FAST keypoints
Estimate pose
estimate_pose runs solvePnP (IPPE_SQUARE) for every detected marker at once.
import numpy as np
camera_matrix = np.array([[600, 0, 320],
[0, 600, 240],
[0, 0, 1]], dtype=np.float64)
dist_coeffs = np.zeros(5, dtype=np.float64)
rvecs, tvecs = det.estimate_pose(res.corners, camera_matrix, dist_coeffs,
marker_size=0.05) # marker side in metres
# rvecs, tvecs: float64 (N, 3) — rotation (Rodrigues) and translation per marker
# With reprojection errors per marker
rvecs, tvecs, reproj_errs = det.estimate_pose(
res.corners, camera_matrix, dist_coeffs, marker_size=0.05, return_reproj=True
)
# reproj_errs: float64 (N,) — RMS reprojection error in pixels per marker
Fisheye distortion model
Both detectors support OpenCV's fisheye distortion model:
# Fisheye intrinsics with exactly 4 distortion coefficients (k1, k2, k3, k4)
camera_matrix_fisheye = np.array([[500, 0, 320],
[0, 500, 240],
[0, 0, 1]], dtype=np.float64)
dist_coeffs_fisheye = np.array([0.1, 0.01, -0.001, 0.0005], dtype=np.float64)
rvecs, tvecs = det.estimate_pose(
res.corners, camera_matrix_fisheye, dist_coeffs_fisheye,
marker_size=0.05, fisheye=True
)
Smooth pose over time
smoother = nf.PoseSmoother(process_noise=1e-4, measurement_noise=1e-2)
# In your frame loop:
rvec, tvec = det.estimate_pose(res.corners, K, D, marker_size=0.05)[0]
rvec_smooth, tvec_smooth = smoother.update(rvec, tvec)
Detect fractal markers
fdet = nf.FractalDetector("FRACTAL_5L_6", marker_size=0.85) # size in metres (optional)
res = fdet.detect(image)
print(res.ids, res.corners.shape) # outer 4 corners of each fractal marker
Fractal pose + visualization (occlusion-robust)
FractalDetector.estimate_pose returns one marker pose (rvec, tvec, reproj_err)
or None. It uses every visible inner and outer corner correspondence when
available (accurate, robust to occlusion) and otherwise falls back to the four
outer corners — so you never call solvePnP yourself or worry about the
empty-inner-points case. reproj_err (RMS pixels) lets you gate noisy poses.
fdet = nf.FractalDetector("FRACTAL_5L_6", marker_size=0.85) # size in metres
res = fdet.detect(image, with_inner_points=True)
pose = fdet.estimate_pose(res, camera_matrix, dist_coeffs)
if pose is not None:
rvec, tvec, reproj_err = pose # rvec, tvec: float64 (3,); reproj_err: px
fdet.draw(image, res, camera_matrix, dist_coeffs, rvec, tvec) # corners + axes
draw(image, result, ...) overlays marker outlines, ids and (given a pose) the
frame axes in place — no cv2.polylines/drawFrameAxes boilerplate. Without a
pose, fdet.draw(image, res) just draws the outlines.
The raw correspondences are still exposed if you prefer to run PnP yourself:
res.points_2d # float32 (M, 2) image points (None unless with_inner_points=True)
res.points_3d # float32 (M, 3) object points (planar, z = 0)
Draw ArUco markers with pose
det = nf.ArucoDetector(nf.Dict.DICT_4X4_50)
res = det.detect(image)
rvecs, tvecs = det.estimate_pose(res.corners, K, D, marker_size=0.05)
# Draw outlines + ids + per-marker axes
det.draw(image, res, K, D, rvecs, tvecs, marker_size=0.05, inplace=True)
cv2.imshow("result", image)
Non-destructive drawing
Pass inplace=False to draw on a copy (preserves the original):
result_image = det.draw(image, res, K, D, rvecs, tvecs, inplace=False)
# image remains unchanged; result_image contains the annotated version
Introspect dictionaries
# Grid size (including border cells)
grid_size = nf.dict_grid_size(nf.Dict.DICT_4X4_50) # returns 6
# Number of markers in the dictionary
num_markers = nf.dict_num_markers(nf.Dict.DICT_4X4_50) # returns 50
num_apriltag = nf.dict_num_markers(nf.Dict.APRILTAG_36h11) # returns 587
Region of interest (ROI)
Restrict detection to a sub-rectangle (x, y, w, h) — handy when you roughly know
where the marker is (faster on large frames). Detection runs on a zero-copy view
and corners come back in full-image coordinates.
res = det.detect(image, roi=(x, y, w, h)) # also on detect_batch(..., roi=...)
Refine corners
Subpixel-refine corners (e.g. after a fast first pass or your own candidate search):
res = det.detect(image)
sharp = nf.refine_corners(image, res.corners, win_size=5) # (N, 4, 2) float32
OpenCV interop
Convert results to/from the cv2.aruco (corners, ids) format:
corners, ids = nf.to_opencv(res) # list[(1,4,2) float32], ids (N,1) int32
res2 = nf.from_opencv(corners, ids) # back to a DetectionResult
Benchmark
Run a quick throughput benchmark (stdlib + NumPy only):
python -m nanofractal.bench --resolution 1280x720 --detector aruco --frames 200
# Output: latency, FPS, library versions, CPU architecture
The benchmarks/ directory has deeper scripts (install the [bench]
extra for cv2): compare_opencv.py (head-to-head vs cv2.aruco) and
robustness.py (detection rate + pose error under blur / rotation / perspective /
noise / scale). Runnable usage scripts live in examples/.
Parallel batch (offline throughput)
Process many frames across a thread pool. The GIL is released, so it scales with
cores. num_threads=0 uses all cores.
frames = [cv2.imread(p) for p in paths] # list of uint8 arrays
results = det.detect_batch(frames, num_threads=0) # list[DetectionResult]
for r in results:
print(r.ids)
API
Dict — marker dictionaries
| Name | Markers | Inner bits | Notes |
|---|---|---|---|
DICT_4X4_50 … DICT_4X4_1000 |
50–1000 | 4×4 | fewest bits, fastest matching |
DICT_5X5_50 … DICT_5X5_1000 |
50–1000 | 5×5 | |
DICT_6X6_50 … DICT_6X6_1000 |
50–1000 | 6×6 | |
DICT_7X7_50 … DICT_7X7_1000 |
50–1000 | 7×7 | most bits, best error detection |
ARUCO_MIP_36h12 |
250 | 6×6 | legacy ArUco MIP dictionary |
APRILTAG_36h11 |
587 | 6×6 | AprilTag 36h11 |
All dictionaries are identical to their OpenCV counterparts — markers printed
with cv2.aruco.generateImageMarker are detected directly.
ArucoDetector(dictionary=Dict.ARUCO_MIP_36h12, max_attempts=1, params=None)
dictionary: Dict— anyDictenum value.max_attempts: int— retries per candidate with small corner jitter.1is fastest (real-time default); raise (up to ~10) for harder images.params: DetectorParams | None— tuning parameters (see below).Noneuses defaults..params— read/write access to theDetectorParamsafter creation.detect(image, roi=None) -> DetectionResult—roi=(x, y, w, h)restricts detection to a sub-rectangle; corners are returned in full-image coordinates.detect_batch(images, num_threads=0, roi=None) -> list[DetectionResult]estimate_pose(corners, camera_matrix, dist_coeffs, marker_size, return_reproj=False, fisheye=False) -> (rvecs, tvecs) | (rvecs, tvecs, reproj_errs)—cornersis(N, 4, 2)float32. Whenreturn_reproj=Truereturns(rvecs, tvecs, reproj_errs)where reproj_errs is float64(N,)per-marker RMS error.fisheye=Trueuses OpenCV fisheye model (dist_coeffs must be exactly 4).draw(image, result, camera_matrix=None, dist_coeffs=None, rvecs=None, tvecs=None, marker_size=None, axis_length=None, inplace=True) -> image— draw outlines + ids; with poses, also draw frame axes per marker.inplace=True(default) modifies and returns the input;inplace=Falsereturns a copy (accepts read-only input).
FractalDetector(config, marker_size=-1.0, params=None)
config: str— one ofFRACTAL_2L_6,FRACTAL_3L_6,FRACTAL_4L_6,FRACTAL_5L_6.marker_size: float— outer marker side in metres; if set,points_3dis returned in metres (otherwise normalized).params: DetectorParams | None— tuning parameters.Noneuses defaults..params— read/write access to theDetectorParamsafter creation.detect(image, with_inner_points=False, roi=None) -> DetectionResult—roi=(x, y, w, h)restricts detection to a sub-rectangle (corners returned in full-image coordinates).detect_batch(images, num_threads=0, roi=None) -> list[DetectionResult]estimate_pose(result, camera_matrix, dist_coeffs, fisheye=False) -> (rvec, tvec, reproj_err) | None— single-marker pose; uses inner+outer points when ≥ 4, else the 4 outer corners;rvec/tvecare float64(3,),reproj_erris RMS pixels.fisheye=Trueuses OpenCV fisheye model (dist_coeffs must be exactly 4).draw(image, result, camera_matrix=None, dist_coeffs=None, rvec=None, tvec=None, axis_length=None, inplace=True) -> image— draw outlines + ids (and frame axes when a pose is given).inplace=True(default) modifies and returns the input;inplace=Falsereturns a copy.
DetectorParams
Shared by both detectors. All fields are optional — defaults reproduce the original hard-coded behaviour so existing code needs no changes.
| Field | Default | Description |
|---|---|---|
min_contour_size |
-1 (auto) |
Minimum contour perimeter in pixels. ArUco default: 50, Fractal: 120. |
adaptive_block_size |
-1 (auto) |
Adaptive threshold block size (odd, ≥ 3). ArUco default: 13; Fractal: scales with image width. |
adaptive_c |
7.0 |
Constant subtracted from the local threshold mean. |
approx_poly_rate |
0.05 |
Polygon approximation: epsilon = perimeter × rate. |
subpix_win_size |
-1 (auto=4) |
Corner sub-pixel half-window (Fractal only); 0 to disable. |
kfilter_min_dist |
10.0 |
Minimum distance (px) between FAST keypoints (Fractal only). |
detection_scale |
1.0 |
Downscale factor for the detection stage (both detectors). 0.5 runs threshold/contour/decode on ¼ the pixels (≈ 4× faster); corners are mapped back and sub-pixel refined at full resolution. min_contour_size stays in original-image pixels. |
DetectionResult
| field | dtype / shape | meaning |
|---|---|---|
ids |
int32 (N,) |
marker ids |
corners |
float32 (N, 4, 2) |
outer corners (subpixel, clockwise) |
points_2d |
float32 (M, 2) or None |
inner+outer image points (fractal, with_inner_points=True) |
points_3d |
float32 (M, 3) or None |
matching object points |
Ergonomics:
len(result)— number of markers.bool(result)—Trueif any markers detected.for mid, corners in result:— iterate over(marker_id, corners_array)pairs.repr(result)— concise summary including marker count and ids.
Empty results are returned as correctly-shaped empty arrays ((0,), (0, 4, 2)),
never None.
Module-level functions
| Function | Returns | Purpose |
|---|---|---|
generate_aruco(marker_id, size_px=200, dictionary=Dict.DICT_4X4_50, border_bits=1) |
uint8 (size_px, size_px) |
Generate an ArUco marker image. |
generate_fractal(config, size_px=400) |
uint8 (size_px, size_px) |
Generate the external level of a fractal marker. |
dict_grid_size(d: Dict) |
int |
Full grid size (including border) for a dictionary. |
dict_num_markers(d: Dict) |
int |
Number of markers in a dictionary. |
refine_corners(image, corners, win_size=5) |
float32 (N, 4, 2) |
Subpixel-refine corners (cornerSubPix). |
to_opencv(result) |
(list[(1,4,2) float32], ids (N,1) int32) |
Convert to the cv2.aruco format. |
from_opencv(corners, ids) |
DetectionResult |
Build a result from cv2.aruco output. |
Note on generate_fractal: Returns only the outermost marker level, which is
detectable by FractalDetector. It is not a full multi-level nested composite.
PoseSmoother
Temporal smoothing of 6-DOF pose using Kalman filtering or exponential moving average.
smoother = nf.PoseSmoother(process_noise=1e-4, measurement_noise=1e-2, mode="kalman")
# Per frame:
rvec, tvec = smoother.update(rvec_measured, tvec_measured)
# Reset state (e.g. on marker loss):
smoother.reset()
mode="kalman"— Kalman filter (default).mode="ema"— Exponential moving average.- Rvec is smoothed component-wise (suitable for small inter-frame rotation changes).
Errors
- Wrong dtype / non-contiguous input →
TypeError. - Unsupported shape, empty frame, invalid dictionary or fractal config →
ValueError. - Invalid camera intrinsics or distortion →
ValueErrorwith clear message.
Performance notes
- Zero-copy input. A contiguous
uint8array is wrapped as acv::Matover the same buffer — no copy. Non-contiguous or wrong-dtype inputs raise instead of silently copying. - GIL released during the native detection, so other Python threads keep
running and
detect_batchscales. - Thread safety. The ArUco detector is stateless and shared across batch
workers. The fractal detector is not thread-safe, so
detect_batchuses a pool of independent detectors (one per worker). A single detector object is fine to call from one thread at a time.
Changelog
See CHANGELOG.md for the full version history.
Latest (0.4):
- ROI detection (
detect(image, roi=(x, y, w, h))). refine_corners,to_opencv/from_opencvconverters.examples/scripts andbenchmarks/(vscv2.aruco+ robustness sweeps).- Coverage + ASan/UBSan CI; faster releases (cached OpenCV, parallel per-arch wheels).
Earlier (0.3): marker generation, ArucoDetector.draw(), per-marker reprojection
errors + fisheye, PoseSmoother, dictionary introspection, benchmark CLI, aarch64 wheels.
Citation
If you use this in research, please cite the original work:
- F. J. Romero-Ramirez, R. Muñoz-Salinas, R. Medina-Carnicer, "Speeded up detection of squared fiducial markers", Image and Vision Computing, 76, 2018.
- S. Garrido-Jurado, R. Muñoz-Salinas, F. J. Madrid-Cuevas, R. Medina-Carnicer, "Generation of fiducial marker dictionaries using mixed integer linear programming", Pattern Recognition, 51, 2016.
- F. J. Romero-Ramirez, R. Muñoz-Salinas, R. Medina-Carnicer, "Fractal Markers: A New Approach for Long-Range Marker Pose Estimation Under Occlusion", IEEE Access, 7, 2019.
License
Apache-2.0. The vendored detectors (ArUco Nano, Fractal markers) are © their
authors and used under their terms; see third_party/ and PATCHES.md.
Release files for nanofractal 0.4.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| nanofractal-0.4.0.tar.gz | 138.7 kB | Details |
Built distributions (wheels)
Total release size: 27.5 MB
Release files / nanofractal-0.4.0.tar.gz
| Download URL | nanofractal-0.4.0.tar.gz |
|---|---|
| Size | 138.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
e0f46f8f18b9a951ae6b62fc481ffaba3e9a5004da1c430372328ce8304e6506
|
|
BLAKE2b-256 checksum How to use checksums |
12f00d0048c3d1bdb3a772c248cffa5645728e27dd003c46cb1a46d734f88aaa
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Release files / nanofractal-0.4.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
| Download URL | nanofractal-0.4.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl |
|---|---|
| Size | 3.1 MB |
| Tags | CPython 3.13 Linux glibc 2.27+ x86-64 Linux glibc 2.28+ x86-64 |
|
SHA-256 checksum How to use checksums |
a725a9cf1852554ec4016b1e7a341eb3efdf2a783f14bf7ebfe19f8ca08d27be
|
|
BLAKE2b-256 checksum How to use checksums |
c1849588a9c9004c17186a4e06e917b98accb36f7963c3bdb4479eb9d99425d1
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Release files / nanofractal-0.4.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl
| Download URL | nanofractal-0.4.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl |
|---|---|
| Size | 2.4 MB |
| Tags | CPython 3.13 Linux glibc 2.27+ ARM64 Linux glibc 2.28+ ARM64 |
|
SHA-256 checksum How to use checksums |
881643470f709707f44f875fa32613779478085191350f72b2a39c4c1703c66b
|
|
BLAKE2b-256 checksum How to use checksums |
2a3215d828699eab242a460a5d52be195ca7f4adce73bbcfe06178b38387207e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Release files / nanofractal-0.4.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
| Download URL | nanofractal-0.4.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl |
|---|---|
| Size | 3.1 MB |
| Tags | CPython 3.12 Linux glibc 2.27+ x86-64 Linux glibc 2.28+ x86-64 |
|
SHA-256 checksum How to use checksums |
a8bcc35cd18ba22b781704772c7be4360ae84f7a008a870d237563f6d322ee49
|
|
BLAKE2b-256 checksum How to use checksums |
f4437c78c90050c6233d74a4d20a96e0b7735e5285972df1676fc146bc418338
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Release files / nanofractal-0.4.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl
| Download URL | nanofractal-0.4.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl |
|---|---|
| Size | 2.4 MB |
| Tags | CPython 3.12 Linux glibc 2.27+ ARM64 Linux glibc 2.28+ ARM64 |
|
SHA-256 checksum How to use checksums |
2310da6f4dc27e488bdaa0590fa651e27fd2392f3c30976efa48f1d42ac6bec4
|
|
BLAKE2b-256 checksum How to use checksums |
931f89672578dcbaf6eccf15b7c1096a37b3c7f9ca2f809e3bf65c985c319784
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Release files / nanofractal-0.4.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
| Download URL | nanofractal-0.4.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl |
|---|---|
| Size | 3.1 MB |
| Tags | CPython 3.11 Linux glibc 2.27+ x86-64 Linux glibc 2.28+ x86-64 |
|
SHA-256 checksum How to use checksums |
e1af93c6445ffb8713633b9649fb2dffd0edb3cfa74303e08489d9e97b16f649
|
|
BLAKE2b-256 checksum How to use checksums |
af856fe8ebd0a37162012383416d87d3e34f86ef4ea510cd8ea7673dbd19eb62
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Release files / nanofractal-0.4.0-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl
| Download URL | nanofractal-0.4.0-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl |
|---|---|
| Size | 2.4 MB |
| Tags | CPython 3.11 Linux glibc 2.27+ ARM64 Linux glibc 2.28+ ARM64 |
|
SHA-256 checksum How to use checksums |
2704c40afd4591d31e4e820190717f32e8948bf6d11332eaf172a47d576b4626
|
|
BLAKE2b-256 checksum How to use checksums |
0672e9ee57f3a84088ccf254a95684e7700adc5230d00fcf3aa84dad874a2426
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Release files / nanofractal-0.4.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
| Download URL | nanofractal-0.4.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl |
|---|---|
| Size | 3.1 MB |
| Tags | CPython 3.10 Linux glibc 2.27+ x86-64 Linux glibc 2.28+ x86-64 |
|
SHA-256 checksum How to use checksums |
ae14e83977db6f59875d2985726ce69b366e342f8305c270662a965bdb2b54d3
|
|
BLAKE2b-256 checksum How to use checksums |
5b1d0dd0641721950080df62922541c1f36d547e39008da0d152db603942b6f6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Release files / nanofractal-0.4.0-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl
| Download URL | nanofractal-0.4.0-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl |
|---|---|
| Size | 2.4 MB |
| Tags | CPython 3.10 Linux glibc 2.27+ ARM64 Linux glibc 2.28+ ARM64 |
|
SHA-256 checksum How to use checksums |
611bfee041d094a8ff74171cdea042807d15999a1d52c334a2d6331c3bebe6a5
|
|
BLAKE2b-256 checksum How to use checksums |
a1c68b58e4cb050f37e087301a64927c2d8e642486d27994ba047cecbc19b6a3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Release files / nanofractal-0.4.0-cp39-cp39-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
| Download URL | nanofractal-0.4.0-cp39-cp39-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl |
|---|---|
| Size | 3.1 MB |
| Tags | CPython 3.9 Linux glibc 2.27+ x86-64 Linux glibc 2.28+ x86-64 |
|
SHA-256 checksum How to use checksums |
3b4e298779d35a83c3edd5fbec1640104437b00b418ef85b33eeb3cb2eed74e9
|
|
BLAKE2b-256 checksum How to use checksums |
cdaa36df064d050c85d5a00e2c5115828745ae37488e30b8600f0ae11df1ae95
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Release files / nanofractal-0.4.0-cp39-cp39-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl
| Download URL | nanofractal-0.4.0-cp39-cp39-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl |
|---|---|
| Size | 2.4 MB |
| Tags | CPython 3.9 Linux glibc 2.27+ ARM64 Linux glibc 2.28+ ARM64 |
|
SHA-256 checksum How to use checksums |
d90ee4fc784a252b4163a7959f4f711b8710ab5556c97eb112e6ec3433f6d9fc
|
|
BLAKE2b-256 checksum How to use checksums |
e31ce1d2eea179b5ea9db9c5b6f94dd38209233173ffbe54bee31bae565babe1
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|