OpenCV/OpenCV 강좌

주사위 눈 개수 세는 OpenCV Python 예제

webnautes 2023. 10. 20. 07:13
반응형

주사위 눈 개수를 세는 OpenCV Pytrhon 예제 코드입니다.

 

깃허브에서 오래전에 발견했던 코드를 수정했습니다. 주사위 눈을 세는 부분을 공유안해주셨지만 힌트가 포함되어 있어서 다행히 동작하도록 수정했네요. 

https://github.com/arnavdutta/OpenCV-Contours-Hierarchy/blob/master/OpenCV_Contours.ipynb 



2023. 5. 28  최초작성





이진화 실행 결과입니다.

 

주사위 눈 검출 결과입니다.  주사위마다 표시된 빨간색 숫자는 눈의 개수이며 보라색 작은 숫자들은 검출된 컨투어의 인덱스 입니다. 왼쪽위에 표시된 28은 주사위 전체 눈 개수입니다. 

 



전체 소스 코드입니다.

import cv2
import numpy as np


image = cv2.imread('dice.png')
image_copy = image.copy()


# 컨투어 검출하기
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
blur = cv2.GaussianBlur(gray, (5, 5), 0)

t, binary = cv2.threshold(blur, -1, 255,  cv2.THRESH_BINARY | cv2.THRESH_OTSU)

contours, hierarchy = cv2.findContours(binary,
                                          cv2.RETR_TREE,
                                          cv2.CHAIN_APPROX_SIMPLE)


dict_i = {}

# 주사위를 검출한 컨투어를 찾습니다.
for i, (c,h) in enumerate(zip(contours,hierarchy[0])):

    rect = cv2.minAreaRect(c)
    box = cv2.boxPoints(rect)
    box = np.intp(box)

    p1 = box[0]
    p2 = box[1]
    p3 = box[2]
   
    dist1 = np.linalg.norm(p1-p2)
    dist2 = np.linalg.norm(p2-p3)

    if dist2 == 0:
        dist2 = 0.000001

    if dist1/dist2 > 0.8 and dist1/dist2 < 1.5:         
        if h[3] == -1:
            dict_i[i] = []


# 주사위 눈을 검출한 컨투어를 찾습니다.
total_pips = []
for i, (c,h) in enumerate(zip(contours,hierarchy[0])):
    if h[3] in dict_i.keys():

        rect = cv2.minAreaRect(c)
        box = cv2.boxPoints(rect)
        box = np.intp(box)

        p1 = box[0]
        p2 = box[1]
        p3 = box[2]
       
        dist1 = np.linalg.norm(p1-p2)
        dist2 = np.linalg.norm(p2-p3)

        if dist2 == 0:
            dist2 = 0.000001

        if dist1/dist2 > 0.8 and dist1/dist2 < 1.5:
           
            dict_i[h[3]].append(i)
            total_pips.append(i)

list_del = []
for key in dict_i.keys():
    if len(dict_i[key]) == 0:
        list_del.append(key)

for del_item in list_del:
    del dict_i[del_item]

print('주사위 목록')
print(dict_i)


for index, (c,h) in enumerate(zip(contours,hierarchy[0])):
   
    rect = cv2.minAreaRect(c)
    box = cv2.boxPoints(rect)
    box = np.intp(box)
   
    x, y, _, _ = cv2.boundingRect(c)

   
    # 주사위 눈 리스트 생성
    list_item = []
    for i in dict_i.values():
        list_item = list_item  + i
   

    if index in dict_i.keys() or index in list_item:
       
        # 주사위와 주사위 눈을 그려줌
        cv2.drawContours(image_copy, [box], 0, (255, 0, 150), 3)
       
        # 주사위 눈 개수 출력
        if index in dict_i and len(dict_i[index]) > 0:
            cv2.putText(image_copy,
                        str(len(dict_i[index])),
                        (x+100, y-5),
                        cv2.FONT_HERSHEY_SIMPLEX,
                        2,
                        (0, 0, 255),
                        2,
                    cv2.LINE_AA)

        # 컨투어 인덱스 출력
        cv2.putText(image_copy,
                    str(index),
                    (x+20, y-5),
                    cv2.FONT_HERSHEY_SIMPLEX,
                    1,
                    (200, 140, 140),
                    1,
                    cv2.LINE_AA)


# 전체 주사위 눈 개수 출력
cv2.putText(image_copy,
            f'total = {len(total_pips)}',
            (100,200),
            cv2.FONT_HERSHEY_SIMPLEX,
            5,
            (0, 0, 255),
            2,
            cv2.LINE_AA)


binary = cv2.resize(binary, None, fx=0.5, fy=0.5)
image_copy = cv2.resize(image_copy, None, fx=0.5, fy=0.5)

cv2.imshow('result', binary)
cv2.waitKey(0)

cv2.imshow('result', image_copy)
cv2.waitKey(0)



테스트에 사용한 이미지입니다.

 

반응형