OpenCV 中的色块检测和标签

Color blocks detection and label in OpenCV

我有一张城市规划图如下:

我想检测图像中的色块并用不同的土地用途标记它们,例如草坪的绿色区域,住宅区的粉红色,商业区的浅蓝色等,最后,如果可能的话变换从 png 图片到 ArcGis 使用的形状文件。请分享您的想法,谢谢。 我已经尝试过 OpenCV Canny 边缘检测,但仍然离我需要的还很远:

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

我在 Jupyter 笔记本中工作。首先下载你的图片:

!wget https://i.stack.imgur.com/SJxo3.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()))

我们想要遍历这些颜色和 select 每种颜色所在的区域。我们开始于:

for index, each in enumerate(colors):

现在每个颜色都是一个元组,在这个 for 循环中当前是一个元组,我们想要一个列表,所以我们这样做:

color=[]
for EACH in each:
    color.append(EACH)

我们现在创建一个包含布尔值的数组,如果相应的 RGBA 分量与我们当前正在检查的颜色相同,则为真:

boolarr=[]
for eachinarr2 in [arr == color]:
    boolarr.append(eachinarr2)

然后我们选择那些与我们当前检查的颜色相同的像素,即RGBA 的所有四个分量都匹配(所以我们有相同的颜色)。我们将这些像素坐标存储在 indexxINDEXX.

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

然后我们创建具有相同颜色的像素的颜色图,有效地 selecting 图片的那部分:

plt.figure()
plt.pcolormesh(grid)

将所有这些放在一起:

!wget https://i.stack.imgur.com/SJxo3.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)

从这里您可以创建不同的颜色组,这样更多的像素将被归类为同一特征。在当前版本中,像素颜色的微小差异会导致它被归类为一个单独的特征。所以我建议创建这些颜色 groups/categories。或者使用颜色数量较少且单个特征仅包含相同颜色的图像。希望这会有所帮助。

正如@Micka 所说,您的图像很容易在颜色上分离。我在下面提供了针对深绿色执行此操作的代码。您可以轻松编辑颜色选择器以获得其他颜色。

请注意,您的图像中存在像素瑕疵,这可能是由于压缩所致。目前的结果似乎不错,但我希望你能获得完整质量的图像——这样结果会最好。

图像转换为HSV-colorspace (image) to make selecting colors easier. (openCV) findContours returns 一个列表,其中包含找到的每个形状的边界周围的坐标。

我对 shapefile 一无所知,但也许 this 会有一些用处。

结果:

代码:

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