Для вашего конкретного изображения я получил довольно хорошие результаты с простой установкой порога на синем канале.
image = cv2.imread("test.png")
t, img = cv2.threshold(image[:,:,0], 80, 255, cv2.THRESH_BINARY)
![enter image description here](https://i.stack.imgur.com/VuBmNs.png)
Чтобы адаптировать порог, я предлагаю простой способ изменения порога, пока вы не получите один компонент. Я также реализовал рисование прямоугольника:
def find_square(image):
markers = 0
threshold = 10
while np.amax(markers) == 0:
threshold += 5
t, img = cv2.threshold(image[:,:,0], threshold, 255, cv2.THRESH_BINARY_INV)
_, markers = cv2.connectedComponents(img)
kernel = np.ones((5,5),np.uint8)
img = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel)
img = cv2.morphologyEx(img, cv2.MORPH_DILATE, kernel)
nonzero = cv2.findNonZero(img)
x, y, w, h = cv2.boundingRect(nonzero)
cv2.rectangle(image, (x, y), (x+w, y+h), (0, 255, 0), 2)
cv2.imshow("image", image)
А результаты на предоставленных примерах изображений:
![enter image description here](https://i.stack.imgur.com/BleNLm.png)
Идея этого подхода основана на наблюдении, что большая часть информации находится в синем канале. Если вы разделите изображения в каналах, вы увидите, что в синем канале темный квадрат имеет наилучшую контрастность. Это также самая темная область на этом канале, поэтому порог работает. Проблема остается в настройке порога. Основываясь на вышеизложенной интуиции, мы ищем самый низкий порог, который будет что-то вызывать (и надеемся, что это будет квадрат). Я просто постепенно увеличивал порог, пока что-то не появилось.
Затем я применил некоторые морфологические операции, чтобы убрать другие маленькие точки, которые могут появиться после установки порога, и чтобы квадрат выглядел немного больше (края квадрата светлее, и поэтому захватывается не весь квадрат). Тогда нужно было нарисовать прямоугольник.
Код можно сделать намного лучше (и эффективнее), выполнив некоторый статистический анализ гистограммы. Просто вычислите порог так, чтобы 5% (или несколько процентов) пикселей были темнее. Вам может потребоваться выполнить анализ связанных компонентов, чтобы сохранить самый большой двоичный объект.
Кроме того, мое использование подключенных компонентов очень плохое и неэффективное. Опять же, код написан на скорую руку, чтобы доказать концепцию.