Как обнаружить и удалить размытый фон с изображения

У меня есть изображение с размытым фоном. Что мне нужно сделать, это удалить размытый фон и сохранить только острые объекты на переднем плане. Есть ли какой-нибудь способ сделать это с помощью openCV? Изображение будет примерно таким, как показано ниже. Мне нужно обнаружить и вычесть размытый фон.

3 ответа

Это априори трудная задача, потому что плоские области (такие как рубашка) имеют такой же внешний вид, что и размытые (то есть активность с низким градиентом). Можно попробовать какой-нибудь метод сегментации и оценить прочность края вокруг каждого региона, но это не так просто.

Вот что я попробовал для бедного человека:

  • используйте детектор краев и оцифруйте их так, чтобы области, представляющие интерес, были закрыты;

  • выполнить анализ подключенных компонентов и выбрать самый большой BLOB-объект (размытая область);

  • Заполните отверстие, чтобы получить сплошную маску.

Поскольку вы упоминаете в комментариях, что не знаете, с чего начать, вы можете начать с простого детектора острых краев, который уже даст вам подсказки о том, как решить проблему:

Canny на пороге 100, 200

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

Этот вопрос был открытым некоторое время, и меня направили сюда из другого вопроса. Я подумал, что поставлю ответ с помощью некоторого кода, просто чтобы реализовать некоторые идеи предыдущих ответов.

Начните с обнаружения края 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);
Другие вопросы по тегам