pythonopencvcolor-detection

Color blocks detection and label in OpenCV


I have a urban plan picture as follows:

Urban Plans

I want to detect the color blocks in the image and label them with different lands utilities, for example, green area for lawn, pink for residence area, light blue for commercial areas, etc. and finally, if possible transform from png picture to shape file for ArcGis use. Please share your ideas, thanks. I have tried with OpenCV Canny edge detection but still far from what I need:

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

Canny edge detection


Solution

  • As @Micka says, your image is very easily separable on color. I've provided code below that does this for the dark green. You can easily edit the color selectors to get the other colors.

    Note that there are pixel artifacts in your image, probably due to compression. The current result seems fine, but I hope you have access to full quality images - then result will be best.

    The image is converted to the HSV-colorspace (image) to make selecting colors easier. (openCV) findContours returns a list that holds the coordinates around the border for every shape found.

    I know nothing of shapefiles, but maybe this could be of some use.

    Result:

    enter image description here

    Code:

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