Удаление пикселей меньше n размера (шума) в изображении - открыть CV Python

Я пытаюсь удалить шум на изображении меньше, и в настоящее время выполняется этот код

import numpy as np
import argparse
import cv2
from skimage import morphology

# Construct the argument parser and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--image", required = True,
    help = "Path to the image")
args = vars(ap.parse_args())

# Load the image, convert it to grayscale, and blur it slightly
image = cv2.imread(args["image"])

cv2.imshow("Image", image)
cv2.imwrite("image.jpg", image)

greenLower = np.array([50, 100, 0], dtype = "uint8")
greenUpper = np.array([120, 255, 120], dtype = "uint8")

green = cv2.inRange(image, greenLower, greenUpper)
#green = cv2.GaussianBlur(green, (3, 3), 0)

cv2.imshow("green", green)
cv2.imwrite("green.jpg", green)

cleaned = morphology.remove_small_objects(green, min_size=64, connectivity=2)

cv2.imshow("cleaned", cleaned)
cv2.imwrite("cleaned.jpg", cleaned)



cv2.waitKey(0)

Однако изображение, похоже, не изменилось с "зеленого" на "очищенное", несмотря на использование функции remove_small_objects. почему это и как я могу очистить изображение? В идеале я хотел бы выделить только изображение капусты.

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

Изменить: сделал несколько ошибок при изменении кода, обновлен до того, что он в настоящее время и отображать 3 изображения

образ:

введите описание изображения здесь

зеленый:

введите описание изображения здесь

чистить:

введите описание изображения здесь

моя цель состоит в том, чтобы получить что-то похожее на эту картинку из реализации Matlab

введите описание изображения здесь

3 ответа

Решение

предварительная обработка

Хорошая идея, когда вы фильтруете изображение - это пропустить изображение или немного размыть его; таким образом, соседние пиксели становятся немного более однородными по цвету, так что это ослабит более яркие и темные пятна на изображении и не даст дырке от маски.

img = cv2.imread('image.jpg')
blur = cv2.GaussianBlur(img, (15, 15), 2)
lower_green = np.array([50, 100, 0])
upper_green = np.array([120, 255, 120])
mask = cv2.inRange(blur, lower_green, upper_green)
masked_img = cv2.bitwise_and(img, img, mask=mask)
cv2.imshow('', masked_img)
cv2.waitKey()

Затуманенное фильтр

Цветовое пространство

В настоящее время вы пытаетесь поместить изображение в диапазоне цветов с различной яркостью - вам нужны зеленые пиксели, независимо от того, являются ли они темными или светлыми. Это гораздо проще сделать в цветовом пространстве HSV. Проверьте мой ответ здесь, углубляясь в цветовое пространство HSV.

img = cv2.imread('image.jpg')
blur = cv2.GaussianBlur(img, (15, 15), 2)
hsv = cv2.cvtColor(blur, cv2.COLOR_BGR2HSV)
lower_green = np.array([37, 0, 0])
upper_green = np.array([179, 255, 255])
mask = cv2.inRange(hsv, lower_green, upper_green)
masked_img = cv2.bitwise_and(img, img, mask=mask)
cv2.imshow('', masked_img)
cv2.waitKey()

Фильтрация HSV

Удаление шума в двоичном изображении / маске

Ответ, предоставленный ngalstyan, показывает, как это сделать с морфологией. То, что вы хотите сделать, называется открытием, которое представляет собой комбинированный процесс разрушения (которое более или менее просто удаляет все в пределах определенного радиуса), а затем расширение (которое добавляет обратно к любым оставшимся объектам, как бы много ни было удалено). В OpenCV это достигается с помощью cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel), Обучающие программы на этой странице показывают, как это работает.

