Reputation: 127
I am working on a project to click images of the tiles and using OpenCV to to find out that the tile is visit-able or not.
Accessible tile should be shown as below -
In the image below tile is not visit-able.
Code i have written is identifying multiple contours.
import numpy as np
import cv2
image1 = cv2.imread('floor3.jpg')#, cv2.IMREAD_ANYCOLOR | cv2.IMREAD_ANYDEPTH)
orig = image1.copy()
cv2.imshow("Game Boy Screen", orig)
cv2.waitKey(0)
gray = cv2.cvtColor(image1, cv2.COLOR_BGR2GRAY)
gray = cv2.bilateralFilter(gray, 11, 17, 17)
edged = cv2.Canny(gray, 30, 200)
flag, thresh = cv2.threshold(edged, 120, 255, cv2.THRESH_BINARY)
im2, contours, hierarchy = cv2.findContours(thresh,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
try: hierarchy = hierarchy[0]
except: hierarchy = []
height, width, _ = image1.shape
min_x, min_y = width, height
max_x = max_y = 0
# computes the bounding box for the contour, and draws it on the frame,
for contour, hier in zip(contours, hierarchy):
(x,y,w,h) = cv2.boundingRect(contour)
min_x, max_x = min(x, min_x), max(x+w, max_x)
min_y, max_y = min(y, min_y), max(y+h, max_y)
if w > 80 and h > 80:
cv2.rectangle(orig, (x,y), (x+w,y+h), (255, 0, 0), 2)
if max_x - min_x > 0 and max_y - min_y > 0:
cv2.rectangle(orig, (min_x, min_y), (max_x, max_y), (255, 0, 0), 3)
cv2.imshow("Game Boy Screen", orig)
cv2.waitKey(0)
Below is the output i am getting -
Original image:
Upvotes: 0
Views: 2073
Reputation: 18341
Original:
minAreaRect
other than boundingRect
to find the rotated rectangles.Update:
I don't think do findContours
on Canny edges is a good idea. I just do it on threshed binary image
, then remove the contours with small area. So we can get the boundary of regions.Then how to judge whether the region is complete or not, it's upto your math knowledge.
#!/usr/bin/python3
# 2017.12.09 00:25:47 CST
# 2017.12.09 14:26:01 CST
import cv2
import numpy as np
img = cv2.imread("test.jpg")
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
gray = cv2.bilateralFilter(gray, 11, 17, 17)
th, threshed = cv2.threshold(gray, 200, 255, cv2.THRESH_BINARY)
cnts = cv2.findContours(threshed,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)[-2]
canvas = np.zeros_like(img, np.uint8)
H,W = img.shape[:2]
AREA = H*W
for cnt in cnts:
area = cv2.contourArea(cnt)
if(area<AREA/100):
continue
_ = cv2.drawContours(canvas, [cnt], -1, (0,255,0), 1, cv2.LINE_AA)
cv2.imwrite("result.png", canvas)
Update 2: After get the contours of regions, then how to judge whether it's complete or not?
You should define what is complete? In this situation, the complete tile means it is a quadrilateral, four corner points, almost equal lengths of side. Then you program the condition to tell the computer how to judge. It's your job, you should try to solve it by yourself first.
Total code and the result:
#!/usr/bin/python3
# 2017.12.09 00:25:47 CST
# 2017.12.09 14:26:01 CST
# 2017.12.09 17:52:17 CST
import cv2
import numpy as np
## lambda: calc distance
dist = lambda pt1, pt2: ((pt1[0]-pt2[0])**2 + (pt1[1]-pt2[1])**2)**0.5
img = cv2.imread("img04.jpg")
## (1) filter, threshed
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
gray = cv2.bilateralFilter(gray, 11, 17, 17)
th, threshed = cv2.threshold(gray, 200, 255, cv2.THRESH_BINARY)
## (2) findContours
cnts = cv2.findContours(threshed,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)[-2]
## (3) some variables
H,W = img.shape[:2]
AREA = H*W
xcnts = []
R = 0.8
## (4) judge wether the contour is belongs to a complete tile
for cnt in cnts:
## (4.1) filter by area
area = cv2.contourArea(cnt)
if(area<AREA/100):
continue
## (4.2) calc arpprox contour
arclen = cv2.arcLength(cnt, closed=True)
approx = cv2.approxPolyDP(cnt, arclen*0.02, closed=True)
## (4.3) filter by "complete ruler"
## "the complete tile means it is a quadrilateral, four corner points, almost equal lengths of side"
pts = np.array(approx).reshape(-1,2)
if len(pts) == 4:
lens = np.array(list(dist(pts[i], pts[(i+1)%4]) for i in range(4)))
flag = True
for x in lens:
if not (R< x/lens[0] < 1.0/R):
flag = False
continue
if flag:
xcnts.append(cnt)
## (5) draw and save
res = img.copy()
for cnt in xcnts:
cv2.drawContours(res, [cnt], -1, (0,255,0), -1, cv2.LINE_AA)
cv2.imwrite("00result.png", res)
Update 3 (The last update):
I use the fixed threshed value in the my code just because your image contains a large dark origin. As for this image
there is no large dark, so change the threshold flag to cv2.THRESH_OTSU
, and modify the area thresh to AREA/20
or larger, modify the R smaller such as R=0.7
.
Then I get the result:
Similar questions:
(1) How to find the object on the noisy background?
Upvotes: 2