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 的所有四个分量都匹配(所以我们有相同的颜色)。我们将这些像素坐标存储在 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
然后我们创建具有相同颜色的像素的颜色图,有效地 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()
我有一张城市规划图如下:
我想检测图像中的色块并用不同的土地用途标记它们,例如草坪的绿色区域,住宅区的粉红色,商业区的浅蓝色等,最后,如果可能的话变换从 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 的所有四个分量都匹配(所以我们有相同的颜色)。我们将这些像素坐标存储在 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
然后我们创建具有相同颜色的像素的颜色图,有效地 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()