크래시 오브 크라운 및 이미지 분석 (1)

7205 단어 Python3OpenCV

하고 싶은 일



스마트 폰 게임의 크래시 오브 크라운 (이하 쿠라 쿠라)에서 대전의 배치 이미지에서 여러가지 (공격 시설의 밀도의 가시화나 배치의 약점 등)를 알기 쉬워지면 재미있을까 생각했기 때문에 파이썬의 공부도 겸하고 배치 이미지를 분석하고 싶습니다. 이번에는 python의 OpenCV를 사용하여 입력 이미지의 전처리까지 하고 싶습니다.

0. 환경



MacOS
VScode 1.52.0
파이썬 2.7.16
numpy==1.18.1
opencv-python==4.4.0.46

1. 대전 배치에 대해



배치는 이하의 사진과 같은 것을 상정하고 있습니다. 레이아웃 에디터로부터 촬영 모드로 해 스크린 쇼트 한 것입니다.
(이 배치는 Queen walkers의 분이 배부한 것으로, 그것을 빌리고 있습니다.)


2. 이미지 가공



클라크라의 배치 형식은 $ 48\times 48 $의 매스 눈 모양이므로 우선 마름모에 배치를 사각형으로해야합니다. 그래서 다음 코드를 실행했습니다.
import numpy as np
import cv2

def resize_image():
  # 入力画像の読み込み
  pictrue = 'picture/GAKU2020.jpeg'
  img = cv2.imread(pictrue, cv2.IMREAD_COLOR)

  # 高さを定義
  height = img.shape[0]                         
  # 幅を定義
  width = img.shape[1]  
  # 回転の中心を指定                          
  center = (int(width/2), int(height/2))
  # 回転角度
  angle = 45.0
  # 拡大・縮小率
  scale = 1.0

  # 画像の横方向を縮小する
  img = cv2.resize(img , (int(width*0.75), height))
  # 画像を回転
  trans = cv2.getRotationMatrix2D(center, angle , scale)
  img2 = cv2.warpAffine(img, trans, (width,height))

 #画像の保存
 cv2.imwrite('./picture/GAKU2020_resize.png',img2)

if __name__ == '__main__':
  img2 = resize_image()



그러면 다음과 같은 이미지를 얻을 수 있습니다.


3. 이미지 자르기



이미지를 정사각형으로 만들 수있었습니다. 다음에 필요없는 부분을 자르고 싶습니다. 원하는 이미지는 기초가 녹색 부분이므로 녹색 부분을 추출하려고 생각했습니다. 구현한 코드는 다음과 같습니다. (거의 참고한 코드입니다만)
def detect_green_color(img):
    # HSV色空間に変換
    hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)

    # 緑色のHSVの値域1
    hsv_min = np.array([20, 64, 0])
    hsv_max = np.array([90,255,255])

    # 緑色領域のマスク(255:赤色、0:赤色以外)    
    mask = cv2.inRange(hsv, hsv_min, hsv_max)

    # マスキング処理
    masked_img = cv2.bitwise_and(img, img, mask=mask)

    return mask, masked_img


참고 : htps : // / l hr thm. 조호.んふぉ / p 로g 라민 g / py 텐 / 오페인 cv-ko r에서 c chion /

얻은 mask의 이미지가 여기입니다. 원하는 부분의 정사각형을 어쩐지 알게 되었다고 생각합니다.


4. 정사각형 감지



마지막으로 위의 이미지에서 배치 부분의 사각형을 감지하고 싶습니다. 사각형을 탐지하는 코드가 검색되면 나왔기 때문에 우선 그것을 그대로 실행해 보았습니다. 그러면 다음과 같은 이미지가 얻어졌습니다.

참고 : htps //w w. 366세 rゔぃ세. 코 m / jp / 쿠 / 886f2 ㅇ cd5 훗바 07 에c3b78b49744 세 b4b


많은 사각형이 감지되었습니다. 게다가 약간 어긋나 있습니다. 그래서 복수 검출한 정사각형 중 가장 큰 것을 선택해, 그것을 종횡의 좌표를 정돈해 출력하는 것과 같은 것을 실장했습니다. 다음은 코드입니다.
더 좋은 방법이 있다고 생각합니다만, 생각하지 못했기 때문에 머리가 나쁜 것 같은 쓰는 방법이 되어 버렸습니다…
import numpy as np
import cv2


def resize_image():
    ...

def detect_green_color(img):
    ...

