Skip to content

Commit

Permalink
手前のサークルの位置を検出
Browse files Browse the repository at this point in the history
  • Loading branch information
kawanoichi committed Oct 22, 2023
1 parent 1dec645 commit e2fec8f
Show file tree
Hide file tree
Showing 9 changed files with 1,124 additions and 413 deletions.
8 changes: 7 additions & 1 deletion rear_camera_py/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,13 @@ create-env-rear:

## 作業用 ##
get_area:
# @${make} rm
python src/get_area_info.py

coodinate:
python work/search_coodinate.py
python work/search_coodinate.py

rm:
bash rm_img.sh
zikken:
python src/zikken.py
4 changes: 4 additions & 0 deletions rear_camera_py/rm_img.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/bin/bash
cd work_image_data
shopt -s extglob
rm !(test.png)
316 changes: 316 additions & 0 deletions rear_camera_py/src/backup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,316 @@
"""ブロックでとレジャーのエリア情報を取得するモジュール
参考資料:
NOTE:HSV空間についての参考ページ
https://www.peko-step.com/html/hsv.html
NOTE:HSV値調べる
https://yanohirota.com/image-spuit/
実行コマンド:
rear_camera/ 直下で実行することを想定
$ make get_area
"""
import numpy as np
import cv2
import os
from enum import Enum

script_dir = os.path.dirname(os.path.abspath(__file__)) # /src
PROJECT_DIR_PATH = os.path.dirname(script_dir) # /rear_camera_py


class Color(Enum):
"""色クラス.
色はBGR
"""
BLACK = [0, 0, 0]
RED = [0, 0, 255]
YELLOW = [0, 255, 255]
GREEN = [0, 255, 0]
BLUE = [255, 0, 0]
WHITE = [255, 255, 255]


class GetAreaInfo:
RED1 = [(0, 15), (90, 255), (100, 255)]
YELLOW = [(16, 30), (50, 255), (150, 255)]
GREEN = [(31, 100), (60, 255), (40, 255)]
BLUE = [(101, 150), (110, 255), (70, 255)]
RED2 = [(151, 180), (80, 255), (90, 255)]

# OpenCVのHSV空間の上限はどれも255
# WHITE_threshold = [100, 50, 145] # 彩度 HSV (以上,以下,以上)
BLACK = [255, 110, 135] # HSV値の上限

def __init__(self, image_name, image_dir_path) -> None:
"""GetAreaInfoのコンストラクタ."""
self.image_name = image_name
self.image_dir_path = image_dir_path
self.course_info = np.zeros(16).reshape(4, 4)
self.basis_angle_deg = None
self.block_area_height = 240

def detect_black(self, hsv_img):
"""黒線を抽出する関数.
Args:
hsv_img: hsvに変換した画像
"""
# 処理結果を保持する配列を宣言(色を白で初期化)
black_line_img = np.full_like(hsv_img, 255, dtype=np.uint8)

# self.BLACK 以下のHSV値をColor.BLACK.valueに変換
black_line_img[np.where((hsv_img[:, :, 1] <= self.BLACK[1]) & (
hsv_img[:, :, 2] <= self.BLACK[2]))] = Color.BLACK.value

return black_line_img

def change_color(self, hsv_img, changed_color_img, search_color, color_value):
"""一定の範囲のHSV値を指定したHSV値に統一する関数.
Args:
hsv_img : HSV値に変換した画像
changed_color_img: 統一した値を書き込む画像
search_color: 一定の範囲を示すHSV値 (self.RED1などを指定)
color_value: 統一するHSV値 (Color.RED.valueなど)
"""
changed_color_img[np.where((search_color[0][0] <= hsv_img[:, :, 0]) &
(hsv_img[:, :, 0] <= search_color[0][1]) &
(search_color[1][0] <= hsv_img[:, :, 1]) &
(hsv_img[:, :, 1] <= search_color[1][1]) &
(search_color[2][0] <= hsv_img[:, :, 2]) &
(hsv_img[:, :, 2] <= search_color[2][1]))
] = color_value
return changed_color_img

