Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
МТ_ЛР7_Иванова_4117.docx
Скачиваний:
0
Добавлен:
29.04.2025
Размер:
11 Mб
Скачать

Часть 3:

Выбрано изображение с реальными искажениями (Рисунок 10).

Рисунок 10 — Изображение с искажениями

Для данного изображения составлены 3 маски. Так как собака прыгает вверх было принято обязательно взять вертикальный смаз (vertical_psf) и смаз диагональный с неебольшим отклонением от угла 90 градусов, так как собака в прыжке немного смещается (diagonal_psf), а также сферичную расфокусировку (sphere_psf), так как она была указана в варианте. Результаты восстановления представлены на Рисунке 11. Также для анализа отдельно вынесены крупным планов фрагменты морды на Рисунке 12.

Основываясь на результатах, можно сделать вывод что для восстановления данного изображения характерна маска вертикального смаза, так как для неё получаются наиболее чёткие результаты, это также объясняется вертикальным движением собаки в кадре.

Листинг 6 — Восстановление искажённого изображения разными методами

import cv2

import numpy as np

import matplotlib.pyplot as plt

from skimage import restoration

# --- PSF: вертикальный смаз ---

def vertical_psf(size=15):

psf = np.zeros((size, size), dtype=np.float32)

psf[:, size // 2] = 1.0

psf /= psf.sum()

return psf

# --- PSF: диагональный смаз

def diagonal_psf(size=10, angle=95):

psf = np.zeros((size, size), dtype=np.float32)

for i in range(size):

psf[i, i] = 1.0

psf /= psf.sum()

center = (size / 2 - 0.5, size / 2 - 0.5)

M = cv2.getRotationMatrix2D(center, angle, 1.0)

psf_rotated = cv2.warpAffine(psf, M, (size, size))

psf_rotated /= psf_rotated.sum()

return psf_rotated

# --- PSF: расфокусировка сферичная

def sphere_psf(size=15, sigma=5):

center = size // 2

y, x = np.ogrid[-center:size-center, -center:size-center]

psf = np.exp(-(x**2 + y**2) / (2 * sigma**2))

psf /= psf.sum()

return psf

# --- Загрузка изображения ---

real_image = cv2.imread('img/p5.jpg')

real_image = cv2.cvtColor(real_image, cv2.COLOR_BGR2RGB)

real_image_float = real_image.astype(np.float32) / 255.0

# --- Настройки ---

noise_var = 0.1

psf_list = [

("Вертикальный смаз", vertical_psf(15)),

("Диагональный смаз (95 градусов)", diagonal_psf(15, angle=95)),

("Расфокусировка", sphere_psf(15, sigma=5)),

]

x1, y1, x2, y2 = 150, 300, 750, 800 # тут где-то морда

# полные изображения

fig1, axes1 = plt.subplots(len(psf_list), 2, figsize=(12, 6 * len(psf_list)))

# фрагменты

fig2, axes2 = plt.subplots(len(psf_list), 2, figsize=(12, 5 * len(psf_list)))

for i, (label, psf) in enumerate(psf_list):

# Виннер

deblur_wiener = np.zeros_like(real_image_float)

for c in range(3):

deblur_wiener[..., c] = restoration.wiener(real_image_float[..., c], psf, noise_var)

deblur_wiener = np.clip(deblur_wiener, 0, 1)

# Люси-Ричардсон

deblur_lucy = np.zeros_like(real_image_float)

for c in range(3):

deblur_lucy[..., c] = restoration.richardson_lucy(real_image_float[..., c], psf, num_iter=16)

deblur_lucy = np.clip(deblur_lucy, 0, 1)

# Отображение всех

axes1[i, 0].imshow(deblur_wiener)

axes1[i, 0].set_title(f'{label} — Винер')

axes1[i, 1].imshow(deblur_lucy)

axes1[i, 1].set_title(f'{label} — Люси–Ричардсон')

for ax in axes1[i]:

ax.axis('off')

# Отображение фрагментов

axes2[i, 0].imshow(deblur_wiener[y1:y2, x1:x2])

axes2[i, 0].set_title(f'{label} — Винер (фрагмент)')

axes2[i, 1].imshow(deblur_lucy[y1:y2, x1:x2])

axes2[i, 1].set_title(f'{label} — Люси–Ричардсон (фрагмент)')

for ax in axes2[i]:

ax.axis('off')

plt.tight_layout()

fig1.suptitle('Восстановленные изображения', fontsize=16)

plt.show()

Рисунок 11 — Восстановленные разными методами изображения

Рисунок 12 — Фрагменты восстановленных изображений

На основе представленных результатов для получения более чёткого изображения морды решено использовать маску вертикального смаза с другими параметрами. В начале на основе фрагмента исходного изображения оценено приблизительное количество пикселей смаза. Для этого фрагмент с глазом собаки выведен на холсте через pyplot. По y верхняя граница блика в зрачке отмечена как 172, нижняя как 217. Разница получилась 45, поэтому принято брать такой размер маски. Также проведены эксперименты с количеством интераций для метода Люси-Ричардсона и параметром шума для метода Винера. Для метода Винера при таком большом размере маски получались множественные сильные артефакты. Так как psf очень длинная, для метода Винера было взято большое значение noise_var, равное 20, чтобы подавлять артефакты.

На Рисунке 13 для наглядного сравнения представлена визуализация исходного изображения и восстановленных методом Винера и Люси-Ричардсона, согласно указанным параметрам. На Рисунке 14 в аналогичном формате выведены фрагменты исходного и восстановленных изображений. Если рассматривать правый глазик собаки на исходном изображении, то его деталей не разглядеть. На восстановленных же изображениях хорошо различимы отблеск в зрачке, коричневая радужка глаза, тёмный зрачок (на Рисунке 17 хорошо видно). В целом качество морды улучшено, особенно это видно по правому глазику, носу, правому уху и пасти собаки. Также лучше различим и левый глазик. Восстановленные изображения сохранены и продемонстрированы для наглядности крупным планом на Рисунках 15-18. Код программы приведён в Листинге 6.

Рисунок 13 — Оптимально восстановленные изображения

Рисунок 14 — Сравнение фрагментов исходного и полученных изображений

Рисунок 15 — Восстановленное изображение, метод Винера

Рисунок 16 — Восстановленное изображение, метод Люси-Ричардсона

Рисунок 17 — Фрагмент морды, метод Винера

Рисунок 18 — Фрагмент морды, метод Люси-Ричардсона

Листинг 6 — Код программы восстановления чёткости изображения на основе только вертикального смаза с оптимальными параметрами, двумя методами.

import cv2

import numpy as np

import matplotlib.pyplot as plt

from skimage import restoration

def vertical_psf(size):

psf = np.zeros((size, size), dtype=np.float64)

psf[:, size // 2] = 1.0

psf /= psf.sum()

return psf

real_image = cv2.imread('img/p5.jpg')

real_image = cv2.cvtColor(real_image, cv2.COLOR_BGR2RGB)

real_image_float = real_image.astype(np.float64) / 255.0

# длина +-45 пикселей,

psf_estimated = vertical_psf(size=45)

# Восстановление методом Винера

noise_var = 20 # параметр для подавления артефактов

deblurred_wiener = np.zeros_like(real_image_float)

for channel in range(3):

deblurred_wiener[:, :, channel] = restoration.wiener(

real_image_float[:, :, channel],

psf_estimated,

noise_var

)

deblurred_wiener = np.clip(deblurred_wiener, 0, 1)

num_iter = 20

# Восстановление методом Люси-Ричардсона

deblurred_lucy = np.zeros_like(real_image_float)

for channel in range(3):

deblurred_lucy[:, :, channel] = restoration.richardson_lucy(

real_image_float[:, :, channel],

psf_estimated,

num_iter=num_iter

)

deblurred_lucy = np.clip(deblurred_lucy, 0, 1)

# Визуализация результатов

plt.figure(figsize=(20, 12))

plt.subplot(131)

plt.imshow(real_image)

plt.title('Исходное изображение')

plt.axis('off')

plt.subplot(132)

plt.imshow(deblurred_wiener)

plt.title(f'Винер (noise_var={noise_var})')

plt.axis('off')

plt.subplot(133)

plt.imshow(deblurred_lucy)

plt.title(f'Люси-Ричардсон ({num_iter} итер.)')

plt.axis('off')

plt.show()

x1, y1, x2, y2 = 100, 250, 750, 850 # тут где-то морда

plt.figure(figsize=(15, 5))

plt.subplot(131)

plt.imshow(real_image[y1:y2, x1:x2])

plt.title('Исходный фрагмент')

plt.axis('off')

plt.subplot(132)

plt.imshow(deblurred_wiener[y1:y2, x1:x2])

plt.title('Винер: фрагмент')

plt.axis('off')

plt.subplot(133)

plt.imshow(deblurred_lucy[y1:y2, x1:x2])

plt.title('Люси-Ричардсон: фрагмент')

plt.axis('off')

plt.show()

Выводы:

В результате выполнения лабораторной работы изучены основы обработки изображений на примере методов фильтрации с использованием пространственных фильтров.

В частности были рассмотрены такие методы восстановления как фильтрация Винера и Люси-Ричардсона. Реализованы различные маски искажения изображений — вертикальное смазывание, горизонтальное смазывание, сферичная расфокусировка.