Danila Gorelko
Danila Gorelko

Reputation: 40

how to correctly select the outline of the board in opencv?

I'm trying to determine the boundaries of the chessboard (they are bounded by a black bar) enter image description here

I do the following

    img = cv2.imread(filename)
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
    cv2.imwrite("gray.jpg", gray)

enter image description here

    thresh = cv2.inRange(gray, hsv_min, hsv_max)

    kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (7, 7))
    thresh = cv2.dilate(thresh, kernel, iterations = 1)
    thresh = cv2.erode(thresh, None, iterations = 4)

enter image description here

and there's no way I can get a better result, after

contours0, hierarchy = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    for cnt in contours0:
        rect = cv2.minAreaRect(cnt)
        box = cv2.boxPoints(rect)
        box = np.int0(box) 
        cv2.drawContours(img, [box], -1, (255, 0, 0), 0)

    cv2.imshow('contours', img)

enter image description here can someone help me?

Upvotes: 1

Views: 1656

Answers (1)

fmw42
fmw42

Reputation: 53119

Here is one way to do that in Python OpenCV. Basically, threshold the image. Apply some morphology. Get the external contours. Then draw the largest ones above some threshold in perimeter on a black background. The important aspect is that you get the 4 corners included. Then get the convex hull and draw that as the boundary.

Input:

enter image description here

import cv2
import numpy as np

# read image
img = cv2.imread('chess.jpg')

# convert to grayscale
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

# threshold to binary
thresh = cv2.threshold(gray, 25, 255, cv2.THRESH_BINARY)[1]

# apply morphology
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (9,9))
morph = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel)
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3,1))
morph = cv2.morphologyEx(morph, cv2.MORPH_CLOSE, kernel)

# invert morph
morph = 255 - morph

# get external contours
cnts = cv2.findContours(morph, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]

# draw white contour on black background
cntr_img = np.zeros_like(morph)
for c in cnts:
    perimeter = cv2.arcLength(c, True)
    if perimeter > 200: 
        cv2.drawContours(cntr_img, [c], 0, 255, 1)

# get all non-zero points
points = np.column_stack(np.where(cntr_img.transpose() > 0))
hull = cv2.convexHull(points)

# draw convex hull vertices on input image
result = img.copy()
cv2.polylines(result, [hull], True, (0,0,255), 2)

# save results
cv2.imwrite('chess_threshold.jpg', thresh)
cv2.imwrite('chess_morph.jpg', morph)
cv2.imwrite('chess_contour.jpg', cntr_img)
cv2.imwrite('chess_convexhull.jpg', result)

# show results
cv2.imshow('thresh', thresh)
cv2.imshow('morph', morph)
cv2.imshow('cntr_img', cntr_img)
cv2.imshow('result', result)
cv2.waitKey(0)
cv2.destroyAllWindows()

Threshold Image:

enter image description here

Morphology Image:

enter image description here

Contour Image:

enter image description here

Resulting Convex Hull on copy of Input:

enter image description here

Upvotes: 5

Related Questions