Advertisement
dan-masek

Untitled

Nov 14th, 2022
935
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 3.87 KB | None | 0 0
  1. from functools import partial
  2.  
  3. import cv2
  4. import numpy as np
  5.  
  6. # ======================================
  7.  
  8. def partition(items, predicate):
  9.     N = len(items)
  10.        
  11.     # // The first O(N) pass: create N single-vertex trees
  12.     parents = [-1] * N
  13.     ranks = [0] * N
  14.    
  15.     def _find_root(i):
  16.         _root = i
  17.         while parents[_root] >= 0:
  18.             _root = parents[_root]
  19.         return _root
  20.        
  21.     def _compress_path(i, target):
  22.         _k = i
  23.         while True:
  24.             parent = parents[_k]
  25.             if parent < 0:
  26.                 break
  27.             parents[_k] = target
  28.             _k = parent
  29.  
  30.     # The main O(N^2) pass: merge connected components
  31.     for i in range(N):
  32.         # Find root
  33.         root = _find_root(i)
  34.            
  35.         for j in range(N):
  36.             if i == j or not predicate(items[i], items[j]):
  37.                 continue
  38.            
  39.             root2 = _find_root(j)
  40.                
  41.             if root != root2:
  42.                 # Unite both trees
  43.                 rank, rank2 = ranks[root], ranks[root2]
  44.                 if rank > rank2:
  45.                     parents[root2] = root
  46.                 else:
  47.                     parents[root] = root2
  48.                     ranks[root2] += 1 if rank == rank2 else 0
  49.                     root = root2
  50.                 assert parents[root] < 0
  51.  
  52.                 _compress_path(j, root)
  53.                 _compress_path(i, root)
  54.                    
  55.     # Final O(N) pass: enumerate classes
  56.     labels = [0] * N
  57.     nclasses = 0
  58.  
  59.     for i in range(N):
  60.         root = _find_root(i)
  61.         # re-use the rank as the class label
  62.         if ranks[root] >= 0:
  63.             ranks[root] = ~nclasses
  64.             nclasses += 1
  65.         labels[i] = ~ranks[root]
  66.  
  67.     return nclasses, labels
  68.  
  69. # ======================================
  70.  
  71. def create_mask(image):
  72.     lower_brown = np.array([29, 39, 52], dtype = "uint8")
  73.     upper_brown = np.array([33, 44, 60], dtype = "uint8")
  74.     return cv2.inRange(image, lower_brown, upper_brown)
  75.  
  76. # ======================================
  77.  
  78. def get_coordinates(mask):
  79.     coord = cv2.findNonZero(mask)  
  80.     return coord.reshape(coord.shape[0], 2)
  81.  
  82. # ======================================
  83.  
  84. # Simple metric -- distance along x and y axis has to be below threshold
  85. def points_are_close_by(pt1, pt2, threshold):
  86.     return (abs(pt1[0] - pt2[0]) < threshold) and (abs(pt1[1] - pt2[1]) < threshold)
  87.  
  88. # ======================================
  89.  
  90. def cluster_coordinates(coord, threshold):
  91.     predicate = partial(points_are_close_by, threshold=threshold)
  92.     cluster_count, labels = partition(coord, predicate)
  93.  
  94.     cluster_map = {}
  95.     for i in range(cluster_count):
  96.         cluster_map[i] = []
  97.  
  98.     for label, pos in zip(labels, coord):
  99.         cluster_map[label].append(tuple(pos))
  100.  
  101.     return cluster_map
  102.  
  103. # ======================================
  104.  
  105. CLOSE_BY_THRESHOLD = 20
  106. MIN_CLUSTER_SIZE = 5
  107.  
  108. image = cv2.imread("bloodweb.png")
  109. mask = create_mask(image)
  110. cv2.imwrite("bloodweb_mask.png", mask)
  111.  
  112. coord = get_coordinates(mask)
  113. clusters = cluster_coordinates(coord, CLOSE_BY_THRESHOLD)
  114.  
  115. print("Found %d clusters." % len(clusters))
  116.  
  117. result = image.copy()
  118. for label, points in clusters.items():
  119.     if len(points) >= MIN_CLUSTER_SIZE:
  120.         center, radius = cv2.minEnclosingCircle(np.array(points))
  121.         center, radius = np.int32(center), np.int32(radius) # Brute, you may wanna do this better
  122.         print("Cluster #%d: center=(%0.3f, %0.3f) radius=%0.3f size=%d"
  123.             % (label, center[0], center[1], radius, len(points)))
  124.         cv2.circle(result, center, radius, (0,255,0), 2)
  125.         cv2.putText(result, str(label), center+radius, cv2.FONT_HERSHEY_DUPLEX, 0.6, (0,255,0), 2)
  126.     else:
  127.         print("Cluster #%d does not contain enough points (%d)." % (label, len(points)))
  128.  
  129. cv2.imwrite("bloodweb_result.png", result)
  130.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement