Как обнаружить и удалить размытый фон с изображения
3 ответа
Это априори трудная задача, потому что плоские области (такие как рубашка) имеют такой же внешний вид, что и размытые (то есть активность с низким градиентом). Можно попробовать какой-нибудь метод сегментации и оценить прочность края вокруг каждого региона, но это не так просто.
Вот что я попробовал для бедного человека:
используйте детектор краев и оцифруйте их так, чтобы области, представляющие интерес, были закрыты;
выполнить анализ подключенных компонентов и выбрать самый большой BLOB-объект (размытая область);
Заполните отверстие, чтобы получить сплошную маску.
Поскольку вы упоминаете в комментариях, что не знаете, с чего начать, вы можете начать с простого детектора острых краев, который уже даст вам подсказки о том, как решить проблему:
С этого момента вы должны искать подходящую итерацию, чтобы отобразить пиксели по краям на новое изображение.
Этот вопрос был открытым некоторое время, и меня направили сюда из другого вопроса. Я подумал, что поставлю ответ с помощью некоторого кода, просто чтобы реализовать некоторые идеи предыдущих ответов.
Начните с обнаружения края Canny, чтобы найти передний план:
Увеличьте изображение, чтобы соединить аккуратные линии. Используйте findContours и выберите самый большой, чтобы создать маску.
В маске есть дыры, потому что контур касается края изображения. Мы можем заполнить небольшие дыры, инвертируя маску и снова используя findContours. На этот раз мы отфильтруем очень большие контуры и нарисуем оставшиеся контуры на маске.
Теперь нам просто нужно использовать маску, чтобы обрезать изображение.
Вот код
import cv2
import numpy as np
# load image
img = cv2.imread("foreground.jpg");
# grayscale
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY);
# canny
canned = cv2.Canny(gray, 100, 200);
# dilate to close holes in lines
kernel = np.ones((5,5),np.uint8)
mask = cv2.dilate(canned, kernel, iterations = 1);
# find contours
# Opencv 3.4, if using a different major version (4.0 or 2.0), remove the first underscore
_, contours, _ = cv2.findContours(mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE);
# find big contours
biggest_cntr = None;
biggest_area = 0;
for contour in contours:
area = cv2.contourArea(contour);
if area > biggest_area:
biggest_area = area;
biggest_cntr = contour;
# draw contours
crop_mask = np.zeros_like(mask);
cv2.drawContours(crop_mask, [biggest_cntr], -1, (255), -1);
# fill in holes
# inverted
inverted = cv2.bitwise_not(crop_mask);
# contours again
_, contours, _ = cv2.findContours(inverted, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE);
# find small contours
small_cntrs = [];
for contour in contours:
area = cv2.contourArea(contour);
if area < 20000:
print(area);
small_cntrs.append(contour);
# draw on mask
cv2.drawContours(crop_mask, small_cntrs, -1, (255), -1);
# opening + median blur to smooth jaggies
crop_mask = cv2.erode(crop_mask, kernel, iterations = 1);
crop_mask = cv2.dilate(crop_mask, kernel, iterations = 1);
crop_mask = cv2.medianBlur(crop_mask, 5);
# crop image
crop = np.zeros_like(img);
crop[crop_mask == 255] = img[crop_mask == 255];
# show
cv2.imshow("original", img);
cv2.imshow("gray", gray);
cv2.imshow("canny", canned);
cv2.imshow("mask", crop_mask);
cv2.imshow("cropped", crop);
cv2.waitKey(0);