mercoledì 15 ottobre 2025

Fractal Aruco Tags

 Questo tipo di tag e' utilizzato per oggetti in movimento che si possono allontanare od avvicinare troppo alla camera rendendo inutile un singolo tag..per questo vengono utlizzati tag piramidali

Generatore (si il codice e' stato completamente generato da Claude.ai)

import cv2
import numpy as np
from matplotlib import pyplot as plt

class FractalArucoGenerator:
    """
    Generate fractal ArUco markers where the marker contains smaller
    versions of itself recursively.
    """
   
    def __init__(self, dictionary=cv2.aruco.DICT_6X6_250):
        self.aruco_dict = cv2.aruco.getPredefinedDictionary(dictionary)
   
    def generate_base_marker(self, marker_id, size):
        """Generate a basic ArUco marker."""
        marker_img = cv2.aruco.generateImageMarker(self.aruco_dict, marker_id, size)
        return marker_img
   
    def create_fractal_marker(self, marker_id, base_size, levels=2, scale_factor=0.25):
        """
        Create a fractal ArUco marker with recursive smaller versions.
       
        Args:
            marker_id: ArUco marker ID
            base_size: Size of the base marker in pixels
            levels: Number of fractal levels (recursion depth)
            scale_factor: Size reduction factor for each level
        """
        # Generate base marker
        marker = self.generate_base_marker(marker_id, base_size)
       
        if levels <= 1:
            return marker
       
        # Create canvas with white border
        border = int(base_size * 0.1)
        canvas_size = base_size + 2 * border
        canvas = np.ones((canvas_size, canvas_size), dtype=np.uint8) * 255
       
        # Place main marker in center
        canvas[border:border+base_size, border:border+base_size] = marker
       
        # Add smaller fractal markers in corners
        small_size = int(base_size * scale_factor)
        small_marker = self.create_fractal_marker(marker_id, small_size, levels-1, scale_factor)
       
        # Calculate positions for corner markers
        positions = [
            (border//4, border//4),  # Top-left
            (canvas_size - border//4 - small_marker.shape[1], border//4),  # Top-right
            (border//4, canvas_size - border//4 - small_marker.shape[0]),  # Bottom-left
            (canvas_size - border//4 - small_marker.shape[1],
             canvas_size - border//4 - small_marker.shape[0])  # Bottom-right
        ]
       
        # Place smaller markers in corners
        for y, x in positions:
            h, w = small_marker.shape
            if y + h <= canvas_size and x + w <= canvas_size:
                canvas[y:y+h, x:x+w] = small_marker
       
        return canvas
   
    def save_printable(self, marker_img, filename, physical_size_mm=100, dpi=300):
        """
        Save marker as printable PDF/PNG with exact physical dimensions.
       
        Args:
            marker_img: The marker image
            filename: Output filename
            physical_size_mm: Physical size in millimeters
            dpi: Dots per inch for printing
        """
        # Calculate required pixel size for exact physical dimensions
        inches = physical_size_mm / 25.4
        pixel_size = int(inches * dpi)
       
        # Resize marker to exact pixel dimensions
        marker_resized = cv2.resize(marker_img, (pixel_size, pixel_size),
                                    interpolation=cv2.INTER_NEAREST)
       
        # Save as high-quality PNG
        cv2.imwrite(filename, marker_resized)
       
        # Also create a figure for PDF output
        fig, ax = plt.subplots(figsize=(inches, inches))
        ax.imshow(marker_resized, cmap='gray', interpolation='nearest')
        ax.axis('off')
        plt.subplots_adjust(left=0, right=1, top=1, bottom=0)
       
        pdf_filename = filename.rsplit('.', 1)[0] + '.pdf'
        plt.savefig(pdf_filename, dpi=dpi, bbox_inches='tight', pad_inches=0)
        plt.close()
       
        return marker_resized, pixel_size


def main():
    """Generate and save fractal ArUco marker ID=0, 100mm size."""
   
    generator = FractalArucoGenerator(dictionary=cv2.aruco.DICT_6X6_250)
   
    # Generate fractal marker (ID=0)
    print("Generating fractal ArUco marker ID=0...")
   
    # Create fractal marker with 3 levels
    base_size = 400  # Base resolution for generation
    fractal_marker = generator.create_fractal_marker(
        marker_id=0,
        base_size=base_size,
        levels=3,  # 3 levels of recursion
        scale_factor=0.2  # Each level is 20% the size of previous
    )
   
    # Save as printable with exact 100mm physical size
    print("Saving printable versions (100mm x 100mm)...")
    marker_resized, pixel_size = generator.save_printable(
        fractal_marker,
        'aruco_fractal_id0_100mm.png',
        physical_size_mm=100,
        dpi=300
    )
   
    print(f"✓ Saved: aruco_fractal_id0_100mm.png ({pixel_size}x{pixel_size} pixels)")
    print(f"✓ Saved: aruco_fractal_id0_100mm.pdf")
    print(f"  Physical size: 100mm x 100mm at 300 DPI")
    print(f"  Ready for printing!")
   
    # Also save a simple version without fractals for comparison
    simple_marker = generator.generate_base_marker(0, base_size)
    generator.save_printable(
        simple_marker,
        'aruco_simple_id0_100mm.png',
        physical_size_mm=100,
        dpi=300
    )
    print(f"✓ Saved: aruco_simple_id0_100mm.png (non-fractal version)")
   
    # Display preview
    plt.figure(figsize=(12, 6))
   
    plt.subplot(1, 2, 1)
    plt.imshow(fractal_marker, cmap='gray', interpolation='nearest')
    plt.title('Fractal ArUco ID=0\n(100mm @ 300 DPI)')
    plt.axis('off')
   
    plt.subplot(1, 2, 2)
    plt.imshow(simple_marker, cmap='gray', interpolation='nearest')
    plt.title('Simple ArUco ID=0\n(100mm @ 300 DPI)')
    plt.axis('off')
   
    plt.tight_layout()
    plt.savefig('aruco_comparison.png', dpi=150, bbox_inches='tight')
    print("✓ Saved: aruco_comparison.png (preview)")
   
    plt.show()
   
    print("\n" + "="*50)
    print("PRINTING INSTRUCTIONS:")
    print("="*50)
    print("1. Open aruco_fractal_id0_100mm.pdf")
    print("2. Print at 100% scale (do NOT scale to fit)")
    print("3. Verify the printed size is exactly 100mm x 100mm")
    print("4. Use thick white paper for best results")
    print("="*50)


if __name__ == "__main__":
    main()

 

 Lettore 

import cv2
import numpy as np
from typing import List, Tuple, Dict
import time

class FractalArucoDetector:
    """
    A fractal/hierarchical ArUco marker detector that searches for markers
    at multiple scales using a pyramid approach for robust detection.
    """
   
    def __init__(self,
                 dictionary=cv2.aruco.DICT_6X6_250,
                 num_scales=4,
                 scale_factor=0.7,
                 min_marker_perimeter=20):
        """
        Initialize the fractal ArUco detector.
       
        Args:
            dictionary: ArUco dictionary to use
            num_scales: Number of scales in the pyramid
            scale_factor: Scale reduction factor between levels
            min_marker_perimeter: Minimum marker perimeter to consider
        """
        self.aruco_dict = cv2.aruco.getPredefinedDictionary(dictionary)
        self.aruco_params = cv2.aruco.DetectorParameters()
        self.detector = cv2.aruco.ArucoDetector(self.aruco_dict, self.aruco_params)
       
        self.num_scales = num_scales
        self.scale_factor = scale_factor
        self.min_marker_perimeter = min_marker_perimeter
       
    def build_gaussian_pyramid(self, image: np.ndarray) -> List[np.ndarray]:
        """Build a Gaussian pyramid of the image."""
        pyramid = [image]
        current = image.copy()
       
        for i in range(1, self.num_scales):
            scale = self.scale_factor ** i
            width = int(image.shape[1] * scale)
            height = int(image.shape[0] * scale)
           
            if width < 50 or height < 50:  # Stop if too small
                break
               
            current = cv2.resize(image, (width, height),
                               interpolation=cv2.INTER_LINEAR)
            pyramid.append(current)
           
        return pyramid
   
    def detect_at_scale(self,
                       image: np.ndarray,
                       scale: float) -> Tuple[List, List, List]:
        """
        Detect ArUco markers at a specific scale.
       
        Returns:
            corners, ids, rejected candidates
        """
        corners, ids, rejected = self.detector.detectMarkers(image)
       
        # Scale corners back to original image coordinates
        if corners is not None and len(corners) > 0:
            scaled_corners = []
            for corner in corners:
                scaled_corner = corner / scale
                scaled_corners.append(scaled_corner)
            return scaled_corners, ids, rejected
       
        return [], [], []
   
    def merge_detections(self,
                        all_detections: List[Dict]) -> Tuple[List, List]:
        """
        Merge detections from multiple scales, removing duplicates.
        Uses spatial proximity to identify duplicate detections.
        """
        if not all_detections:
            return [], []
       
        merged_corners = []
        merged_ids = []
       
        # Flatten all detections
        for detection in all_detections:
            corners = detection['corners']
            ids = detection['ids']
           
            if ids is not None and len(ids) > 0:
                for corner, marker_id in zip(corners, ids):
                    merged_corners.append(corner)
                    merged_ids.append(marker_id[0])
       
        if not merged_corners:
            return [], []
       
        # Remove duplicates based on spatial proximity
        unique_corners = []
        unique_ids = []
       
        for i, (corner, marker_id) in enumerate(zip(merged_corners, merged_ids)):
            is_duplicate = False
            center = np.mean(corner[0], axis=0)
           
            for j, existing_corner in enumerate(unique_corners):
                if unique_ids[j] == marker_id:
                    existing_center = np.mean(existing_corner[0], axis=0)
                    distance = np.linalg.norm(center - existing_center)
                   
                    # If centers are close, it's a duplicate
                    if distance < 50:  # threshold in pixels
                        is_duplicate = True
                        break
           
            if not is_duplicate:
                unique_corners.append(corner)
                unique_ids.append(marker_id)
       
        return unique_corners, np.array(unique_ids).reshape(-1, 1)
   
    def detect_markers(self,
                      image: np.ndarray,
                      visualize=False) -> Tuple[List, List, np.ndarray]:
        """
        Detect ArUco markers using fractal/multi-scale approach.
       
        Args:
            image: Input image (color or grayscale)
            visualize: If True, return annotated image
           
        Returns:
            corners, ids, annotated_image (if visualize=True)
        """
        # Convert to grayscale if needed
        if len(image.shape) == 3:
            gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
        else:
            gray = image
       
        # Build pyramid
        pyramid = self.build_gaussian_pyramid(gray)
       
        # Detect at each scale
        all_detections = []
       
        for level, scaled_image in enumerate(pyramid):
            scale = self.scale_factor ** level
            corners, ids, rejected = self.detect_at_scale(scaled_image, scale)
           
            if ids is not None and len(ids) > 0:
                all_detections.append({
                    'corners': corners,
                    'ids': ids,
                    'scale': scale,
                    'level': level
                })
       
        # Merge detections from all scales
        final_corners, final_ids = self.merge_detections(all_detections)
       
        # Create visualization if requested
        annotated = None
        if visualize:
            annotated = image.copy() if len(image.shape) == 3 else cv2.cvtColor(image, cv2.COLOR_GRAY2BGR)
           
            if final_corners and final_ids is not None:
                cv2.aruco.drawDetectedMarkers(annotated, final_corners, final_ids)
               
                # Add scale information
                for corner, marker_id in zip(final_corners, final_ids):
                    center = np.mean(corner[0], axis=0).astype(int)
                    cv2.putText(annotated, f"ID: {marker_id[0]}",
                              tuple(center), cv2.FONT_HERSHEY_SIMPLEX,
                              0.6, (0, 255, 0), 2)
       
        return final_corners, final_ids, annotated


# Example usage
def main():
    """Example: Detect ArUco markers from webcam or image."""
   
    # Initialize detector
    detector = FractalArucoDetector(
        dictionary=cv2.aruco.DICT_6X6_250,
        num_scales=5,
        scale_factor=0.75
    )
   
    # Option 1: Use webcam
    cap = cv2.VideoCapture(0)
   
    print("Press 'q' to quit, 's' to save detection")
   
    while True:
        ret, frame = cap.read()
        if not ret:
            break
       
        # Detect markers
        start_time = time.time()
        corners, ids, annotated = detector.detect_markers(frame, visualize=True)
        detection_time = (time.time() - start_time) * 1000
       
        # Display results
        if annotated is not None:
            cv2.putText(annotated, f"Detection time: {detection_time:.1f}ms",
                       (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 0), 2)
           
            if ids is not None:
                cv2.putText(annotated, f"Markers found: {len(ids)}",
                           (10, 60), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 0), 2)
           
            cv2.imshow('Fractal ArUco Detection', annotated)
       
        key = cv2.waitKey(1) & 0xFF
        if key == ord('q'):
            break
        elif key == ord('s') and annotated is not None:
            cv2.imwrite('aruco_detection.png', annotated)
            print("Detection saved!")
   
    cap.release()
    cv2.destroyAllWindows()
   
    # Option 2: Use static image
    # image = cv2.imread('your_image.jpg')
    # corners, ids, annotated = detector.detect_markers(image, visualize=True)
    # cv2.imshow('Detection', annotated)
    # cv2.waitKey(0)
    # cv2.destroyAllWindows()


if __name__ == "__main__":
    main()

 

 

 

 

 

 

 

 

Nessun commento:

Posta un commento

Algoritmo Reed Solomon

 Sto progettando una trasmissione radio di immagini ed uno dei vincoli e' che non e' garantita la perfetta qualita' della trasmi...