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

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 изображения

Образ:

enter image description here

Зеленый :

enter image description here

Чистый :

enter image description here

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

enter image description here

6
Jack Yeoh 29 Авг 2017 в 19:00

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()

Blurred filter

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

В настоящее время вы пытаетесь поместить изображение в диапазоне цветов с различной яркостью - вам нужны зеленые пиксели, независимо от того, являются ли они темными или светлыми. Это гораздо проще сделать в цветовом пространстве 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 filtering

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

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

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()

Opened mask

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

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

9
alkasm 29 Авг 2017 в 21:40

Хотя вышеупомянутая проблема решается с помощью 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)

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

enter image description here

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

1
alkasm 21 Авг 2019 в 19:20

Кажется, то, что вы хотите удалить, - это разрозненная группа маленьких капель. Я думаю, что 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)
0
ngalstyan 29 Авг 2017 в 18:16