Home > other >  How can I identify objects inside the image using python opencv?
How can I identify objects inside the image using python opencv?

Time:12-03

I'm trying to identify objects present inside the plane area as in below image for some automation

image1

for this I tried finding the contours on masked image obtained using thresholding the hsv range of object border colors which is yellowish then I did morphing operation to remove the small open lines and dilution operation to merge the area of object as shown in below code

    img = cv2.imread(img_f)
    img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    imghsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
    lower_blue = np.array([0,255,206])
    upper_blue = np.array([179,255,255])
    mask_blue = cv2.inRange(imghsv, lower_blue, upper_blue)
    kernel = np.ones((2, 2), np.uint8)
    img_erosion = cv2.erode(mask_blue, kernel, iterations=1)
    kernel = np.ones((3, 3), np.uint8)
    img_erosion = cv2.dilate(img_erosion, kernel, iterations=30)
    contours, _ = cv2.findContours(img_erosion, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
    im = np.copy(img)
    cv2.drawContours(im, contours, -1, (0,255,0), 3)

contour obtained is as shown in below image image2 and mask image is as below image3

with this approach I'm getting many unwanted detection and failing to detect many objects.

How can I able to achieve this? any suggestion or guidance will be highly appreciated ,thanks

CodePudding user response:

Not perfect but here is another possible method:

import cv2
from matplotlib import pyplot as plt
import matplotlib
import numpy as np

matplotlib.use('TkAgg')


def remove_noise(binary_image, max_noise_size=20):
    labels_count, labeled_image, stats, centroids = cv2.connectedComponentsWithStats(
        binary_image, 8, cv2.CV_32S)
    new_image = np.zeros_like(binary_image)
    for i in range(1, labels_count):
        if stats[i, -1] <= max_noise_size:
            continue
        new_image[labeled_image == i] = 255
    return new_image


def main():
    original_image = cv2.imread('BWQyx.png')

    image = np.array(original_image)
    for y in range(image.shape[0]):
        for x in range(image.shape[1]):
            # remove grey background
            if 150 <= image[y, x, 0] <= 180 and \
                    150 <= image[y, x, 1] <= 180 and \
                    150 <= image[y, x, 2] <= 180:
                image[y, x, 0] = 0
                image[y, x, 1] = 0
                image[y, x, 2] = 0

            # remove green dashes
            if image[y, x, 0] == 0 and \
                    image[y, x, 1] == 169 and \
                    image[y, x, 2] == 0:
                image[y, x, 0] = 0
                image[y, x, 1] = 0
                image[y, x, 2] = 0

    image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    image[image < 128] = 0
    image[image > 128] = 255

    image = cv2.dilate(image, np.ones((3, 3), np.uint8), iterations=2)
    image = cv2.erode(image, np.ones((3, 3), np.uint8), iterations=2)

    contours, _ = cv2.findContours(
        image, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
    cv2.drawContours(image, contours, -1, (0,), 2)

    image = remove_noise(image)

    contours, _ = cv2.findContours(
        image, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

    for contour in contours:
        min_area_rect = cv2.minAreaRect(contour)
        width, height = min_area_rect[1]
        if width * height > 20000 or width * height < 400:
            continue
        box = np.int0(cv2.boxPoints(min_area_rect))
        cv2.drawContours(original_image, [box], 0, (0, 0, 255), 2)

    plt.imshow(original_image)
    plt.show()


if __name__ == '__main__':
    main()

The main idea is to remove all the grid lines by drawing over their contours. You can tune it and achieve better results. However, I feel that it is really difficult to get everything 100% right. You will need more heuristics to remove unwanted rectangles.

  • Related