I'm trying to identify objects present inside the plane area as in below image for some automation
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.