https://habr.com/ru/post/458138/- Python
- Программирование
- Data Mining
- Машинное обучение
Привет!
Данная статья по дефолту подразумевает, что у вас уже есть Jupyter Notebook или IDE, с помощью которых можно запускать установленные Python и OpenCV.
Несколько важных понятий
Контуры
Контуром называется кривая, которая объединяет все непрерывные точки (по границе) одного цвета или интенсивности. Контуры являются весьма полезными инструментами для анализа форм, обнаружения и распознавания объектов.
Пороговые значения
Пороговая обработка полутонового изображения (в оттенках серого) превращает его в бинарное. Вы задаете некое пороговое значение, и все значения ниже порога становятся черными, а выше — белыми.
Выполнение
Теперь у вас есть все необходимое для работы. Знакомство с цветовой сегментацией мы начнем с простого примера. Наберитесь терпения, скоро начнется самое интересное.
Круг Омбре
Если захотите повторить все самостоятельно, то скачайте картинку
здесь.
В коде ниже я поделю данное изображение на 17 уровней серого. Затем измерю площадь каждого уровня с помощью оконтуривания.
import cv2
import numpy as np
def viewImage(image):
cv2.namedWindow('Display', cv2.WINDOW_NORMAL)
cv2.imshow('Display', image)
cv2.waitKey(0)
cv2.destroyAllWindows()
def grayscale_17_levels (image):
high = 255
while(1):
low = high - 15
col_to_be_changed_low = np.array([low])
col_to_be_changed_high = np.array([high])
curr_mask = cv2.inRange(gray, col_to_be_changed_low,col_to_be_changed_high)
gray[curr_mask > 0] = (high)
high -= 15
if(low == 0 ):
break
image = cv2.imread('./path/to/image')
viewImage(image)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
grayscale_17_levels(gray)
viewImage(gray)
Это же изображение, разделенное на 17 уровней серого
def get_area_of_each_gray_level(im):
## convert image to gray scale (must br done before contouring)
image = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
output = []
high = 255
first = True
while(1):
low = high - 15
if(first == False):
# making values that are of a greater gray level black
## so it won't get detected
to_be_black_again_low = np.array([high])
to_be_black_again_high = np.array([255])
curr_mask = cv2.inRange(image, to_be_black_again_low,
to_be_black_again_high)
image[curr_mask > 0] = (0)
# making values of this gray level white so we can calculate
# it's area
ret, threshold = cv2.threshold(image, low, 255, 0)
contours, hirerchy = cv2.findContours(threshold,
cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE)
if(len(contours) > 0):
output.append([cv2.contourArea(contours[0])])
cv2.drawContours(im, contours, -1, (0,0,255), 3)
high -= 15
first = False
if(low == 0 ):
break
return output
В этой функции я выполняю преобразование шкалы (интенсивности) серого, которую планирую оконтурить (выделить). Для этого я задаю одинаковое значение интенсивности всем уровням, находящимся в диапазоне данной шкалы. Остальная интенсивность (меньшая и большая) становится черной.
Второй шаг — это пороговая обработка изображения. Она делается для того, чтобы цвет, который я сейчас буду оконтуривать, стал белым, а все остальные части окрасились в черный. Этот шаг мало что меняет, но выполнение его обязательно, поскольку лучше всего оконтуривание работает на черно-белых (пороговых) изображениях.
До выполнения пороговой обработки наше изображение будет выглядеть так же, с той лишь разницей, что белое кольцо окрашено серым (интенсивность серого из 10-го уровня (255–15*10))
Показывается только 10–й сегмент для расчета его площади
image = cv2.imread('./path/to/image')
print(get_area_of_each_gray_level(image))
viewImage(image)
Контуры 17 уровней серого в исходном изображении
Массив со значениями площадей
Так мы получаем площади каждого уровня серого. Перед тем, как продолжить, я хочу подчеркнуть всю важность данного этапа.
Я — учусь на факультете компьютерной инженерии и работаю над проектом под названием «Машинное обучения для умного обнаружения и идентификации опухолей».
Цветовая сегментация изображений нужна для того, чтобы научить компьютер обнаружению опухолей. Получая МРТ снимок, программа должна определить по нему стадию развития рака. Это делается путем разделения снимка на различные полутоновые уровни, в которых самые темные области заполнены раковыми клетками, а белые — здоровыми. Затем программа рассчитывает степень принадлежности каждого полутонового уровня к раковой опухоли. Благодаря этой информации программа может не только обнаружить опухоль, но и определить её стадию.
Данный проект основан на мягких вычислениях, нечеткой логике и машинном обучении.
Обнаружение объектов
Скачайте изображение
здесь. Только обрежьте его.
Здесь мы будем оконтуривать листок. Текстура изображения неровная и неоднородная. Несмотря на то, что на картинке не так много цветов, интенсивность зеленого также меняет и его яркость. Поэтому правильнее всего будет унифицировать зеленый цвет и свести его к одному оттенку. Тогда при оконтуривании лист будет рассматриваться единым объектом.
Примечание: ниже представлен результат оконтуривания без предварительной обработки изображения. Я хочу показать вам, как неравномерная структура листа мешает OpenCV понять, что на картинке изображен один объект.
Оконтуривание без предварительной обработки. Обнаружен 531 контур
import cv2
import numpy as np
def viewImage(image):
cv2.namedWindow('Display', cv2.WINDOW_NORMAL)
cv2.imshow('Display', image)
cv2.waitKey(0)
cv2.destroyAllWindows()
Для начала необходимо определить HSV-представление цвета. Это можно сделать путем преобразования его RGB в HSV:
## getting green HSV color representation
green = np.uint8([[[0, 255, 0 ]]])
green_hsv = cv2.cvtColor(green,cv2.COLOR_BGR2HSV)
print( green_hsv)
Зеленый HSV цвет
Конвертация изображения в HSV. С HSV проще получить полный диапазон одного цвета. H здесь означает Hue (тон), S — Saturation (насыщенность), а V — Value (значение). Мы уже знаем, что зеленый цвет — это [60, 255, 255]. Весь зеленый цвет в мире находится в диапазоне с [45, 100, 50] по [75, 255, 255], то есть с [60–15, 100, 50] по [60+15, 255, 255]. 15 — это примерное значение.
Мы берем этот диапазон и превращаем его в [75, 255, 200] или любой другой светлый цвет (третье значение должно быть сравнительно большим). Последняя цифра представляет собой яркость цвета — как раз та величина, которая «покрасит» данную область в белый после порогового преобразования изображения.
image = cv2.imread('./path/to/image.jpg')
hsv_img = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
viewImage(hsv_img) ## 1
green_low = np.array([45 , 100, 50] )
green_high = np.array([75, 255, 255])
curr_mask = cv2.inRange(hsv_img, green_low, green_high)
hsv_img[curr_mask > 0] = ([75,255,200])
viewImage(hsv_img) ## 2
## converting the HSV image to Gray inorder to be able to apply
## contouring
RGB_again = cv2.cvtColor(hsv_img, cv2.COLOR_HSV2RGB)
gray = cv2.cvtColor(RGB_again, cv2.COLOR_RGB2GRAY)
viewImage(gray) ## 3
ret, threshold = cv2.threshold(gray, 90, 255, 0)
viewImage(threshold) ## 4
contours, hierarchy = cv2.findContours(threshold,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
cv2.drawContours(image, contours, -1, (0, 0, 255), 3)
viewImage(image) ## 5
Слева: изображение после конвертации в HSV (1), справа: изображение после наложения маски для унификации цвета (2)
Слева: изображение после преобразования HSV к оттенкам серого (3), справа: пороговое изображение, последний этап (4)
Конечное оконтуривание (5)
На заднем плане все еще заметна неоднородность. С этим методом мы создадим самый крупный контур, и это — конечно же, лист. Индекс контура листа можно получить из массива contours. Оттуда же берем площадь и центр листа.
Контуры обладают и другими признаками, которые можно использовать в работе: периметр контура, выпуклая оболочка, ограничивающий прямоугольник и т.д.
Здесь все описано подробнее.
def findGreatesContour(contours):
largest_area = 0
largest_contour_index = -1
i = 0
total_contours = len(contours)
while (i < total_contours ):
area = cv2.contourArea(contours[i])
if(area > largest_area):
largest_area = area
largest_contour_index = i
i+=1
return largest_area, largest_contour_index
# to get the center of the contour
cnt = contours[13]
M = cv2.moments(cnt)
cX = int(M["m10"] / M["m00"])
cY = int(M["m01"] / M["m00"])
largest_area, largest_contour_index = findGreatesContour(contours)
print(largest_area)
print(largest_contour_index)
print(len(contours))
print(cX)
print(cY)
Результат вывода операторов
В конечном итоге получаем результат вывода операторов. Больше подобных статей можно читать в
телеграм-канале Нейрон (@neurondata)
Всем знаний!