Python решение, основанное на ответе Юнуса Темурленка. Сначала применили пороговое значение Otsu, обнаружение острых краев и расширение, чтобы получить хороший контур. Затем самый большой контур выделяется по площади, а четыре точки выделяются на основе минимального прямоугольника области.
Этот код также будет работать без шага dilation
на этом изображении. В этом случае контур будет плотнее прилегать к прямоугольнику.
Код:
## Press ESC button to get next image
import cv2
import cv2 as cv
import numpy as np
#frame = cv2.imread('resources/pstr1.png')
frame = cv2.imread('resources/pstr2.png')
## keeping a copy of original
print(frame.shape)
original_frame = frame.copy()
## Show the original image
winName = 'Original'
cv.namedWindow(winName, cv.WINDOW_NORMAL)
cv.resizeWindow(winName, 800, 800)
cv.imshow(winName, original_frame)
cv.waitKey(0)
# Otsu's thresholding
grayimg = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
ret2,thresh_n = cv.threshold(grayimg,0,255,cv.THRESH_BINARY+cv.THRESH_OTSU)
thresh_n = cv2.cvtColor(thresh_n, cv2.COLOR_GRAY2BGR)
frame = thresh_n
## edge detection
frame = cv2.Canny(frame,100,200)
## dilate the edges
kernel = np.ones((5,5),np.uint8)
frame = cv2.dilate(frame,kernel,iterations = 1)
## Get largest contour from contours
contours, hierarchy = cv2.findContours(frame, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
## Get minimum area rectangle and corner points
rect = cv2.minAreaRect(max(contours, key = cv2.contourArea))
box = cv2.boxPoints(rect)
print(box)
## draw anchor points on corner
z = 6
for b in box:
cv2.circle(original_frame, tuple(b), z, 255, -1)
## show original image with corners
box2 = np.int0(box)
cv2.drawContours(original_frame,[box2],0,(0,0,255), 2)
cv2.imshow('Detected Corners',original_frame)
cv2.waitKey(0)
cv2.destroyAllWindows()
Исходное изображение:
![enter image description here](https://i.stack.imgur.com/KrAyG.png)
Выходное изображение:
![enter image description here](https://i.stack.imgur.com/16tHC.png)