from __future__ import annotations from dataclasses import dataclass import numpy as np from entities.block_grid8 import BlockGrid8 from entities.lsb_row8 import LsbRow8 from entities.label64 import Label64 from entities.sequence8 import Sequence8 @dataclass(frozen=True) class Extractor: """Извлечение метки из 2D-компоненты через LSB верхней строки блоков 8×8.""" def extract_label(self, component: np.ndarray, seq: Sequence8) -> Label64: """Вернуть Label64, восстановленную из компоненты.""" if component.ndim != 2: raise ValueError("Ожидается 2D-компонента.") h, w = component.shape if h % 8 != 0 or w % 8 != 0: raise ValueError("Размеры компоненты должны быть кратны 8.") blocks = BlockGrid8.split(component) if blocks.shape[0] != 4096: raise ValueError("Для метки 64x64 требуется 4096 блоков 8x8.") bits = np.empty(4096, dtype=np.uint8) s0 = seq.seq0 s1 = seq.seq1 # Поблочный выбор по минимальной хэмминговой дистанции for i, blk in enumerate(blocks): b = LsbRow8.extract(blk) d0 = np.count_nonzero(b != s0) d1 = np.count_nonzero(b != s1) bits[i] = 0 if d0 <= d1 else 1 return Label64.from_vector(bits)