ArUcoマーカーの検出を使った、Telloのプログラミングゲーム
ArUcoマーカーの検出を使った、Telloのプログラミングゲーム

ArUcoマーカーの検出を使った、Telloのプログラミングゲーム

⬛⬛⬛⬛⬛⬛⬛⬛
⬛⬜⬜⬜⬜⬜⬜⬛
⬛⬜⬛⬜⬛⬛⬜⬛
⬛⬛⬜⬜⬛⬛⬜⬛
⬛⬜⬜⬜⬜⬜⬛⬛
⬛⬛⬜⬛⬛⬜⬜⬛
⬛⬜⬛⬜⬜⬜⬜⬛
⬛⬛⬛⬛⬛⬛⬛⬛

IDは「白黒のパターン」で表現されている!

⬜ ⬛ ⬜ ⬛ ⬛
⬜ ⬜ ⬛ ⬛ ⬜
⬜ ⬜ ⬜ ⬜ ⬛
⬜ ⬛ ⬛ ⬜ ⬜
⬛ ⬜ ⬜ ⬜ ⬜

import cv2
import cv2.aruco as aruco

# マーカー辞書(4x4の50種類のうちの1つ
aruco_dict = aruco.getPredefinedDictionary(aruco.DICT_4X4_50)

# ID=1 のマーカーを 200x200ピクセルで生成
marker_image = aruco.drawMarker(aruco_dict, id=1, sidePixels=200)

# 画像として保存
cv2.imwrite("aruco_id1.png", marker_image)

# 表示任意
cv2.imshow("AR Marker - ID 1", marker_image)
cv2.waitKey(0)
cv2.destroyAllWindows()

import cv2
import cv2.aruco as aruco
import numpy as np
import socket, threading, time
import pygame
aruco_dict = aruco.getPredefinedDictionary(aruco.DICT_4X4_50)
parameters = aruco.DetectorParameters()
host = '0.0.0.0'
port = 8889
tello_addr = ('192.168.10.1', 8889)
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind((host, port))
def recv():
    while True:
        try:
            data, _ = sock.recvfrom(1518)
            print(data.decode('utf-8'))
        except:
            break
threading.Thread(target=recv, daemon=True).start()
def send(cmd, delay=1):
    sock.sendto(cmd.encode(), tello_addr)
    print(f">>> {cmd}")
    time.sleep(delay)
send('command')
send('streamon')
cap = cv2.VideoCapture("udp://192.168.10.1:11111")
pygame.mixer.init()
point_sound = pygame.mixer.Sound("point.wav")
def play_point_sound():
    point_sound.stop()
    point_sound.play()
