Обнаружение и маркировка цветовых блоков в 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)

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

Другие вопросы по тегам