Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/usnistgov/NFIQ2/llms.txt

Use this file to discover all available pages before exploring further.

Overview

Actionable quality feedback provides interpretable quality assessments that can guide operators during fingerprint capture. Unlike unified quality scores (which predict recognition performance), actionable feedback identifies specific issues that can be corrected through recapture.
Actionable feedback translates complex quality measures into simple yes/no indicators that operators can use to determine if a recapture is needed and why.

Purpose and Benefits

Actionable quality feedback helps:
  • Operators: Understand why a fingerprint was rejected
  • Capture systems: Provide real-time guidance during enrollment
  • Quality assurance: Identify systematic capture problems
  • Training: Teach proper capture techniques
Use actionable feedback during live capture to guide operators. Use unified quality scores for post-capture quality assessment and enrollment decisions.

Available Feedback Indicators

NFIQ2 provides four primary actionable quality feedback indicators:
namespace NFIQ2::Identifiers::ActionableQualityFeedback {
    // Image appears blank or has insufficient contrast
    extern const char EmptyImageOrContrastTooLow[];
    
    // Image shows no variation (solid color/uniform gray)
    extern const char UniformImage[];
    
    // Image contains sufficient minutiae for matching
    extern const char FingerprintImageWithMinutiae[];
    
    // Image has adequate foreground area
    extern const char SufficientFingerprintForeground[];
}

Computing Actionable Feedback

Basic Usage

#include <nfiq2.hpp>

NFIQ2::FingerprintImageData fingerprintImage(/* ... */);

// Compute actionable quality feedback
auto feedback = 
    NFIQ2::QualityMeasures::computeActionableQualityFeedback(fingerprintImage);

// Check specific indicators
bool hasMinutiae = feedback["FingerprintImageWithMinutiae"] >= 
    NFIQ2::Thresholds::ActionableQualityFeedback::FingerprintImageWithMinutiae;

bool hasSufficientForeground = feedback["SufficientFingerprintForeground"] >= 
    NFIQ2::Thresholds::ActionableQualityFeedback::SufficientFingerprintForeground;

bool notEmpty = feedback["EmptyImageOrContrastTooLow"] < 
    NFIQ2::Thresholds::ActionableQualityFeedback::EmptyImageOrContrastTooLow;

bool notUniform = feedback["UniformImage"] > 
    NFIQ2::Thresholds::ActionableQualityFeedback::UniformImage;

From Pre-Computed Quality Measures

If you’ve already computed native quality measures, extract actionable feedback without reprocessing:
// Compute quality measure algorithms
auto algorithms = 
    NFIQ2::QualityMeasures::computeNativeQualityMeasureAlgorithms(fingerprintImage);

// Extract actionable feedback from algorithms
auto feedback = 
    NFIQ2::QualityMeasures::getActionableQualityFeedback(algorithms);

// Use feedback values as before
for (const auto& [indicator, value] : feedback) {
    std::cout << indicator << ": " << value << std::endl;
}

Feedback Indicators Explained

EmptyImageOrContrastTooLow

What it detects: Images that are blank, nearly blank, or have insufficient contrast.
This indicator checks if the mean gray level appears white or near-white, suggesting:
  • Empty image (no finger present)
  • Sensor not properly contacted
  • Overexposure
  • Very light impression
A mean gray level near 255 (white) almost always indicates a capture problem that requires operator intervention.

UniformImage

What it detects: Images with no variation in gray levels.
This indicator uses the standard deviation of gray levels to detect:
  • Solid gray images (no detail)
  • Sensor malfunction
  • Obstructed sensor (e.g., dirt, film)
  • Extreme underexposure
Uniform images are rare in normal operation. This indicator often signals equipment problems requiring maintenance.

FingerprintImageWithMinutiae

What it detects: Whether the image contains sufficient minutiae for matching.
This indicator reports the number of minutiae detected by the integrated FingerJet FX OSE feature extractor.Minutiae count correlates with:
  • Contact area
  • Ridge clarity
  • Overall capture quality
Low minutiae count suggests:
  • Partial print (insufficient contact)
  • Dry finger
  • Smudged impression
Expected minutiae counts:
  • Excellent captures: 50-80 minutiae
  • Good captures: 30-50 minutiae
  • Acceptable: 20-30 minutiae
  • Marginal: 12-20 minutiae
  • Insufficient: < 12 minutiae

