Skip to main content

NBIS-rs

This is a Rust/Python binding to the NIST Biometric Image Software (NBIS) library, which is used for processing biometric images, particularly in the context of fingerprint recognition.

For convenience, this library also binds to the NIST Fingerprint Image Quality (NFIQ) version 2.

Features

  • Bindings to NBIS functions for minutia extraction, matching
  • Exports minutiae templates in ISO/IEC 19794-2:2011 format (loads 2005 templates too)
  • Matches minutiae templates against each other using the NBIS Bozorth3 algorithm
  • Provides support for NFIQ2 quality assessment

Building from source

Native dependencies (OpenCV 4.13, Rust 1.95 / edition 2024, CMake, C++ toolchain) are required. See DEPENDENCIES.md.

# macOS
./scripts/install-deps-macos.sh

# Linux (Debian/Ubuntu)
./scripts/install-deps-linux.sh

cargo build --release
cargo test
make python   # optional Python wheel

Python package (nbis-python on PyPI)

pip install "nbis-python>=0.1.15"

Maintainers: build macOS + Linux wheels and upload — see docs/PUBLISHING.md.

make wheels-all
make publish-check
make publish

Installation (Rust)

To use NBIS-rs, add the following to your Cargo.toml:

[dependencies]
nbis-rs = { git = "https://github.com/Seventh-Sense-Artificial-Intelligence/nbis-rs", branch = "main", version = "0.1.3" }

Or you can run the following command on the terminal of your new rust project:

cargo add nbis-rs --git https://github.com/Seventh-Sense-Artificial-Intelligence/nbis-rs --branch main

Running the above command will add the above dependency in your Cargo.toml

Now you can use the nbis-rs rust library in your project as mentioned in next section.

Usage (Rust)

Here's a simple example of how to use NBIS-rs in your project:

fn main() -> Result<(), Box<dyn std::error::Error>> {
    use nbis;
    use nbis::Minutiae;
    use nbis::NbisExtractorSettings;
    // Configuration for the NbisExtractor
    let settings = NbisExtractorSettings {
        // No filtering on minutiae quality (all minutiae will be included)
        min_quality: 0.0,
        // Do not compute ROI or center to save computing resources
        get_center: false,
        // Do not check if the image is a fingerprint using SIVV
        check_fingerprint: false,
        // compute the NFIQ score
        compute_nfiq2: true,
        // No specific PPI, use the default
        ppi: None,
    };

    let extractor = nbis::NbisExtractor::new(settings)?;

    // Read the bytes from a file (you could also use nbis::extract_minutiae_from_image_file)
    // but here we just load the image bytes as image paths on mobile platforms can be tricky.
    let image_bytes = std::fs::read("test_data/p1/p1_1.png")?;

    let minutiae_1 = extractor.extract_minutiae(&image_bytes)?;

    let image_bytes = std::fs::read("test_data/p1/p1_2.png")?;
    let minutiae_2 = extractor.extract_minutiae(&image_bytes)?;

    let image_bytes = std::fs::read("test_data/p1/p1_3.png")?;
    let minutiae_3 = extractor.extract_minutiae(&image_bytes)?;

    // Compare the two sets of minutiae
    let score = minutiae_1.compare(&minutiae_2);
    assert!(score > 35, "Expected a high similarity score between p1_1 and p1_2");
    let score = minutiae_1.compare(&minutiae_3);
    assert!(score > 35, "Expected a high similarity score between p1_1 and p1_3");
    let score = minutiae_2.compare(&minutiae_3);
    assert!(score > 35, "Expected a high similarity score between p1_2 and p1_3");

    // Next we will demonstrate conversion to ISO/IEC 19794-2:2011 format
    // and back to a `Minutiae` object.
    // First, convert the minutiae to ISO template bytes
    let iso_template: Vec<u8> = minutiae_1.to_iso_19794_2_2011()?;
    // And load it back
    let minutiae_from_iso = extractor.load_iso_19794_2_2011(&iso_template)?;
    // Compare the original minutiae with the one loaded from ISO template
    for (a, b) in minutiae_from_iso.get().iter().zip(minutiae_1.get().iter()) {
        assert_eq!(a.x(), b.x());
        assert_eq!(a.y(), b.y());
        assert_eq!(a.angle(), b.angle());
        assert_eq!(a.kind(), b.kind());
        // Reliability is quantized in the round-trip conversion,
        // so we allow a small margin of error.
        assert!((a.reliability() - b.reliability()).abs() < 1e-1);
    }

    // Finally we demonstrate loading from a file and comparing a negative match
    let minutiae_4 = extractor.extract_minutiae_from_image_file("test_data/p2/p2_1.png")?;
    let score = minutiae_1.compare(&minutiae_4);
    assert!(score < 35, "Expected a low similarity score between p1_1 and p2_1");

    // We can access the NFIQ2 quality via:
    let nfiq2_quality = minutiae_1.quality();
    assert!(nfiq2_quality.score > 50, "Expected a positive NFIQ2 quality score");

    Ok(())
}

Installation (Python)

pip install "nbis-python>=0.1.15"

See docs/PUBLISHING.md for PyPI release steps.

Usage (Python)

Here's a simple example of how to use the NBIS Python bindings:

import nbis
from nbis import NbisExtractor, NbisExtractorSettings

 #Configuration for the NbisExtractor
settings = NbisExtractorSettings(
    # Do not filter on minutiae quality (get all minutiae)
    min_quality=0.0,
    # Do not get the fingerprint center or ROI
    get_center=False,
    # Do not use SIVV to check if the image is a fingerprint
    check_fingerprint=False,
    # Compute the NFIQ2 quality score
    compute_nfiq2=True,
    # No specific PPI, use the default
    ppi=None,
)

extractor = nbis.new_nbis_extractor(settings)

# Read the bytes from a file
image_bytes = open("test_data/p1/p1_1.png", "rb").read()
minutiae_1 = extractor.extract_minutiae(image_bytes)
image_bytes = open("test_data/p1/p1_2.png", "rb").read()
minutiae_2 = extractor.extract_minutiae(image_bytes)
image_bytes = open("test_data/p1/p1_3.png", "rb").read()
minutiae_3 = extractor.extract_minutiae(image_bytes)

# Compare the two sets of minutiae
score = minutiae_1.compare(minutiae_2)
assert score > 50, "Expected a high similarity score between p1_1 and p1_2"
score = minutiae_1.compare(minutiae_3)
assert score > 50, "Expected a high similarity score between p1_1 and p1_3"
score = minutiae_2.compare(minutiae_3)
assert score > 50, "Expected a high similarity score between p1_2 and p1_3"

# Convert minutiae to ISO/IEC 19794-2:2011 format
iso_template = minutiae_1.to_iso_19794_2_2011()?
# Load it back
minutiae_from_iso = extractor.load_iso_19794_2_2011(iso_template)
# Compare the original minutiae with the one loaded from ISO template
for a, b in zip(minutiae_from_iso.get(), minutiae_1.get()):
    assert a.x() == b.x()
    assert a.y() == b.y()
    assert a.angle() == b.angle()
    assert a.kind() == b.kind()
    # Reliability is quantized in the round-trip conversion,
    # so we allow a small margin of error.
    assert abs(a.reliability() - b.reliability()) < 0.1

# Finally we demonstrate loading from a file and comparing a negative match
minutiae_4 = extractor.extract_minutiae_from_image_file("test_data/p2/p2_1.png")
score = minutiae_1.compare(minutiae_4)
assert score < 50, "Expected a low similarity score between p1_1 and p2_1"

# We can access the NFIQ2 quality via:
nfiq2_quality = minutiae_1.quality()
assert nfiq2_quality.score > 50, "Expected a positive NFIQ2 quality score"

Contributing

Contributions are welcome! Please open an issue or submit a pull request on GitHub.

License

This project is licensed under the MIT License - see the LICENSE file for details.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

nbis_python-0.1.17-py3-none-manylinux_2_28_x86_64.whl (23.8 MB view details)

Uploaded Python 3manylinux: glibc 2.28+ x86-64

nbis_python-0.1.17-py3-none-manylinux_2_28_aarch64.whl (8.0 MB view details)

Uploaded Python 3manylinux: glibc 2.28+ ARM64

nbis_python-0.1.17-py3-none-macosx_11_0_arm64.whl (3.5 MB view details)

Uploaded Python 3macOS 11.0+ ARM64

File details

Details for the file nbis_python-0.1.17-py3-none-manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for nbis_python-0.1.17-py3-none-manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 d6d74265646453eb200002ecdae00f15b71994838408ceadc3821da04379f8b1
MD5 4433b3365f14eb274faab3e1e6c9e37d
BLAKE2b-256 a7f530aa676722a5807433e2c0051146279bb13a1f1cfff81c89cd6de05bb903

See more details on using hashes here.

File details

Details for the file nbis_python-0.1.17-py3-none-manylinux_2_28_aarch64.whl.

File metadata

File hashes

Hashes for nbis_python-0.1.17-py3-none-manylinux_2_28_aarch64.whl
Algorithm Hash digest
SHA256 4fc0e4255c5a810ec47e1d6a23b14aac10f91f540f932a9c5ed44ea4c3dbd9e8
MD5 aca494491922d4e7ac1c9df9e4ba5ad4
BLAKE2b-256 e76ac0d1e8d5576486900f8012187e36064b40e67ed83630ec839adb1150f1ea

See more details on using hashes here.

File details

Details for the file nbis_python-0.1.17-py3-none-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for nbis_python-0.1.17-py3-none-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 6a0c7375d1ca7397359f39d6ae48e5e171b36733b1fcb6ce2102acb831176cad
MD5 2a1c48c3510a4f540836667bcd54a430
BLAKE2b-256 cd140f3c43b9a827db97035b8cafee66d0e69a8b22fa889b11b01120d568e266

See more details on using hashes here.

Release history Release notifications | RSS feed

0.1.21

3 files

0.1.20

3 files

0.1.19

3 files

0.1.18

3 files

This release

0.1.17 This release

3 files

0.1.16

3 files

0.1.15

3 files

0.1.14

2 files

0.1.13

2 files

0.1.12

2 files

0.1.11

2 files

0.1.10

2 files

0.1.9

2 files

0.1.8

2 files

0.1.7

2 files

0.1.5

1 file

0.1.4

1 file

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page