def draw_star(img, center, size, color, thickness):
score = 0
passed = set()
MARKERS = {
    0: 'star_floor', ...
}
DESIRED_HEIGHT_CM = 90
while True:
    ret, frame = cap.read()
    if not ret:
        continue
    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    corners, ids, _ = aruco.detectMarkers(gray, aruco_dict, parameters=parameters)
    frame_center = (frame.shape[1] // 2, frame.shape[0] // 2)

if ids is not None:
        for idx, i in enumerate(ids.flatten()):
            c = corners[idx][0]
            cx, cy = int(c[:, 0].mean()), int(c[:, 1].mean())
            size_px = np.linalg.norm(c[0] - c[2])
            cm_per_px = size_px / 21.0
            shape = MARKERS.get(i, 'unknown')
            size = int(25 * cm_per_px)

            offset_y = int(-DESIRED_HEIGHT_CM * cm_per_px)
            cy_offset = cy + offset_y
            cy_offset = max(0, min(frame.shape[0] - 1, cy_offset))
            center_pos = (cx, cy_offset)
if ids is not None:
    for idx, i in enumerate(ids.flatten()):
        c = corners[idx][0]
        cx, cy = int(c[:, 0].mean()), int(c[:, 1].mean())
        size_px = np.linalg.norm(c[0] - c[2])
        cm_per_px = size_px / 21.0
        shape = MARKERS.get(i, 'unknown')
        size = int(25 * cm_per_px)
        offset_y = int(-DESIRED_HEIGHT_CM * cm_per_px)
        cy_offset = cy + offset_y
        cy_offset = max(0, min(frame.shape[0] - 1, cy_offset))
        center_pos = (cx, cy_offset)

最終的に図形を描画する中心位置を (x, y) のタプルで保存します。

            cx, cy = int(c[:, 0].mean()), int(c[:, 1].mean())
            size_px = np.linalg.norm(c[0] - c[2])
            cm_per_px = size_px / 21.0
            offset_y = int(-DESIRED_HEIGHT_CM * cm_per_px)
  if shape == 'star_floor' or shape == 'star_floor2':
                draw_star(frame, center_pos, size, (0, 255, 255), thickness=10)
            elif shape == 'pentagon' or shape == 'pentagon2':
                draw_polygon(frame, center_pos, size, 5, (255, 0, 0), thickness=10)
            elif shape == 'circle':
                draw_circle(frame, center_pos, size, (0, 0, 255), thickness=10)
            elif shape == 'triangle':
                draw_polygon(frame, center_pos, size, 3, (0, 255, 0), thickness=10)
            elif shape == 'star_vertical':
                draw_star(frame, center_pos, size, (0, 165, 255), thickness=10)
            elif shape == 'pyramid':
                draw_pyramid(frame, center_pos, size)
            elif shape == 'cube_transparent':
                draw_transparent_cube(frame, center_pos, size)
            elif shape == 'shadow_square':
                draw_shadowed_square(frame, center_pos, size)
            distance = np.hypot(cx - frame_center[0], cy - frame_center[1])
            if distance < 100 and marker_key not in passed:
                score += 10
                passed.add(marker_key)
                play_point_sound()
            if marker_key in passed:
                cv2.putText(frame, "X", ...)
    cv2.putText(frame, f"Score: {score}", ...)
    cv2.imshow("Tello AR 7Shapes", frame)
    if cv2.waitKey(1) == 27:
        break
def draw_star(img, center, size, color, thickness):
    pts = []
    cx, cy = center
    for i in range(5):
        angle = np.pi / 2 + i * 2 * np.pi / 5
        pts.append((int(cx + size * np.cos(angle)), int(cy - size * np.sin(angle))))
    cv2.polylines(img, [np.array(pts)], True, color, thickness)
def draw_polygon(img, center, size, sides, color, thickness):
    pts = []
    cx, cy = center
    for i in range(sides):
        angle = np.pi / 2 + i * 2 * np.pi / sides
        pts.append((int(cx + size * np.cos(angle)), int(cy - size * np.sin(angle))))
    cv2.polylines(img, [np.array(pts)], True, color, thickness)
def draw_circle(img, center, size, color, thickness):
    cv2.circle(img, center, int(size), color, thickness)
def draw_shadowed_square(img, center, size, square_color=(0, 128, 255), shadow_color=(50, 50, 50), thickness=4):
    cx, cy = center
    d = size // 2
    offset = size // 5

    # 
    shadow_pts = np.array([
        (cx - d + offset, cy - d + offset),
        (cx + d + offset, cy - d + offset),
        (cx + d + offset, cy + d + offset),
        (cx - d + offset, cy + d + offset)
    ])
    cv2.fillPoly(img, [shadow_pts], shadow_color)

    # 本体
    square_pts = np.array([
        (cx - d, cy - d),
        (cx + d, cy - d),
        (cx + d, cy + d),
        (cx - d, cy + d)
    ])
    cv2.fillPoly(img, [square_pts], square_color)
import cv2
import cv2.aruco as aruco
import numpy as np
import socket, threading, time
import pygame

# --- ArUco 設定 ---
aruco_dict = aruco.getPredefinedDictionary(aruco.DICT_4X4_50)
parameters = aruco.DetectorParameters()

# --- 通信設定 ---
host = '0.0.0.0'
port = 8889
tello_addr = ('192.168.10.1', 8889)
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind((host, port))

def recv():
    while True:
        try:
            data, _ = sock.recvfrom(1518)
            print(data.decode('utf-8'))
        except:
            break

threading.Thread(target=recv, daemon=True).start()

def send(cmd, delay=1):
    sock.sendto(cmd.encode(), tello_addr)
    print(f">>> {cmd}")
    time.sleep(delay)

# --- Tello 飛行映像 ---
send('command')
send('streamon')
cap = cv2.VideoCapture("udp://192.168.10.1:11111")

# --- 効果音の初期化 ---
pygame.mixer.init()
point_sound = pygame.mixer.Sound("point.wav")

def play_point_sound():
    point_sound.stop()
    point_sound.play()

# --- 図形描画関数 ---
def draw_star(img, center, size, color, thickness):
    pts = []
    cx, cy = center
    for i in range(5):
        angle = np.pi / 2 + i * 2 * np.pi / 5
        pts.append((int(cx + size * np.cos(angle)), int(cy - size * np.sin(angle))))
    cv2.polylines(img, [np.array(pts)], True, color, thickness)

def draw_polygon(img, center, size, sides, color, thickness):
    pts = []
    cx, cy = center
    for i in range(sides):
        angle = np.pi / 2 + i * 2 * np.pi / sides
        pts.append((int(cx + size * np.cos(angle)), int(cy - size * np.sin(angle))))
    cv2.polylines(img, [np.array(pts)], True, color, thickness)

def draw_circle(img, center, size, color, thickness):
    cv2.circle(img, center, int(size), color, thickness)
    
def draw_pyramid(img, center, size, color=(0, 200, 255), thickness=2):
    cx, cy = center
    d = size // 2

    # 底面三角
    base = np.array([
        (cx - d, cy + d),
        (cx + d, cy + d),
        (cx, cy - d)
    ])

    # 頂点
    apex = (cx, cy - int(size * 1.5))

    # 三角面を線で描く
    for pt in base:
        cv2.line(img, apex, pt, color, thickness)
    cv2.polylines(img, [base], isClosed=True, color=color, thickness=thickness)
    
    
def draw_transparent_cube(img, center, size, color=(200, 255, 200), thickness=2):
    cx, cy = center
    d = size // 2
    offset = size // 3

    front = np.array([
        (cx - d, cy - d),
        (cx + d, cy - d),
        (cx + d, cy + d),
        (cx - d, cy + d)
    ])
    back = np.array([
        (cx - d + offset, cy - d - offset),
        (cx + d + offset, cy - d - offset),
        (cx + d + offset, cy + d - offset),
        (cx - d + offset, cy + d - offset)
    ])

    for i in range(4):
        cv2.line(img, front[i], front[(i+1)%4], color, thickness)
        cv2.line(img, back[i], back[(i+1)%4], color, thickness)
        cv2.line(img, front[i], back[i], color, thickness)

def draw_shadowed_square(img, center, size, square_color=(0, 128, 255), shadow_color=(50, 50, 50), thickness=4):
    cx, cy = center
    d = size // 2
    offset = size // 5

    # 影を描画
    shadow_pts = np.array([
        (cx - d + offset, cy - d + offset),
        (cx + d + offset, cy - d + offset),
        (cx + d + offset, cy + d + offset),
        (cx - d + offset, cy + d + offset)
    ])
    cv2.fillPoly(img, [shadow_pts], shadow_color)

    # 正方形本体
    square_pts = np.array([
        (cx - d, cy - d),
        (cx + d, cy - d),
        (cx + d, cy + d),
        (cx - d, cy + d)
    ])
    cv2.fillPoly(img, [square_pts], square_color)

   
    
    
    

# --- メインループ変数 ---
score = 0
passed = set()
MARKERS = {
    0: 'star_floor',
    1: 'pentagon',
    2: 'circle',
    3: 'triangle',
    4: 'star_vertical',
    5: 'star_floor2',
    6: 'pentagon2',
    7: 'pyramid',
    8: 'cube_transparent',
    9: 'shadow_square'
}

DESIRED_HEIGHT_CM = 90

# --- メインループ ---
while True:
    ret, frame = cap.read()
    if not ret:
        continue

    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    corners, ids, _ = aruco.detectMarkers(gray, aruco_dict, parameters=parameters)

    frame_center = (frame.shape[1] // 2, frame.shape[0] // 2)
    cv2.circle(frame, frame_center, 10, (0, 255, 0), 2)

    if ids is not None:
        for idx, i in enumerate(ids.flatten()):
            c = corners[idx][0]
            cx, cy = int(c[:, 0].mean()), int(c[:, 1].mean())
            size_px = np.linalg.norm(c[0] - c[2])
            cm_per_px = size_px / 21.0
            shape = MARKERS.get(i, 'unknown')
            size = int(25 * cm_per_px)

            offset_y = int(-DESIRED_HEIGHT_CM * cm_per_px)
            cy_offset = cy + offset_y
            cy_offset = max(0, min(frame.shape[0] - 1, cy_offset))
            center_pos = (cx, cy_offset)

            # 図形描画
            if shape == 'star_floor' or shape == 'star_floor2':
                draw_star(frame, center_pos, size, (0, 255, 255), thickness=10)
            elif shape == 'pentagon' or shape == 'pentagon2':
                draw_polygon(frame, center_pos, size, 5, (255, 0, 0), thickness=10)
            elif shape == 'circle':
                draw_circle(frame, center_pos, size, (0, 0, 255), thickness=10)
            elif shape == 'triangle':
                draw_polygon(frame, center_pos, size, 3, (0, 255, 0), thickness=10)
            elif shape == 'star_vertical':
                draw_star(frame, center_pos, size, (0, 165, 255), thickness=10)
            elif shape == 'pyramid':
                draw_pyramid(frame, center_pos, size)
            elif shape == 'cube_transparent':
                draw_transparent_cube(frame, center_pos, size)
            elif shape == 'shadow_square':
                draw_shadowed_square(frame, center_pos, size)
   
                
                
                

            aruco.drawDetectedMarkers(frame, corners)
            cv2.putText(frame, shape, (cx + 10, cy + 10),
                        cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 255, 255), 2)

            # --- 接触判定とX表示 ---
            distance = np.hypot(cx - frame_center[0], cy - frame_center[1])
            marker_key = (i, cx, cy)

            if distance < 100 and marker_key not in passed:
                score += 10
                passed.add(marker_key)
                play_point_sound()
                print(f"Hit marker {i}! +10 points. Score: {score}")

            # 通過済みマーカーには常にXを表示
            if marker_key in passed:
                cv2.putText(frame, "X", (center_pos[0] - 20, center_pos[1] + 20),
                            cv2.FONT_HERSHEY_SIMPLEX, 2.0, (0, 0, 255), 5)

    # スコア表示
    cv2.putText(frame, f"Score: {score}", (30, 50),
                cv2.FONT_HERSHEY_SIMPLEX, 1.5, (0, 255, 0), 3)

    cv2.imshow("Tello AR 7Shapes", frame)
    if cv2.waitKey(1) == 27:
        break

# --- 終了処理 ---
send('land')
cap.release()
cv2.destroyAllWindows()
ホーム » プログラミング » ArUcoマーカーの検出を使った、Telloのプログラミングゲーム

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です