Вот один из способов сделать это в Python / OpenCV.
Используйте медианную фильтрацию для заполнения отверстий.
- Считайте ввод
- Преобразовать в серый
- Порог, чтобы сделать маска (пятна черные)
- Инвертирование маски (пятна белые)
- Найдите наибольший периметр контура пятна из инвертированной маски и используйте половину этого значения в качестве среднего размера фильтра
- Примените медианную фильтрацию к изображению
- Примените маску к входному сигналу
- Примените обратную маску к медианно-фильтрованному изображению
- Добавьте их вместе, чтобы сформировать результат
- Сохранить результаты
Ввод:
import cv2
import numpy as np
import math
# read image
img = cv2.imread('spots.png')
# convert to gray
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# threshold
mask = cv2.threshold(gray,0,255,cv2.THRESH_BINARY)[1]
# erode mask to make black regions slightly larger
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5,5))
mask = cv2.morphologyEx(mask, cv2.MORPH_ERODE, kernel)
# make mask 3 channel
mask = cv2.merge([mask,mask,mask])
# invert mask
mask_inv = 255 - mask
# get area of largest contour
contours = cv2.findContours(mask_inv[:,:,0], cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
contours = contours[0] if len(contours) == 2 else contours[1]
perimeter_max = 0
for c in contours:
perimeter = cv2.arcLength(c, True)
if perimeter > perimeter_max:
perimeter_max = perimeter
# approx radius from largest area
radius = int(perimeter_max/2) + 1
if radius % 2 == 0:
radius = radius + 1
print(radius)
# median filter input image
median = cv2.medianBlur(img, radius)
# apply mask to image
img_masked = cv2.bitwise_and(img, mask)
# apply inverse mask to median
median_masked = cv2.bitwise_and(median, mask_inv)
# add together
result = cv2.add(img_masked,median_masked)
# save results
cv2.imwrite('spots_mask.png', mask)
cv2.imwrite('spots_mask_inv.png', mask_inv)
cv2.imwrite('spots_median.png', median)
cv2.imwrite('spots_masked.png', img_masked)
cv2.imwrite('spots_median_masked.png', median_masked)
cv2.imwrite('spots_removed.png', result)
cv2.imshow('mask', mask)
cv2.imshow('mask_inv', mask_inv )
cv2.imshow('median', median)
cv2.imshow('img_masked', img_masked)
cv2.imshow('median_masked', median_masked)
cv2.imshow('result', result)
cv2.waitKey(0)
cv2.destroyAllWindows()
Пороговое изображение в качестве маски:
Инвертированная маска:
Отфильтровано по медиане изображение:
Маскированное изображение:
Маскированная фильтрованная медиана изображение:
Результат: