perimetr.py 2.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273
  1. import cv2
  2. import matplotlib.pyplot as plt
  3. import numpy as np
  4. sum_length = 0
  5. def extract_and_measure_edges(img_bin):
  6. # Detect possible corners, and extract candidates
  7. dst = cv2.cornerHarris(img_bin, 2, 3, 0.04)
  8. cand = []
  9. for i, c in enumerate(np.argwhere(dst > 0.1 * np.max(dst)).tolist()):
  10. c = np.flip(np.array(c))
  11. if len(cand) == 0:
  12. cand.append(c)
  13. else:
  14. add = True
  15. for j, d in enumerate(cand):
  16. d = np.array(d)
  17. if np.linalg.norm(c - d) < 5:
  18. add = False
  19. break
  20. if add:
  21. cand.append(c)
  22. # Get indices of actual, nearest matching contour points
  23. corners = sorted([np.argmin(np.linalg.norm(c - cnt.squeeze(), axis=1))
  24. for c in cand])
  25. # Extract edges from contour, and measure their lengths
  26. output = cv2.cvtColor(np.zeros_like(img_bin), cv2.COLOR_GRAY2BGR)
  27. #sum_length = 0
  28. for i_c, c in enumerate(corners):
  29. if i_c == len(corners) - 1:
  30. edge = np.vstack([cnt[c:, ...], cnt[0:corners[0], ...]])
  31. else:
  32. edge = cnt[c:corners[i_c + 1], ...]
  33. loc = tuple(np.mean(edge.squeeze(), axis=0, dtype=int).tolist())
  34. color = tuple(np.random.randint(0, 255, 3).tolist())
  35. length = cv2.arcLength(edge, False)
  36. global sum_length
  37. sum_length += length
  38. cv2.polylines(output, [edge], False, color, 2)
  39. cv2.putText(output, '{:.2f}'.format(length), loc, cv2.FONT_HERSHEY_COMPLEX, 0.5, color, 1)
  40. #print(sum_length)
  41. return output
  42. # Read and pre-process image, extract contour of shape
  43. # TODO: MODIFY TO FIT YOUR INPUT IMAGES
  44. img = cv2.imread('test4.png')
  45. gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
  46. thr = cv2.threshold(gray, 16, 255, cv2.THRESH_BINARY_INV)[1]
  47. cnts = cv2.findContours(thr, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
  48. cnts = cnts[0] if len(cnts) == 2 else cnts[1]
  49. cnt = max(cnts, key=cv2.contourArea)
  50. thr = cv2.drawContours(np.zeros_like(thr), [cnt], -1, 255, 1)
  51. # Extract and measure edges, and visualize output
  52. out = extract_and_measure_edges(thr)
  53. plt.figure(figsize=(18, 6))
  54. plt.subplot(1, 3, 1), plt.imshow(img), plt.title('Original input image')
  55. plt.subplot(1, 3, 2), plt.imshow(thr, cmap='gray'), plt.title('Contour needed')
  56. plt.subplot(1, 3, 3), plt.imshow(out), plt.title(f'Results: perimetr = {round(sum_length)}')
  57. plt.savefig('result4.png')
  58. plt.tight_layout(), plt.show()