def detect_line(self, img, save_img_name, length_threshold=200):
"""線分検出を行う関数.
Args:
img: 線分検出を行う画像
save_img_name: 線分検出を行った保存画像の名前
Return:
lines: 検出したライン
max_index: linesの中の最長ラインのインデックス
"""
## 線分検出 ##
fast_line_detector = cv2.ximgproc.createFastLineDetector(
length_threshold=length_threshold,
distance_threshold=1.41421356,
canny_th1=50,
canny_th2=50,
canny_aperture_size=3,
do_merge=False)

# グレースケール化
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

lines = fast_line_detector.detect(gray)
if lines is None:
return None, None

# 検出した線を描画する配列を作成(色を白で初期化)
result_line_img = np.full_like(img, 255, dtype=np.uint8)

# 最も長い線分を見つける
max_length = 0
max_length_index = -1
for i, line in enumerate(lines):
x1, y1, x2, y2 = map(int, line[0])
length = np.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2)
if length > max_length:
max_length = length
max_length_index = i

# 検出した線の描画
for i, line in enumerate(lines):
x1, y1, x2, y2 = map(int, line[0])
if i == max_length_index:
# 最も長い線は青で表示
cv2.line(result_line_img, (x1, y1), (x2, y2), (255, 0, 0), 3)
else:
# 他の線を赤で表示
cv2.line(result_line_img, (x1, y1), (x2, y2), (0, 0, 255), 3)
save_path = os.path.join(self.image_dir_path, save_img_name)
cv2.imwrite(save_path, result_line_img)

return lines, max_length_index

def predict_course_info(self, black_lines, changed_color_img):
"""エリア情報を生成する関数.
Args:
black_lines: 線分を格納した配列(x1, y1, x2, y2)
changed_color_img: 6色画像
"""
angle_threshold = 3
print("changed_color_img.shape", changed_color_img.shape)
black_lines = black_lines[:, 0]

print("black_lines.shape", black_lines.shape)

save_img = np.zeros_like(changed_color_img, dtype=np.uint8)

print("self.basis_angle_deg", self.basis_angle_deg)

y_max = 0
front_line_index = 0
for i, line in enumerate(black_lines):
x1, y1, x2, y2 = map(int, line)
# 度数を求める
a = ((y2 - y1) / (x2 - x1))
angle = np.degrees(np.arctan2(a, 1))
if np.abs(angle - self.basis_angle_deg) < angle_threshold:
y_max = max(y1, y2)
front_line_index = i

for i, line in enumerate(black_lines):
x1, y1, x2, y2 = map(int, line)
if i == front_line_index:
cv2.line(changed_color_img, (x1, y1), (x2, y2), (255, 0, 0), 3) # BGR
else:
cv2.line(changed_color_img, (x1, y1), (x2, y2), (0, 0, 255), 3) # BGR

x1, y1, x2, y2 = black_lines[front_line_index]
# 直線の方程式 y = ax + b を解く
a = ((y2 - y1) / (x2 - x1))
# 度数を求める
b = y1 - a * x1
mask_width = 80
for x in range(changed_color_img.shape[1]-mask_width):
y = int(a * x + b)
changed_color_img[y-20:y+20, x:x+mask_width] = Color.GREEN.value

mask = changed_color_img[y-20:y+20, x:x+mask_width]
black_num = np.where(
(mask[:, :, 0] == Color.BLACK.value[0]) &
(mask[:, :, 1] == Color.BLACK.value[1]) &
(mask[:, :, 2] == Color.BLACK.value[2]))
print(f"len(black_num): {len(black_num)}")
break

save_path = os.path.join(self.image_dir_path, "area_info_"+self.image_name)
cv2.imwrite(save_path, changed_color_img)

# for x in range(changed_color_img.shape[1]-mask_width):
# y = int(a * x + b)
# changed_color_img[int(a * x + b + 20), x] = Color.GREEN.value
# break

def start(self) -> None:
"""画像を6色画像に変換する関数.
Args:
game_area_img (cv2.Mat): ゲームエリア画像
save_path (str): 出力画像ファイルの保存パス
"""
# 画像読み込み
image_path = os.path.join(self.image_dir_path, self.image_name)
course_img = cv2.imread(image_path)

# BGR色空間からHSV色空間への変換
game_area_img = cv2.cvtColor(course_img, cv2.COLOR_BGR2HSV)

# 処理結果を保持する配列を宣言(色を白で初期化)
processed_img = np.full_like(game_area_img, 255, dtype=np.uint8)

# 緑検出
processed_img = self.change_color(
game_area_img, processed_img, self.GREEN, Color.BLACK.value)

# 緑の場所を検出
save_path = os.path.join(self.image_dir_path, "green_area_"+self.image_name)
# cv2.imwrite(save_path, processed_img)

# 線分を検出
lines, max_index = self.detect_line(processed_img,
"detected_line_green_area_"+self.image_name,
length_threshold=200)
x1, y1, x2, y2 = map(int, lines[max_index][0]) # x1, y1, x2, y2
# 直線の方程式 y = ax + b を解く
a = ((y2 - y1) / (x2 - x1))
# 度数を求める
self.basis_angle_deg = np.degrees(np.arctan2(a, 1))
b = y1 - a * x1 - 5

# 直線より下の部分を黒にする
for x in range(course_img.shape[1]):
course_img[int(a * x + b):, x] = Color.WHITE.value # 黒に変換
course_img[:int(a * x + b - self.block_area_height), x] = Color.WHITE.value # 黒に変換
save_path = os.path.join(self.image_dir_path, "unnecessary_area_"+self.image_name)
cv2.imwrite(save_path, course_img)

# BGR色空間からHSV色空間への変換
game_area_img = cv2.cvtColor(course_img, cv2.COLOR_BGR2HSV)

# # 処理結果を保持する配列を宣言(色を白で初期化)
changed_color_img = np.full_like(game_area_img, 255, dtype=np.uint8)

# 処理結果を保持する配列を宣言(色を黒で初期化)
# changed_color_img = np.zeros_like(game_area_img, dtype=np.uint8)

# 赤1,2
changed_color_img = self.change_color(
game_area_img, changed_color_img, self.RED1, Color.BLACK.value)
changed_color_img = self.change_color(
game_area_img, changed_color_img, self.RED2, Color.BLACK.value)

# 黄
changed_color_img = self.change_color(
game_area_img, changed_color_img, self.YELLOW, Color.BLACK.value)

# 緑
changed_color_img = self.change_color(
game_area_img, changed_color_img, self.GREEN, Color.BLACK.value)

# 青
changed_color_img = self.change_color(
game_area_img, changed_color_img, self.BLUE, Color.BLACK.value)

# 6色画像を保存
save_path = os.path.join(self.image_dir_path, "changed_color_"+self.image_name)
cv2.imwrite(save_path, changed_color_img)
# """

# ブロックエリアの黒ラインを検出
black_line_img = self.detect_black(game_area_img)
save_path = os.path.join(self.image_dir_path, "black_line_"+self.image_name)
cv2.imwrite(save_path, black_line_img)

black_lines, max_index = self.detect_line(black_line_img,
"detected_line_black_img.png",
length_threshold=140)

# エリア情報を生成
self.predict_course_info(black_lines, changed_color_img)

return self.course_info


if __name__ == "__main__":
# 処理時間計測用
import time
start = time.time()

# 作業用の読み込みや保存用のディレクトリパス
work_dir_path = os.path.join(PROJECT_DIR_PATH, "work_image_data")
work_dir_path2 = os.path.join(PROJECT_DIR_PATH, "work_image_data2")

# 画像ファイル名
image_name = "test.png"

cc = GetAreaInfo(image_name, work_dir_path)
cc.start()

# """
cc2 = GetAreaInfo(image_name, work_dir_path2)
cc2.start()
# """

# 処理時間計測用
execute_time = time.time() - start
print(f"実行時間: {str(execute_time)[:5]}s")

print("完了!")
Loading

0 comments on commit e2fec8f

Please sign in to comment.