Skip to content

Commit d0d7dbb

Browse files
author
10x Genomics
committed
feat: Space Ranger 3.1.1
0 parents  commit d0d7dbb

26 files changed

+6182
-0
lines changed

Cargo.lock

+2,642
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
[workspace]
2+
members = [
3+
"fiducial",
4+
"image-transform"
5+
]

LICENSE.txt

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
Copyright (c) 2023 10x Genomics
2+
3+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to use, copy, modify, and/or merge copies of the Software, in both source code and object code format, solely for your internal use, subject to the following conditions:
4+
5+
1. The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6+
7+
2. The above rights granted in the Software may be exercised only in connection with a 10x Genomics Product (defined below), rightfully purchased from 10x Genomics or an authorized reseller, or data generated using such a 10x Genomics Product. A “10X Genomics Product” means, collectively, 10x Genomics branded instruments, reagents, consumables, kits, and labware used in accordance with the 10X Genomics Product Terms and Conditions of Sale or, if applicable, any written contract between you and 10x Genomics. The rights granted may also be exercised in connection with other products when doing so is an integral part of an experiment where the data is generated primarily using a 10x Genomics Product.
8+
9+
3. You agree not to redistribute or sublicense the Software, either in source code or object code format.
10+
11+
4. All derivative works, including any modifications of the Software, shall be subject to all of the restrictions set forth herein.
12+
13+
5. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE, THE USE OR INABILITY TO USE, OR OTHER DEALINGS IN THE SOFTWARE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
14+
15+
You may not use, propagate or modify the Software, or any derivatives thereof, except as expressly provided herein. Any attempt otherwise to use, propagate or modify it is void, and will automatically terminate your rights under this license.

