'How can i find selected area in photo using OpenCV?

I need to detect a selected area in a photo:

enter image description here

Original photo:

enter image description here

I used this code:

import cv2 as cv
import numpy as np
img = cv.imread(cv.samples.findFile('./Pictures/GreenPool720.png',))

gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY)
edges = cv.Canny(gray,50,150,apertureSize = 3)
lines = cv.HoughLinesP(edges,1,np.pi/180,100,minLineLength=1, maxLineGap=30)
for line in lines:
    x1,y1,x2,y2 = line[0]
    cv.line(img,(x1,y1),(x2,y2),(0,255,0),2)
cv.imshow('1', img)
cv.waitKey()

And got this photo:

enter image description here

Please tell me what to do so that I get the right photo



Solution 1:[1]

Basic Idea

The green color is pretty distinct in the image and can be segmented using a different color space. Here we use the LAB color space to segment the green from the a-component. The a-component represents color variation between red and green making easy to isolate either color. More on this here

Once the green board is segmented you can follow your approach.

Approach:

  • Segmenting green pool board:
    • Perform Otsu Threshold on a-component
    • Find the largest contour and create a mask out of it
    • Capture the region of interest (green board)
  • Edge detection using Canny algorithm
  • Line detection using Hough transform
  • Post processing to filter out unwanted lines

Code:

img = cv2.imread('image_path')
# creating a duplicate copy
img2 = img.copy()        
lab = cv2.cvtColor(img, cv2.COLOR_BGR2LAB)
a_comp = lab[:,:,1]
# Otsu Threshold on a-channel
th = cv2.threshold(a_comp,127,255,cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)[1]

# Finding the contour with maximum area and create a mask
contours, hierarchy = cv2.findContours(th, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
c = max(contours, key = cv2.contourArea)
black = np.zeros((img.shape[0], img.shape[1]), np.uint8)
mask = cv2.drawContours(black,[c],0,255, -1)

enter image description here

# Mask out the green board
anded = cv2.bitwise_and(img, img, mask = mask)

enter image description here

# Following the approach as above
gray = cv2.cvtColor(anded,cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(gray,50,150,apertureSize = 3)
lines = cv2.HoughLinesP(edges,1,np.pi/180,100,minLineLength=1, maxLineGap=30)
for line in lines:
    x1,y1,x2,y2 = line[0]
    cv2.line(img2,(x1,y1),(x2,y2),(0,255,0),2)

enter image description here

# to avoid the lines detected on the edge of the board, perform erosion on the mask
kernel_ellipse = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5,5))
erode = cv2.erode(mask, kernel_ellipse, iterations=1)
fin = cv2.bitwise_and(img2, img2, mask = erode) 

enter image description here

fin2 = fin.copy()
fin2[erode[:] == 0,...] = img[erode[:] == 0,...]

In the above, assign pixel values from the original image where the mask (erode) has black pixels:

enter image description here

You can tweak the parameters of cv2.HoughLinesP() to get better results

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1