ring-sizer / src /viz_constants.py
feng-x's picture
Upload folder using huggingface_hub
347d1a8 verified
"""
Shared visualization constants for debug output across all algorithms.
This module provides centralized configuration for fonts, colors, sizes, and
layout used in debug visualizations throughout the Ring Sizer system.
Used by:
- card_detection.py - Multi-strategy card detection debug output
- finger_segmentation.py - Hand/finger detection debug output
- geometry.py - Axis, zone, measurement debug output
- visualization.py - Final composite debug overlay
- confidence.py - Confidence visualization
Example usage:
from viz_constants import Color, FontScale, FontThickness, FONT_FACE
cv2.putText(img, "Title", (20, 100), FONT_FACE,
FontScale.TITLE, Color.WHITE,
FontThickness.TITLE_OUTLINE, cv2.LINE_AA)
"""
import cv2
from typing import Tuple
# ============================================================================
# FONT SETTINGS
# ============================================================================
# Font face used across all visualizations
FONT_FACE = cv2.FONT_HERSHEY_SIMPLEX
class FontScale:
"""
Font scale constants for text hierarchy levels.
Larger values = bigger text. These are base scales that may be
adjusted based on image size in some visualizations.
"""
TITLE = 3.5 # Main titles (e.g., "Card Detection", "Final Result")
SUBTITLE = 2.5 # Section headers (e.g., "Score: 0.85")
LABEL = 1.8 # Inline labels (e.g., "#1 Score:0.83")
BODY = 1.5 # Body text (normal annotations)
SMALL = 1.0 # Small text (fine details)
class FontThickness:
"""
Font thickness (stroke width) for text rendering.
Larger values = thicker/bolder text.
Use OUTLINE variants for background layer to create outlined text effect.
"""
# Main text thickness
TITLE = 7
SUBTITLE = 5
LABEL = 4
BODY = 2
# Outline/shadow thickness (draw first for outline effect)
TITLE_OUTLINE = 10
SUBTITLE_OUTLINE = 8
LABEL_OUTLINE = 6
BODY_OUTLINE = 4
# ============================================================================
# COLORS (BGR format for OpenCV)
# ============================================================================
class Color:
"""
Standard colors used across all visualizations.
All colors in BGR format (Blue, Green, Red) as required by OpenCV.
Example: (255, 255, 255) = White in BGR
Usage:
cv2.circle(img, center, radius, Color.GREEN, -1)
"""
# ========================================================================
# Basic Colors
# ========================================================================
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
RED = (0, 0, 255) # BGR: (0, 0, 255)
GREEN = (0, 255, 0) # BGR: (0, 255, 0)
BLUE = (255, 0, 0) # BGR: (255, 0, 0)
# ========================================================================
# Extended Palette
# ========================================================================
CYAN = (255, 255, 0) # BGR: (255, 255, 0)
YELLOW = (0, 255, 255) # BGR: (0, 255, 255)
MAGENTA = (255, 0, 255) # BGR: (255, 0, 255)
ORANGE = (0, 128, 255) # BGR: (0, 128, 255)
PINK = (128, 128, 255) # BGR: (128, 128, 255)
# ========================================================================
# Semantic Colors (what they represent in the system)
# ========================================================================
# Object colors
CARD = GREEN # Credit card outline
FINGER = MAGENTA # Finger contour
# Axis/geometry colors
AXIS_PALM = CYAN # Palm-side axis endpoint
AXIS_TIP = ORANGE # Fingertip axis endpoint
AXIS_LINE = YELLOW # Finger principal axis line
# Measurement colors
RING_ZONE = CYAN # Ring-wearing zone overlay
CROSS_SECTION = ORANGE # Cross-section lines
POINT = BLUE # Intersection/measurement points
# Text colors
TEXT_PRIMARY = WHITE # Primary text (titles, main info)
TEXT_SUCCESS = GREEN # Success messages
TEXT_ERROR = RED # Error messages
TEXT_WARNING = YELLOW # Warning messages
class StrategyColor:
"""
Colors for different card detection strategies.
Used to visually distinguish candidates from different detection methods
in debug visualizations.
"""
CANNY = Color.CYAN # Canny edge detection (cyan)
ADAPTIVE = Color.ORANGE # Adaptive thresholding (orange)
OTSU = Color.MAGENTA # Otsu's thresholding (magenta)
COLOR_BASED = Color.GREEN # Color-based detection (green)
ALL_CANDIDATES = Color.PINK # Combined candidates (pink/purple)
# ============================================================================
# DRAWING SIZES
# ============================================================================
class Size:
"""
Size constants for drawing geometric elements (circles, lines, etc.).
All sizes in pixels.
"""
# Circle radii
CORNER_RADIUS = 8 # Card corners, small points
ENDPOINT_RADIUS = 15 # Axis endpoints (palm/tip)
INTERSECTION_RADIUS = 8 # Cross-section intersection points
POINT_RADIUS = 5 # Generic points
# Line thicknesses
CONTOUR_THICK = 5 # Thick contours (finger, card)
CONTOUR_NORMAL = 3 # Normal contours (candidates)
LINE_THICK = 4 # Thick lines (axis)
LINE_NORMAL = 2 # Normal lines (cross-sections)
LINE_THIN = 1 # Thin lines (grid, reference)
# ============================================================================
# LAYOUT CONSTANTS
# ============================================================================
class Layout:
"""
Layout positioning constants for text and elements.
All positions in pixels from top-left corner.
"""
# Title positioning (top-left text block)
TITLE_Y = 100 # Y position for main title
SUBTITLE_Y = 200 # Y position for subtitle/secondary text
LINE_SPACING = 100 # Vertical spacing between text lines
# Text offsets
TEXT_OFFSET_X = 20 # Horizontal margin from left edge
TEXT_OFFSET_Y = 25 # Vertical offset for inline text
LABEL_OFFSET = 20 # Offset for labels near objects
# Result text area (final visualization)
RESULT_TEXT_Y_START = 60 # Starting Y for result text block
RESULT_TEXT_LINE_HEIGHT = 55 # Height between result text lines
RESULT_TEXT_X_OFFSET = 40 # X offset for result text
# ============================================================================
# HELPER FUNCTIONS
# ============================================================================
def get_scaled_font_size(base_scale: float, image_height: int,
reference_height: int = 1200,
min_scale: float = 1.5) -> float:
"""
Scale font size based on image dimensions for consistent appearance.
Args:
base_scale: Base font scale (e.g., FontScale.TITLE)
image_height: Height of the image in pixels
reference_height: Reference height for scaling (default: 1200px)
min_scale: Minimum scale to prevent text from being too small
Returns:
Scaled font size adjusted for image dimensions
Example:
# For a 2400px tall image, double the font size
scale = get_scaled_font_size(FontScale.TITLE, 2400)
# scale = 3.5 * 2 = 7.0
"""
scale_factor = image_height / reference_height
scaled = base_scale * scale_factor
return max(scaled, min_scale)
def create_outlined_text(image, text, position, font_scale,
color, outline_color=None,
thickness=None, outline_thickness=None):
"""
Draw text with outline for better visibility.
Args:
image: Image to draw on
text: Text string to draw
position: (x, y) position tuple
font_scale: Font scale (from FontScale)
color: Main text color (from Color)
outline_color: Outline color (default: Color.WHITE)
thickness: Main text thickness (auto-selected if None)
outline_thickness: Outline thickness (auto-selected if None)
Example:
create_outlined_text(img, "Title", (20, 100),
FontScale.TITLE, Color.GREEN)
"""
if outline_color is None:
outline_color = Color.WHITE
# Auto-select thickness based on font scale
if thickness is None:
if font_scale >= FontScale.TITLE:
thickness = FontThickness.TITLE
elif font_scale >= FontScale.SUBTITLE:
thickness = FontThickness.SUBTITLE
elif font_scale >= FontScale.LABEL:
thickness = FontThickness.LABEL
else:
thickness = FontThickness.BODY
if outline_thickness is None:
outline_thickness = thickness + 3
# Draw outline first (background layer)
cv2.putText(image, text, position, FONT_FACE,
font_scale, outline_color, outline_thickness, cv2.LINE_AA)
# Draw main text on top
cv2.putText(image, text, position, FONT_FACE,
font_scale, color, thickness, cv2.LINE_AA)
# ============================================================================
# VALIDATION (Optional: for type checking and debugging)
# ============================================================================
def validate_color(color: Tuple[int, int, int]) -> bool:
"""
Validate that a color tuple is in correct BGR format.
Args:
color: Tuple of (B, G, R) values
Returns:
True if valid, False otherwise
"""
if not isinstance(color, tuple) or len(color) != 3:
return False
return all(0 <= val <= 255 for val in color)
# ============================================================================
# EXPORTS
# ============================================================================
__all__ = [
# Font settings
'FONT_FACE',
'FontScale',
'FontThickness',
# Colors
'Color',
'StrategyColor',
# Sizes
'Size',
# Layout
'Layout',
# Helper functions
'get_scaled_font_size',
'create_outlined_text',
'validate_color',
]