-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
close #KLI-193 配置エリアAでの撮影動作の実装 #7
Merged
Merged
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
ccc30fd
add: 物体検出を行うための処理
takahashitom bf1a6b0
update: poetry.lockを更新
takahashitom 3052fc3
update: Windows環境でも推論できるように更新
takahashitom 6959798
add: 物体検出を行うための処理の追加
takahashitom 4590eb3
refactor: フォーマットの調整
takahashitom 46a5617
fix: フォーマットの修正2
takahashitom 0c5e1d1
fix: フォーマットの修正3
takahashitom 6a99e3c
fix 重複していた処理を修正
takahashitom File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,4 +3,9 @@ | |
coverage* | ||
*.jpeg | ||
*.csv | ||
*.json | ||
*.json | ||
|
||
# 推論 | ||
fig_image | ||
*.pt | ||
*.flag |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,240 @@ | ||
"""物体検出を行うモジュール. | ||
|
||
ベストショット画像を選択するための物体検出を行う。 | ||
|
||
NOTE: | ||
重みファイル'exp17_best.pt'(現状)は以下にあります。 | ||
https://drive.google.com/drive/folders/1FZPZu1xNMaarVyKfaLlm3HZPFgYp5RCZ | ||
etrobocon2024-camera-system/yolo/の中にダウンロードしてください | ||
|
||
参考コード: | ||
https://github.com/ultralytics/yolov5 | ||
@author: takahashitom | ||
""" | ||
|
||
import torch | ||
import pathlib | ||
from pathlib import Path | ||
import os | ||
import numpy as np | ||
import sys | ||
from ultralytics.utils.plotting import Annotator, colors | ||
|
||
script_dir = os.path.dirname(os.path.abspath(__file__)) # noqa | ||
YOLO_PATH = os.path.join(script_dir, "..", "yolo") # noqa | ||
sys.path.append(YOLO_PATH) # noqa | ||
YOLO_PATH = Path(YOLO_PATH) # noqa | ||
from models.common import DetectMultiBackend | ||
from utils.general import ( | ||
check_img_size, cv2, non_max_suppression, scale_boxes) | ||
from utils.torch_utils import select_device | ||
from utils.augmentations import letterbox | ||
|
||
# Linux環境で推論する場合はコメントアウト | ||
temp = pathlib.PosixPath | ||
pathlib.PosixPath = pathlib.WindowsPath | ||
|
||
PROJECT_DIR_PATH = os.path.dirname(script_dir) | ||
IMAGE_DIR_PATH = Path(os.path.join(PROJECT_DIR_PATH, "fig_image")) | ||
|
||
|
||
class DetectObject(): | ||
"""yolov5(物体検出)をロボコン用に編集したクラス.""" | ||
|
||
__DEVICE = 'cpu' | ||
__IMG_SIZE = (640, 480) | ||
|
||
def __init__(self, | ||
weights=YOLO_PATH/'exp17_best.pt', | ||
label_data=YOLO_PATH/'label_data.yaml', | ||
conf_thres=0.6, | ||
iou_thres=0.45, | ||
max_det=1, | ||
line_thickness=1, | ||
stride=32): | ||
"""コンストラクタ. | ||
|
||
Args: | ||
weights (str): 重みファイルパス | ||
label_data (str): ラベルを記述したファイルパス | ||
conf_thres (float): 信頼度閾値 | ||
iou_thres (float): NMS IOU 閾値 | ||
max_det (int): 最大検出数 | ||
line_thickness (int): バウンディングボックスの太さ | ||
stride (int): ストライド | ||
""" | ||
self.check_exist(weights) | ||
self.check_exist(label_data) | ||
self.weights = str(weights) | ||
self.label_data = str(label_data) | ||
self.conf_thres = conf_thres | ||
self.iou_thres = iou_thres | ||
self.max_det = max_det | ||
self.line_thickness = line_thickness | ||
self.stride = stride | ||
|
||
@staticmethod | ||
def check_exist(path: str) -> None: | ||
"""ファイル, ディレクトリが存在するかの確認. | ||
|
||
Args: | ||
path (str): ファイルまたはディレクトリのパス | ||
|
||
raise: | ||
FileNotFoundError: ファイルがない場合に発生 | ||
""" | ||
try: | ||
if not os.path.exists(path): | ||
raise FileNotFoundError(f"'{path}' is not found") | ||
|
||
except FileNotFoundError as e: | ||
print("Error:", e) | ||
|
||
def detect_object(self, | ||
img_path=IMAGE_DIR_PATH/'test_image.png', | ||
save_path=None) -> list: | ||
"""物体の検出を行う関数. | ||
|
||
Args: | ||
img_path(str): 物体検出を行う画像パス | ||
save_path(str): 検出結果の画像保存パス | ||
Noneの場合、保存しない | ||
Returns: | ||
list: 検出したオブジェクト | ||
""" | ||
self.check_exist(img_path) | ||
|
||
# cpuを指定 | ||
device = select_device(self.__DEVICE) | ||
|
||
# モデルの読み込み | ||
model = DetectMultiBackend(self.weights, | ||
device=device, | ||
dnn=False, | ||
data=self.label_data, | ||
fp16=False) | ||
|
||
stride, labels, pt = model.stride, model.names, model.pt | ||
|
||
# 画像のサイズを指定されたストライド(ステップ)の倍数に合わせるための関数 | ||
img_size = check_img_size( | ||
self.__IMG_SIZE, s=stride) # >> [640, 640] | ||
|
||
# モデルの初期化 | ||
batch_size = 1 | ||
model.warmup( | ||
imgsz=(1 if pt or model.triton else batch_size, 3, *img_size)) | ||
|
||
# 画像の読み込み | ||
original_img = cv2.imread(img_path) # BGR | ||
|
||
# パディング処理 | ||
img = letterbox(original_img, | ||
self.__IMG_SIZE, | ||
stride=self.stride, | ||
auto=True)[0] | ||
img = img.transpose((2, 0, 1))[::-1] # BGR -> RGB | ||
img = np.ascontiguousarray(img) # 連続したメモリ領域に変換 | ||
img = torch.from_numpy(img).to(model.device) # PyTorchのテンソルに変換 | ||
img = img.half() if model.fp16 else img.float() # uint8 to fp16/32 | ||
|
||
# スケーリング | ||
img /= 255 # 0 - 255 to 0.0 - 1.0 | ||
|
||
# torch.Size([3, 640, 640]) >> torch.Size([1, 3, 640, 640]) | ||
if len(img.shape) == 3: | ||
img = img[None] | ||
|
||
# 検出 | ||
pred = model(img, augment=False, visualize=False) | ||
|
||
# 非最大値抑制 (NMS) により重複検出を拒否 | ||
pred = non_max_suppression(pred, | ||
self.conf_thres, # 信頼度の閾値 | ||
self.iou_thres, # IoUの閾値 | ||
max_det=self.max_det, # 保持する最大検出数 | ||
classes=None, # 検出するクラスのリスト | ||
agnostic=False # Trueの場合、クラスを無視してNMSを実行 | ||
) | ||
|
||
# 検出結果を画像に描画 | ||
objects = pred[0] | ||
print(Path(img_path).name, " 検出数", len(objects)) | ||
|
||
save_img = original_img.copy() | ||
|
||
# 画像にバウンディングボックスやラベルなどのアノテーションを追加 | ||
annotator = Annotator(save_img, | ||
line_width=self.line_thickness, | ||
example=str(labels)) | ||
|
||
if len(objects): | ||
# バウンディングボックスをimgサイズからsave_imgサイズに再スケールします | ||
objects[:, :4] = scale_boxes( | ||
img.shape[2:], objects[:, :4], save_img.shape).round() | ||
|
||
if save_path is not None: | ||
# xyxy: バウンディングボックスの座標([x_min, y_min, x_max, y_max] 形式) | ||
# conf: 信頼度 | ||
# cls: クラスID | ||
for *xyxy, conf, cls in reversed(objects): | ||
c = int(cls) | ||
label = f'{labels[int(cls)]} {conf:.2f}' | ||
# 画像にバウンディングボックスとラベルを追加 | ||
annotator.box_label(xyxy, label, color=colors(c, True)) | ||
|
||
# 検出結果を含む画像を保存 | ||
save_img = annotator.result() | ||
cv2.imwrite(save_path, save_img) | ||
|
||
""" | ||
NOTE: | ||
objectsの型について | ||
行数:検出数 | ||
列数:6列([x_min, y_min, x_max, y_max, conf, cls]) | ||
""" | ||
return objects.tolist() | ||
|
||
|
||
if __name__ == '__main__': | ||
"""作業用. | ||
$ poetry run python ./src/detect_object.py | ||
--img_path fig_image/test_image.png | ||
""" | ||
import argparse | ||
save_path = os.path.join(str(IMAGE_DIR_PATH), "detect_test_image.png") | ||
|
||
parser = argparse.ArgumentParser(description="リアカメラに関するプログラム") | ||
|
||
parser.add_argument("-wpath", "--weights", type=str, | ||
default=YOLO_PATH/'exp17_best.pt', | ||
help='重みファイルパス') | ||
parser.add_argument("-label", "--label_data", type=str, | ||
default=YOLO_PATH/'label_data.yaml', | ||
help='ラベルを記述したファイルパス') | ||
parser.add_argument("-conf", "--conf_thres", type=int, | ||
default=0.6, help='信頼度閾値') | ||
parser.add_argument("-iou", "--iou_thres", type=int, | ||
default=0.45, help='IOU 閾値') | ||
parser.add_argument("--max_det", type=int, default=10, help='最大検出数') | ||
parser.add_argument("--line_thickness", type=int, | ||
default=1, help='バウンディングボックスの太さ') | ||
parser.add_argument("--stride", type=int, default=32, help='ストライド') | ||
parser.add_argument("-img", "--img_path", type=str, | ||
default=IMAGE_DIR_PATH/'FigA_1.png', help='入力画像') | ||
parser.add_argument("-spath", "--save_path", type=str, | ||
default=save_path, help='検出画像の保存先. Noneの場合保存しない') | ||
args = parser.parse_args() | ||
|
||
d = DetectObject(args.weights, | ||
args.label_data, | ||
args.conf_thres, | ||
args.iou_thres, | ||
args.max_det, | ||
args.line_thickness, | ||
args.stride) | ||
|
||
objects = d.detect_object(args.img_path, args.save_path) | ||
print("objects\n", objects) | ||
|
||
print("完了") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -1,7 +1,7 @@ | ||||||||||||||||||||||||||
""" | ||||||||||||||||||||||||||
走行体と通信するWebサーバー. | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
@author Keiya121 CHIHAYATAKU KakinokiKanta | ||||||||||||||||||||||||||
@author Keiya121 CHIHAYATAKU KakinokiKanta takahashitom | ||||||||||||||||||||||||||
""" | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
import os | ||||||||||||||||||||||||||
|
@@ -10,6 +10,7 @@ | |||||||||||||||||||||||||
from flask_cors import CORS | ||||||||||||||||||||||||||
from ..csv_to_json import CSVToJSONConverter | ||||||||||||||||||||||||||
from ..official_interface import OfficialInterface | ||||||||||||||||||||||||||
from ..detect_object import DetectObject | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
from flask import Flask, request, jsonify, send_file | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
|
@@ -67,6 +68,60 @@ def get_image() -> jsonify: | |||||||||||||||||||||||||
|
||||||||||||||||||||||||||
return jsonify({"message": "File uploaded successfully"}), 200 | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
# '/detect'へのPOSTリクエストに対する操作 | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
@app.route('/detect', methods=['POST']) | ||||||||||||||||||||||||||
def get_detection_image() -> jsonify: | ||||||||||||||||||||||||||
"""走行体から画像ファイルを取得し、物体検出した結果を送信するための関数. | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
Return: | ||||||||||||||||||||||||||
jsonify (string, int): レスポンスメッセージ,ステータスコード | ||||||||||||||||||||||||||
""" | ||||||||||||||||||||||||||
# curlコマンドのエラーハンドリング | ||||||||||||||||||||||||||
if 'file' not in request.files: | ||||||||||||||||||||||||||
return jsonify({"error": "No file part"}), 400 | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
file = request.files['file'] | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
if file.filename == '': | ||||||||||||||||||||||||||
return jsonify({"error": "No selected file"}), 400 | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
file_name = file.filename | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
upload_folder = os.path.join(os.path.dirname(__file__), 'image_data') | ||||||||||||||||||||||||||
os.makedirs(upload_folder, exist_ok=True) | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
# src/server/image_dataに、受信したファイルを保存する | ||||||||||||||||||||||||||
file_path = os.path.join(upload_folder, file_name) | ||||||||||||||||||||||||||
file.save(file_path) | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
# 取得した画像に対し物体検出を行う | ||||||||||||||||||||||||||
d = DetectObject() | ||||||||||||||||||||||||||
detected_img_path = os.path.join(upload_folder, "detected_"+file_name) | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
try: | ||||||||||||||||||||||||||
objects = d.detect_object(img_path=file_path, | ||||||||||||||||||||||||||
save_path=detected_img_path) | ||||||||||||||||||||||||||
print(objects) | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
cls = int(objects[0][5]) | ||||||||||||||||||||||||||
empty_file = os.path.abspath(f"{cls}_skip_camera_action.flag") | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
# 空のフラグ管理用ファイルを作成 | ||||||||||||||||||||||||||
with open(empty_file, 'w') as file: | ||||||||||||||||||||||||||
pass | ||||||||||||||||||||||||||
Comment on lines
+108
to
+113
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 99行目に
Suggested change
|
||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
return send_file(empty_file, | ||||||||||||||||||||||||||
as_attachment=True, | ||||||||||||||||||||||||||
download_name=empty_file, | ||||||||||||||||||||||||||
mimetype='text/plain'), 200 | ||||||||||||||||||||||||||
except Exception: | ||||||||||||||||||||||||||
print("Error: detect failed") | ||||||||||||||||||||||||||
objects = [] | ||||||||||||||||||||||||||
return jsonify({"message": "File uploaded successfully", | ||||||||||||||||||||||||||
"detect_results": "detect failed"}), 200 | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
# '/run-log'へのPOSTリクエストに対する操作 | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
import os | ||
import platform | ||
import sys | ||
from pathlib import Path | ||
|
||
import pandas as pd | ||
|
||
FILE = Path(__file__).resolve() | ||
ROOT = FILE.parents[0] # YOLOv5 root directory | ||
if str(ROOT) not in sys.path: | ||
sys.path.append(str(ROOT)) # add ROOT to PATH | ||
if platform.system() != 'Windows': | ||
ROOT = Path(os.path.relpath(ROOT, Path.cwd())) # relative | ||
|
||
|
||
MACOS = platform.system() == 'Darwin' # macOS environment | ||
|
||
|
||
def export_formats(): | ||
# YOLOv5 export formats | ||
x = [ | ||
['PyTorch', '-', '.pt', True, True], | ||
['TorchScript', 'torchscript', '.torchscript', True, True], | ||
['ONNX', 'onnx', '.onnx', True, True], | ||
['OpenVINO', 'openvino', '_openvino_model', True, False], | ||
['TensorRT', 'engine', '.engine', False, True], | ||
['CoreML', 'coreml', '.mlmodel', True, False], | ||
['TensorFlow SavedModel', 'saved_model', '_saved_model', True, True], | ||
['TensorFlow GraphDef', 'pb', '.pb', True, True], | ||
['TensorFlow Lite', 'tflite', '.tflite', True, False], | ||
['TensorFlow Edge TPU', 'edgetpu', '_edgetpu.tflite', False, False], | ||
['TensorFlow.js', 'tfjs', '_web_model', False, False], | ||
['PaddlePaddle', 'paddle', '_paddle_model', True, True], ] | ||
return pd.DataFrame(x, columns=['Format', 'Argument', 'Suffix', 'CPU', 'GPU']) |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.