2021-07-02 Minion tracking enhancements.

  1. Minion Tracking
    • 이것저것 많이 건드려보았는데 미니언 트랙킹 자체가 변수가 많고 고려해야하는 경우의 수가 많아서 앞으로도 계속 보완해야 할 것 같음.
    • 1) Centroid 거리 비교 고도화
    • 기존의 방법은 scikit-image를 활용하여 얻은 미니언 웨이브마다의 centroid를 얻은 다음 단순히 centroid 사이의 거리를 바탕으로 교착상태인지 결정
    • 미니언 웨이브의 크기와 미니언으로 간주된 챔피언 아이콘이 길게 늘어질 경우 centroid와 웨이브의 가장자리 지점까지의 거리가 멀어 centroid 비교로는 정확도가 떨어짐
    • Centroid의 거리에 각 웨이브의 major axis length의 절반(타원의 반지름으로 이해)만큼을 빼주어서 두 웨이브 사이의 최단 거리를 고려하는 방법으로 보완

        def get_minion_lock(red_minion_map, blue_minion_map, dist_threshold=25):
          # Dilate
          kernel = np.ones((3,3), np.uint8)
          red_minion_map_di = cv2.dilate(red_minion_map.astype(np.uint8).copy(), kernel, iterations=1)
          blue_minion_map_di = cv2.dilate(blue_minion_map.astype(np.uint8).copy(), kernel, iterations=1)
      
          # Centroids
          red_labels = label(red_minion_map_di)
          red_centroids = [[np.array(prop.centroid), prop.major_axis_length] for prop in regionprops(red_labels)]
      
          blue_labels = label(blue_minion_map_di)
          blue_centroids = [[np.array(prop.centroid), prop.major_axis_length] for prop in regionprops(blue_labels)]
      
          lock_pts = []
          for r_cen, r_len in red_centroids:
            for b_cen, b_len in blue_centroids:
              dist = np.linalg.norm(r_cen - b_cen) - r_len//2 - b_len//2
      
              if dist < dist_threshold:
                lock_pts.append([int((r_cen[1]+b_cen[1])/2), int((r_cen[0]+b_cen[0])/2)])
      
          return lock_pts
      
  • 2) 라인별 교착 지점 분리
    • 기존의 방법은 각 라인(탑, 미드, 정글)의 구분 없이 교착 상태를 따졌기 때문에 interpolation에 한계가 있었다
    • 챔피언 아이콘에 의해 웨이브가 완전히 가려진 경우를 커버하기 위하여 우선 각 교착 지점을 라인별로 구분하였다.

        def merge_graphs_to_each_line(lock_graph_dfs_itp, minimap_size):
            # merge graphs to each line (top, mid, bottom)
            sep_line_map = get_separate_line_map(minimap_size)
      
            top_graphs, mid_graphs, bot_graphs = [], [], []
            for graph_df in lock_graph_dfs_itp:
                x, y = graph_df.iloc[0].astype(int)
                line_idx = sep_line_map[y,x]
      
                if line_idx == 1:
                    top_graphs.append(graph_df)
                elif line_idx == 2:
                    mid_graphs.append(graph_df)
                elif line_idx == 3:
                    bot_graphs.append(graph_df)
      
            top_graphs, mid_graphs, bot_graphs = pd.concat(top_graphs), pd.concat(mid_graphs), pd.concat(bot_graphs)
            return top_graphs, mid_graphs, bot_graphs
      
  • 3) 누락된 프레임 interpolation
    • 챔피언 아이콘에 의해 웨이브가 완전히 가려진 경우, 이전에 챔피언 아이콘을 각 진영의 미니언 웨이브로 간주하는 방법으로 성능을 향상하였다.
    • 하지만 한쪽 진영의 챔피언만 라인 상에 존재하여 남은 미니언을 클리어하는 경우에는 상대 미니언과 챔피언 아이콘 모두 존재하지 않기 때문에 직접적으로 해당 교착 지점을 찾는 것이 불가능하였다.
    • 따라서 2)에서 각 라인별로 합친 교착 지점의 좌표들을 이용하여 위와 같은 상황으로 인하여 누락된 프레임에 대해서는 이전 프레임의 좌표값을 그대로 사용하는 방식을 사용하였다. (미니언 아이콘이 존재하는 좌표로 수정하는 방법도 고려 중)

        def fillna_lock_frame(lock_graph_dfs_itp, minimap_size):
            top_graphs, mid_graphs, bot_graphs = merge_graphs_to_each_line(lock_graph_dfs_itp, minimap_size)
      
            lock_graph_dfs_itp_wo_na = []
            for pts_df in [top_graphs, mid_graphs, bot_graphs]:
                # add NaN frame rows to Dataframe
                frame_idcs = pts_df.index
                pts_df_w_na = []
      
                for idx in range(min(frame_idcs), max(frame_idcs)+1):
                    try:
                        pts_df_w_na.append(pts_df.loc[idx])
                    except:
                        pts_df_w_na.append(pd.Series([np.nan, np.nan], name=idx))
                pts_df_w_na = pd.concat(pts_df_w_na, 1).T
      
                # Interpolate the NaN frame rows
                pts_df_itp = pts_df_w_na.fillna(method='ffill')
      
                lock_graph_dfs_itp_wo_na.append(pts_df_itp)
      
            return lock_graph_dfs_itp_wo_na
      
  • 4) 향상된 결과 시각화

    Daily%20Report%202021%2007%2002%20(Fri)%20e7a4041f84e34676a918a6846f5d3741/ezgif.com-gif-maker_(11).gif

  1. Champion Tracking
    • 기존의 모델은 ‘죽은 챔피언까지 tracking해버리는 문제’ 발생 (아래 예시 참고)

      Daily%20Report%202021%2007%2002%20(Fri)%20e7a4041f84e34676a918a6846f5d3741/ezgif.com-gif-maker_(12).gif

    • 해결된 영상

      Daily%20Report%202021%2007%2002%20(Fri)%20e7a4041f84e34676a918a6846f5d3741/ezgif.com-gif-maker_(13).gif

    • 해결 방법

      • 해당 프레임에 특정 챔피언이 죽은 상태라면 해당 챔피언에 대한 좌표값 제거
      • 챔피언이 죽어있는지 여부는 양쪽의 챔피언 아이콘에 회색 빛이 돌고 부활시까지 걸리는 남은 시간이 표시되어 있을 경우를 인식 (아래 예시 참고. 미니맵만 고려하지 않는다는 이슈 존재)

        Daily%20Report%202021%2007%2002%20(Fri)%20e7a4041f84e34676a918a6846f5d3741/Untitled.png

      • Code

          for frame in tqdm(frames, desc='Converting to CSV dataset...'):
          				# Get current champion icon
                  current_icons = get_all_icons_in_frame(frame)
                    
          				# Alive check
                  is_alive = structural_similarity(icons[i], current_icons[i], multichannel=True) > 0.7
                            
                  if is_alive:
                      # Matching
                            
                  # Dead
                  else:
                    csv_row.extend([ID, -1000., -1000., position])