# resize_imageの続き
def trim_image(img2):
  # 緑の部分を抽出
  green_mask, green_masked_img = detect_green_color(img2)
  cv2.imwrite("./picture/green_mask.png", green_mask)
  #cv2.imwrite("./picture/green_masked_img.png", green_masked_img)

  square = find_squares(green_mask)
  print(square)
  cv2.drawContours(img2, square, -1, (0, 255, 0), 3)

  # 検知した領域を表示
  cv2.imwrite('./picture/GAKU2020_a.png', img2)


# cosの計算
def angle_cos(p0, p1, p2):
    d1, d2 = (p0-p1).astype('float'), (p2-p1).astype('float')
    return abs( np.dot(d1, d2) / np.sqrt( np.dot(d1, d1)*np.dot(d2, d2) ) )

# 正方形の検出
def find_squares(img):
    img = cv2.GaussianBlur(img, (5, 5), 0)
    squares = []
    for gray in cv2.split(img):
        for thrs in range(0, 255, 26):
            if thrs == 0:
                bin = cv2.Canny(gray, 0, 50, apertureSize=5)
                bin = cv2.dilate(bin, None)
            else:
                _retval, bin = cv2.threshold(gray, thrs, 255, cv2.THRESH_BINARY)
            contours, _hierarchy = cv2.findContours(bin, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
            for cnt in contours:
                cnt_len = cv2.arcLength(cnt, True)
                cnt = cv2.approxPolyDP(cnt, 0.02*cnt_len, True)
                if len(cnt) == 4 and cv2.contourArea(cnt) > 1000 and cv2.isContourConvex(cnt):
                    cnt = cnt.reshape(-1, 2)
                    max_cos = np.max([angle_cos( cnt[i], cnt[(i+1) % 4], cnt[(i+2) % 4] ) for i in range(4)])
                    if max_cos < 0.1:
                        squares.append(cnt)

    max_length = 0
    largest_square = None
    for square in squares:
      # 全ての座標の読み込み
      x0, y0 = square[0]
      x1, y1 = square[1]
      x2, y2 = square[2]
      x3, y3 = square[3]

      # 横と縦の長さの平均
      x_length = int(1/2 * (abs(x1 - x2) +  abs(x3 - x0)))
      y_length = int(1/2 * (abs(y0 - y1) +  abs(y2 - y3)))
      length = int(1/2*(x_length+y_length))

      # 新しい座標(仮)
      x0_new = int(1/2 * (x0 + x1)) 
      x1_new = int(1/2 * (x2 + x3))
      y0_new = int(1/2 * (y1 + y2))
      y1_new = int(1/2 * (y0 + y3))
      #print('*old*')
      #print(y0_new)
      #print(y1_new)

      # 横と縦の長さを揃えるための処理
      x_len = x1_new - x0_new
      y_len = y0_new - y1_new

      x_diff = length - x_len
      y_diff = length - y_len

      x0_new += int(x_diff/2)
      x1_new = x0_new + length
      y0_new += int(y_diff/2)
      y1_new = y0_new - length
      #print('*new*')
      #print(y0_new)
      #print(y1_new)

      x_len = x1_new - x0_new
      y_len = y0_new - y1_new

      # 新しい座標
      new_square = np.array([[x0_new, y1_new],
                            [x0_new, y0_new],
                            [x1_new, y0_new],
                            [x1_new, y1_new]])
    # 一番長い辺を持つ正方形を記憶
      if length > max_length:
        max_length = length
        largest_square = new_square

    # データ形状の微調整
    largest = []
    largest.append(largest_square)

    return largest


if __name__ == '__main__':
  img2 = resize_image()
  trim_image(img2)



얻은 이미지가 여기입니다.



좋은 느낌이지만 왼쪽과 위가 약간 어긋나있는 것이 걱정된다. 어긋난 부분은 10픽셀 정도로, 배치의 1매스가 40픽셀 정도이기 때문에 이것이 어떻게 울려 오는지…

5. 마지막으로



이번에는 입력 이미지를 성형하여 원하는 부분을 추출했습니다.
다음은 시설을 검출할 수 있을지 어떨지를 시험하고 싶습니다.
$48\times 48$매스의 어디에 있는지 알면 좋기 때문에 비교적 간단할 것 (아마)

(정정 2020/12/29) 매스 눈은 $48\times 48$가 아니라 $44\times 44$같았다.

좋은 웹페이지 즐겨찾기