简体   繁体   中英

extract pattern from image via python opencv

I have a bunch of images like this. 源图像

as we can see from the image, there are two kinds of buildings, the first ones are filled with solid color and the second ones are filled with slashes.

I marked the first kind with green and the second kind with red.

两种建筑

I think I can extract buildings of the first style with just color masks, but what about the second kind?

I know I might reach the goal by training an image segmentation model, but is it possible to use a pure image processing method to get it?

I'm thresholding the image based off of color and then using findContours to get each individual building. Then I'm sorting them by size into either "big building" or "small building" depending on if they're bigger or smaller than the "cutoff" value.

cutoff = 2000

在此处输入图像描述

cutoff = 4000

在此处输入图像描述

cutoff = 6000

在此处输入图像描述

Here's the code I used. You need to press 'q' to move past the first window (it's for clicking on the image to get the color). You can change the building split by modifying the cutoff variable.

import cv2
import numpy as np

# get pixel value under mouse
def clicky(event, x, y, flags, params):
    if event == cv2.EVENT_LBUTTONUP:
        global img;
        print(img[y][x]);

# load image
img = cv2.imread("town.png");

# find values
cv2.namedWindow("Original");
cv2.setMouseCallback("Original", clicky);
while True:
    cv2.imshow("Original", img);
    if cv2.waitKey(1) == ord('q'):
        break;

# threshold values
# [232 232 238]
mask = cv2.inRange(img, (232, 232, 238), (232, 232, 238));

# erode to get some seperation
kernel = np.ones((3,3),np.uint8)
mask = cv2.erode(mask,kernel,iterations = 1);

# get contours 
# Opencv 3.4, if using a different major version (4.0 or 2.0), remove the first underscore
_, contours, _ = cv2.findContours(mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE);

# filter by size
cutoff = 6000; # change this to change how they are classified
big_contours = [];
small_contours = [];
for contour in contours:
    area = cv2.contourArea(contour);
    if area > cutoff: 
        big_contours.append(contour);
    else:
        small_contours.append(contour);

# draw contours on mask
colored_mask = np.zeros_like(img);
cv2.drawContours(colored_mask, big_contours, -1, (155, 200, 0), -1);
cv2.drawContours(colored_mask, small_contours, -1, (0, 155, 200), -1);

# show
cv2.imshow("town", img);
cv2.imshow("mask", mask);
cv2.imshow("colored_mask", colored_mask);
cv2.waitKey(0);

Edit:

Here's some code for finding the "thin lines" buildings. This method of segmenting by specific color is kinda janky though, especially for these buildings since they don't have one single color.

在此处输入图像描述

import cv2
import numpy as np

# get pixel value under mouse
def clicky(event, x, y, flags, params):
    if event == cv2.EVENT_LBUTTONUP:
        global img;
        print(img[y][x]);

# load image
img = cv2.imread("town.png");

# find color values
cv2.namedWindow("Original");
cv2.setMouseCallback("Original", clicky);
while True:
    cv2.imshow("Original", img);
    if cv2.waitKey(1) == ord('q'):
        break;

# set color values
colors = [];
colors.append((227, 228, 228));
colors.append((248, 251, 251));
colors.append((229, 241, 238));
colors.append((240, 242, 242));
colors.append((234, 236, 238));

# threshold values
mask = np.zeros_like(img[:,:,0]);
for color in colors:
    next_mask = cv2.inRange(img, color, color);
    mask = cv2.bitwise_or(mask, next_mask);

# dilate and erode
kernel = np.ones((3,3),np.uint8);
mask = cv2.dilate(mask, kernel, iterations = 5);
mask = cv2.erode(mask, kernel, iterations = 5);

# colored
img[mask == 255] = (155, 200, 0);

# show
cv2.imshow("town", img);
cv2.imshow("mask", mask);
cv2.waitKey(0);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM