Вы можете выполнить следующие шаги обработки:
- Пороговое изображение для двоичного изображения, используя
cv2.threshold
.
Это не обязательно, но в вашем случае это выглядит как оттенки серого не важный. - Используйте морфологическую операцию для закрытия небольших пробелов в двоичном изображении.
- Используйте
cv2.findContours
с параметром cv2.RETR_EXTERNAL
, чтобы получить контуры (периметр), окружающие белые скопления. - Измените лог c "плохого контура", чтобы он возвращал значение true, только если область большая (при условии, что вы хотите очистить только три больших контура).
Вот обновленный код:
### LOAD MODULES ###
import numpy as np
import imutils
import cv2
def is_contour_bad(c): # Decide what I want to find and its features
peri = cv2.contourArea(c) # Find areas
return peri > 50 # Large area is considered "bad"
### DATA PROCESSING ###
image = cv2.imread("025.jpg") # Load a picture
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) # Convert to grayscale
# Convert to binary image (all values above 20 are converted to 1 and below to 0)
ret, thresh_gray = cv2.threshold(gray, 20, 255, cv2.THRESH_BINARY)
# Use "close" morphological operation to close the gaps between contours
# https://stackoverflow.com/questions/18339988/implementing-imcloseim-se-in-opencv
thresh_gray = cv2.morphologyEx(thresh_gray, cv2.MORPH_CLOSE, cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5,5)));
#Find contours on thresh_gray, use cv2.RETR_EXTERNAL to get external perimeter
_, cnts, _ = cv2.findContours(thresh_gray, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE) # Find contours: a curve joining all the continuous points (along the boundary), having same color or intensity
image_cleaned = gray
# Loop over the detected contours
for c in cnts:
# If the contour satisfies "is_contour_bad", draw it on the mask
if is_contour_bad(c):
# Draw black contour on gray image, instead of using a mask
cv2.drawContours(image_cleaned, [c], -1, 0, -1)
#cv2.imshow("Adopted mask", mask) # Plot
cv2.imshow("Cleaned image", image_cleaned) # Plot
cv2.imwrite("cleaned_025.jpg", image_cleaned) # Write in a file
cv2.waitKey(0)
cv2.destroyAllWindows()
Результат:
Контуры разметки, найденные для тестирования:
for c in cnts:
if is_contour_bad(c):
# Draw green line for marking the contour
cv2.drawContours(image, [c], 0, (0, 255, 0), 1)
Результат:
Работа еще не завершена ...
Обновление
Подход с двумя итерациями:
- Первая итерация - удалить большой контур.
- Вторая итерация - удалить небольшие, но яркие контуры.
Вот код:
import numpy as np
import imutils
import cv2
def is_contour_bad(c, thrs): # Decide what I want to find and its features
peri = cv2.contourArea(c) # Find areas
return peri > thrs # Large area is considered "bad"
image = cv2.imread("025.jpg") # Load a picture
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) # Convert to grayscale
# First iteration - remove the large contour
###########################################################################
# Convert to binary image (all values above 20 are converted to 1 and below to 0)
ret, thresh_gray = cv2.threshold(gray, 20, 255, cv2.THRESH_BINARY)
# Use "close" morphological operation to close the gaps between contours
# https://stackoverflow.com/questions/18339988/implementing-imcloseim-se-in-opencv
thresh_gray = cv2.morphologyEx(thresh_gray, cv2.MORPH_CLOSE, cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5,5)));
#Find contours on thresh_gray, use cv2.RETR_EXTERNAL to get external perimeter
_, cnts, _ = cv2.findContours(thresh_gray, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE) # Find contours: a curve joining all the continuous points (along the boundary), having same color or intensity
image_cleaned = gray
# Loop over the detected contours
for c in cnts:
# If the contour satisfies "is_contour_bad", draw it on the mask
if is_contour_bad(c, 1000):
# Draw black contour on gray image, instead of using a mask
cv2.drawContours(image_cleaned, [c], -1, 0, -1)
###########################################################################
# Second iteration - remove small but bright contours
###########################################################################
# In the second iteration, use high threshold
ret, thresh_gray = cv2.threshold(image_cleaned, 150, 255, cv2.THRESH_BINARY)
# Use "dilate" with small radius
thresh_gray = cv2.morphologyEx(thresh_gray, cv2.MORPH_DILATE, cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (2,2)));
#Find contours on thresh_gray, use cv2.RETR_EXTERNAL to get external perimeter
_, cnts, _ = cv2.findContours(thresh_gray, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE) # Find contours: a curve joining all the continuous points (along the boundary), having same color or intensity
# Loop over the detected contours
for c in cnts:
# If the contour satisfies "is_contour_bad", draw it on the mask
# Remove contour if area is above 20 pixels
if is_contour_bad(c, 20):
# Draw black contour on gray image, instead of using a mask
cv2.drawContours(image_cleaned, [c], -1, 0, -1)
###########################################################################
Отмеченные контуры: