41 lines
1.8 KiB
Python
41 lines
1.8 KiB
Python
|
|
from __future__ import annotations
|
|||
|
|
from dataclasses import dataclass
|
|||
|
|
import numpy as np
|
|||
|
|
|
|||
|
|
|
|||
|
|
@dataclass(frozen=True)
|
|||
|
|
class BlockGrid8:
|
|||
|
|
"""Разбиение и сборка блоков 8×8."""
|
|||
|
|
|
|||
|
|
@staticmethod
|
|||
|
|
def split(component: np.ndarray) -> np.ndarray:
|
|||
|
|
"""Разбить 2D-компоненту на блоки (N,8,8)."""
|
|||
|
|
if component.ndim != 2:
|
|||
|
|
raise ValueError("Ожидается 2D-массив компоненты.")
|
|||
|
|
h, w = component.shape
|
|||
|
|
if h % 8 != 0 or w % 8 != 0:
|
|||
|
|
raise ValueError("Размеры должны быть кратны 8.")
|
|||
|
|
# Перестановка осей даёт (nH, nW, 8, 8) -> (N, 8, 8)
|
|||
|
|
arr = np.asarray(component)
|
|||
|
|
nH, nW = h // 8, w // 8
|
|||
|
|
blocks = arr.reshape(nH, 8, nW, 8).transpose(
|
|||
|
|
0, 2, 1, 3).reshape(nH * nW, 8, 8)
|
|||
|
|
return blocks
|
|||
|
|
|
|||
|
|
@staticmethod
|
|||
|
|
def merge(blocks: np.ndarray, height: int, width: int) -> np.ndarray:
|
|||
|
|
"""Собрать 2D-компоненту из блоков (N,8,8)."""
|
|||
|
|
if blocks.ndim != 3 or blocks.shape[1:] != (8, 8):
|
|||
|
|
raise ValueError("Ожидается массив блоков формы (N,8,8).")
|
|||
|
|
if height % 8 != 0 or width % 8 != 0:
|
|||
|
|
raise ValueError("Размеры должны быть кратны 8.")
|
|||
|
|
nH, nW = height // 8, width // 8
|
|||
|
|
if blocks.shape[0] != nH * nW:
|
|||
|
|
raise ValueError(
|
|||
|
|
"Количество блоков не соответствует размеру выходной матрицы.")
|
|||
|
|
# Обратная перестановка из (N,8,8) -> (nH, nW, 8, 8) -> (H, W)
|
|||
|
|
arr = np.asarray(blocks)
|
|||
|
|
comp = arr.reshape(nH, nW, 8, 8).transpose(
|
|||
|
|
0, 2, 1, 3).reshape(height, width)
|
|||
|
|
return comp
|