I have an image like following, I want to find four coordinate (corners) from this image.
I have tried with below code:
# dilate thresholded image - merges top/bottom
kernel = np.ones((3,3), np.uint8)
dilated = cv2.dilate(img, kernel, iterations=3)
# Finding contours for the thresholded image
contours, hierarchy = cv2.findContours(img, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
First, I dilated the image so that it fill up the scatter portion and tried to find out contours from there. But it gives me wrong output. What I can do this for finding out four corner coordinates?
CodePudding user response:
I have found your points by putting a regression line threw each of your sides and taking their interception points.
First I import stuff and find the contour points with open cv.
import numpy as np
import cv2
import matplotlib.pyplot as plt
from scipy.stats import linregress
from sympy import solve, symbols
import itertools
img = cv2.imread('ZrSqG.png')
img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
threshold, binarized_img = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY cv2.THRESH_OTSU)
contours, hierarchy = cv2.findContours(binarized_img, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
contours = (contours[1].reshape(-1,2)).T
Now I get a few of the top most, left most etc. points and put a line threw them. Then I calculate their interceptions and plot it all.
def interpolate_function(x,y):
line = interpolate(x,y)
return lambda x: x*line.slope line.intercept
def interpolate(x,y):
idx = np.argsort(x)
line = linregress(x[idx], y[idx])
return line
def interception(line1, line2):
x = symbols('x')
x = solve(x*line1.slope line1.intercept-(x*line2.slope line2.intercept))[0]
return (x,x*line1[0] line1[1])
idx_x = np.argsort(contours[0])
idx_y = np.argsort(contours[1])
left = [contours[0][idx_x[:30]], contours[1][idx_x[:30]]]
right = contours[0][idx_x[-10:]], contours[1][idx_x[-10:]]
top = contours[0][idx_y[:10]], contours[1][idx_y[:10]]
bottom = contours[0][idx_y[-30:]], contours[1][idx_y[-30:]]
contour_functions = [interpolate_function(*left), interpolate_function(*right),interpolate_function(*top), interpolate_function(*bottom)]
contour_function_eqs = [[interpolate(*left), interpolate(*right)],
[interpolate(*top), interpolate(*bottom)]]
for f in contour_functions:
t = np.linspace(0, img.shape[1], 10**4)
t = t[(0 < f(t)) & (f(t) < img.shape[0])]
plt.plot(t,f(t))
itersections = np.array([interception(line1, line2)
for line1, line2 in itertools.product(contour_function_eqs[0], contour_function_eqs[1])])
plt.scatter(itersections[:,0], itersections[:,1])
plt.imshow(img, cmap='gray')
Or if you prefer to follow the bottom left part you just reduce the points in the bottom by replaying
bottom = contours[0][idx_y[-30:]], contours[1][idx_y[-30:]]
with
bottom = contours[0][idx_y[-10:]], contours[1][idx_y[-10:]]