{"id":338271,"date":"2022-09-12T21:00:30","date_gmt":"2022-09-12T21:00:30","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=338271"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=338271","title":{"rendered":"<span>\u0423\u0440\u043e\u043a\u0438 \u043a\u043e\u043c\u043f\u044c\u044e\u0442\u0435\u0440\u043d\u043e\u0433\u043e \u0437\u0440\u0435\u043d\u0438\u044f \u043d\u0430 Python + OpenCV \u0441 \u0441\u0430\u043c\u044b\u0445 \u0430\u0437\u043e\u0432. \u0427\u0430\u0441\u0442\u044c 8<\/span>"},"content":{"rendered":"<div><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u041d\u0430 <a href=\"https:\/\/habr.com\/ru\/post\/676838\/\" rel=\"noopener noreferrer nofollow\">\u043f\u0440\u043e\u0448\u043b\u043e\u043c \u0443\u0440\u043e\u043a\u0435<\/a> \u043c\u044b \u0443\u0433\u043b\u0443\u0431\u0438\u043b\u0438\u0441\u044c \u0432 \u0438\u0437\u0443\u0447\u0435\u043d\u0438\u0435 \u043a\u043e\u043d\u0442\u0443\u0440\u043e\u0432. \u0412 \u0447\u0430\u0441\u0442\u043d\u043e\u0441\u0442\u0438, \u043d\u0430\u0443\u0447\u0438\u043b\u0438\u0441\u044c \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0441\u043e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u043e\u0439, \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u0432\u044b\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u043a\u043e\u043d\u0442\u0443\u0440\u043e\u0432, \u043d\u0430\u0443\u0447\u0438\u043b\u0438\u0441\u044c \u0430\u043f\u043f\u0440\u043e\u043a\u0441\u0438\u043c\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0438 \u043e\u0431\u0445\u043e\u0434\u0438\u0442\u044c \u043a\u043e\u043d\u0442\u0443\u0440, \u043d\u0430\u0443\u0447\u0438\u043b\u0438\u0441\u044c \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043a\u043e\u0435-\u043a\u0430\u043a\u0438\u0435 \u0433\u0435\u043e\u043c\u0435\u0442\u0440\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438, \u0447\u0442\u043e\u0431\u044b \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0438\u043d\u0432\u0430\u0440\u0438\u0430\u043d\u0442\u043d\u043e\u0435 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u043e\u0431\u044a\u0435\u043a\u0442\u0430. \u041d\u0430\u043f\u043e\u043c\u043d\u044e, \u043a\u0430\u043a \u044d\u0442\u043e \u043c\u044b \u0441\u0434\u0435\u043b\u0430\u043b\u0438: \u043d\u0430\u0448\u043b\u0438 \u043a\u043e\u043d\u0442\u0443\u0440 \u043e\u0431\u044a\u0435\u043a\u0442\u0430, \u0430\u043f\u043f\u0440\u043e\u043a\u0441\u0438\u043c\u0438\u0440\u043e\u0432\u0430\u043b\u0438 \u0435\u0433\u043e, \u043e\u0431\u043e\u0448\u043b\u0438 \u044d\u0442\u043e\u0442 \u043a\u043e\u043d\u0442\u0443\u0440, \u0432\u044b\u0447\u0438\u0441\u043b\u0438\u043b\u0438 \u043a\u043e\u0441\u0438\u043d\u0443\u0441\u044b \u0443\u0433\u043b\u043e\u0432 \u043c\u0435\u0436\u0434\u0443 \u0433\u0440\u0430\u043d\u044f\u043c\u0438 \u0430\u043f\u043f\u0440\u043e\u043a\u0441\u0438\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0433\u043e \u043a\u043e\u043d\u0442\u0443\u0440\u0430. <\/p>\n<p>\u0421\u0435\u0433\u043e\u0434\u043d\u044f \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0438\u043c \u0442\u0435\u043c\u0443 <a href=\"https:\/\/habr.com\/ru\/post\/676838\/\" rel=\"noopener noreferrer nofollow\">\u043f\u0440\u043e\u0448\u043b\u043e\u0433\u043e \u0443\u0440\u043e\u043a\u0430<\/a>. \u0412\u044b\u0447\u0438\u0441\u043b\u0438\u043c \u0438\u043d\u0432\u0430\u0440\u0438\u0430\u043d\u0442\u043d\u044b\u0439 \u0432\u0435\u043a\u0442\u043e\u0440 \u043d\u043e\u0432\u044b\u043c \u043c\u0435\u0442\u043e\u0434\u043e\u043c: \u0447\u0435\u0440\u0435\u0437 \u043e\u0442\u043d\u043e\u0448\u0435\u043d\u0438\u044f \u0434\u043b\u0438\u043d \u0441\u0442\u043e\u0440\u043e\u043d. \u041c\u044b \u043d\u0430\u0447\u043d\u0435\u043c \u043e\u0431\u0445\u043e\u0434 \u0442\u0430\u043a \u0436\u0435 \u0441 \u0441\u0430\u043c\u043e\u0439 \u0443\u0434\u0430\u043b\u0435\u043d\u043d\u043e\u0439 \u043e\u0442 \u0446\u0435\u043d\u0442\u0440\u0430 \u0442\u043e\u0447\u043a\u0438, \u0442\u043e\u043b\u044c\u043a\u043e \u0431\u0443\u0434\u0435\u043c \u0431\u0440\u0430\u0442\u044c \u0441\u0442\u043e\u0440\u043e\u043d\u044b, \u0430 \u043d\u0435 \u0443\u0433\u043b\u044b \u043c\u0435\u0436\u0443 \u0441\u0442\u043e\u0440\u043e\u043d\u0430\u043c\u0438. \u0418 \u043f\u0435\u0440\u0432\u0430\u044f \u0441\u0442\u043e\u0440\u043e\u043d\u0430 \u044d\u0442\u043e \u0442\u0430, \u0447\u0442\u043e \u043f\u0440\u0438\u043b\u0435\u0433\u0430\u0435\u0442 \u043a \u043f\u0435\u0440\u0432\u043e\u0439 \u0442\u043e\u0447\u043a\u0435. \u0422\u043e \u0435\u0441\u0442\u044c \u043e\u043d\u0430 \u0441\u043e\u0435\u0434\u0438\u043d\u044f\u0435\u0442 \u043f\u0435\u0440\u0432\u0443\u044e \u0442\u043e\u0447\u043a\u0443 \u0438 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0443\u044e \u0437\u0430 \u043d\u0435\u0439 \u043f\u043e \u0447\u0430\u0441\u043e\u0432\u043e\u0439 \u0441\u0442\u0440\u0435\u043b\u043a\u0435. \u0418 \u0432\u0441\u0435 \u044d\u0442\u0438 \u0434\u043b\u0438\u043d\u044b \u0441\u0442\u043e\u0440\u043e\u043d \u043c\u044b \u0440\u0430\u0437\u0434\u0435\u043b\u0438\u043c \u043d\u0430 \u0441\u0430\u043c\u0443\u044e \u0434\u043b\u0438\u043d\u043d\u0443\u044e \u0441\u0442\u043e\u0440\u043e\u043d\u0443. \u0425\u043e\u0442\u044f \u043d\u0435\u0442, \u0441\u0434\u0435\u043b\u0430\u043c \u043b\u0443\u0447\u0448\u0435. \u0421\u0434\u0435\u043b\u0430\u0435\u043c \u043c\u0438\u043d\u0438\u043c\u0430\u043a\u0441 \u043d\u043e\u0440\u043c\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e: \u0432\u044b\u0447\u0442\u0435\u043c \u0438\u0437 \u0434\u043b\u0438\u043d\u044b \u0441\u0442\u043e\u0440\u043e\u043d\u044b \u043c\u0438\u043d\u0438\u043c\u0443\u043c \u0438 \u0440\u0430\u0437\u0434\u0435\u043b\u0438\u043c \u043d\u0430 \u0440\u0430\u0437\u043d\u0438\u0446\u0443 \u043c\u0435\u0436\u0434\u0443 \u043c\u0438\u043d\u0438\u043c\u0443\u043c\u043e\u043c \u0438 \u043c\u0430\u043a\u0441\u0438\u043c\u0443\u043c\u043e\u043c. \u0423 \u043d\u0430\u0441 \u0431\u0443\u0434\u0435\u0442 \u0432\u0435\u043a\u0442\u043e\u0440 \u0447\u0438\u0441\u0435\u043b \u043e\u0442 0 \u0434\u043e 1. <\/p>\n<p>\u0418 \u0442\u0430\u043a, \u0437\u0430\u0439\u043c\u0435\u043c\u0441\u044f \u043a\u043e\u0434\u0438\u043d\u0433\u043e\u043c. \u0421\u043d\u0430\u0447\u0430\u043b\u0430 \u043d\u0430\u043f\u0438\u0448\u0435\u043c \u0446\u0438\u043a\u043b, \u0441\u043e\u0437\u0434\u0430\u044e\u0449\u0438\u0439 \u0438\u0441\u0445\u043e\u0434\u043d\u044b\u0439 \u043c\u0430\u0441c\u0438\u0432:<\/p>\n<pre><code class=\"python\">lengths=[] for i in range(size-1):     lengths.append(get_length(polar_coordinates[i],polar_coordinates[i+1])) lengths.append(get_length(polar_coordinates[size-1],polar_coordinates[0])) print(get_normalize_normalize(lengths))<\/code><\/pre>\n<p>\u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0432\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u044f \u0434\u043b\u0438\u043d\u044b \u0441\u0442\u043e\u0440\u043e\u043d\u044b (\u043e\u043d\u0430 \u043f\u0440\u043e\u0441\u0442\u043e \u0438\u0437\u0432\u0435\u043a\u0430\u0435\u0442 \u0438\u0437 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b, \u0433\u0434\u0435 \u0443 \u043d\u0430\u0441 \u0432\u0441\u0435 \u0445\u0440\u0430\u043d\u0438\u0442\u044c\u0441\u044f, \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u044b \u0438 \u0441\u0447\u0438\u0442\u0430\u0435\u0442 \u044d\u0432\u043a\u043b\u0438\u0434\u043e\u0432\u043e \u0440\u0430\u0441\u0441\u0442\u043e\u044f\u043d\u0438\u0435):<\/p>\n<pre><code class=\"python\">#\u042d\u0432\u043a\u043b\u0438\u0434\u043e\u0432\u043e \u0440\u0430\u0441\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u043c\u0435\u0436\u0434\u0443 \u0434\u0432\u0443\u043c\u044f \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u043c\u0438 def get_length(item1, item2):     _, point1 = item1     _, point2 = item2     x1, y1 = point1     x2, y2 = point2     dx=x1-x2     dy=y1-y2     r=math.sqrt(dx*dx+dy*dy)     return r<\/code><\/pre>\n<p>\u041d\u0443 \u0438 \u043d\u043e\u0440\u043c\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f, \u043a\u043e\u043d\u0432\u0435\u0440\u0442\u0438\u043c \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u044b\u0439 \u0441\u043f\u0438\u0441\u043e\u043a \u0432 numpy \u043c\u0430\u0441\u0441\u0438\u0432 \u0438 \u0434\u0435\u043b\u0430\u0435\u043c \u043c\u0438\u043d\u0438\u043c\u0430\u043a\u0441 \u043d\u043e\u0440\u043c\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e: <\/p>\n<pre><code class=\"python\">def get_normalized_vector(list):     arr=np.array(list)     return (arr-arr.min())\/(arr.max()-arr.min())<\/code><\/pre>\n<p>\u041f\u043e\u0435\u0445\u0430\u043b\u0438 \u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c, \u0447\u0442\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u043e\u0441\u044c.<\/p>\n<p>\u041f\u0435\u0440\u0432\u044b\u0439 \u043f\u0440\u0438\u043c\u0435\u0440:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/944\/694\/b62\/944694b62b51c7fe99e6bb776f0442d0.png\" width=\"693\" height=\"493\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/944\/694\/b62\/944694b62b51c7fe99e6bb776f0442d0.png\"\/><figcaption><\/figcaption><\/figure>\n<p>\u0412\u0435\u043a\u0442\u043e\u0440: [0.11331868 1.\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 0.\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 0.02997931 0.96756226 0.1022278 ]<\/p>\n<p>\u00a0<\/p>\n<p>\u0412\u0442\u043e\u0440\u043e\u0439 \u043f\u0440\u0438\u043c\u0435\u0440:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/16d\/f43\/5ec\/16df435ec536e807b096b6f0eb222c67.png\" width=\"693\" height=\"492\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/16d\/f43\/5ec\/16df435ec536e807b096b6f0eb222c67.png\"\/><figcaption><\/figcaption><\/figure>\n<p>\u0412\u0435\u043a\u0442\u043e\u0440: [0.16953268 0.9532099\u00a0 0.\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 0.01245409 1.\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 0.10313678]<\/p>\n<p>\u00a0<\/p>\n<p>\u041a\u0430\u043a \u0432\u0438\u0434\u0438\u043c, \u0432\u0435\u043a\u0442\u043e\u0440\u044b \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u043e\u043a\u0430\u0437\u0430\u043b\u0438\u0441\u044c \u0431\u043b\u0438\u0437\u043a\u0438\u0435. \u041f\u0440\u0438\u0447\u0435\u043c, \u0432 \u043e\u0442\u043b\u0438\u0447\u0438\u0435 \u043e\u0442 \u043f\u0440\u043e\u0448\u043b\u043e\u0433\u043e \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u0430, \u0443 \u043d\u0430\u0441 \u043e\u0441\u0442\u0430\u044e\u0442\u0441\u044f \u0441\u0442\u0430\u0431\u0438\u043b\u044c\u043d\u044b\u043c\u0438 \u0432\u0441\u0435 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u044b \u0432\u0435\u043a\u0442\u043e\u0440\u0430.<\/p>\n<p>\u0412\u043e\u043e\u0431\u0449\u0435, \u043f\u043e-\u0445\u043e\u0440\u043e\u0448\u0435\u043c\u0443, \u043a\u043e\u043d\u0435\u0447\u043d\u043e \u043d\u0430\u0434\u043e \u0431\u044b \u043f\u0440\u043e\u0432\u0435\u0441\u0442\u0438 \u0438\u0441\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u043d\u0438\u0435: \u043f\u0440\u043e\u0430\u043d\u0430\u043b\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u043e \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0439, \u0441\u0440\u0430\u0432\u043d\u0438\u0442\u044c, \u043d\u0430\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0440\u0430\u0441\u0445\u043e\u0434\u044f\u0442\u0441\u044f \u0432\u0435\u043a\u0442\u043e\u0440\u044b \u0438\u043d\u0432\u0430\u0440\u0438\u0430\u043d\u0442\u043d\u044b\u0445 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0439 \u043f\u0440\u0438 \u0442\u043e\u043c \u0438\u043b\u0438 \u0438\u043d\u043e\u043c \u043c\u0435\u0442\u043e\u0434\u0435 \u0440\u0430\u0441\u0447\u0435\u0442\u0430. \u0414\u0430 \u0438 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0430 \u043d\u0443\u0436\u0434\u0430\u0435\u0442\u0441\u044f \u0432 \u0440\u0435\u0444\u0430\u043a\u0442\u043e\u0440\u0438\u043d\u0433\u0435. \u041d\u043e \u044d\u0442\u043e \u0443\u0436\u0435 \u0432\u044b\u0445\u043e\u0434\u0438\u0442 \u0437\u0430 \u0440\u0430\u043c\u043a\u0438 \u0443\u0440\u043e\u043a\u043e\u0432. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u044f \u043f\u0440\u0438\u0432\u043e\u0436\u0443 \u043f\u043e\u043b\u043d\u044b\u0439 \u043a\u043e\u0434 \u043f\u0440\u0438\u043c\u0435\u0440\u043e\u0432 \u043a\u0430\u043a \u0435\u0441\u0442\u044c, \u0438 \u043c\u044b \u0434\u0432\u0438\u0433\u0430\u0435\u043c\u0441\u044f \u0434\u0430\u043b\u044c\u0448\u0435:<\/p>\n<pre><code class=\"python\">import cv2 import numpy as np import math import os img = cv2.imread(\"Samples\/1.jpg\") gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) thresh = 100  def custom_sort(countour):     return -countour.shape[0]  def polar_sort(item):     return item[0][0]  def get_normalized_vector(list):     arr=np.array(list)     return (arr-arr.min())\/(arr.max()-arr.min())  #\u042d\u0432\u043a\u043b\u0438\u0434\u043e\u0432\u043e \u0440\u0430\u0441\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u043c\u0435\u0436\u0434\u0443 \u0434\u0432\u0443\u043c\u044f \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u043c\u0438 def get_length(item1, item2):     _, point1 = item1     _, point2 = item2     x1, y1 = point1     x2, y2 = point2     dx=x1-x2     dy=y1-y2     r=math.sqrt(dx*dx+dy*dy)     return r  def get_cos_edges(edges):     dx1, dy1, dx2, dy2=edges     r1 = math.sqrt(dx1 * dx1 + dy1 * dy1)     r2 = math.sqrt(dx2 * dx2 + dy2 * dy2)     return (dx1*dx2+dy1*dy2)\/r1\/r2  def get_polar_coordinates(x0,y0,x,y,xc,yc):     #\u041f\u0435\u0440\u0432\u0430\u044f \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u0430 \u0432 \u043f\u043e\u043b\u044f\u0440\u043d\u044b\u0445 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u0430\u0445 - \u0440\u0430\u0434\u0438\u0443\u0441     dx=xc-x     dy=yc-y     r=math.sqrt(dx*dx+dy*dy)      #\u0412\u0442\u043e\u0440\u0430\u044f \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u0430 \u0432 \u043f\u043e\u043b\u044f\u0440\u043d\u044b\u0445 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u0430\u0445 - \u0443\u0437\u0435\u043b, \u0432\u044b\u0447\u0438\u0441\u043b\u0438\u043c \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e\u0439 \u0442\u043e\u0447\u043a\u0438     dx0=xc-x0     dy0=yc-y0     r0 = math.sqrt(dx0 * dx0 + dy0 * dy0)     scal_mul=dx0*dx+dy0*dy     cos_angle=scal_mul\/r\/r0     sgn=dx0*dy-dx*dy0 #\u043e\u043f\u0440\u0435\u0434\u0435\u0434\u043b\u044f\u0435\u043c, \u0432 \u043a\u0430\u043a\u0443\u044e \u0441\u0442\u043e\u0440\u043e\u043d\u0443 \u043f\u043e\u0432\u0435\u0440\u043d\u0443\u0442 \u0432\u0435\u043a\u0442\u043e\u0440     if cos_angle>1:         if cos_angle>1.0001:             raise Exception(\"\u0427\u0442\u043e-\u0442\u043e \u043f\u043e\u0448\u043b\u043e \u043d\u0435 \u0442\u0430\u043a\")         cos_angle=1     angle=math.acos(cos_angle)     if sgn&lt;0:         angle=2*math.pi-angle     return angle,r  def get_coords(item1, item2, item3):     _, point1 = item1     _, point2 = item2     _, point3 = item3     x1, y1 = point1     x2, y2 = point2     x3, y3 = point3     dx1=x1-x2     dy1=y1-y2     dx2=x3-x2     dy2=y3-y2     return dx1,dy1,dx2,dy2  #get threshold image ret,thresh_img = cv2.threshold(gray, thresh, 255, cv2.THRESH_BINARY)  # find contours without approx contours,_ = cv2.findContours(thresh_img,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE) contours=list(contours) contours.sort(key=custom_sort) sel_countour=contours[1]  # calc arclentgh arclen = cv2.arcLength(sel_countour, True)  # do approx eps = 0.01 epsilon = arclen * eps approx = cv2.approxPolyDP(sel_countour, epsilon, True)  sum_x=0.0 sum_y=0.0 for point in approx:     x = float(point[0][0])     y = float(point[0][1])     sum_x+=x     sum_y+=y xc=sum_x\/float(len((approx))) yc=sum_y\/float(len((approx)))  max=0 beg_point=-1 for i in range(0,len(approx)):     point=approx[i]     x = float(point[0][0])     y = float(point[0][1])     dx=x-xc     dy=y-yc     r=math.sqrt(dx*dx+dy*dy)     if r>max:         max=r         beg_point=i  polar_coordinates=[] x0=approx[beg_point][0][0] y0=approx[beg_point][0][1]  for point in approx:     x = int(point[0][0])     y = int(point[0][1])     angle,r=get_polar_coordinates(x0,y0,x,y,xc,yc)     polar_coordinates.append(((angle,r),(x,y)))  polar_coordinates.sort(key=polar_sort)  img_contours = np.uint8(np.zeros((img.shape[0],img.shape[1]))) size=len(polar_coordinates) for i in range(1,size):     _ , point1=polar_coordinates[i-1]     _, point2 = polar_coordinates[i]     x1,y1=point1     x2,y2=point2     cv2.line(img_contours, (x1, y1), (x2, y2), 255, thickness=i) _ , point1=polar_coordinates[size-1] _, point2 = polar_coordinates[0] x1,y1=point1 x2,y2=point2 cv2.line(img_contours, (x1, y1), (x2, y2), 255, thickness=size)  cv2.circle(img_contours, (int(xc), int(yc)), 7, (255,255,255), 2)  coses=[] coses.append(get_cos_edges(get_coords(polar_coordinates[size-1],polar_coordinates[0],polar_coordinates[1]))) for i in range(1,size-1):     coses.append(get_cos_edges(get_coords(polar_coordinates[i-1], polar_coordinates[i],polar_coordinates[i+1]))) coses.append(get_cos_edges(get_coords(polar_coordinates[size-2], polar_coordinates[size-1],polar_coordinates[0]))) print(coses)  lengths=[] for i in range(size-1):     lengths.append(get_length(polar_coordinates[i],polar_coordinates[i+1])) lengths.append(get_length(polar_coordinates[size-1],polar_coordinates[0])) print(get_normalized_vector(lengths))    point=approx[beg_point] x = float(point[0][0]) y = float(point[0][1]) cv2.circle(img_contours, (int(x), int(y)), 7, (255,255,255), 2)  cv2.imshow('origin', img) # \u0432\u044b\u0432\u043e\u0434\u0438\u043c \u0438\u0442\u043e\u0433\u043e\u0432\u043e\u0435 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u0432 \u043e\u043a\u043d\u043e cv2.imshow('res', img_contours) # \u0432\u044b\u0432\u043e\u0434\u0438\u043c \u0438\u0442\u043e\u0433\u043e\u0432\u043e\u0435 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u0432 \u043e\u043a\u043d\u043e  cv2.waitKey() cv2.destroyAllWindows()<\/code><\/pre>\n<p>\u041d\u0430\u0448 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u0448\u0430\u0433 \u0432 \u043e\u0441\u0432\u043e\u0435\u043d\u0438\u0438 OpenCV \u2013 \u044d\u0442\u043e \u043f\u043e\u0438\u0441\u043a \u043f\u0440\u0435\u0434\u043c\u0435\u0442\u0430 \u043d\u0430 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0438. \u0418\u0441\u043a\u0430\u0442\u044c \u043c\u044b \u0431\u0443\u0434\u0435\u0442 \u0432\u0441\u0435 \u0442\u0443 \u0436\u0435 \u0440\u0443\u0447\u043a\u0443, \u043d\u043e \u0442\u0435\u043f\u0435\u0440\u044c \u043d\u0430 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0438 \u0443 \u043d\u0430\u0441 \u0431\u0443\u0434\u0443\u0442 \u0434\u0440\u0443\u0433\u0438\u0435 \u043f\u0440\u0435\u0434\u043c\u0435\u0442\u044b:<\/p>\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/e17\/bc0\/675\/e17bc06752cfca5e3b9d972d3c6c3991.png\" width=\"364\" height=\"484\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/e17\/bc0\/675\/e17bc06752cfca5e3b9d972d3c6c3991.png\"\/><figcaption><\/figcaption><\/figure>\n<p>\u0417\u0434\u0435\u0441\u044c \u043c\u044b \u0442\u043e\u0447\u043d\u043e \u0442\u0430\u043a \u0436\u0435 \u0432\u044b\u0434\u0435\u043b\u0438\u043c \u043a\u043e\u043d\u0442\u0443\u0440\u044b \u043d\u0430 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0438, \u0430 \u043f\u043e\u0442\u043e\u043c \u043a\u0430\u0436\u0434\u044b\u0439 \u0438\u0437 \u043a\u043e\u043d\u0442\u0443\u0440\u043e\u0432 \u0431\u0443\u0434\u0435\u043c \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0442\u044c \u043d\u0430 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0438\u0438 \u0437\u0430\u0434\u0430\u043d\u043d\u043e\u043c\u0443 \u0448\u0430\u0431\u043b\u043e\u043d\u0443 \u2013 \u0448\u0435\u0441\u0442\u044c \u0433\u0440\u0430\u043d\u0435\u0439 \u0438 \u0432\u0435\u043a\u0442\u043e\u0440 \u0438\u043d\u0432\u0430\u0440\u0438\u0430\u043d\u0442\u043d\u043e\u0433\u043e \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u0431\u043b\u0438\u0437\u043e\u043a \u043a \u0438\u0441\u0445\u043e\u0434\u043d\u043e\u043c\u0443. \u041d\u0430\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0431\u043b\u0438\u0437\u043e\u043a? \u042d\u0442\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043c \u044d\u043c\u043f\u0438\u0440\u0438\u0447\u0435\u0441\u043a\u0438\u043c \u043f\u0443\u0442\u0435\u043c, \u043f\u043e\u0434\u0431\u0438\u0440\u0430\u044f \u043f\u043e\u0440\u043e\u0433.<\/p>\n<p>\u0418 \u0442\u0430\u043a, \u0432\u043e\u0442 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0430:<\/p>\n<pre><code class=\"python\">import cv2 import numpy as np import math  template_vector=np.array([0.16953268, 0.9532099, 0, 0.01245409, 1, 0.10313678]) distance_thresh=0.1  img = cv2.imread(\"Samples\/objects.jpg\") gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) thresh = 100  def polar_sort(item):     return item[0][0]  def get_normalized_vector(list):     arr=np.array(list)     return (arr-arr.min())\/(arr.max()-arr.min())  #\u042d\u0432\u043a\u043b\u0438\u0434\u043e\u0432\u043e \u0440\u0430\u0441\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u043c\u0435\u0436\u0434\u0443 \u0434\u0432\u0443\u043c\u044f \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u043c\u0438 def get_length(item1, item2):     _, point1 = item1     _, point2 = item2     x1, y1 = point1     x2, y2 = point2     dx=x1-x2     dy=y1-y2     r=math.sqrt(dx*dx+dy*dy)     return r  def get_polar_coordinates(x0,y0,x,y,xc,yc):     #\u041f\u0435\u0440\u0432\u0430\u044f \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u0430 \u0432 \u043f\u043e\u043b\u044f\u0440\u043d\u044b\u0445 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u0430\u0445 - \u0440\u0430\u0434\u0438\u0443\u0441     dx=xc-x     dy=yc-y     r=math.sqrt(dx*dx+dy*dy)      #\u0412\u0442\u043e\u0440\u0430\u044f \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u0430 \u0432 \u043f\u043e\u043b\u044f\u0440\u043d\u044b\u0445 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u0430\u0445 - \u0443\u0437\u0435\u043b, \u0432\u044b\u0447\u0438\u0441\u043b\u0438\u043c \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e\u0439 \u0442\u043e\u0447\u043a\u0438     dx0=xc-x0     dy0=yc-y0     r0 = math.sqrt(dx0 * dx0 + dy0 * dy0)     scal_mul=dx0*dx+dy0*dy     cos_angle=scal_mul\/r\/r0     sgn=dx0*dy-dx*dy0 #\u043e\u043f\u0440\u0435\u0434\u0435\u0434\u043b\u044f\u0435\u043c, \u0432 \u043a\u0430\u043a\u0443\u044e \u0441\u0442\u043e\u0440\u043e\u043d\u0443 \u043f\u043e\u0432\u0435\u0440\u043d\u0443\u0442 \u0432\u0435\u043a\u0442\u043e\u0440     if cos_angle>1:         if cos_angle>1.0001:             raise Exception(\"\u0427\u0442\u043e-\u0442\u043e \u043f\u043e\u0448\u043b\u043e \u043d\u0435 \u0442\u0430\u043a\")         cos_angle=1     angle=math.acos(cos_angle)     if sgn&lt;0:         angle=2*math.pi-angle     return angle,r   #get threshold image ret,thresh_img = cv2.threshold(gray, thresh, 255, cv2.THRESH_BINARY)  # find contours without approx contours,_ = cv2.findContours(thresh_img,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE) for sel_countour in contours:     # calc arclentgh     arclen = cv2.arcLength(sel_countour, True)      # do approx     eps = 0.01     epsilon = arclen * eps     approx = cv2.approxPolyDP(sel_countour, epsilon, True)      #\u041e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u043c \u0442\u043e\u043b\u044c\u043a\u043e \u043a\u043e\u043d\u0442\u0443\u0440\u044b \u0434\u043b\u0438\u043d\u043e\u0439 6 \u0443\u0433\u043b\u043e\u0432     if len(approx)==6:          # \u0432\u044b\u0447\u0438\u0441\u043b\u0438\u043c \u0446\u0435\u043d\u0442\u0440 \u0442\u044f\u0436\u0435\u0441\u0442\u0438 \u043a\u043e\u043d\u0442\u0443\u0440\u0430         sum_x = 0.0         sum_y = 0.0         for point in approx:             x = float(point[0][0])             y = float(point[0][1])             sum_x += x             sum_y += y         xc = sum_x \/ float(len((approx)))         yc = sum_y \/ float(len((approx)))          #\u043d\u0430\u0439\u0434\u0435\u043c \u043d\u0430\u0447\u0430\u043b\u044c\u043d\u0443\u044e \u0442\u043e\u0447\u043a\u0443         max = 0         beg_point = -1         for i in range(0, len(approx)):             point = approx[i]             x = float(point[0][0])             y = float(point[0][1])             dx = x - xc             dy = y - yc             r = math.sqrt(dx * dx + dy * dy)             if r > max:                 max = r                 beg_point = i          #\u0412\u044b\u0447\u0438\u0441\u043b\u043c\u0438 \u043f\u043e\u043b\u044f\u0440\u043d\u044b\u0435 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u044b         polar_coordinates=[]         x0=approx[beg_point][0][0]         y0=approx[beg_point][0][1]         for point in approx:             x = int(point[0][0])             y = int(point[0][1])             angle, r = get_polar_coordinates(x0, y0, x, y, xc, yc)             polar_coordinates.append(((angle, r), (x, y)))          #\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0432\u0435\u043a\u0442\u043e\u0440 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435         polar_coordinates.sort(key=polar_sort)         size = len(polar_coordinates)         lengths = []         for i in range(size - 1):             lengths.append(get_length(polar_coordinates[i], polar_coordinates[i + 1]))         lengths.append(get_length(polar_coordinates[size - 1], polar_coordinates[0]))         descr=get_normalized_vector(lengths)          #\u0412\u044b\u0447\u0438\u0441\u043b\u0438\u043c \u044d\u0432\u043a\u043b\u0438\u0434\u043e\u0432\u043e \u0440\u0430\u0441\u0441\u0442\u043e\u044f\u043d\u0438\u0435         square = np.square(descr - template_vector)         sum_square = np.sum(square)         distance = np.sqrt(sum_square)         if distance&lt;distance_thresh:             for i in range(1, size):                 _, point1 = polar_coordinates[i - 1]                 _, point2 = polar_coordinates[i]                 x1, y1 = point1                 x2, y2 = point2                 cv2.line(img, (x1, y1), (x2, y2), (0,0,255), thickness=4)             _, point1 = polar_coordinates[size - 1]             _, point2 = polar_coordinates[0]             x1, y1 = point1             x2, y2 = point2             cv2.line(img, (x1, y1), (x2, y2), (0,0,255), thickness=size)   cv2.imshow('origin', img) # \u0432\u044b\u0432\u043e\u0434\u0438\u043c \u0438\u0442\u043e\u0433\u043e\u0432\u043e\u0435 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u0432 \u043e\u043a\u043d\u043e  cv2.waitKey() cv2.destroyAllWindows()<\/code><\/pre>\n<p>\u041f\u043e\u0440\u043e\u0433 \u043f\u043e\u0434\u043e\u0431\u0440\u0430\u043d 0.1, \u0448\u0430\u0431\u043b\u043e\u043d \u2013 \u0432\u0435\u043a\u0442\u043e\u0440 \u043a\u043e \u0432\u0442\u043e\u0440\u043e\u0439 \u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0435, \u0433\u0434\u0435 \u0438\u0441\u043a\u043e\u043c\u044b\u0439 \u043e\u0431\u044a\u0435\u043a\u0442 \u043f\u043e\u0432\u0435\u0440\u043d\u0443\u0442 \u0432 \u0434\u0440\u0443\u0433\u0443\u044e \u0441\u0442\u043e\u0440\u043e\u043d\u0443, \u0447\u0435\u043c \u0442\u043e\u0442, \u0447\u0442\u043e \u043d\u0430 \u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0435:<\/p>\n<pre><code class=\"python\">template_vector=np.array([0.16953268, 0.9532099, 0, 0.01245409, 1, 0.10313678]) distance_thresh=0.1<\/code><\/pre>\n<p>\u0418 \u0432\u043e\u0442 \u0447\u0442\u043e \u0443 \u043d\u0430\u0441 \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u043e\u0441\u044c:<\/p>\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/030\/3a2\/466\/0303a2466d6ba986b09a6e8899922a1c.png\" width=\"363\" height=\"517\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/030\/3a2\/466\/0303a2466d6ba986b09a6e8899922a1c.png\"\/><figcaption><\/figcaption><\/figure>\n<p>\u041d\u0430\u0439\u0434\u0435\u043d \u0432\u0441\u0435\u0433\u043e \u043e\u0434\u0438\u043d \u043e\u0431\u044a\u0435\u043a\u0442. \u0415\u0441\u043b\u0438 \u043f\u043e\u0440\u043e\u0433 \u0443\u0432\u0435\u043b\u0438\u0447\u0438\u0442\u044c \u0434\u043e 0.4, \u0442\u043e \u0431\u0443\u0434\u0435\u0442 \u043d\u0430\u0439\u0434\u0435\u0442 \u0438 \u0432\u0442\u043e\u0440\u043e\u0439 \u043e\u0431\u044a\u0435\u043a\u0442, \u043d\u043e \u0435\u0449\u0435 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u00ab\u043b\u0435\u0432\u044b\u0445\u00bb \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432:<\/p>\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/660\/ab2\/a54\/660ab2a546bef461f77b37431fb38e7f.png\" width=\"364\" height=\"486\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/660\/ab2\/a54\/660ab2a546bef461f77b37431fb38e7f.png\"\/><figcaption><\/figcaption><\/figure>\n<p>\u0418\u0437\u0431\u0430\u0432\u0438\u0442\u044c \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u043e\u0442 \u043d\u0438\u0445, \u043f\u0440\u043e\u0441\u0442\u043e \u0432\u0432\u0435\u0434\u044f \u043a\u0440\u0438\u0442\u0435\u0440\u0438\u0439 \u0440\u0430\u0437\u043c\u0435\u0440\u0430 (\u043d\u0435 \u0438\u043c\u0435\u0435\u0442 \u0441\u043c\u044b\u0441\u043b \u0440\u0430\u0441\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430\u0442\u044c \u0441\u043b\u0438\u0448\u043a\u043e\u043c \u043c\u0430\u043b\u044b\u0435 \u043e\u0431\u044a\u0435\u043a\u0442\u044b):<\/p>\n<pre><code class=\"python\">\u2026 for sel_countour in contours:     # calc arclentgh     arclen = cv2.arcLength(sel_countour, True)     if arclen&lt;20:         continue \u2026<\/code><\/pre>\n<p>\u0418 \u0432\u043e\u0442 \u0447\u0442\u043e \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u043c \u0442\u0435\u043f\u0435\u0440\u044c:<\/p>\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/40c\/119\/f83\/40c119f8326cbf80c964d966540d7bad.png\" width=\"367\" height=\"514\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/40c\/119\/f83\/40c119f8326cbf80c964d966540d7bad.png\"\/><figcaption><\/figcaption><\/figure>\n<p>\u041d\u043e \u043a\u0442\u043e \u0441\u043a\u0430\u0437\u0430\u043b, \u0447\u0442\u043e \u043d\u0430\u0434\u043e \u0432\u043e\u043e\u0431\u0449\u0435 \u0430\u043f\u043f\u0440\u043e\u043a\u0441\u0438\u043c\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043a\u043e\u043d\u0442\u0443\u0440 \u0438 \u0441\u0447\u0438\u0442\u0430\u0442\u044c \u0443\u0433\u043b\u044b? \u041c\u044b \u043c\u043e\u0436\u0435\u043c \u043f\u0440\u043e\u0441\u0442\u043e \u043e\u0431\u043e\u0439\u0442\u0438 \u043a\u043e\u043d\u0442\u0443\u0440 \u043f\u043e \u043a\u0440\u0443\u0433\u0443, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0440\u0430\u0437\u0434\u0435\u043b\u0438\u043c \u043d\u0430 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u043e\u0435 \u043a\u043e\u043b-\u0432\u043e \u0441\u0435\u043a\u0442\u043e\u0440\u043e\u0432:<\/p>\n<pre><code class=\"python\">count=100 full_angle=2*math.pi i=1 end_angle = float(i) * full_angle \/ float(count) summ=0.0 count_angles=0.0 signature=[] for item_coord in polar_coord:     angle,r=item_coord     if angle>end_angle:         signature.append((angle,summ\/count_angles))         i+=1         end_angle = float(i) * full_angle \/ float(count)         summ=0         count_angles=0     summ+=r     count_angles+=1 signature.append((angle,summ\/count_angles)) print(signature)<\/code><\/pre>\n<p>\u0414\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u00a0\u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0441\u0438\u0433\u043d\u0430\u0442\u0443\u0440\u044b, \u043f\u0435\u0440\u0435\u0432\u0435\u0434\u0435\u043c \u0435\u0435 \u043e\u043f\u044f\u0442\u044c \u0432 \u0434\u0435\u043a\u0430\u0440\u0442\u043e\u0432\u044b \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u044b \u0438 \u043e\u0442\u043e\u0431\u0440\u0430\u0437\u0438\u043c. \u0424\u0443\u043d\u043a\u0446\u0438\u044f \u043f\u0435\u0440\u0435\u0432\u043e\u0434\u0430 \u043f\u043e\u043b\u044f\u0440\u043d\u044b\u0445 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442 \u0432 \u0434\u0435\u043a\u0430\u0440\u0442\u043e\u0432\u044b:<\/p>\n<pre><code class=\"python\">def polar_to_decart(angle,r):     x=math.sin(angle)*r     y=math.cos(angle)*r     return x,y<\/code><\/pre>\n<p>\u0418 \u0432\u043e\u0442 \u0442\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u043c\u044b \u043e\u0442\u043e\u0431\u0440\u0430\u0437\u0438\u043c \u0441\u0438\u0433\u043d\u0430\u0442\u0443\u0440\u0443:<\/p>\n<pre><code class=\"python\">img_contours = np.zeros((img.shape[0],img.shape[1],3), np.uint8) # np.uint8(np.zeros((img.shape[0],img.shape[1]))) cv2.drawContours(img_contours, [sel_countour], -1, (255,0,0), 1)  for i in range(1,len(signature)):     angle1,r1=signature[i-1]     angle2,r2=signature[i]     x1, y1=polar_to_decart(angle1,r1)     x2, y2 = polar_to_decart(angle2, r2)     cv2.line(img_contours, (int(x1+xc), int(y1+yc)), (int(x2+xc), int(y2+yc)), (0,0,255), thickness=1) angle1,r1=signature[len(signature)-1] angle2,r2=signature[0] x1, y1=polar_to_decart(angle1,r1) x2, y2 = polar_to_decart(angle2, r2) cv2.line(img_contours, (int(x1+xc), int(y1+yc)), (int(x2+xc), int(y2+yc)), (0,0,255), thickness=1)<\/code><\/pre>\n<p>\u0414\u0430, \u044f \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u043e \u043d\u0435 \u0441\u0442\u0430\u043b \u0434\u0435\u043b\u0430\u0442\u044c \u043f\u043e\u043f\u0440\u0430\u0432\u043a\u0443 \u043d\u0430 \u0443\u0433\u043e\u043b, \u0447\u0442\u043e\u0431\u044b \u0441\u043e\u0432\u043c\u0435\u0449\u0430\u0442\u044c \u043a\u043e\u043d\u0442\u0443\u0440\u044b, \u043f\u0443\u0441\u0442\u044c \u043a\u0440\u0430\u0441\u043d\u044b\u0439 \u043a\u043e\u043d\u0442\u0443\u0440 (\u0441\u0438\u0433\u043d\u0430\u0442\u0443\u0440\u0430) \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u0432\u0435\u0440\u043d\u0443\u0442, \u0447\u0442\u043e\u0431\u044b \u0431\u044b\u043b\u043e \u043b\u0443\u0447\u0448\u0435 \u0432\u0438\u0434\u043d\u043e:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/27a\/8c4\/86f\/27a8c486f305019295541e49f4cad36f.png\" width=\"693\" height=\"494\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/27a\/8c4\/86f\/27a8c486f305019295541e49f4cad36f.png\"\/><figcaption><\/figcaption><\/figure>\n<p>\u041c\u043e\u0436\u043d\u043e \u043e\u0442\u043e\u0431\u0440\u0430\u0437\u0438\u0442\u044c \u044d\u0442\u0443 \u0441\u0438\u0433\u043d\u0430\u0442\u0443\u0440\u0443 \u043d\u0430 \u0433\u0440\u0430\u0444\u0438\u043a\u0435:<\/p>\n<pre><code class=\"python\">x=[] y=[] for item in signature:     angle,r=item     x.append(angle)     y.append(r)  plt.plot(x,y) plt.show()<\/code><\/pre>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/90f\/278\/65e\/90f27865e6f0b9ef9de575dea6a405ff.png\" width=\"644\" height=\"558\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/90f\/278\/65e\/90f27865e6f0b9ef9de575dea6a405ff.png\"\/><figcaption><\/figcaption><\/figure>\n<p>\u0417\u0430\u043c\u0435\u0442\u0438\u043c, \u0447\u0442\u043e \u043d\u0435\u0432\u0430\u0436\u043d\u043e, \u043a\u0430\u043a\u043e\u0439 \u0443\u0433\u043e\u043b \u043f\u043e\u0432\u043e\u0440\u043e\u0442\u0430, \u0433\u0440\u0430\u0444\u0438\u043a\u0438 \u0431\u0443\u0434\u0443\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432\u043e:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/baf\/700\/c26\/baf700c26c4869e767e1013a44b9e476.png\" width=\"692\" height=\"281\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/baf\/700\/c26\/baf700c26c4869e767e1013a44b9e476.png\"\/><figcaption><\/figcaption><\/figure>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/4c7\/9f0\/e63\/4c79f0e637ea9fe3a1caa1cda5cbb233.png\" width=\"689\" height=\"270\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/4c7\/9f0\/e63\/4c79f0e637ea9fe3a1caa1cda5cbb233.png\"\/><figcaption><\/figcaption><\/figure>\n<p>\u041d\u0443, \u0438\u043b\u0438 \u043f\u043e\u0447\u0442\u0438 \u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432\u043e:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/734\/7e8\/996\/7347e8996bf315627ecc4e3af997cb21.png\" width=\"690\" height=\"261\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/734\/7e8\/996\/7347e8996bf315627ecc4e3af997cb21.png\"\/><figcaption><\/figcaption><\/figure>\n<p>\u0421\u0440\u0430\u0432\u043d\u0438\u0442\u044c \u043c\u044b \u0435\u0433\u043e \u0441\u043c\u043e\u0436\u0435\u0442 \u0442\u0430\u043a \u0436\u0435, \u043a\u0430\u043a \u0438 \u0432\u0435\u043a\u0442\u043e\u0440\u0430. \u0422\u0435\u043c \u0431\u043e\u043b\u0435\u0435, \u0447\u0442\u043e \u0442\u0435\u043f\u0435\u0440\u044c \u0443 \u043d\u0430\u0441 \u043a\u043e\u043d\u0442\u0443\u0440 \u043f\u0440\u0438\u0432\u0435\u0434\u0435\u043d \u043a \u0435\u0434\u0438\u043d\u043e\u0440\u0430\u0437\u043c\u0435\u0440\u043d\u043e\u0439 \u0441\u0438\u0433\u043d\u0430\u0442\u0443\u0440\u0435. <\/p>\n<p>\u041f\u043e\u043f\u0440\u043e\u0431\u0443\u0435\u043c \u0434\u0440\u0443\u0433\u043e\u0439 \u043f\u0440\u0435\u0434\u043c\u0435\u0442:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/195\/417\/6f9\/1954176f9b6a53ecfcb0f19285d97677.png\" width=\"693\" height=\"262\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/195\/417\/6f9\/1954176f9b6a53ecfcb0f19285d97677.png\"\/><figcaption><\/figcaption><\/figure>\n<p>\u041a\u0430\u043a \u0432\u0438\u0434\u0438\u043c, \u0432 \u0441\u043b\u0443\u0447\u0430\u0435 \u043a\u0440\u0443\u0433\u043b\u043e\u0433\u043e \u043f\u0440\u0435\u0434\u043c\u0435\u0442\u0430 \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0441\u044f \u0448\u0443\u043c \u0432\u043e\u043a\u0440\u0443\u0433 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u043e\u0433\u043e \u0443\u0440\u043e\u0432\u043d\u044f &#8212; \u0440\u0430\u0434\u0438\u0443\u0441\u0430 \u044d\u0442\u043e\u0433\u043e \u043a\u0440\u0443\u0433\u0430. \u0412 \u0438\u0434\u0435\u0430\u043b\u0435 \u0434\u043e\u043b\u0436\u043d\u0430, \u043a\u043e\u043d\u0435\u0447\u043d\u043e, \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c\u0441\u044f \u043f\u0440\u044f\u043c\u0430\u044f, \u043d\u043e \u043d\u0438\u0447\u0435\u0433\u043e \u0432 \u044d\u0442\u043e\u043c \u043c\u0438\u0440\u0435 \u043d\u0435\u0442 \u0438\u0434\u0435\u0430\u043b\u044c\u043d\u043e\u0433\u043e. \u00a0<\/p>\n<p>\u0415\u0449\u0435 \u043e\u0434\u0438\u043d \u043f\u0440\u0435\u0434\u043c\u0435\u0442:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/77b\/045\/f34\/77b045f3476951485183939a5470267e.png\" width=\"693\" height=\"254\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/77b\/045\/f34\/77b045f3476951485183939a5470267e.png\"\/><figcaption><\/figcaption><\/figure>\n<p>\u0415\u0449\u0435 \u0441\u0438\u0433\u043d\u0430\u0442\u0443\u0440\u0443 \u043c\u043e\u0436\u043d\u043e \u043d\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u0442\u044c, \u0442\u043e\u0433\u0434\u0430 \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u043c \u0438\u043d\u0432\u0430\u0440\u0438\u0430\u043d\u0442\u043d\u044b\u0439 \u043a \u0440\u0430\u0437\u043c\u0435\u0440\u0443 \u0432\u0435\u043a\u0442\u043e\u0440. \u0412 \u043f\u0440\u043e\u0448\u043b\u044b\u0439 \u0440\u0430\u0437 \u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b\u0438 \u043c\u0438\u043d\u0438\u043c\u0430\u043a\u0441, \u043d\u043e \u0435\u0441\u0442\u044c \u0438 \u0434\u0440\u0443\u0433\u0438\u0435 \u0441\u043f\u043e\u0441\u043e\u0431\u044b, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043c\u043e\u0436\u043d\u043e \u0440\u0430\u0437\u0434\u0435\u043b\u0438\u0442\u044c \u043d\u0430 \u0440\u0430\u0434\u0438\u0443\u0441 \u0438\u043b\u0438 \u0434\u0435\u043b\u0438\u0442\u044c \u0440\u0430\u0437\u043d\u0438\u0446\u0443 \u043c\u0435\u0436\u0434\u0443 \u0442\u0435\u043a\u0443\u0449\u0438\u043c \u0438 \u0441\u0440\u0435\u0434\u043d\u0438\u043c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435\u043c \u043d\u0430 \u0441\u0440\u0435\u0434\u043d\u0435\u043a\u0432\u0430\u0434\u0440\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0435 \u043e\u0442\u043a\u043b\u043e\u043d\u0435\u043d\u0438\u0435. \u041d\u043e \u043e\u0431\u0441\u0443\u0436\u0434\u0435\u043d\u0438\u0435 \u0441\u043f\u043e\u0441\u043e\u0431\u043e\u0432 \u043d\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0443\u0436\u0435 \u0432\u044b\u0445\u043e\u0434\u0438\u0442 \u0437\u0430 \u0440\u0430\u043c\u043a\u0438 \u0441\u0442\u0430\u0442\u044c\u0438.<\/p>\n<p>\u0412 \u0437\u0430\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0438 \u043f\u043e\u043b\u043d\u044b\u0439 \u0442\u0435\u043a\u0441\u0442 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b.<\/p>\n<p>\u0424\u0430\u0439\u043b SignLib.py:<\/p>\n<pre><code class=\"python\">import math   def custom_sort(countour):     return -countour.shape[0]  def get_center(countour):     # \u0432\u044b\u0447\u0438\u0441\u043b\u0438\u043c \u0446\u0435\u043d\u0442\u0440 \u0442\u044f\u0436\u0435\u0441\u0442\u0438 \u043a\u043e\u043d\u0442\u0443\u0440\u0430     sum_x = 0.0     sum_y = 0.0     for point in countour:         x = float(point[0][0])         y = float(point[0][1])         sum_x += x         sum_y += y     xc = sum_x \/ float(len((countour)))     yc = sum_y \/ float(len((countour)))     return xc,yc  def get_beg_point(countour,xc,yc):     max = 0     beg_point = -1     for i in range(0, len(countour)):         point = countour[i]         x = float(point[0][0])         y = float(point[0][1])         dx = x - xc         dy = y - yc         r = math.sqrt(dx * dx + dy * dy)         if r > max:             max = r             beg_point = i         return beg_point  def get_polar_coordinates(x0,y0,x,y,xc,yc):     #\u041f\u0435\u0440\u0432\u0430\u044f \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u0430 \u0432 \u043f\u043e\u043b\u044f\u0440\u043d\u044b\u0445 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u0430\u0445 - \u0440\u0430\u0434\u0438\u0443\u0441     dx=xc-x     dy=yc-y     r=math.sqrt(dx*dx+dy*dy)      #\u0412\u0442\u043e\u0440\u0430\u044f \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u0430 \u0432 \u043f\u043e\u043b\u044f\u0440\u043d\u044b\u0445 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u0430\u0445 - \u0443\u0437\u0435\u043b, \u0432\u044b\u0447\u0438\u0441\u043b\u0438\u043c \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e\u0439 \u0442\u043e\u0447\u043a\u0438     dx0=xc-x0     dy0=yc-y0     r0 = math.sqrt(dx0 * dx0 + dy0 * dy0)     scal_mul=dx0*dx+dy0*dy     cos_angle=scal_mul\/r\/r0     sgn=dx0*dy-dx*dy0 #\u043e\u043f\u0440\u0435\u0434\u0435\u0434\u043b\u044f\u0435\u043c, \u0432 \u043a\u0430\u043a\u0443\u044e \u0441\u0442\u043e\u0440\u043e\u043d\u0443 \u043f\u043e\u0432\u0435\u0440\u043d\u0443\u0442 \u0432\u0435\u043a\u0442\u043e\u0440     if cos_angle>1:         if cos_angle>1.0001:             raise Exception(\"\u0427\u0442\u043e-\u0442\u043e \u043f\u043e\u0448\u043b\u043e \u043d\u0435 \u0442\u0430\u043a\")         cos_angle=1     angle=math.acos(cos_angle)     if sgn&lt;0:         angle=2*math.pi-angle     return angle,r  def polar_to_decart(angle,r):     x=math.sin(angle)*r     y=math.cos(angle)*r     return x,y  def polar_sort(item):     return item[0]  def get_polar_coordinates_list(countour,xc,yc,beg_point):     polar_coordinates = []     x0 = countour[beg_point][0][0]     y0 = countour[beg_point][0][1]     for point in countour:         x = int(point[0][0])         y = int(point[0][1])         angle, r = get_polar_coordinates(x0, y0, x, y, xc, yc)         polar_coordinates.append((angle, r))      # \u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0432\u0435\u043a\u0442\u043e\u0440 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435     polar_coordinates.sort(key=polar_sort)      return polar_coordinates<\/code><\/pre>\n<p>\u00a0\u041e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u0444\u0430\u0439\u043b \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b:<\/p>\n<pre><code class=\"python\">import math import matplotlib.pyplot as plt import cv2 import numpy as np  from SignLib import custom_sort, get_center, get_beg_point, get_polar_coordinates_list, polar_to_decart  img = cv2.imread(\"Samples\/battery.jpg\") gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) thresh = 100  #get threshold image ret,thresh_img = cv2.threshold(gray, thresh, 255, cv2.THRESH_BINARY)  # find contours without approx contours,_ = cv2.findContours(thresh_img,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE) contours=list(contours) contours.sort(key=custom_sort) sel_countour=contours[1] xc,yc=get_center(sel_countour) beg_point=get_beg_point(sel_countour,xc,yc) polar_coord=get_polar_coordinates_list(sel_countour,xc,yc,beg_point) count=100 full_angle=2*math.pi i=1 end_angle = float(i) * full_angle \/ float(count) summ=0.0 count_angles=0.0 signature=[] for item_coord in polar_coord:     angle,r=item_coord     if angle>end_angle:         signature.append((angle,summ\/count_angles))         i+=1         end_angle = float(i) * full_angle \/ float(count)         summ=0         count_angles=0     summ+=r     count_angles+=1 signature.append((angle,summ\/count_angles)) print(signature)  img_contours = np.zeros((img.shape[0],img.shape[1],3), np.uint8) # np.uint8(np.zeros((img.shape[0],img.shape[1]))) cv2.drawContours(img_contours, [sel_countour], -1, (255,0,0), 1)  for i in range(1,len(signature)):     angle1,r1=signature[i-1]     angle2,r2=signature[i]     x1, y1=polar_to_decart(angle1,r1)     x2, y2 = polar_to_decart(angle2, r2)     cv2.line(img_contours, (int(x1+xc), int(y1+yc)), (int(x2+xc), int(y2+yc)), (0,0,255), thickness=1) angle1,r1=signature[len(signature)-1] angle2,r2=signature[0] x1, y1=polar_to_decart(angle1,r1) x2, y2 = polar_to_decart(angle2, r2) cv2.line(img_contours, (int(x1+xc), int(y1+yc)), (int(x2+xc), int(y2+yc)), (0,0,255), thickness=1)  cv2.imshow('origin', img) # \u0432\u044b\u0432\u043e\u0434\u0438\u043c \u0438\u0442\u043e\u0433\u043e\u0432\u043e\u0435 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u0432 \u043e\u043a\u043d\u043e cv2.imshow('res', img_contours) # \u0432\u044b\u0432\u043e\u0434\u0438\u043c \u0438\u0442\u043e\u0433\u043e\u0432\u043e\u0435 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u0432 \u043e\u043a\u043d\u043e  x=[] y=[] for item in signature:     angle,r=item     x.append(angle)     y.append(r)  plt.plot(x,y) plt.show()  cv2.waitKey() cv2.destroyAllWindows()<\/code><\/pre>\n<\/p>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"v-portal\" style=\"display:none;\"><\/div>\n<\/div>\n<p> <!----> <!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/post\/687864\/\"> https:\/\/habr.com\/ru\/post\/687864\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u041d\u0430 <a href=\"https:\/\/habr.com\/ru\/post\/676838\/\" rel=\"noopener noreferrer nofollow\">\u043f\u0440\u043e\u0448\u043b\u043e\u043c \u0443\u0440\u043e\u043a\u0435<\/a> \u043c\u044b \u0443\u0433\u043b\u0443\u0431\u0438\u043b\u0438\u0441\u044c \u0432 \u0438\u0437\u0443\u0447\u0435\u043d\u0438\u0435 \u043a\u043e\u043d\u0442\u0443\u0440\u043e\u0432. \u0412 \u0447\u0430\u0441\u0442\u043d\u043e\u0441\u0442\u0438, \u043d\u0430\u0443\u0447\u0438\u043b\u0438\u0441\u044c \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0441\u043e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u043e\u0439, \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u0432\u044b\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u043a\u043e\u043d\u0442\u0443\u0440\u043e\u0432, \u043d\u0430\u0443\u0447\u0438\u043b\u0438\u0441\u044c \u0430\u043f\u043f\u0440\u043e\u043a\u0441\u0438\u043c\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0438 \u043e\u0431\u0445\u043e\u0434\u0438\u0442\u044c \u043a\u043e\u043d\u0442\u0443\u0440, \u043d\u0430\u0443\u0447\u0438\u043b\u0438\u0441\u044c \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043a\u043e\u0435-\u043a\u0430\u043a\u0438\u0435 \u0433\u0435\u043e\u043c\u0435\u0442\u0440\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438, \u0447\u0442\u043e\u0431\u044b \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0438\u043d\u0432\u0430\u0440\u0438\u0430\u043d\u0442\u043d\u043e\u0435 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u043e\u0431\u044a\u0435\u043a\u0442\u0430. \u041d\u0430\u043f\u043e\u043c\u043d\u044e, \u043a\u0430\u043a \u044d\u0442\u043e \u043c\u044b \u0441\u0434\u0435\u043b\u0430\u043b\u0438: \u043d\u0430\u0448\u043b\u0438 \u043a\u043e\u043d\u0442\u0443\u0440 \u043e\u0431\u044a\u0435\u043a\u0442\u0430, \u0430\u043f\u043f\u0440\u043e\u043a\u0441\u0438\u043c\u0438\u0440\u043e\u0432\u0430\u043b\u0438 \u0435\u0433\u043e, \u043e\u0431\u043e\u0448\u043b\u0438 \u044d\u0442\u043e\u0442 \u043a\u043e\u043d\u0442\u0443\u0440, \u0432\u044b\u0447\u0438\u0441\u043b\u0438\u043b\u0438 \u043a\u043e\u0441\u0438\u043d\u0443\u0441\u044b \u0443\u0433\u043b\u043e\u0432 \u043c\u0435\u0436\u0434\u0443 \u0433\u0440\u0430\u043d\u044f\u043c\u0438 \u0430\u043f\u043f\u0440\u043e\u043a\u0441\u0438\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0433\u043e \u043a\u043e\u043d\u0442\u0443\u0440\u0430. <\/p>\n<p>\u0421\u0435\u0433\u043e\u0434\u043d\u044f \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0438\u043c \u0442\u0435\u043c\u0443 <a href=\"https:\/\/habr.com\/ru\/post\/676838\/\" rel=\"noopener noreferrer nofollow\">\u043f\u0440\u043e\u0448\u043b\u043e\u0433\u043e \u0443\u0440\u043e\u043a\u0430<\/a>. \u0412\u044b\u0447\u0438\u0441\u043b\u0438\u043c \u0438\u043d\u0432\u0430\u0440\u0438\u0430\u043d\u0442\u043d\u044b\u0439 \u0432\u0435\u043a\u0442\u043e\u0440 \u043d\u043e\u0432\u044b\u043c \u043c\u0435\u0442\u043e\u0434\u043e\u043c: \u0447\u0435\u0440\u0435\u0437 \u043e\u0442\u043d\u043e\u0448\u0435\u043d\u0438\u044f \u0434\u043b\u0438\u043d \u0441\u0442\u043e\u0440\u043e\u043d. \u041c\u044b \u043d\u0430\u0447\u043d\u0435\u043c \u043e\u0431\u0445\u043e\u0434 \u0442\u0430\u043a \u0436\u0435 \u0441 \u0441\u0430\u043c\u043e\u0439 \u0443\u0434\u0430\u043b\u0435\u043d\u043d\u043e\u0439 \u043e\u0442 \u0446\u0435\u043d\u0442\u0440\u0430 \u0442\u043e\u0447\u043a\u0438, \u0442\u043e\u043b\u044c\u043a\u043e \u0431\u0443\u0434\u0435\u043c \u0431\u0440\u0430\u0442\u044c \u0441\u0442\u043e\u0440\u043e\u043d\u044b, \u0430 \u043d\u0435 \u0443\u0433\u043b\u044b \u043c\u0435\u0436\u0443 \u0441\u0442\u043e\u0440\u043e\u043d\u0430\u043c\u0438. \u0418 \u043f\u0435\u0440\u0432\u0430\u044f \u0441\u0442\u043e\u0440\u043e\u043d\u0430 \u044d\u0442\u043e \u0442\u0430, \u0447\u0442\u043e \u043f\u0440\u0438\u043b\u0435\u0433\u0430\u0435\u0442 \u043a \u043f\u0435\u0440\u0432\u043e\u0439 \u0442\u043e\u0447\u043a\u0435. \u0422\u043e \u0435\u0441\u0442\u044c \u043e\u043d\u0430 \u0441\u043e\u0435\u0434\u0438\u043d\u044f\u0435\u0442 \u043f\u0435\u0440\u0432\u0443\u044e \u0442\u043e\u0447\u043a\u0443 \u0438 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0443\u044e \u0437\u0430 \u043d\u0435\u0439 \u043f\u043e \u0447\u0430\u0441\u043e\u0432\u043e\u0439 \u0441\u0442\u0440\u0435\u043b\u043a\u0435. \u0418 \u0432\u0441\u0435 \u044d\u0442\u0438 \u0434\u043b\u0438\u043d\u044b \u0441\u0442\u043e\u0440\u043e\u043d \u043c\u044b \u0440\u0430\u0437\u0434\u0435\u043b\u0438\u043c \u043d\u0430 \u0441\u0430\u043c\u0443\u044e \u0434\u043b\u0438\u043d\u043d\u0443\u044e \u0441\u0442\u043e\u0440\u043e\u043d\u0443. \u0425\u043e\u0442\u044f \u043d\u0435\u0442, \u0441\u0434\u0435\u043b\u0430\u043c \u043b\u0443\u0447\u0448\u0435. \u0421\u0434\u0435\u043b\u0430\u0435\u043c \u043c\u0438\u043d\u0438\u043c\u0430\u043a\u0441 \u043d\u043e\u0440\u043c\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e: \u0432\u044b\u0447\u0442\u0435\u043c \u0438\u0437 \u0434\u043b\u0438\u043d\u044b \u0441\u0442\u043e\u0440\u043e\u043d\u044b \u043c\u0438\u043d\u0438\u043c\u0443\u043c \u0438 \u0440\u0430\u0437\u0434\u0435\u043b\u0438\u043c \u043d\u0430 \u0440\u0430\u0437\u043d\u0438\u0446\u0443 \u043c\u0435\u0436\u0434\u0443 \u043c\u0438\u043d\u0438\u043c\u0443\u043c\u043e\u043c \u0438 \u043c\u0430\u043a\u0441\u0438\u043c\u0443\u043c\u043e\u043c. \u0423 \u043d\u0430\u0441 \u0431\u0443\u0434\u0435\u0442 \u0432\u0435\u043a\u0442\u043e\u0440 \u0447\u0438\u0441\u0435\u043b \u043e\u0442 0 \u0434\u043e 1. <\/p>\n<p>\u0418 \u0442\u0430\u043a, \u0437\u0430\u0439\u043c\u0435\u043c\u0441\u044f \u043a\u043e\u0434\u0438\u043d\u0433\u043e\u043c. \u0421\u043d\u0430\u0447\u0430\u043b\u0430 \u043d\u0430\u043f\u0438\u0448\u0435\u043c \u0446\u0438\u043a\u043b, \u0441\u043e\u0437\u0434\u0430\u044e\u0449\u0438\u0439 \u0438\u0441\u0445\u043e\u0434\u043d\u044b\u0439 \u043c\u0430\u0441c\u0438\u0432:<\/p>\n<pre><code class=\"python\">lengths=[] for i in range(size-1):     lengths.append(get_length(polar_coordinates[i],polar_coordinates[i+1])) lengths.append(get_length(polar_coordinates[size-1],polar_coordinates[0])) print(get_normalize_normalize(lengths))<\/code><\/pre>\n<p>\u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0432\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u044f \u0434\u043b\u0438\u043d\u044b \u0441\u0442\u043e\u0440\u043e\u043d\u044b (\u043e\u043d\u0430 \u043f\u0440\u043e\u0441\u0442\u043e \u0438\u0437\u0432\u0435\u043a\u0430\u0435\u0442 \u0438\u0437 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b, \u0433\u0434\u0435 \u0443 \u043d\u0430\u0441 \u0432\u0441\u0435 \u0445\u0440\u0430\u043d\u0438\u0442\u044c\u0441\u044f, \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u044b \u0438 \u0441\u0447\u0438\u0442\u0430\u0435\u0442 \u044d\u0432\u043a\u043b\u0438\u0434\u043e\u0432\u043e \u0440\u0430\u0441\u0441\u0442\u043e\u044f\u043d\u0438\u0435):<\/p>\n<pre><code class=\"python\">#\u042d\u0432\u043a\u043b\u0438\u0434\u043e\u0432\u043e \u0440\u0430\u0441\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u043c\u0435\u0436\u0434\u0443 \u0434\u0432\u0443\u043c\u044f \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u043c\u0438 def get_length(item1, item2):     _, point1 = item1     _, point2 = item2     x1, y1 = point1     x2, y2 = point2     dx=x1-x2     dy=y1-y2     r=math.sqrt(dx*dx+dy*dy)     return r<\/code><\/pre>\n<p>\u041d\u0443 \u0438 \u043d\u043e\u0440\u043c\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f, \u043a\u043e\u043d\u0432\u0435\u0440\u0442\u0438\u043c \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u044b\u0439 \u0441\u043f\u0438\u0441\u043e\u043a \u0432 numpy \u043c\u0430\u0441\u0441\u0438\u0432 \u0438 \u0434\u0435\u043b\u0430\u0435\u043c \u043c\u0438\u043d\u0438\u043c\u0430\u043a\u0441 \u043d\u043e\u0440\u043c\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e: <\/p>\n<pre><code class=\"python\">def get_normalized_vector(list):     arr=np.array(list)     return (arr-arr.min())\/(arr.max()-arr.min())<\/code><\/pre>\n<p>\u041f\u043e\u0435\u0445\u0430\u043b\u0438 \u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c, \u0447\u0442\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u043e\u0441\u044c.<\/p>\n<p>\u041f\u0435\u0440\u0432\u044b\u0439 \u043f\u0440\u0438\u043c\u0435\u0440:<\/p>\n<figure class=\"full-width\"><figcaption><\/figcaption><\/figure>\n<p>\u0412\u0435\u043a\u0442\u043e\u0440: [0.11331868 1.\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 0.\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 0.02997931 0.96756226 0.1022278 ]<\/p>\n<p>\u00a0<\/p>\n<p>\u0412\u0442\u043e\u0440\u043e\u0439 \u043f\u0440\u0438\u043c\u0435\u0440:<\/p>\n<figure class=\"full-width\"><figcaption><\/figcaption><\/figure>\n<p>\u0412\u0435\u043a\u0442\u043e\u0440: [0.16953268 0.9532099\u00a0 0.\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 0.01245409 1.\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 0.10313678]<\/p>\n<p>\u00a0<\/p>\n<p>\u041a\u0430\u043a \u0432\u0438\u0434\u0438\u043c, \u0432\u0435\u043a\u0442\u043e\u0440\u044b \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u043e\u043a\u0430\u0437\u0430\u043b\u0438\u0441\u044c \u0431\u043b\u0438\u0437\u043a\u0438\u0435. \u041f\u0440\u0438\u0447\u0435\u043c, \u0432 \u043e\u0442\u043b\u0438\u0447\u0438\u0435 \u043e\u0442 \u043f\u0440\u043e\u0448\u043b\u043e\u0433\u043e \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u0430, \u0443 \u043d\u0430\u0441 \u043e\u0441\u0442\u0430\u044e\u0442\u0441\u044f \u0441\u0442\u0430\u0431\u0438\u043b\u044c\u043d\u044b\u043c\u0438 \u0432\u0441\u0435 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u044b \u0432\u0435\u043a\u0442\u043e\u0440\u0430.<\/p>\n<p>\u0412\u043e\u043e\u0431\u0449\u0435, \u043f\u043e-\u0445\u043e\u0440\u043e\u0448\u0435\u043c\u0443, \u043a\u043e\u043d\u0435\u0447\u043d\u043e \u043d\u0430\u0434\u043e \u0431\u044b \u043f\u0440\u043e\u0432\u0435\u0441\u0442\u0438 \u0438\u0441\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u043d\u0438\u0435: \u043f\u0440\u043e\u0430\u043d\u0430\u043b\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u043e \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0439, \u0441\u0440\u0430\u0432\u043d\u0438\u0442\u044c, \u043d\u0430\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0440\u0430\u0441\u0445\u043e\u0434\u044f\u0442\u0441\u044f \u0432\u0435\u043a\u0442\u043e\u0440\u044b \u0438\u043d\u0432\u0430\u0440\u0438\u0430\u043d\u0442\u043d\u044b\u0445 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0439 \u043f\u0440\u0438 \u0442\u043e\u043c \u0438\u043b\u0438 \u0438\u043d\u043e\u043c \u043c\u0435\u0442\u043e\u0434\u0435 \u0440\u0430\u0441\u0447\u0435\u0442\u0430. \u0414\u0430 \u0438 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0430 \u043d\u0443\u0436\u0434\u0430\u0435\u0442\u0441\u044f \u0432 \u0440\u0435\u0444\u0430\u043a\u0442\u043e\u0440\u0438\u043d\u0433\u0435. \u041d\u043e \u044d\u0442\u043e \u0443\u0436\u0435 \u0432\u044b\u0445\u043e\u0434\u0438\u0442 \u0437\u0430 \u0440\u0430\u043c\u043a\u0438 \u0443\u0440\u043e\u043a\u043e\u0432. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u044f \u043f\u0440\u0438\u0432\u043e\u0436\u0443 \u043f\u043e\u043b\u043d\u044b\u0439 \u043a\u043e\u0434 \u043f\u0440\u0438\u043c\u0435\u0440\u043e\u0432 \u043a\u0430\u043a \u0435\u0441\u0442\u044c, \u0438 \u043c\u044b \u0434\u0432\u0438\u0433\u0430\u0435\u043c\u0441\u044f \u0434\u0430\u043b\u044c\u0448\u0435:<\/p>\n<pre><code class=\"python\">import cv2 import numpy as np import math import os img = cv2.imread(\"Samples\/1.jpg\") gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) thresh = 100  def custom_sort(countour):     return -countour.shape[0]  def polar_sort(item):     return item[0][0]  def get_normalized_vector(list):     arr=np.array(list)     return (arr-arr.min())\/(arr.max()-arr.min())  #\u042d\u0432\u043a\u043b\u0438\u0434\u043e\u0432\u043e \u0440\u0430\u0441\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u043c\u0435\u0436\u0434\u0443 \u0434\u0432\u0443\u043c\u044f \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u043c\u0438 def get_length(item1, item2):     _, point1 = item1     _, point2 = item2     x1, y1 = point1     x2, y2 = point2     dx=x1-x2     dy=y1-y2     r=math.sqrt(dx*dx+dy*dy)     return r  def get_cos_edges(edges):     dx1, dy1, dx2, dy2=edges     r1 = math.sqrt(dx1 * dx1 + dy1 * dy1)     r2 = math.sqrt(dx2 * dx2 + dy2 * dy2)     return (dx1*dx2+dy1*dy2)\/r1\/r2  def get_polar_coordinates(x0,y0,x,y,xc,yc):     #\u041f\u0435\u0440\u0432\u0430\u044f \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u0430 \u0432 \u043f\u043e\u043b\u044f\u0440\u043d\u044b\u0445 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u0430\u0445 - \u0440\u0430\u0434\u0438\u0443\u0441     dx=xc-x     dy=yc-y     r=math.sqrt(dx*dx+dy*dy)      #\u0412\u0442\u043e\u0440\u0430\u044f \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u0430 \u0432 \u043f\u043e\u043b\u044f\u0440\u043d\u044b\u0445 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u0430\u0445 - \u0443\u0437\u0435\u043b, \u0432\u044b\u0447\u0438\u0441\u043b\u0438\u043c \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e\u0439 \u0442\u043e\u0447\u043a\u0438     dx0=xc-x0     dy0=yc-y0     r0 = math.sqrt(dx0 * dx0 + dy0 * dy0)     scal_mul=dx0*dx+dy0*dy     cos_angle=scal_mul\/r\/r0     sgn=dx0*dy-dx*dy0 #\u043e\u043f\u0440\u0435\u0434\u0435\u0434\u043b\u044f\u0435\u043c, \u0432 \u043a\u0430\u043a\u0443\u044e \u0441\u0442\u043e\u0440\u043e\u043d\u0443 \u043f\u043e\u0432\u0435\u0440\u043d\u0443\u0442 \u0432\u0435\u043a\u0442\u043e\u0440     if cos_angle>1:         if cos_angle>1.0001:             raise Exception(\"\u0427\u0442\u043e-\u0442\u043e \u043f\u043e\u0448\u043b\u043e \u043d\u0435 \u0442\u0430\u043a\")         cos_angle=1     angle=math.acos(cos_angle)     if sgn&lt;0:         angle=2*math.pi-angle     return angle,r  def get_coords(item1, item2, item3):     _, point1 = item1     _, point2 = item2     _, point3 = item3     x1, y1 = point1     x2, y2 = point2     x3, y3 = point3     dx1=x1-x2     dy1=y1-y2     dx2=x3-x2     dy2=y3-y2     return dx1,dy1,dx2,dy2  #get threshold image ret,thresh_img = cv2.threshold(gray, thresh, 255, cv2.THRESH_BINARY)  # find contours without approx contours,_ = cv2.findContours(thresh_img,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE) contours=list(contours) contours.sort(key=custom_sort) sel_countour=contours[1]  # calc arclentgh arclen = cv2.arcLength(sel_countour, True)  # do approx eps = 0.01 epsilon = arclen * eps approx = cv2.approxPolyDP(sel_countour, epsilon, True)  sum_x=0.0 sum_y=0.0 for point in approx:     x = float(point[0][0])     y = float(point[0][1])     sum_x+=x     sum_y+=y xc=sum_x\/float(len((approx))) yc=sum_y\/float(len((approx)))  max=0 beg_point=-1 for i in range(0,len(approx)):     point=approx[i]     x = float(point[0][0])     y = float(point[0][1])     dx=x-xc     dy=y-yc     r=math.sqrt(dx*dx+dy*dy)     if r>max:         max=r         beg_point=i  polar_coordinates=[] x0=approx[beg_point][0][0] y0=approx[beg_point][0][1]  for point in approx:     x = int(point[0][0])     y = int(point[0][1])     angle,r=get_polar_coordinates(x0,y0,x,y,xc,yc)     polar_coordinates.append(((angle,r),(x,y)))  polar_coordinates.sort(key=polar_sort)  img_contours = np.uint8(np.zeros((img.shape[0],img.shape[1]))) size=len(polar_coordinates) for i in range(1,size):     _ , point1=polar_coordinates[i-1]     _, point2 = polar_coordinates[i]     x1,y1=point1     x2,y2=point2     cv2.line(img_contours, (x1, y1), (x2, y2), 255, thickness=i) _ , point1=polar_coordinates[size-1] _, point2 = polar_coordinates[0] x1,y1=point1 x2,y2=point2 cv2.line(img_contours, (x1, y1), (x2, y2), 255, thickness=size)  cv2.circle(img_contours, (int(xc), int(yc)), 7, (255,255,255), 2)  coses=[] coses.append(get_cos_edges(get_coords(polar_coordinates[size-1],polar_coordinates[0],polar_coordinates[1]))) for i in range(1,size-1):     coses.append(get_cos_edges(get_coords(polar_coordinates[i-1], polar_coordinates[i],polar_coordinates[i+1]))) coses.append(get_cos_edges(get_coords(polar_coordinates[size-2], polar_coordinates[size-1],polar_coordinates[0]))) print(coses)  lengths=[] for i in range(size-1):     lengths.append(get_length(polar_coordinates[i],polar_coordinates[i+1])) lengths.append(get_length(polar_coordinates[size-1],polar_coordinates[0])) print(get_normalized_vector(lengths))    point=approx[beg_point] x = float(point[0][0]) y = float(point[0][1]) cv2.circle(img_contours, (int(x), int(y)), 7, (255,255,255), 2)  cv2.imshow('origin', img) # \u0432\u044b\u0432\u043e\u0434\u0438\u043c \u0438\u0442\u043e\u0433\u043e\u0432\u043e\u0435 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u0432 \u043e\u043a\u043d\u043e cv2.imshow('res', img_contours) # \u0432\u044b\u0432\u043e\u0434\u0438\u043c \u0438\u0442\u043e\u0433\u043e\u0432\u043e\u0435 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u0432 \u043e\u043a\u043d\u043e  cv2.waitKey() cv2.destroyAllWindows()<\/code><\/pre>\n<p>\u041d\u0430\u0448 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u0448\u0430\u0433 \u0432 \u043e\u0441\u0432\u043e\u0435\u043d\u0438\u0438 OpenCV \u2013 \u044d\u0442\u043e \u043f\u043e\u0438\u0441\u043a \u043f\u0440\u0435\u0434\u043c\u0435\u0442\u0430 \u043d\u0430 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0438. \u0418\u0441\u043a\u0430\u0442\u044c \u043c\u044b \u0431\u0443\u0434\u0435\u0442 \u0432\u0441\u0435 \u0442\u0443 \u0436\u0435 \u0440\u0443\u0447\u043a\u0443, \u043d\u043e \u0442\u0435\u043f\u0435\u0440\u044c \u043d\u0430 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0438 \u0443 \u043d\u0430\u0441 \u0431\u0443\u0434\u0443\u0442 \u0434\u0440\u0443\u0433\u0438\u0435 \u043f\u0440\u0435\u0434\u043c\u0435\u0442\u044b:<\/p>\n<figure class=\"\"><figcaption><\/figcaption><\/figure>\n<p>\u0417\u0434\u0435\u0441\u044c \u043c\u044b \u0442\u043e\u0447\u043d\u043e \u0442\u0430\u043a \u0436\u0435 \u0432\u044b\u0434\u0435\u043b\u0438\u043c \u043a\u043e\u043d\u0442\u0443\u0440\u044b \u043d\u0430 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0438, \u0430 \u043f\u043e\u0442\u043e\u043c \u043a\u0430\u0436\u0434\u044b\u0439 \u0438\u0437 \u043a\u043e\u043d\u0442\u0443\u0440\u043e\u0432 \u0431\u0443\u0434\u0435\u043c \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0442\u044c \u043d\u0430 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0438\u0438 \u0437\u0430\u0434\u0430\u043d\u043d\u043e\u043c\u0443 \u0448\u0430\u0431\u043b\u043e\u043d\u0443 \u2013 \u0448\u0435\u0441\u0442\u044c \u0433\u0440\u0430\u043d\u0435\u0439 \u0438 \u0432\u0435\u043a\u0442\u043e\u0440 \u0438\u043d\u0432\u0430\u0440\u0438\u0430\u043d\u0442\u043d\u043e\u0433\u043e \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u0431\u043b\u0438\u0437\u043e\u043a \u043a \u0438\u0441\u0445\u043e\u0434\u043d\u043e\u043c\u0443. \u041d\u0430\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0431\u043b\u0438\u0437\u043e\u043a? \u042d\u0442\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043c \u044d\u043c\u043f\u0438\u0440\u0438\u0447\u0435\u0441\u043a\u0438\u043c \u043f\u0443\u0442\u0435\u043c, \u043f\u043e\u0434\u0431\u0438\u0440\u0430\u044f \u043f\u043e\u0440\u043e\u0433.<\/p>\n<p>\u0418 \u0442\u0430\u043a, \u0432\u043e\u0442 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0430:<\/p>\n<pre><code class=\"python\">import cv2 import numpy as np import math  template_vector=np.array([0.16953268, 0.9532099, 0, 0.01245409, 1, 0.10313678]) distance_thresh=0.1  img = cv2.imread(\"Samples\/objects.jpg\") gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) thresh = 100  def polar_sort(item):     return item[0][0]  def get_normalized_vector(list):     arr=np.array(list)     return (arr-arr.min())\/(arr.max()-arr.min())  #\u042d\u0432\u043a\u043b\u0438\u0434\u043e\u0432\u043e \u0440\u0430\u0441\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u043c\u0435\u0436\u0434\u0443 \u0434\u0432\u0443\u043c\u044f \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u043c\u0438 def get_length(item1, item2):     _, point1 = item1     _, point2 = item2     x1, y1 = point1     x2, y2 = point2     dx=x1-x2     dy=y1-y2     r=math.sqrt(dx*dx+dy*dy)     return r  def get_polar_coordinates(x0,y0,x,y,xc,yc):     #\u041f\u0435\u0440\u0432\u0430\u044f \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u0430 \u0432 \u043f\u043e\u043b\u044f\u0440\u043d\u044b\u0445 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u0430\u0445 - \u0440\u0430\u0434\u0438\u0443\u0441     dx=xc-x     dy=yc-y     r=math.sqrt(dx*dx+dy*dy)      #\u0412\u0442\u043e\u0440\u0430\u044f \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u0430 \u0432 \u043f\u043e\u043b\u044f\u0440\u043d\u044b\u0445 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u0430\u0445 - \u0443\u0437\u0435\u043b, \u0432\u044b\u0447\u0438\u0441\u043b\u0438\u043c \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e\u0439 \u0442\u043e\u0447\u043a\u0438     dx0=xc-x0     dy0=yc-y0     r0 = math.sqrt(dx0 * dx0 + dy0 * dy0)     scal_mul=dx0*dx+dy0*dy     cos_angle=scal_mul\/r\/r0     sgn=dx0*dy-dx*dy0 #\u043e\u043f\u0440\u0435\u0434\u0435\u0434\u043b\u044f\u0435\u043c, \u0432 \u043a\u0430\u043a\u0443\u044e \u0441\u0442\u043e\u0440\u043e\u043d\u0443 \u043f\u043e\u0432\u0435\u0440\u043d\u0443\u0442 \u0432\u0435\u043a\u0442\u043e\u0440     if cos_angle>1:         if cos_angle>1.0001:             raise Exception(\"\u0427\u0442\u043e-\u0442\u043e \u043f\u043e\u0448\u043b\u043e \u043d\u0435 \u0442\u0430\u043a\")         cos_angle=1     angle=math.acos(cos_angle)     if sgn&lt;0:         angle=2*math.pi-angle     return angle,r   #get threshold image ret,thresh_img = cv2.threshold(gray, thresh, 255, cv2.THRESH_BINARY)  # find contours without approx contours,_ = cv2.findContours(thresh_img,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE) for sel_countour in contours:     # calc arclentgh     arclen = cv2.arcLength(sel_countour, True)      # do approx     eps = 0.01     epsilon = arclen * eps     approx = cv2.approxPolyDP(sel_countour, epsilon, True)      #\u041e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u043c \u0442\u043e\u043b\u044c\u043a\u043e \u043a\u043e\u043d\u0442\u0443\u0440\u044b \u0434\u043b\u0438\u043d\u043e\u0439 6 \u0443\u0433\u043b\u043e\u0432     if len(approx)==6:          # \u0432\u044b\u0447\u0438\u0441\u043b\u0438\u043c \u0446\u0435\u043d\u0442\u0440 \u0442\u044f\u0436\u0435\u0441\u0442\u0438 \u043a\u043e\u043d\u0442\u0443\u0440\u0430         sum_x = 0.0         sum_y = 0.0         for point in approx:             x = float(point[0][0])             y = float(point[0][1])             sum_x += x             sum_y += y         xc = sum_x \/ float(len((approx)))         yc = sum_y \/ float(len((approx)))          #\u043d\u0430\u0439\u0434\u0435\u043c \u043d\u0430\u0447\u0430\u043b\u044c\u043d\u0443\u044e \u0442\u043e\u0447\u043a\u0443         max = 0         beg_point = -1         for i in range(0, len(approx)):             point = approx[i]             x = float(point[0][0])             y = float(point[0][1])             dx = x - xc             dy = y - yc             r = math.sqrt(dx * dx + dy * dy)             if r > max:                 max = r                 beg_point = i          #\u0412\u044b\u0447\u0438\u0441\u043b\u043c\u0438 \u043f\u043e\u043b\u044f\u0440\u043d\u044b\u0435 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u044b         polar_coordinates=[]         x0=approx[beg_point][0][0]         y0=approx[beg_point][0][1]         for<\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-338271","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/338271","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=338271"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/338271\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=338271"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=338271"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=338271"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}