| 
									
										
										
										
											2020-12-09 06:45:25 +00:00
										 |  |  | """
 | 
					
						
							|  |  |  | Locality aware nms. | 
					
						
							| 
									
										
										
										
											2021-11-04 09:54:32 +00:00
										 |  |  | This code is refered from: https://github.com/songdejia/EAST/blob/master/locality_aware_nms.py | 
					
						
							| 
									
										
										
										
											2020-12-09 06:45:25 +00:00
										 |  |  | """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import numpy as np | 
					
						
							|  |  |  | from shapely.geometry import Polygon | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def intersection(g, p): | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     Intersection. | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     g = Polygon(g[:8].reshape((4, 2))) | 
					
						
							|  |  |  |     p = Polygon(p[:8].reshape((4, 2))) | 
					
						
							|  |  |  |     g = g.buffer(0) | 
					
						
							|  |  |  |     p = p.buffer(0) | 
					
						
							|  |  |  |     if not g.is_valid or not p.is_valid: | 
					
						
							|  |  |  |         return 0 | 
					
						
							|  |  |  |     inter = Polygon(g).intersection(Polygon(p)).area | 
					
						
							|  |  |  |     union = g.area + p.area - inter | 
					
						
							|  |  |  |     if union == 0: | 
					
						
							|  |  |  |         return 0 | 
					
						
							|  |  |  |     else: | 
					
						
							|  |  |  |         return inter / union | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def intersection_iog(g, p): | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     Intersection_iog. | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     g = Polygon(g[:8].reshape((4, 2))) | 
					
						
							|  |  |  |     p = Polygon(p[:8].reshape((4, 2))) | 
					
						
							|  |  |  |     if not g.is_valid or not p.is_valid: | 
					
						
							|  |  |  |         return 0 | 
					
						
							|  |  |  |     inter = Polygon(g).intersection(Polygon(p)).area | 
					
						
							|  |  |  |     #union = g.area + p.area - inter | 
					
						
							|  |  |  |     union = p.area | 
					
						
							|  |  |  |     if union == 0: | 
					
						
							|  |  |  |         print("p_area is very small") | 
					
						
							|  |  |  |         return 0 | 
					
						
							|  |  |  |     else: | 
					
						
							|  |  |  |         return inter / union | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def weighted_merge(g, p): | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     Weighted merge. | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     g[:8] = (g[8] * g[:8] + p[8] * p[:8]) / (g[8] + p[8]) | 
					
						
							|  |  |  |     g[8] = (g[8] + p[8]) | 
					
						
							|  |  |  |     return g | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def standard_nms(S, thres): | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     Standard nms. | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     order = np.argsort(S[:, 8])[::-1] | 
					
						
							|  |  |  |     keep = [] | 
					
						
							|  |  |  |     while order.size > 0: | 
					
						
							|  |  |  |         i = order[0] | 
					
						
							|  |  |  |         keep.append(i) | 
					
						
							|  |  |  |         ovr = np.array([intersection(S[i], S[t]) for t in order[1:]]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         inds = np.where(ovr <= thres)[0] | 
					
						
							|  |  |  |         order = order[inds + 1] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return S[keep] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def standard_nms_inds(S, thres): | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     Standard nms, retun inds. | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     order = np.argsort(S[:, 8])[::-1] | 
					
						
							|  |  |  |     keep = [] | 
					
						
							|  |  |  |     while order.size > 0: | 
					
						
							|  |  |  |         i = order[0] | 
					
						
							|  |  |  |         keep.append(i) | 
					
						
							|  |  |  |         ovr = np.array([intersection(S[i], S[t]) for t in order[1:]]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         inds = np.where(ovr <= thres)[0] | 
					
						
							|  |  |  |         order = order[inds + 1] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return keep | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def nms(S, thres): | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     nms. | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     order = np.argsort(S[:, 8])[::-1] | 
					
						
							|  |  |  |     keep = [] | 
					
						
							|  |  |  |     while order.size > 0: | 
					
						
							|  |  |  |         i = order[0] | 
					
						
							|  |  |  |         keep.append(i) | 
					
						
							|  |  |  |         ovr = np.array([intersection(S[i], S[t]) for t in order[1:]]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         inds = np.where(ovr <= thres)[0] | 
					
						
							|  |  |  |         order = order[inds + 1] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return keep | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def soft_nms(boxes_in, Nt_thres=0.3, threshold=0.8, sigma=0.5, method=2): | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     soft_nms | 
					
						
							|  |  |  |     :para boxes_in, N x 9 (coords + score) | 
					
						
							|  |  |  |     :para threshould, eliminate cases min score(0.001) | 
					
						
							|  |  |  |     :para Nt_thres, iou_threshi | 
					
						
							|  |  |  |     :para sigma, gaussian weght | 
					
						
							|  |  |  |     :method, linear or gaussian | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     boxes = boxes_in.copy() | 
					
						
							|  |  |  |     N = boxes.shape[0] | 
					
						
							|  |  |  |     if N is None or N < 1: | 
					
						
							|  |  |  |         return np.array([]) | 
					
						
							|  |  |  |     pos, maxpos = 0, 0 | 
					
						
							|  |  |  |     weight = 0.0 | 
					
						
							|  |  |  |     inds = np.arange(N) | 
					
						
							|  |  |  |     tbox, sbox = boxes[0].copy(), boxes[0].copy() | 
					
						
							|  |  |  |     for i in range(N): | 
					
						
							|  |  |  |         maxscore = boxes[i, 8] | 
					
						
							|  |  |  |         maxpos = i | 
					
						
							|  |  |  |         tbox = boxes[i].copy() | 
					
						
							|  |  |  |         ti = inds[i] | 
					
						
							|  |  |  |         pos = i + 1 | 
					
						
							|  |  |  |         #get max box | 
					
						
							|  |  |  |         while pos < N: | 
					
						
							|  |  |  |             if maxscore < boxes[pos, 8]: | 
					
						
							|  |  |  |                 maxscore = boxes[pos, 8] | 
					
						
							|  |  |  |                 maxpos = pos | 
					
						
							|  |  |  |             pos = pos + 1 | 
					
						
							|  |  |  |         #add max box as a detection | 
					
						
							|  |  |  |         boxes[i, :] = boxes[maxpos, :] | 
					
						
							|  |  |  |         inds[i] = inds[maxpos] | 
					
						
							|  |  |  |         #swap | 
					
						
							|  |  |  |         boxes[maxpos, :] = tbox | 
					
						
							|  |  |  |         inds[maxpos] = ti | 
					
						
							|  |  |  |         tbox = boxes[i].copy() | 
					
						
							|  |  |  |         pos = i + 1 | 
					
						
							|  |  |  |         #NMS iteration | 
					
						
							|  |  |  |         while pos < N: | 
					
						
							|  |  |  |             sbox = boxes[pos].copy() | 
					
						
							|  |  |  |             ts_iou_val = intersection(tbox, sbox) | 
					
						
							|  |  |  |             if ts_iou_val > 0: | 
					
						
							|  |  |  |                 if method == 1: | 
					
						
							|  |  |  |                     if ts_iou_val > Nt_thres: | 
					
						
							|  |  |  |                         weight = 1 - ts_iou_val | 
					
						
							|  |  |  |                     else: | 
					
						
							|  |  |  |                         weight = 1 | 
					
						
							|  |  |  |                 elif method == 2: | 
					
						
							|  |  |  |                     weight = np.exp(-1.0 * ts_iou_val**2 / sigma) | 
					
						
							|  |  |  |                 else: | 
					
						
							|  |  |  |                     if ts_iou_val > Nt_thres: | 
					
						
							|  |  |  |                         weight = 0 | 
					
						
							|  |  |  |                     else: | 
					
						
							|  |  |  |                         weight = 1 | 
					
						
							|  |  |  |                 boxes[pos, 8] = weight * boxes[pos, 8] | 
					
						
							|  |  |  |                 #if box score falls below thresold, discard the box by | 
					
						
							|  |  |  |                 #swaping last box update N | 
					
						
							|  |  |  |                 if boxes[pos, 8] < threshold: | 
					
						
							|  |  |  |                     boxes[pos, :] = boxes[N - 1, :] | 
					
						
							|  |  |  |                     inds[pos] = inds[N - 1] | 
					
						
							|  |  |  |                     N = N - 1 | 
					
						
							|  |  |  |                     pos = pos - 1 | 
					
						
							|  |  |  |             pos = pos + 1 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return boxes[:N] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def nms_locality(polys, thres=0.3): | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     locality aware nms of EAST | 
					
						
							|  |  |  |     :param polys: a N*9 numpy array. first 8 coordinates, then prob | 
					
						
							|  |  |  |     :return: boxes after nms | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     S = [] | 
					
						
							|  |  |  |     p = None | 
					
						
							|  |  |  |     for g in polys: | 
					
						
							|  |  |  |         if p is not None and intersection(g, p) > thres: | 
					
						
							|  |  |  |             p = weighted_merge(g, p) | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             if p is not None: | 
					
						
							|  |  |  |                 S.append(p) | 
					
						
							|  |  |  |             p = g | 
					
						
							|  |  |  |     if p is not None: | 
					
						
							|  |  |  |         S.append(p) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if len(S) == 0: | 
					
						
							|  |  |  |         return np.array([]) | 
					
						
							|  |  |  |     return standard_nms(np.array(S), thres) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | if __name__ == '__main__': | 
					
						
							|  |  |  |     # 343,350,448,135,474,143,369,359 | 
					
						
							|  |  |  |     print( | 
					
						
							|  |  |  |         Polygon(np.array([[343, 350], [448, 135], [474, 143], [369, 359]])) | 
					
						
							|  |  |  |         .area) |