Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Opencv rectangle detection on noisy image

One question, is it possible to dectect rectangle on image when it touch noise lines and other shapes This is my function to detect contoures on image:

def findContours(img_in):
w, h, c = img_in.shape  # img_in is the input image
resize_coeff = 0.25
img_in = cv2.resize(img_in,(int(resize_coeff * h), int(resize_coeff * w)))
img_in = ip.findObjects(img_in)




blr = cv2.GaussianBlur(img_in, (9, 9), 0)
img = cv2.Canny(blr, 50, 250, L2gradient=False)

kernel = np.ones((5, 5), np.uint8)
img_dilate = cv2.dilate(img, kernel, iterations=1)
img = cv2.erode(img_dilate, kernel, iterations=1)
contours, hierarchy = cv2.findContours(img, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
max_index, max_area = max(enumerate([cv2.contourArea(x) for x in contours]), key=lambda x: x[1])
max_contour = contours[max_index]
img_out = cv2.resize(img, (int(resize_coeff * h), int(resize_coeff * w)))
cv2.drawContours(img_in, [max_contour], 0, (0, 0, 255), 2)
re.rectangle(img, [max_contour])
cv2.imshow("test",img_in)
cv2.imshow("test1",img)

cv2.waitKey()
return img

I got this result: enter image description here

The result I want: enter image description here

When I use shape detecion I got result that it have 15 angles and not four. Function:

def rectangle(img, contours):
for contour in contours:
    approx = cv2.approxPolyDP(contour, 0.01 * cv2.arcLength(contour, True), True)
    print(len(approx))
    x = approx.ravel()[0]
    y = approx.ravel()[1] - 5

    if len(approx) == 4:
        print("Rect")
        x, y, w, h = cv2.boundingRect(approx)
        aspectRatio = float(w) / h
        print(aspectRatio)
        cv2.putText(img, "rectangle", (x, y), cv2.FONT_HERSHEY_COMPLEX, 0.5, (0, 0, 0))

EDIT: Original image: enter image description here

like image 525
jan Avatar asked Jan 20 '26 21:01

jan


1 Answers

What if you can remove noise around that shape? I think your mask is good for more processing:

import numpy as np
import sys
import cv2

# Load the mask
dir = sys.path[0]
im = cv2.imread(dir+'/img.png')
H, W = im.shape[:2]

# Make gray scale image
gry = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)

# Make binary image
bw = cv2.threshold(gry, 127, 255, cv2.THRESH_BINARY)[1]
bw = ~bw

# Focuse on edges
bw = cv2.erode(bw, np.ones((5, 5)))

# Use flood fill to remove noise
cv2.floodFill(bw, np.zeros((H+2, W+2), np.uint8), (0, 0), 0)
bw = cv2.medianBlur(bw, 7)

# Remove remained noise with another flood fill
nonRectArea = bw.copy()
cv2.floodFill(nonRectArea, np.zeros((H+2, W+2), np.uint8), (W//2, H//2), 0)
bw[np.where(nonRectArea == 255)] = 0

# Find contours and sort them by width
cnts, _ = cv2.findContours(bw, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
cnts.sort(key=lambda p: cv2.boundingRect(p)[2], reverse=True)

# Find biggest blob
x, y, w, h = cv2.boundingRect(cnts[0])
cv2.rectangle(im, (x, y), (x+w, y+h), 127, 1)

# Save output
cv2.imwrite(dir+'/img_1.png', im)
cv2.imwrite(dir+'/img_2.png', bw)
cv2.imwrite(dir+'/img_3.png', nonRectArea)

enter image description here

like image 84
Shamshirsaz.Navid Avatar answered Jan 22 '26 10:01

Shamshirsaz.Navid