img = cv2.imread('image.jpg')
blur = cv2.GaussianBlur(img, (15, 15), 2)
hsv = cv2.cvtColor(blur, cv2.COLOR_BGR2HSV)
lower_green = np.array([37, 0, 0])
upper_green = np.array([179, 255, 255])
mask = cv2.inRange(hsv, lower_green, upper_green)
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (15, 15))
opened_mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel)
masked_img = cv2.bitwise_and(img, img, mask=opened_mask)
cv2.imshow('', masked_img)
cv2.waitKey()

Открытая маска

Заполнение пробелов

Выше было показано, что открытие - это метод удаления маленьких кусочков белого из вашей двоичной маски. Закрытие является противоположной операцией - удаление кусков черного с вашего изображения, которые окружены белым. Вы можете сделать это с той же идеей, что и выше, но используя cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel), Это даже не нужно после вышеперечисленного в вашем случае, так как маска не имеет никаких отверстий. Но если это произойдет, вы можете закрыть их с закрытием. Вы заметите, что мой первый шаг фактически убрал немного растения внизу. Вы могли бы на самом деле заполнить эти пробелы, закрыв сначала, а затем открыв, чтобы удалить ложные биты в другом месте, но это, вероятно, не нужно для этого изображения.

Опробовать новые значения для порога

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

Хотя вышеупомянутая проблема решается с помощью cv2.morphologyEx (img, cv2.MORPH_OPEN, kernel). Но если кто-то хочет использовать morphology.remove_small_objects, чтобы удалить область меньше указанного размера, для тех этот ответ может быть полезен.

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

import numpy as np
import cv2
from skimage import morphology
# Load the image, convert it to grayscale, and blur it slightly
image = cv2.imread('im.jpg')
cv2.imshow("Image", image)
#cv2.imwrite("image.jpg", image)
greenLower = np.array([50, 100, 0], dtype = "uint8")
greenUpper = np.array([120, 255, 120], dtype = "uint8")
green = cv2.inRange(image, greenLower, greenUpper)
#green = cv2.GaussianBlur(green, (3, 3), 0)
cv2.imshow("green", green)
cv2.imwrite("green.jpg", green)
imglab = morphology.label(green) # create labels in segmented image
cleaned = morphology.remove_small_objects(imglab, min_size=64, connectivity=2)

img3 = np.zeros((cleaned.shape)) # create array of size cleaned
img3[cleaned > 0] = 255 
img3= np.uint8(img3)
cv2.imshow("cleaned", img3)
cv2.imwrite("cleaned.jpg", img3)
cv2.waitKey(0)

Очищенное изображение показано ниже:

Чтобы использовать morphology.remove_small_objects, необходимо сначала пометить капли. Для этого я использую imglab = morphology.label(зеленый). Маркировка выполняется следующим образом: все пиксели 1-го объекта нумеруются как 1. Аналогично, все пиксели 7-го объекта нумеруются как 7 и так далее. Таким образом, после удаления небольшой области значения пикселей оставшегося BLOB- объекта должны быть установлены на 255, чтобы cv2.imshow() мог показывать эти BLOB- объекты. Для этого я создаю массив img3 того же размера, что и очищенное изображение. Я использовал строку img3[cleaned > 0] = 255, чтобы преобразовать все пиксели, значение которых больше 0 - 255.

Кажется, то, что вы хотите удалить, - это разрозненная группа маленьких капель. Я думаю, что erode() сделает хорошую работу, удалив их с правильным ядром.

Для ядра nxn erode перемещает ядро ​​по изображению и заменяет центральный пиксель минимальным пикселем в ядре. Затем вы можете расширить () полученное изображение, чтобы восстановить размытые края зеленой части.

Другим вариантом будет использование fastndenoising

#####  option 1
kernel_size = (5,5) # should roughly have the size of the elements you want to remove
kernel_el = cv2.getStructuringElement(cv2.MORPH_RECT, kernel_size)
eroded =   cv2.erode(green, kernel_el, (-1, -1))
cleaned = cv2.dilate(eroded, kernel_el, (-1, -1))

##### option 2
cleaned = cv2.fastNlMeansDenoisingColored(green, h=10)
Другие вопросы по тегам