SufficientFingerprintForeground

What it detects: Whether adequate foreground (fingerprint) area is present.
This indicator counts pixels in the computed foreground region (ROI).Low foreground area indicates:
  • Partial print
  • Finger not fully contacting sensor
  • Edge placement (finger off-center)
  • Small finger (children)

Implementing Real-Time Feedback

Simple Capture Loop

#include <nfiq2.hpp>

bool captureWithFeedback(NFIQ2::FingerprintImageData& image) {
    // Compute actionable feedback
    auto feedback = NFIQ2::QualityMeasures::computeActionableQualityFeedback(image);
    
    // Check each indicator
    bool passedAllChecks = true;
    std::vector<std::string> issues;
    
    // Empty or low contrast?
    if (feedback["EmptyImageOrContrastTooLow"] >= 
        NFIQ2::Thresholds::ActionableQualityFeedback::EmptyImageOrContrastTooLow) {
        issues.push_back("Image appears blank or has very low contrast");
        passedAllChecks = false;
    }
    
    // Uniform image?
    if (feedback["UniformImage"] <= 
        NFIQ2::Thresholds::ActionableQualityFeedback::UniformImage) {
        issues.push_back("Image shows no detail (possible sensor issue)");
        passedAllChecks = false;
    }
    
    // Sufficient minutiae?
    if (feedback["FingerprintImageWithMinutiae"] < 
        NFIQ2::Thresholds::ActionableQualityFeedback::FingerprintImageWithMinutiae) {
        issues.push_back("Insufficient minutiae detected");
        passedAllChecks = false;
    }
    
    // Sufficient foreground?
    if (feedback["SufficientFingerprintForeground"] < 
        NFIQ2::Thresholds::ActionableQualityFeedback::SufficientFingerprintForeground) {
        issues.push_back("Insufficient foreground area");
        passedAllChecks = false;
    }
    
    if (!passedAllChecks) {
        std::cout << "Capture issues detected:" << std::endl;
        for (const auto& issue : issues) {
            std::cout << "  - " << issue << std::endl;
        }
        return false;
    }
    
    return true;
}

Advanced Feedback with Quality Score

bool captureWithDetailedFeedback(
    NFIQ2::FingerprintImageData& image,
    NFIQ2::Algorithm& algorithm,
    unsigned int minQualityScore = 50
) {
    // Compute everything at once
    auto algorithms = 
        NFIQ2::QualityMeasures::computeNativeQualityMeasureAlgorithms(image);
    
    // Get actionable feedback
    auto feedback = NFIQ2::QualityMeasures::getActionableQualityFeedback(algorithms);
    
    // Get unified quality score
    unsigned int qualityScore = algorithm.computeUnifiedQualityScore(algorithms);
    
    // Check actionable feedback first (critical issues)
    bool hasCriticalIssues = false;
    
    if (feedback["EmptyImageOrContrastTooLow"] >= 
        NFIQ2::Thresholds::ActionableQualityFeedback::EmptyImageOrContrastTooLow) {
        std::cout << "CRITICAL: Image is blank or nearly blank" << std::endl;
        hasCriticalIssues = true;
    }
    
    if (feedback["UniformImage"] <= 
        NFIQ2::Thresholds::ActionableQualityFeedback::UniformImage) {
        std::cout << "CRITICAL: Image is uniform (no detail)" << std::endl;
        hasCriticalIssues = true;
    }
    
    if (hasCriticalIssues) {
        return false;  // Don't proceed with recapture attempts
    }
    
    // Check quality-related issues
    if (feedback["FingerprintImageWithMinutiae"] < 
        NFIQ2::Thresholds::ActionableQualityFeedback::FingerprintImageWithMinutiae) {
        std::cout << "WARNING: Low minutiae count - try increasing contact area" << std::endl;
    }
    
    if (feedback["SufficientFingerprintForeground"] < 
        NFIQ2::Thresholds::ActionableQualityFeedback::SufficientFingerprintForeground) {
        std::cout << "WARNING: Small foreground - center finger on sensor" << std::endl;
    }
    
    // Final quality check
    if (qualityScore < minQualityScore) {
        std::cout << "Quality score " << qualityScore 
                  << " below minimum " << minQualityScore << std::endl;
        return false;
    }
    
    std::cout << "Capture successful! Quality score: " << qualityScore << std::endl;
    return true;
}