README.md

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# Image Analysis
2+
3+
[![Test](https://github.com/10XDev/rust-template/actions/workflows/test.yaml/badge.svg)](https://github.com/10XDev/rust-template/actions/workflows/test.yaml)
4+
5+
This repository holds rust implementations of image analysis algorithms used in Spaceranger.
6+
Currently, this includes implementations of Visium HD fiducial detection and basic image transformations.
7+
8+
## Fiducial Detection and Registration
9+
Fiducial code for Visium HD. Contains the fiducial detection, decoding and registration algorithms used in Spaceranger.
10+
An outline of the fiducial detection algorithm is described [here][].
11+
12+
[here]: https://www.cv-foundation.org/openaccess/content_cvpr_2016/papers/Calvet_Detection_and_Accurate_CVPR_2016_paper.pdf

deny.toml

+175
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
# If 1 or more target triples (and optionally, target_features) are specified,
2+
# only the specified targets will be checked when running `cargo deny check`.
3+
# This means, if a particular package is only ever used as a target specific
4+
# dependency, such as, for example, the `nix` crate only being used via the
5+
# `target_family = "unix"` configuration, that only having windows targets in
6+
# this list would mean the nix crate, as well as any of its exclusive
7+
# dependencies not shared by any other crates, would be ignored, as the target
8+
# list here is effectively saying which targets you are building for.
9+
targets = [
10+
{ triple = "x86_64-unknown-linux-gnu" },
11+
]
12+
13+
# This section is considered when running `cargo deny check advisories`
14+
# More documentation for the advisories section can be found here:
15+
# https://embarkstudios.github.io/cargo-deny/checks/advisories/cfg.html
16+
[advisories]
17+
# The path where the advisory database is cloned/fetched into
18+
# db-path = "~/.cargo/advisory-db"
19+
# The url(s) of the advisory databases to use
20+
db-urls = ["https://github.com/rustsec/advisory-db"]
21+
# The lint level for security vulnerabilities
22+
vulnerability = "deny"
23+
# The lint level for unmaintained crates
24+
unmaintained = "warn"
25+
# The lint level for crates that have been yanked from their source registry
26+
yanked = "warn"
27+
# The lint level for crates with security notices. Note that as of
28+
# 2019-12-17 there are no security notice advisories in
29+
# https://github.com/rustsec/advisory-db
30+
notice = "warn"
31+
# A list of advisory IDs to ignore. Note that ignored advisories will still
32+
# output a note when they are encountered.
33+
ignore = [
34+
]
35+
36+
# This section is considered when running `cargo deny check licenses`
37+
# More documentation for the licenses section can be found here:
38+
# https://embarkstudios.github.io/cargo-deny/checks/licenses/cfg.html
39+
[licenses]
40+
# The lint level for crates which do not have a detectable license
41+
unlicensed = "deny"
42+
# Allow us to keep a consistent list across projects without needing
43+
# to customize deny.toml based on what's actually present.
44+
unused-allowed-license = "allow"
45+
# List of explictly allowed licenses
46+
# See https://spdx.org/licenses/ for list of possible licenses
47+
# [possible values: any SPDX 3.11 short identifier (+ optional exception)].
48+
allow = [
49+
"0BSD",
50+
"Apache-2.0",
51+
"Apache-2.0 WITH LLVM-exception",
52+
"BSD-2-Clause",
53+
"BSD-3-Clause",
54+
"ISC",
55+
"MIT",
56+
"MIT-0",
57+
"MPL-2.0",
58+
"OpenSSL",
59+
"Unicode-DFS-2016",
60+
"WTFPL",
61+
]
62+
# List of explictly disallowed licenses
63+
# See https://spdx.org/licenses/ for list of possible licenses
64+
# [possible values: any SPDX 3.11 short identifier (+ optional exception)].
65+
deny = [
66+
#"Nokia",
67+
]
68+
# Lint level for licenses considered copyleft
69+
copyleft = "deny"
70+
# Blanket approval or denial for OSI-approved or FSF Free/Libre licenses
71+
# * both - The license will be approved if it is both OSI-approved *AND* FSF
72+
# * either - The license will be approved if it is either OSI-approved *OR* FSF
73+
# * osi-only - The license will be approved if is OSI-approved *AND NOT* FSF
74+
# * fsf-only - The license will be approved if is FSF *AND NOT* OSI-approved
75+
# * neither - This predicate is ignored and the default lint level is used
76+
allow-osi-fsf-free = "neither"
77+
# Lint level used when no other predicates are matched
78+
# 1. License isn't in the allow or deny lists
79+
# 2. License isn't copyleft
80+
# 3. License isn't OSI/FSF, or allow-osi-fsf-free = "neither"
81+
default = "deny"
82+
# The confidence threshold for detecting a license from license text.
83+
# The higher the value, the more closely the license text must be to the
84+
# canonical license text of a valid SPDX license file.
85+
# [possible values: any between 0.0 and 1.0].
86+
confidence-threshold = 0.6
87+
88+
[licenses.private]
89+
# If true, ignores workspace crates that aren't published, or are only
90+
# published to private registries
91+
ignore = true
92+
# One or more private registries that you might publish crates to, if a crate
93+
# is only published to private registries, and ignore is true, the crate will
94+
# not have its license(s) checked
95+
registries = [
96+
#"https://sekretz.com/registry
97+
]
98+
99+
[[licenses.exceptions]]
100+
name = "intel-mkl-src"
101+
allow = ["LicenseRef-Intel-SmpL"]
102+
103+
# Some crates don't have (easily) machine readable licensing information,
104+
# adding a clarification entry for it allows you to manually specify the
105+
# licensing information
106+
[[licenses.clarify]]
107+
name = "intel-mkl-src"
108+
expression = "LicenseRef-Intel-SmpL"
109+
110+
[[licenses.clarify.license-files]]
111+
path = "../License.txt"
112+
hash = 0x3bf8c2d0
113+
114+
# This section is considered when running `cargo deny check bans`.
115+
# More documentation about the 'bans' section can be found here:
116+
# https://embarkstudios.github.io/cargo-deny/checks/bans/cfg.html
117+
[bans]
118+
# Lint level for when multiple versions of the same crate are detected
119+
multiple-versions = "deny"
120+
# Lint level for when a crate version requirement is `*`
121+
wildcards = "allow"
122+
# The graph highlighting used when creating dotgraphs for crates
123+
# with multiple versions
124+
# * lowest-version - The path to the lowest versioned duplicate is highlighted
125+
# * simplest-path - The path to the version with the fewest edges is highlighted
126+
# * all - Both lowest-version and simplest-path are used
127+
highlight = "all"
128+
# List of crates that are allowed. Use with care!
129+
130+
[[bans.skip]]
131+
# so many things still on syn 1
132+
name = "syn"
133+
version = "1.0.109"
134+
135+
[[bans.skip]]
136+
# remove after updating ndarray-stats
137+
name = "indexmap"
138+
version = "1.9.3"
139+
140+
[[bans.skip]]
141+
# remove after updating ndarray-stats
142+
name = "hashbrown"
143+
version = "0.12.3"
144+
145+
[[bans.skip]]
146+
# remove after updating ndarray
147+
name = "approx"
148+
version = "0.4.0"
149+
150+
[[bans.skip]]
151+
# remove after updating ndarray-stats
152+
name = "itertools"
153+
version = "0.10.5"
154+
155+
[[bans.skip]]
156+
name = "bitflags"
157+
version = "1.3.2"
158+
159+
# This section is considered when running `cargo deny check sources`.
160+
# More documentation about the 'sources' section can be found here:
161+
# https://embarkstudios.github.io/cargo-deny/checks/sources/cfg.html
162+
[sources]
163+
# Lint level for what to happen when a crate from a crate registry that is not
164+
# in the allow list is encountered
165+
unknown-registry = "deny"
166+
# Lint level for what to happen when a crate from a git repository that is not
167+
# in the allow list is encountered
168+
unknown-git = "deny"
169+
# List of URLs for allowed crate registries. Defaults to the crates.io index
170+
# if not specified. If it is specified but empty, no registries are allowed.
171+
allow-registry = ["https://github.com/rust-lang/crates.io-index"]
172+
173+
[sources.allow-org]
174+
# 1 or more github.com organizations to allow git sources for
175+
github = ["10XGenomics"]

fiducial/Cargo.toml

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
[package]
2+
name = "fiducial"
3+
version = "0.1.0"
4+
authors = ["Chaitanya Aluru <chaitanya.aluru@10xgenomics.com>"]
5+
edition = "2018"
6+
license = "LicRef-10XGenomics"
7+
license-file = "../LICENSE.txt"
8+
include = ["src/**/*.rs", "Cargo.toml"]
9+
publish = false
10+
11+
[lib]
12+
name = "fiducial"
13+
14+
[dependencies]
15+
image = { version = "0.25", default-features = false, features = ["tiff"] }
16+
itertools = ">=0.10.0"
17+
kd-tree = "0.6.0"
18+
ndarray = { version = "0.15.3", features = ["approx", "blas", "serde-1"] }
19+
ndarray-npy = { version = "*", default-features = false }
20+
ndarray-linalg = "0.16.0"
21+
assert_approx_eq = "1.1.0"
22+
ndarray-stats = "0.5.0"
23+
rand = "0.8.4"
24+
slog = "2.7.0"
25+
slog-term = "2"
26+
slog-async = "2.7.0"
27+
28+
[dev-dependencies]
29+
clap = {version = "4.5.16", features = ["derive"]}
30+
31+
[target.'cfg(target_os = "macos")'.dependencies]
32+
accelerate-src = "0.3.2"
33+
34+
[target.'cfg(not(target_os = "macos"))'.dependencies]
35+
intel-mkl-src = { git = "https://github.com/10XGenomics/intel-mkl-src", branch = "master", features = [
36+
"mkl-static-lp64-seq",
37+
] }
+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
//Perform Fiducial Detection and Decoding on an input image
2+
3+
use clap::Parser;
4+
use fiducial::{
5+
fiducial_detector::{detect_fiducial, FidDetectionParameter},
6+
utils::ImageUtil,
7+
};
8+
9+
#[derive(Parser)]
10+
#[command(version, about, long_about = None)]
11+
struct Args {
12+
//path to RGB TIFF file
13+
#[arg(short, long)]
14+
image_path: String,
15+
}
16+
17+
fn main() {
18+
//read input image
19+
let args = Args::parse();
20+
let full_image = ImageUtil::read_r_channel(&args.image_path);
21+
let param = FidDetectionParameter::new_visium_hd_param();
22+
let (detected_names, detected_centers): (Vec<_>, Vec<_>) =
23+
detect_fiducial(&full_image, &param, &None)
24+
.iter()
25+
.cloned()
26+
.unzip();
27+
detected_names
28+
.iter()
29+
.zip(detected_centers)
30+
.for_each(|(name, center)| println!("{}: {:?}", name, center));
31+
}
+68
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
//Perform fiducial detection and registration between an input image and
2+
//the Visium HD design
3+
4+
use std::{
5+
fs::File,
6+
io::{BufRead, BufReader},
7+
};
8+
9+
use clap::Parser;
10+
use fiducial::utils::ImageUtil;
11+
use fiducial::{
12+
fiducial_detector::{detect_fiducial, FidDetectionParameter},
13+
fiducial_registration::{
14+
fiducial_refinement_and_perspective_transform_isolation, fiducial_registration, Coord,
15+
FiducialFrame, FiducialPoint,
16+
},
17+
};
18+
19+
#[derive(Parser)]
20+
#[command(version, about, long_about = None)]
21+
struct Args {
22+
//path to RGB TIFF file
23+
#[arg(short, long)]
24+
image_path: String,
25+
}
26+
27+
fn main() {
28+
//read design
29+
let path = "testing_data/design.txt";
30+
let file = File::open(path).expect("could not read design file");
31+
let buf = BufReader::new(file);
32+
let temp: Vec<FiducialPoint> = buf.lines().map(|x| x.unwrap().parse().unwrap()).collect();
33+
let mut design = FiducialFrame::new(temp);
34+
35+
//run fiducial detection
36+
let args = Args::parse();
37+
let full_image = ImageUtil::read_r_channel(&args.image_path);
38+
let param = FidDetectionParameter::new_visium_hd_param();
39+
let (detected_names, detected_centers): (Vec<_>, Vec<_>) =
40+
detect_fiducial(&full_image, &param, &None)
41+
.iter()
42+
.cloned()
43+
.unzip();
44+
45+
let detected_centers: Vec<_> = detected_centers
46+
.iter()
47+
.map(|x| Coord(x[0] as f64, x[1] as f64))
48+
.collect();
49+
let mut detected_frame = FiducialFrame::from_points(&detected_names, &detected_centers);
50+
51+
let homography = fiducial_registration(&mut detected_frame, &mut design)
52+
.expect("could not compute homography")
53+
.0;
54+
55+
println!("Computed Homography:\n{:?}", homography);
56+
57+
let refinement_with_perspective_transform =
58+
fiducial_refinement_and_perspective_transform_isolation(
59+
&args.image_path,
60+
&homography,
61+
&mut design,
62+
)
63+
.unwrap();
64+
println!(
65+
"Refinement with perspective transform isolation output:\n{:?}\n{:?}",
66+
refinement_with_perspective_transform.0, refinement_with_perspective_transform.1
67+
);
68+
}

0 commit comments

Comments
 (0)