Внёс изменения в графический интерфейс
теперь есть возможность использовать метод DCT
This commit is contained in:
65
core/dct.py
65
core/dct.py
@@ -1,6 +1,7 @@
|
||||
"""
|
||||
Модуль DCT стеганографии с квантованием (JPEG-style)
|
||||
Оптимизирован для длинных сообщений
|
||||
Поддержка цветных изображений (RGB)
|
||||
Оптимизирован для GUI
|
||||
"""
|
||||
|
||||
import numpy as np
|
||||
@@ -10,16 +11,16 @@ from .utils import text_to_bits, bits_to_text
|
||||
|
||||
BLOCK_SIZE = 8
|
||||
|
||||
# Более мягкая таблица квантования (качество ~70-80%)
|
||||
# Таблица квантования JPEG (качество 50%)
|
||||
QUANT_TABLE = np.array([
|
||||
[8, 6, 5, 8, 12, 20, 26, 31],
|
||||
[6, 6, 7, 10, 13, 29, 30, 28],
|
||||
[7, 7, 8, 12, 20, 29, 35, 28],
|
||||
[7, 9, 11, 15, 26, 44, 40, 31],
|
||||
[9, 11, 19, 28, 34, 55, 52, 39],
|
||||
[12, 18, 28, 32, 41, 52, 57, 46],
|
||||
[25, 32, 39, 44, 52, 61, 60, 51],
|
||||
[36, 46, 48, 49, 56, 50, 52, 50]
|
||||
[16, 11, 10, 16, 24, 40, 51, 61],
|
||||
[12, 12, 14, 19, 26, 58, 60, 55],
|
||||
[14, 13, 16, 24, 40, 57, 69, 56],
|
||||
[14, 17, 22, 29, 51, 87, 80, 62],
|
||||
[18, 22, 37, 56, 68, 109, 103, 77],
|
||||
[24, 35, 55, 64, 81, 104, 113, 92],
|
||||
[49, 64, 78, 87, 103, 121, 120, 101],
|
||||
[72, 92, 95, 98, 112, 100, 103, 99]
|
||||
])
|
||||
|
||||
|
||||
@@ -41,8 +42,8 @@ def _get_zigzag_order() -> list:
|
||||
|
||||
|
||||
ZIGZAG_ORDER = _get_zigzag_order()
|
||||
# Используем больше коэффициентов (1-50)
|
||||
MID_FREQ_INDICES = ZIGZAG_ORDER[1:50]
|
||||
# Используем среднечастотные коэффициенты
|
||||
MID_FREQ_INDICES = ZIGZAG_ORDER[10:40]
|
||||
|
||||
|
||||
def _dct_quantize(block: np.ndarray) -> np.ndarray:
|
||||
@@ -98,7 +99,13 @@ def encode_dct(image_path: str, message: str, output_path: str) -> bool:
|
||||
img = Image.open(image_path).convert('RGB')
|
||||
pixels = np.array(img, dtype=np.float64)
|
||||
height, width, channels = pixels.shape
|
||||
|
||||
|
||||
# Проверка размеров
|
||||
if height % BLOCK_SIZE != 0 or width % BLOCK_SIZE != 0:
|
||||
print(f"Ошибка: размеры {width}x{height} не кратны {BLOCK_SIZE}")
|
||||
return False
|
||||
|
||||
# Формат: [длина: 32 бита] + [сообщение]
|
||||
msg_bytes = message.encode('utf-8')
|
||||
msg_length = len(msg_bytes)
|
||||
length_bits = format(msg_length, '032b')
|
||||
@@ -106,19 +113,20 @@ def encode_dct(image_path: str, message: str, output_path: str) -> bool:
|
||||
all_bits = length_bits + message_bits
|
||||
bit_list = [int(b) for b in all_bits]
|
||||
total_bits = len(bit_list)
|
||||
|
||||
|
||||
# Проверка вместимости
|
||||
blocks_per_row = width // BLOCK_SIZE
|
||||
blocks_per_col = height // BLOCK_SIZE
|
||||
max_bits = blocks_per_row * blocks_per_col * len(MID_FREQ_INDICES) * 3
|
||||
|
||||
|
||||
if total_bits > max_bits:
|
||||
print(f"Ошибка: сообщение слишком большое.")
|
||||
print(f"Доступно: {max_bits}, требуется: {total_bits}")
|
||||
return False
|
||||
|
||||
|
||||
modified_pixels = pixels.copy()
|
||||
bit_index = 0
|
||||
|
||||
|
||||
for i in range(0, height - BLOCK_SIZE + 1, BLOCK_SIZE):
|
||||
for j in range(0, width - BLOCK_SIZE + 1, BLOCK_SIZE):
|
||||
if bit_index >= total_bits:
|
||||
@@ -127,7 +135,7 @@ def encode_dct(image_path: str, message: str, output_path: str) -> bool:
|
||||
for c in range(3):
|
||||
if bit_index >= total_bits:
|
||||
break
|
||||
|
||||
|
||||
block = pixels[i:i+BLOCK_SIZE, j:j+BLOCK_SIZE, c]
|
||||
quant_block = _dct_quantize(block)
|
||||
quant_block, bit_index = _embed_bits_in_block(quant_block, bit_list, bit_index)
|
||||
@@ -136,7 +144,7 @@ def encode_dct(image_path: str, message: str, output_path: str) -> bool:
|
||||
|
||||
if bit_index >= total_bits:
|
||||
break
|
||||
|
||||
|
||||
result_img = Image.fromarray(modified_pixels.astype(np.uint8), mode='RGB')
|
||||
result_img.save(output_path)
|
||||
print(f"Успешно! Спрятано {total_bits} бит ({total_bits // 8} байт)")
|
||||
@@ -148,7 +156,11 @@ def decode_dct(image_path: str) -> str:
|
||||
img = Image.open(image_path).convert('RGB')
|
||||
pixels = np.array(img, dtype=np.float64)
|
||||
height, width, channels = pixels.shape
|
||||
|
||||
|
||||
if height % BLOCK_SIZE != 0 or width % BLOCK_SIZE != 0:
|
||||
return ""
|
||||
|
||||
# Извлекаем все биты
|
||||
all_bits = []
|
||||
|
||||
for i in range(0, height - BLOCK_SIZE + 1, BLOCK_SIZE):
|
||||
@@ -158,7 +170,8 @@ def decode_dct(image_path: str) -> str:
|
||||
quant_block = _dct_quantize(channel_block)
|
||||
bits_from_block = _extract_bits_from_block(quant_block, len(MID_FREQ_INDICES))
|
||||
all_bits.extend(bits_from_block)
|
||||
|
||||
|
||||
# Читаем длину сообщения (первые 32 бита)
|
||||
if len(all_bits) < 32:
|
||||
return ""
|
||||
|
||||
@@ -166,15 +179,13 @@ def decode_dct(image_path: str) -> str:
|
||||
length_str = ''.join(str(b) for b in length_bits)
|
||||
msg_length = int(length_str, 2)
|
||||
|
||||
if msg_length > (len(all_bits) - 32) // 8:
|
||||
# Проверка
|
||||
if msg_length <= 0 or msg_length > (len(all_bits) - 32) // 8:
|
||||
return ""
|
||||
|
||||
# Читаем сообщение
|
||||
message_bits = all_bits[32:32 + msg_length * 8]
|
||||
|
||||
remainder = len(message_bits) % 8
|
||||
if remainder != 0:
|
||||
message_bits.extend([0] * (8 - remainder))
|
||||
|
||||
if len(message_bits) == 0:
|
||||
return ""
|
||||
|
||||
@@ -182,5 +193,5 @@ def decode_dct(image_path: str) -> str:
|
||||
try:
|
||||
return bits_to_text(bits_string)
|
||||
except Exception as e:
|
||||
print(f"Ошибка при декодировании: {e}")
|
||||
print(f"Ошибка декодирования: {e}")
|
||||
return ""
|
||||
Reference in New Issue
Block a user