Getting Feedback Indicator IDs

// Get all actionable quality feedback identifiers
std::vector<std::string> feedbackIDs = 
    NFIQ2::QualityMeasures::getActionableQualityFeedbackIDs();

std::cout << "Available feedback indicators:" << std::endl;
for (const auto& id : feedbackIDs) {
    std::cout << "  - " << id << std::endl;
}

// Output:
// Available feedback indicators:
//   - EmptyImageOrContrastTooLow
//   - UniformImage
//   - FingerprintImageWithMinutiae
//   - SufficientFingerprintForeground

User Interface Integration

Visual Feedback Examples

void displayFeedback(const std::unordered_map<std::string, double>& feedback) {
    std::cout << "\n=== Capture Quality Feedback ===\n" << std::endl;
    
    // Empty/low contrast check
    bool empty = feedback.at("EmptyImageOrContrastTooLow") >= 
        NFIQ2::Thresholds::ActionableQualityFeedback::EmptyImageOrContrastTooLow;
    std::cout << (empty ? "✗" : "✓") 
              << " Image contrast: " 
              << (empty ? "TOO LOW" : "OK") << std::endl;
    
    // Uniform check
    bool uniform = feedback.at("UniformImage") <= 
        NFIQ2::Thresholds::ActionableQualityFeedback::UniformImage;
    std::cout << (uniform ? "✗" : "✓") 
              << " Image detail: " 
              << (uniform ? "NONE" : "OK") << std::endl;
    
    // Minutiae check
    double minutiae = feedback.at("FingerprintImageWithMinutiae");
    bool hasMinutiae = minutiae >= 
        NFIQ2::Thresholds::ActionableQualityFeedback::FingerprintImageWithMinutiae;
    std::cout << (hasMinutiae ? "✓" : "✗") 
              << " Minutiae count: " << minutiae 
              << (hasMinutiae ? " (OK)" : " (LOW)") << std::endl;
    
    // Foreground check
    double foreground = feedback.at("SufficientFingerprintForeground");
    bool hasForeground = foreground >= 
        NFIQ2::Thresholds::ActionableQualityFeedback::SufficientFingerprintForeground;
    std::cout << (hasForeground ? "✓" : "✗") 
              << " Foreground area: " << foreground 
              << (hasForeground ? " px (OK)" : " px (LOW)") << std::endl;
}

Best Practices

Address feedback indicators in order of severity:
  1. UniformImage: May indicate hardware failure
  2. EmptyImageOrContrastTooLow: Requires immediate operator action
  3. SufficientFingerprintForeground: Needs repositioning
  4. FingerprintImageWithMinutiae: May need multiple recapture attempts
Set a maximum number of recapture attempts (typically 3-5):
const int MAX_ATTEMPTS = 3;
int attempts = 0;

while (attempts < MAX_ATTEMPTS) {
    if (captureWithFeedback(image)) {
        break;  // Success
    }
    attempts++;
    // Provide progressively more detailed guidance
}
Use actionable feedback for immediate capture decisions, but always compute unified quality scores for final enrollment decisions.Actionable feedback catches obvious problems; quality scores predict matching performance.
While NFIQ2 provides default thresholds, you may need to adjust them based on:
  • Your specific sensor characteristics
  • Population demographics (children, elderly)
  • Application requirements (forensic vs. access control)
  • Environmental conditions
Test adjustments against actual matching performance in your environment.

Troubleshooting Common Issues

Symptoms: EmptyImageOrContrastTooLow triggers repeatedlyPossible Causes:
  • Sensor needs cleaning
  • Sensor lighting/exposure misconfigured
  • Operator not positioning finger correctly
  • Very dry or worn fingerprints
Solutions:
  • Clean sensor thoroughly
  • Check sensor configuration
  • Provide operator training
  • Try different fingers

Next Steps

Quality Scores

Understand unified quality score computation

Quality Measures

Learn about underlying native quality measures

Quality Measures API

Complete API documentation

Integration Guide

Integrate NFIQ2 into your application