Обнаружение и маркировка цветовых блоков в OpenCV
У меня есть план городского изображения следующим образом:
Я хочу обнаружить цветовые блоки на изображении и пометить их различными утилитами земель, например, зеленой зоной для газона, розовой для жилой зоны, голубым для коммерческих площадей и т. Д. И, наконец, если возможно, преобразовать изображение PNG в форму файл для использования в ArcGis. Пожалуйста, поделитесь своими идеями, спасибо. Я пытался с OpenCV Canny Edge края, но все еще далеко от того, что мне нужно:
import cv2
import numpy as np
img = cv2.imread("test.png", 0)
img = cv2.GaussianBlur(img,(3,3),0)
canny = cv2.Canny(img, 50, 150)
cv2.imshow('Canny', canny)
cv2.waitKey(0)
cv2.destroyAllWindows()
2 ответа
Как говорит @Micka, ваше изображение очень легко разделить по цвету. Ниже приведен код, который делает это для темно-зеленого цвета. Вы можете легко редактировать селекторы цвета, чтобы получить другие цвета.
Обратите внимание, что в изображении присутствуют пиксельные артефакты, возможно, из-за сжатия. Текущий результат выглядит неплохо, но я надеюсь, что у вас есть доступ к полному качеству изображений - тогда результат будет наилучшим.
Изображение преобразуется в HSV-цветовое пространство ( изображение) для облегчения выбора цветов. ( openCV) findContours возвращает список, содержащий координаты вокруг границы для каждой найденной фигуры.
Я ничего не знаю о шейп-файлах, но, возможно, это может быть полезным.
Результат:
Код:
# load image
img = cv2.imread("city.png")
# add blur because of pixel artefacts
img = cv2.GaussianBlur(img, (5, 5),5)
# convert to HSV
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
# set lower and upper color limits
lower_val = (40, 100, 100)
upper_val = (60,255,200)
# Threshold the HSV image to get only green colors
mask = cv2.inRange(hsv, lower_val, upper_val)
# apply mask to original image
res = cv2.bitwise_and(img,img, mask= mask)
#show imag
cv2.imshow("Result", res)
# detect contours in image
im2, contours, hierarchy = cv2.findContours(mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
# draw filled contour on result
for cnt in contours:
cv2.drawContours(res, [cnt], 0, (0,0,255), 2)
# detect edges in mask
edges = cv2.Canny(mask,100,100)
# to save an image use cv2.imwrite('filename.png',img)
#show images
cv2.imshow("Result_with_contours", res)
cv2.imshow("Mask", mask)
cv2.imshow("Edges", edges)
cv2.waitKey(0)
cv2.destroyAllWindows()
Я работаю в Jupyter Notebook. Сначала загрузите ваше изображение:
!wget https://stackru.com/images/6bbe20c4b57fe5dad32636dfc9d21dd37c3a5b6c.png
Затем создайте массив RGBA из вашей картинки:
import numpy as np
from PIL import Image
import matplotlib.pyplot as plt
img = Image.open('SJxo3.png').convert('RGBA')
arr = np.array(img)
Мы хотим, чтобы на вашем изображении был набор разных цветов, поэтому мы создаем его:
colors=set()
for each in arr:
for EACH in each:
colors.add(tuple(EACH.tolist()))
Мы хотим зациклить эти цвета и выбрать область, в которой присутствует каждый цвет. Начнем с:
for index, each in enumerate(colors):
Теперь каждый цвет является кортежем в этом цикле for, в настоящее время это кортеж, и нам нужен список, поэтому мы делаем:
color=[]
for EACH in each:
color.append(EACH)
Теперь мы создадим массив, содержащий логические значения, True, если соответствующий компонент RGBA совпадает с цветом, который мы сейчас проверяем:
boolarr=[]
for eachinarr2 in [arr == color]:
boolarr.append(eachinarr2)
Затем мы выбираем те пиксели, которые совпадают с цветом, который мы в настоящее время проверяем, т.е. все четыре компонента RGBA совпадают (поэтому у нас один и тот же цвет). Мы храним эти пиксельные кординаты в indexx
а также INDEXX
,
featurepixels=[]
for indexx, eachh in enumerate(boolarr[0]):
for INDEXX, EACHH in enumerate(eachh):
if EACHH.all() == True:
featurepixels.append([indexx, INDEXX])
Теперь мы создаем сетку нулей:
grid = np.zeros((len(arr[0]),len(arr)))
Мы меняем значение этой сетки с полными нулями на 1 в местах, где у нас есть пиксель от определенного цвета, который мы проверяем:
for eachhh in featurepixels:
grid[eachhh[1],eachhh[0]] = 1
Затем мы создаем цветовую карту пикселей того же цвета, эффективно выбирая эту часть изображения:
plt.figure()
plt.pcolormesh(grid)
Собираем все это вместе:
!wget https://stackru.com/images/6bbe20c4b57fe5dad32636dfc9d21dd37c3a5b6c.png
import numpy as np
from PIL import Image
import matplotlib.pyplot as plt
img = Image.open('SJxo3.png').convert('RGBA')
arr = np.array(img)
colors=set()
for eachH in arr:
for eACH in eachH:
colors.add(tuple(eACH.tolist()))
for index, each in enumerate(colors):
if index < 30: # for debugging
color=[]
for EACH in each:
color.append(EACH)
boolarr=[]
for eachinarr2 in [arr == color]:
boolarr.append(eachinarr2)
featurepixels=[]
for indexx, eachh in enumerate(boolarr[0]):
for INDEXX, EACHH in enumerate(eachh):
if EACHH.all() == True:
featurepixels.append([indexx, INDEXX])
grid = np.zeros((len(arr[0]),len(arr)))
for eachhh in featurepixels:
grid[eachhh[1],eachhh[0]] = 1
plt.figure()
plt.pcolormesh(grid)
Отсюда вы можете создавать разные цветовые группы, поэтому больше пикселей будут классифицироваться как принадлежащие к одной функции. В этой текущей версии одно небольшое различие в цвете пикселя заставляет его классифицироваться как отдельная особенность. Поэтому я предлагаю создать эти цветовые группы / категории. Или используйте изображение, где количество цветов мало, и один элемент состоит только из одних и тех же цветов. Надеюсь это поможет.