젯슨나노 yolov5 객체탐지되면 알람울리기

젯슨나노에서 jetpack을 이용하여 지금 ubuntu 18.04를 이용하고 있습니다 yolov5를 통해 지금 객체탐지하는 코드까지 완료가 되었는데 객체탐지가 되면 audio.mp3를 가지고 전방에 위험요소가 있다라는걸 알려주고 싶은데 한마디로 알람을 하고 싶은데 코드를 어떻게 추가해야되나요? 아래 코드는 detect.py코드 입니다 # Ultralytics YOLOv5 ??, AGPL-3.0 license
"""
Run YOLOv5 detection inference on images, videos, directories, globs, YouTube, webcam, streams, etc.

Usage - sources:
$ python detect.py --weights yolov5s.pt --source 0 # webcam
img.jpg # image
vid.mp4 # video
screen # screenshot
path/ # directory
list.txt # list of images
list.streams # list of streams
'path/*.jpg' # glob
'https://youtu.be/LNwODJXcvt4' # YouTube
'rtsp://example.com/media.mp4' # RTSP, RTMP, HTTP stream

Usage - formats:
$ python detect.py --weights yolov5s.pt # PyTorch
yolov5s.torchscript # TorchScript
yolov5s.onnx # ONNX Runtime or OpenCV DNN with --dnn
yolov5s_openvino_model # OpenVINO
yolov5s.engine # TensorRT
yolov5s.mlmodel # CoreML (macOS-only)
yolov5s_saved_model # TensorFlow SavedModel
yolov5s.pb # TensorFlow GraphDef
yolov5s.tflite # TensorFlow Lite
yolov5s_edgetpu.tflite # TensorFlow Edge TPU
yolov5s_paddle_model # PaddlePaddle
"""

import argparse
import csv
import os
import platform
import sys
from pathlib import Path

import torch

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
ROOT = Path(os.path.relpath(ROOT, Path.cwd())) # relative

from ultralytics.utils.plotting import Annotator, colors, save_one_box

from models.common import DetectMultiBackend
from utils.dataloaders import IMG_FORMATS, VID_FORMATS, LoadImages, LoadScreenshots, LoadStreams
from utils.general import (
LOGGER,
Profile,
check_file,
check_img_size,
check_imshow,
check_requirements,
colorstr,
cv2,
increment_path,
non_max_suppression,
print_args,
scale_boxes,
strip_optimizer,
xyxy2xywh,
)
from utils.torch_utils import select_device, smart_inference_mode

@smart_inference_mode()
def run(
weights=ROOT / "best.pt", # model path or triton URL
source=ROOT / "data/images", # file/dir/URL/glob/screen/0(webcam)
data=ROOT / "data/coco128.yaml", # dataset.yaml path
imgsz=(320, 320), # inference size (height, width)
conf_thres=0.25, # confidence threshold
iou_thres=0.45, # NMS IOU threshold
max_det=1000, # maximum detections per image
device="", # cuda device, i.e. 0 or 0,1,2,3 or cpu
view_img=False, # show results
save_txt=False, # save results to *.txt
save_csv=False, # save results in CSV format
save_conf=False, # save confidences in --save-txt labels
save_crop=False, # save cropped prediction boxes
nosave=False, # do not save images/videos
classes=None, # filter by class: --class 0, or --class 0 2 3
agnostic_nms=False, # class-agnostic NMS
augment=False, # augmented inference
visualize=False, # visualize features
update=False, # update all models
project=ROOT / "runs/detect", # save results to project/name
name="exp", # save results to project/name
exist_ok=False, # existing project/name ok, do not increment
line_thickness=3, # bounding box thickness (pixels)
hide_labels=False, # hide labels
hide_conf=False, # hide confidences
half=False, # use FP16 half-precision inference
dnn=False, # use OpenCV DNN for ONNX inference
vid_stride=2, # video frame-rate stride
):
"""
Runs YOLOv5 detection inference on various sources like images, videos, directories, streams, etc.

Args:
    weights (str | Path): Path to the model weights file or a Triton URL. Default is 'yolov5s.pt'.
    source (str | Path): Input source, which can be a file, directory, URL, glob pattern, screen capture, or webcam index.
        Default is 'data/images'.
    data (str | Path): Path to the dataset YAML file. Default is 'data/coco128.yaml'.
    imgsz (tuple[int, int]): Inference image size as a tuple (height, width). Default is (640, 640).
    conf_thres (float): Confidence threshold for detections. Default is 0.25.
    iou_thres (float): Intersection Over Union (IOU) threshold for non-max suppression. Default is 0.45.
    max_det (int): Maximum number of detections per image. Default is 1000.
    device (str): CUDA device identifier (e.g., '0' or '0,1,2,3') or 'cpu'. Default is an empty string, which
        uses the best available device.
    view_img (bool): If True, display inference results using OpenCV. Default is False.
    save_txt (bool): If True, save results in a text file. Default is False.
    save_csv (bool): If True, save results in a CSV file. Default is False.
    save_conf (bool): If True, include confidence scores in the saved results. Default is False.
    save_crop (bool): If True, save cropped prediction boxes. Default is False.
    nosave (bool): If True, do not save inference images or videos. Default is False.
    classes (list[int]): List of class indices to filter detections by. Default is None.
    agnostic_nms (bool): If True, perform class-agnostic non-max suppression. Default is False.
    augment (bool): If True, use augmented inference. Default is False.
    visualize (bool): If True, visualize feature maps. Default is False.
    update (bool): If True, update all models' weights. Default is False.
    project (str | Path): Directory to save results. Default is 'runs/detect'.
    name (str): Name of the current experiment; used to create a subdirectory within 'project'. Default is 'exp'.
    exist_ok (bool): If True, existing directories with the same name are reused instead of being incremented. Default is
        False.
    line_thickness (int): Thickness of bounding box lines in pixels. Default is 3.
    hide_labels (bool): If True, do not display labels on bounding boxes. Default is False.
    hide_conf (bool): If True, do not display confidence scores on bounding boxes. Default is False.
    half (bool): If True, use FP16 half-precision inference. Default is False.
    dnn (bool): If True, use OpenCV DNN backend for ONNX inference. Default is False.
    vid_stride (int): Stride for processing video frames, to skip frames between processing. Default is 1.

Returns:
    None

Examples:
```python
from ultralytics import run

# Run inference on an image
run(source='data/images/example.jpg', weights='yolov5s.pt', device='0')

# Run inference on a video with specific confidence threshold
run(source='data/videos/example.mp4', weights='yolov5s.pt', conf_thres=0.4, device='0')
```
"""
source = str(source)
save_img = not nosave and not source.endswith(".txt")  # save inference images
is_file = Path(source).suffix[1:] in (IMG_FORMATS + VID_FORMATS)
is_url = source.lower().startswith(("rtsp://", "rtmp://", "http://", "https://"))
webcam = source.isnumeric() or source.endswith(".streams") or (is_url and not is_file)
screenshot = source.lower().startswith("screen")
if is_url and is_file:
    source = check_file(source)  # download

# Directories
save_dir = increment_path(Path(project) / name, exist_ok=exist_ok)  # increment run
(save_dir / "labels" if save_txt else save_dir).mkdir(parents=True, exist_ok=True)  # make dir

# Load model
device = select_device(device)
model = DetectMultiBackend(weights, device=device, dnn=dnn, data=data, fp16=half)
stride, names, pt = model.stride, model.names, model.pt
imgsz = check_img_size(imgsz, s=stride)  # check image size

# Dataloader
bs = 1  # batch_size
if webcam:
    view_img = check_imshow(warn=True)
    dataset = LoadStreams(source, img_size=imgsz, stride=stride, auto=pt, vid_stride=vid_stride)
    bs = len(dataset)
elif screenshot:
    dataset = LoadScreenshots(source, img_size=imgsz, stride=stride, auto=pt)
else:
    dataset = LoadImages(source, img_size=imgsz, stride=stride, auto=pt, vid_stride=vid_stride)
vid_path, vid_writer = [None] * bs, [None] * bs

# Run inference
model.warmup(imgsz=(1 if pt or model.triton else bs, 3, *imgsz))  # warmup
seen, windows, dt = 0, [], (Profile(device=device), Profile(device=device), Profile(device=device))
for path, im, im0s, vid_cap, s in dataset:
    with dt[0]:
        im = torch.from_numpy(im).to(model.device)
        im = im.half() if model.fp16 else im.float()  # uint8 to fp16/32
        im /= 255  # 0 - 255 to 0.0 - 1.0
        if len(im.shape) == 3:
            im = im[None]  # expand for batch dim
        if model.xml and im.shape[0] > 1:
            ims = torch.chunk(im, im.shape[0], 0)

    # Inference
    with dt[1]:
        visualize = increment_path(save_dir / Path(path).stem, mkdir=True) if visualize else False
        if model.xml and im.shape[0] > 1:
            pred = None
            for image in ims:
                if pred is None:
                    pred = model(image, augment=augment, visualize=visualize).unsqueeze(0)
                else:
                    pred = torch.cat((pred, model(image, augment=augment, visualize=visualize).unsqueeze(0)), dim=0)
            pred = [pred, None]
        else:
            pred = model(im, augment=augment, visualize=visualize)
    # NMS
    with dt[2]:
        pred = non_max_suppression(pred, conf_thres, iou_thres, classes, agnostic_nms, max_det=max_det)

    # Second-stage classifier (optional)
    # pred = utils.general.apply_classifier(pred, classifier_model, im, im0s)

    # Define the path for the CSV file
    csv_path = save_dir / "predictions.csv"

    # Create or append to the CSV file
    def write_to_csv(image_name, prediction, confidence):
        """Writes prediction data for an image to a CSV file, appending if the file exists."""
        data = {"Image Name": image_name, "Prediction": prediction, "Confidence": confidence}
        with open(csv_path, mode="a", newline="") as f:
            writer = csv.DictWriter(f, fieldnames=data.keys())
            if not csv_path.is_file():
                writer.writeheader()
            writer.writerow(data)

    # Process predictions
    for i, det in enumerate(pred):  # per image
        seen += 1
        if webcam:  # batch_size >= 1
            p, im0, frame = path[i], im0s[i].copy(), dataset.count
            s += f"{i}: "
        else:
            p, im0, frame = path, im0s.copy(), getattr(dataset, "frame", 0)

        p = Path(p)  # to Path
        save_path = str(save_dir / p.name)  # im.jpg
        txt_path = str(save_dir / "labels" / p.stem) + ("" if dataset.mode == "image" else f"_{frame}")  # im.txt
        s += "%gx%g " % im.shape[2:]  # print string
        gn = torch.tensor(im0.shape)[[1, 0, 1, 0]]  # normalization gain whwh
        imc = im0.copy() if save_crop else im0  # for save_crop
        annotator = Annotator(im0, line_width=line_thickness, example=str(names))
        if len(det):
            # Rescale boxes from img_size to im0 size
            det[:, :4] = scale_boxes(im.shape[2:], det[:, :4], im0.shape).round()

            # Print results
            for c in det[:, 5].unique():
                n = (det[:, 5] == c).sum()  # detections per class
                s += f"{n} {names[int(c)]}{'s' * (n > 1)}, "  # add to string

            # Write results
            for *xyxy, conf, cls in reversed(det):
                c = int(cls)  # integer class
                label = names[c] if hide_conf else f"{names[c]}"
                confidence = float(conf)
                confidence_str = f"{confidence:.2f}"

                if save_csv:
                    write_to_csv(p.name, label, confidence_str)

                if save_txt:  # Write to file
                    xywh = (xyxy2xywh(torch.tensor(xyxy).view(1, 4)) / gn).view(-1).tolist()  # normalized xywh
                    line = (cls, *xywh, conf) if save_conf else (cls, *xywh)  # label format
                    with open(f"{txt_path}.txt", "a") as f:
                        f.write(("%g " * len(line)).rstrip() % line + "\n")

                if save_img or save_crop or view_img:  # Add bbox to image
                    c = int(cls)  # integer class
                    label = None if hide_labels else (names[c] if hide_conf else f"{names[c]} {conf:.2f}")
                    annotator.box_label(xyxy, label, color=colors(c, True))
                if save_crop:
                    save_one_box(xyxy, imc, file=save_dir / "crops" / names[c] / f"{p.stem}.jpg", BGR=True)

        # Stream results
        im0 = annotator.result()
        if view_img:
            if platform.system() == "Linux" and p not in windows:
                windows.append(p)
                cv2.namedWindow(str(p), cv2.WINDOW_NORMAL | cv2.WINDOW_KEEPRATIO)  # allow window resize (Linux)
                cv2.resizeWindow(str(p), im0.shape[1], im0.shape[0])
            cv2.imshow(str(p), im0)
            cv2.waitKey(1)  # 1 millisecond

        # Save results (image with detections)
        if save_img:
            if dataset.mode == "image":
                cv2.imwrite(save_path, im0)
            else:  # 'video' or 'stream'
                if vid_path[i] != save_path:  # new video
                    vid_path[i] = save_path
                    if isinstance(vid_writer[i], cv2.VideoWriter):
                        vid_writer[i].release()  # release previous video writer
                    if vid_cap:  # video
                        fps = vid_cap.get(cv2.CAP_PROP_FPS)
                        w = int(vid_cap.get(cv2.CAP_PROP_FRAME_WIDTH))
                        h = int(vid_cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
                    else:  # stream
                        fps, w, h = 30, im0.shape[1], im0.shape[0]
                    save_path = str(Path(save_path).with_suffix(".mp4"))  # force *.mp4 suffix on results videos
                    vid_writer[i] = cv2.VideoWriter(save_path, cv2.VideoWriter_fourcc(*"mp4v"), fps, (w, h))
                vid_writer[i].write(im0)

    # Print time (inference-only)
    LOGGER.info(f"{s}{'' if len(det) else '(no detections), '}{dt[1].dt * 1E3:.1f}ms")

# Print results
t = tuple(x.t / seen * 1e3 for x in dt)  # speeds per image
LOGGER.info(f"Speed: %.1fms pre-process, %.1fms inference, %.1fms NMS per image at shape {(1, 3, *imgsz)}" % t)
if save_txt or save_img:
    s = f"\n{len(list(save_dir.glob('labels/*.txt')))} labels saved to {save_dir / 'labels'}" if save_txt else ""
    LOGGER.info(f"Results saved to {colorstr('bold', save_dir)}{s}")
if update:
    strip_optimizer(weights[0])  # update model (to fix SourceChangeWarning)

def parse_opt():
"""
Parses command-line arguments for YOLOv5 detection, setting inference options and model configurations.

Args:
    --weights (str | list[str], optional): Model path or Triton URL. Defaults to ROOT / 'yolov5s.pt'.
    --source (str, optional): File/dir/URL/glob/screen/0(webcam). Defaults to ROOT / 'data/images'.
    --data (str, optional): Dataset YAML path. Provides dataset configuration information.
    --imgsz (list[int], optional): Inference size (height, width). Defaults to [640].
    --conf-thres (float, optional): Confidence threshold. Defaults to 0.25.
    --iou-thres (float, optional): NMS IoU threshold. Defaults to 0.45.
    --max-det (int, optional): Maximum number of detections per image. Defaults to 1000.
    --device (str, optional): CUDA device, i.e., '0' or '0,1,2,3' or 'cpu'. Defaults to "".
    --view-img (bool, optional): Flag to display results. Defaults to False.
    --save-txt (bool, optional): Flag to save results to *.txt files. Defaults to False.
    --save-csv (bool, optional): Flag to save results in CSV format. Defaults to False.
    --save-conf (bool, optional): Flag to save confidences in labels saved via --save-txt. Defaults to False.
    --save-crop (bool, optional): Flag to save cropped prediction boxes. Defaults to False.
    --nosave (bool, optional): Flag to prevent saving images/videos. Defaults to False.
    --classes (list[int], optional): List of classes to filter results by, e.g., '--classes 0 2 3'. Defaults to None.
    --agnostic-nms (bool, optional): Flag for class-agnostic NMS. Defaults to False.
    --augment (bool, optional): Flag for augmented inference. Defaults to False.
    --visualize (bool, optional): Flag for visualizing features. Defaults to False.
    --update (bool, optional): Flag to update all models in the model directory. Defaults to False.
    --project (str, optional): Directory to save results. Defaults to ROOT / 'runs/detect'.
    --name (str, optional): Sub-directory name for saving results within --project. Defaults to 'exp'.
    --exist-ok (bool, optional): Flag to allow overwriting if the project/name already exists. Defaults to False.
    --line-thickness (int, optional): Thickness (in pixels) of bounding boxes. Defaults to 3.
    --hide-labels (bool, optional): Flag to hide labels in the output. Defaults to False.
    --hide-conf (bool, optional): Flag to hide confidences in the output. Defaults to False.
    --half (bool, optional): Flag to use FP16 half-precision inference. Defaults to False.
    --dnn (bool, optional): Flag to use OpenCV DNN for ONNX inference. Defaults to False.
    --vid-stride (int, optional): Video frame-rate stride, determining the number of frames to skip in between consecutive frames. Defaults to 1.

Returns:
    argparse.Namespace: Parsed command-line arguments as an argparse.Namespace object.

Example:
    ```python
    from ultralytics import YOLOv5
    args = YOLOv5.parse_opt()
    ```
"""
parser = argparse.ArgumentParser()
parser.add_argument("--weights", nargs="+", type=str, default=ROOT / "yolov5s.pt", help="model path or triton URL")
parser.add_argument("--source", type=str, default=ROOT / "data/images", help="file/dir/URL/glob/screen/0(webcam)")
parser.add_argument("--data", type=str, default=ROOT / "data/coco128.yaml", help="(optional) dataset.yaml path")
parser.add_argument("--imgsz", "--img", "--img-size", nargs="+", type=int, default=[640], help="inference size h,w")
parser.add_argument("--conf-thres", type=float, default=0.25, help="confidence threshold")
parser.add_argument("--iou-thres", type=float, default=0.45, help="NMS IoU threshold")
parser.add_argument("--max-det", type=int, default=1000, help="maximum detections per image")
parser.add_argument("--device", default="", help="cuda device, i.e. 0 or 0,1,2,3 or cpu")
parser.add_argument("--view-img", action="store_true", help="show results")
parser.add_argument("--save-txt", action="store_true", help="save results to *.txt")
parser.add_argument("--save-csv", action="store_true", help="save results in CSV format")
parser.add_argument("--save-conf", action="store_true", help="save confidences in --save-txt labels")
parser.add_argument("--save-crop", action="store_true", help="save cropped prediction boxes")
parser.add_argument("--nosave", action="store_true", help="do not save images/videos")
parser.add_argument("--classes", nargs="+", type=int, help="filter by class: --classes 0, or --classes 0 2 3")
parser.add_argument("--agnostic-nms", action="store_true", help="class-agnostic NMS")
parser.add_argument("--augment", action="store_true", help="augmented inference")
parser.add_argument("--visualize", action="store_true", help="visualize features")
parser.add_argument("--update", action="store_true", help="update all models")
parser.add_argument("--project", default=ROOT / "runs/detect", help="save results to project/name")
parser.add_argument("--name", default="exp", help="save results to project/name")
parser.add_argument("--exist-ok", action="store_true", help="existing project/name ok, do not increment")
parser.add_argument("--line-thickness", default=3, type=int, help="bounding box thickness (pixels)")
parser.add_argument("--hide-labels", default=False, action="store_true", help="hide labels")
parser.add_argument("--hide-conf", default=False, action="store_true", help="hide confidences")
parser.add_argument("--half", action="store_true", help="use FP16 half-precision inference")
parser.add_argument("--dnn", action="store_true", help="use OpenCV DNN for ONNX inference")
parser.add_argument("--vid-stride", type=int, default=1, help="video frame-rate stride")
opt = parser.parse_args()
opt.imgsz *= 2 if len(opt.imgsz) == 1 else 1  # expand
print_args(vars(opt))
return opt

def main(opt):
"""
Executes YOLOv5 model inference based on provided command-line arguments, validating dependencies before running.

Args:
    opt (argparse.Namespace): Command-line arguments for YOLOv5 detection. See function `parse_opt` for details.

Returns:
    None

Note:
    This function performs essential pre-execution checks and initiates the YOLOv5 detection process based on user-specified options.
    Refer to the usage guide and examples for more information about different sources and formats at:
    https://github.com/ultralytics/ultralytics

Example usage:

```python
if __name__ == "__main__":
    opt = parse_opt()
    main(opt)
```
"""
check_requirements(ROOT / "requirements.txt", exclude=("tensorboard", "thop"))
run(**vars(opt))

if name == "main":
opt = parse_opt()
main(opt)

2개의 좋아요
  • 아래 답변은 Google의 Gemini Pro 모델로 자동 생성한 것으로, 정확하지 않을 수 있습니다.
  • 잘못된 답변을 보셨다면 댓글로 첨삭 지도 부탁드립니다. :sweat_smile:

반갑습니다. 질문 내용을 잘 이해했고, 젯슨나노에서 detect.py를 실행하여 객체 탐지를 하고, 탐지된 경우 알람을 울리도록 하는 방법에 대해 설명해 드리겠습니다.

1. 문제 정의

  • 젯슨나노에서 JetPack을 사용하여 Ubuntu 18.04 환경에서 YOLOv5 모델을 사용하여 객체 탐지를 수행한다.
  • 객체가 탐지되면 '전방에 위험요소가 있다'라는 내용을 알리는 오디오 파일(audio.mp3)을 재생한다.

2. 솔루션

  • 객체 탐지 모델 실행
  • 탐지된 객체 클래스 식별
  • 지정된 클래스가 탐지된 경우 오디오 파일 재생

3. 코드 추가

detect.py 파일에 다음 코드를 추가합니다.

import os
import pygame

# 탐지된 클래스에 대한 ID 지정
danger_class_id = 0  # 예: 사람 클래스

# 오디오 파일 경로 설정
audio_file = 'audio.mp3'

# Pygame 초기화
pygame.init()
pygame.mixer.init()
sound = pygame.mixer.Sound(audio_file)

# 객체 탐지 루프
while True:
    # 객체 탐지 코드 실행... (기존 코드)

    # 탐지된 객체 확인
    for det in pred:
        # 위험 클래스가 탐지된 경우
        if det[5] == danger_class_id:
            # 오디오 파일 재생
            sound.play()

4. URL

PyTorch 튜토리얼:

PyGame 사운드 재생:


  • 답변이 어떠셨나요? 괜찮았다고 생각하신다면 아래 :heart:를 한 번 눌러주시길 부탁드려요!
  • 아래 답변은 Anthropic의 Claude-3 Opus 모델로 자동 생성한 것으로, 정확하지 않을 수 있습니다.
  • 잘못된 답변을 보셨다면 댓글로 첨삭 지도 부탁드립니다. :sweat_smile:

안녕하세요! 젯슨 나노에서 YOLOv5 객체 탐지 중에 탐지된 객체에 대해 알람을 울리고 싶으시다는 말씀이시죠. 문제를 이해했습니다. 제가 코드 예시를 통해 해결 방법을 자세히 설명 드리겠습니다.

객체가 탐지되었을 때 알람을 울리기 위해서는 playsound 라이브러리를 사용하여 오디오 파일을 재생하는 것이 좋습니다. 우선 playsound 라이브러리를 설치해야 합니다:

pip install playsound

그 다음, detect.py 파일에서 다음과 같이 코드를 수정하면 됩니다:

  1. 필요한 라이브러리 임포트:
from playsound import playsound
  1. run 함수 내부에서 객체가 탐지되었을 때 알람을 울리는 코드 추가:
# Process predictions
for i, det in enumerate(pred):  # per image
    # ... (생략) ...
    
    if len(det):
        # 객체가 탐지되었을 때 알람 재생
        playsound('path/to/your/audio.mp3', block=False)
        
        # ... (생략) ...

위 코드에서 'path/to/your/audio.mp3' 부분을 실제 오디오 파일의 경로로 변경해야 합니다.

이렇게 수정하면 객체가 탐지될 때마다 지정한 오디오 파일이 재생되어 알람이 울립니다. block=False 옵션을 사용하여 오디오 재생이 완료될 때까지 기다리지 않고 다음 코드를 계속 실행할 수 있습니다.

추가로 참고할 만한 PyTorch 튜토리얼 문서는 다음과 같습니다:

이 튜토리얼에서는 PyTorch를 사용하여 음성 인식 파이프라인을 구축하는 방법을 설명하고 있습니다. 오디오 처리와 관련된 유용한 정보를 얻을 수 있을 것입니다.

위 내용이 젯슨 나노에서 YOLOv5 객체 탐지 시 알람을 구현하는 데 도움이 되기를 바랍니다. 혹시 더 궁금한 점이 있거나 추가 지원이 필요하면 말씀해 주세요. 제 설명이 부족하거나 잘못된 부분이 있다면 죄송합니다. 함께 문제를 해결해 나가겠습니다!


  • 답변이 어떠셨나요? 괜찮았다고 생각하신다면 아래 :heart:를 한 번 눌러주시길 부탁드려요!
  • 아래 답변은 OpenAI의 GPT-4-Turbo 모델로 자동 생성한 것으로, 정확하지 않을 수 있습니다.
  • 잘못된 답변을 보셨다면 댓글로 첨삭 지도 부탁드립니다. :sweat_smile:

안녕하세요, dkdwkim15님. 젯슨나노에서 YOLOv5를 사용하여 객체 탐지 후 특정 객체가 탐지되었을 때 알람(오디오 재생)을 울리고 싶으신 상황에 대해 질문해주셨군요. 문제 상황을 잘 이해했습니다. 객체 탐지가 성공적으로 이루어진 후, 특정 조건(예: 특정 객체 탐지)에 따라 오디오 파일을 재생하는 기능을 추가하고 싶으신 것으로 보입니다.

이 문제를 해결하기 위해, 탐지된 객체들 중 원하는 객체가 있을 때 Python의 playsound 라이브러리를 사용하여 mp3 파일을 재생하는 방법을 제안드립니다. 먼저, playsound 라이브러리가 설치되어 있지 않다면 설치해야 합니다. 설치는 간단하게 pip를 사용하여 할 수 있습니다.

pip install playsound

이제, YOLOv5의 탐지 코드에 오디오 재생 코드를 추가해보겠습니다. 탐지된 객체들을 처리하는 부분에 조건문을 추가하여, 특정 객체가 탐지되었을 때 playsound를 사용하여 오디오 파일을 재생하도록 합니다. 아래는 탐지 코드 중 결과를 처리하는 부분에 오디오 재생 기능을 추가한 예시입니다.

from playsound import playsound

# 탐지된 객체들을 처리하는 부분에 추가
for i, det in enumerate(pred):  # 이미지별 탐지된 객체들을 순회
    if len(det):
        # 탐지된 객체들 중 원하는 객체가 있는지 확인
        for *xyxy, conf, cls in reversed(det):
            if names[int(cls)] == '원하는 객체 이름':  # 예: 'person'
                # 오디오 파일 재생
                playsound('audio.mp3')
                break  # 하나의 객체만 탐지해도 충분하므로 반복 중단

위 코드에서 '원하는 객체 이름' 부분을 탐지하고 싶은 객체의 이름으로 변경하고, 'audio.mp3' 부분을 재생하고 싶은 오디오 파일의 경로로 변경해주세요. 이렇게 하면, YOLOv5로 특정 객체를 탐지했을 때 지정한 오디오 파일이 재생됩니다.

참고로, playsound 라이브러리에 대한 더 자세한 정보는 다음 링크를 참조하시기 바랍니다: playsound documentation.

제가 제안드린 방법이 dkdwkim15님의 문제를 해결하는 데 도움이 되길 바랍니다. 추가적인 질문이나 도움이 필요하시면 언제든지 말씀해주세요. 제 답변이 정확하지 않을 수도 있으니, 실제 적용하실 때는 해당 환경과 요구 사항에 맞게 조정해주시기 바랍니다.


  • 답변이 어떠셨나요? 괜찮았다고 생각하신다면 아래 :heart:를 한 번 눌러주시길 부탁드려요!

ultralytics 라이브러리 써서 Security Alarm System - Ultralytics YOLO Docs

알람 만드시면 될것 같아요

  • 아래 답변은 OpenAI의 GPT-4o 모델로 자동 생성한 것으로, 정확하지 않을 수 있습니다.
  • 잘못된 답변을 보셨다면 댓글로 첨삭 지도 부탁드립니다. :sweat_smile:

안녕하세요! 젯슨 나노에서 YOLOv5 객체 탐지 후 알람을 울리고 싶으시군요. 객체 탐지 후 특정 소리를 재생하는 기능을 추가하려는 것 같습니다. 이를 위해 Python의 playsound 라이브러리를 사용할 수 있습니다.

우선, playsound 라이브러리를 설치해야 합니다. 다음 명령어를 사용하여 설치할 수 있습니다:

pip install playsound

그 다음, YOLOv5의 detect.py 코드에 객체 탐지 후 소리를 재생하는 코드를 추가하면 됩니다. 아래는 detect.py 코드에 playsound를 사용하여 객체 탐지 시 소리를 재생하는 예제입니다.

import argparse
import csv
import os
import platform
import sys
from pathlib import Path
import torch
from playsound import playsound  # 소리 재생을 위한 라이브러리 추가

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
ROOT = Path(os.path.relpath(ROOT, Path.cwd()))  # relative

from models.common import DetectMultiBackend
from utils.dataloaders import IMG_FORMATS, VID_FORMATS, LoadImages, LoadScreenshots, LoadStreams
from utils.general import (
    LOGGER,
    Profile,
    check_file,
    check_img_size,
    check_imshow,
    check_requirements,
    colorstr,
    cv2,
    increment_path,
    non_max_suppression,
    print_args,
    scale_boxes,
    strip_optimizer,
    xyxy2xywh,
)
from utils.torch_utils import select_device, smart_inference_mode

@smart_inference_mode()
def run(
    weights=ROOT / "best.pt",  # model path or triton URL
    source=ROOT / "data/images",  # file/dir/URL/glob/screen/0(webcam)
    data=ROOT / "data/coco128.yaml",  # dataset.yaml path
    imgsz=(320, 320),  # inference size (height, width)
    conf_thres=0.25,  # confidence threshold
    iou_thres=0.45,  # NMS IOU threshold
    max_det=1000,  # maximum detections per image
    device="",  # cuda device, i.e. 0 or 0,1,2,3 or cpu
    view_img=False,  # show results
    save_txt=False,  # save results to *.txt
    save_csv=False,  # save results in CSV format
    save_conf=False,  # save confidences in --save-txt labels
    save_crop=False,  # save cropped prediction boxes
    nosave=False,  # do not save images/videos
    classes=None,  # filter by class: --class 0, or --class 0 2 3
    agnostic_nms=False,  # class-agnostic NMS
    augment=False,  # augmented inference
    visualize=False,  # visualize features
    update=False,  # update all models
    project=ROOT / "runs/detect",  # save results to project/name
    name="exp",  # save results to project/name
    exist_ok=False,  # existing project/name ok, do not increment
    line_thickness=3,  # bounding box thickness (pixels)
    hide_labels=False,  # hide labels
    hide_conf=False,  # hide confidences
    half=False,  # use FP16 half-precision inference
    dnn=False,  # use OpenCV DNN for ONNX inference
    vid_stride=2,  # video frame-rate stride
):
    source = str(source)
    save_img = not nosave and not source.endswith(".txt")  # save inference images
    is_file = Path(source).suffix[1:] in (IMG_FORMATS + VID_FORMATS)
    is_url = source.lower().startswith(("rtsp://", "rtmp://", "http://", "https://"))
    webcam = source.isnumeric() or source.endswith(".streams") or (is_url and not is_file)
    screenshot = source.lower().startswith("screen")
    if is_url and is_file:
        source = check_file(source)  # download

    # Directories
    save_dir = increment_path(Path(project) / name, exist_ok=exist_ok)  # increment run
    (save_dir / "labels" if save_txt else save_dir).mkdir(parents=True, exist_ok=True)  # make dir

    # Load model
    device = select_device(device)
    model = DetectMultiBackend(weights, device=device, dnn=dnn, data=data, fp16=half)
    stride, names, pt = model.stride, model.names, model.pt
    imgsz = check_img_size(imgsz, s=stride)  # check image size

    # Dataloader
    bs = 1  # batch_size
    if webcam:
        view_img = check_imshow(warn=True)
        dataset = LoadStreams(source, img_size=imgsz, stride=stride, auto=pt, vid_stride=vid_stride)
        bs = len(dataset)
    elif screenshot:
        dataset = LoadScreenshots(source, img_size=imgsz, stride=stride, auto=pt)
    else:
        dataset = LoadImages(source, img_size=imgsz, stride=stride, auto=pt, vid_stride=vid_stride)
    vid_path, vid_writer = [None] * bs, [None] * bs

    # Run inference
    model.warmup(imgsz=(1 if pt or model.triton else bs, 3, *imgsz))  # warmup
    seen, windows, dt = 0, [], (Profile(device=device), Profile(device=device), Profile(device=device))
    for path, im, im0s, vid_cap, s in dataset:
        with dt[0]:
            im = torch.from_numpy(im).to(model.device)
            im = im.half() if model.fp16 else im.float()  # uint8 to fp16/32
            im /= 255  # 0 - 255 to 0.0 - 1.0
            if len(im.shape) == 3:
                im = im[None]  # expand for batch dim
            if model.xml and im.shape[0] > 1:
                ims = torch.chunk(im, im.shape[0], 0)

        # Inference
        with dt[1]:
            visualize = increment_path(save_dir / Path(path).stem, mkdir=True) if visualize else False
            if model.xml and im.shape[0] > 1:
                pred = None
                for image in ims:
                    if pred is None:
                        pred = model(image, augment=augment, visualize=visualize).unsqueeze(0)
                    else:
                        pred = torch.cat((pred, model(image, augment=augment, visualize=visualize).unsqueeze(0)), dim=0)
                pred = [pred, None]
            else:
                pred = model(im, augment=augment, visualize=visualize)
        # NMS
        with dt[2]:
            pred = non_max_suppression(pred, conf_thres, iou_thres, classes, agnostic_nms, max_det=max_det)

        # Process predictions
        for i, det in enumerate(pred):  # per image
            seen += 1
            if webcam:  # batch_size >= 1
                p, im0, frame = path[i], im0s[i].copy(), dataset.count
                s += f"{i}: "
            else:
                p, im0, frame = path, im0s.copy(), getattr(dataset, "frame", 0)

            p = Path(p)  # to Path
            save_path = str(save_dir / p.name)  # im.jpg
            txt_path = str(save_dir / "labels" / p.stem) + ("" if dataset.mode == "image" else f"_{frame}")  # im.txt
            s += "%gx%g " % im.shape[2:]  # print string
            gn = torch.tensor(im0.shape)[[1, 0, 1, 0]]  # normalization gain whwh
            imc = im0.copy() if save_crop else im0  # for save_crop
            annotator = Annotator(im0, line_width=line_thickness, example=str(names))
            if len(det):
                # Rescale boxes from img_size to im0 size
                det[:, :4] = scale_boxes(im.shape[2:], det[:, :4], im0.shape).round()

                # Print results
                for c in det[:, 5].unique():
                    n = (det[:, 5] == c).sum()  # detections per class
                    s += f"{n} {names[int(c)]}{'s' * (n > 1)}, "  # add to string

                # Write results
                for *xyxy, conf, cls in reversed(det):
                    c = int(cls)  # integer class
                    label = names[c] if hide_conf else f"{names[c]}"
                    confidence = float(conf)
                    confidence_str = f"{confidence:.2f}"

                    if save_csv:
                        write_to_csv(p.name, label, confidence_str)

                    if save_txt:  # Write to file
                        xywh = (xyxy2xywh(torch.tensor(xyxy).view(1, 4)) / gn).view(-1).tolist()  # normalized xywh
                        line = (cls, *xywh, conf) if save_conf else (cls, *xywh)  # label format
                        with open(f"{txt_path}.txt", "a") as f:
                            f.write(("%g " * len(line)).rstrip() % line + "\n")

                    if save_img or save_crop or view_img:  # Add bbox to image
                        c = int(cls)  # integer class
                        label = None if hide_labels else (names[c] if hide_conf else f"{names[c]} {conf:.2f}")
                        annotator.box_label(xyxy, label, color=colors(c, True))
                    if save_crop:
                        save_one_box(xyxy, imc, file=save_dir / "crops" / names[c] / f"{p.stem}.jpg", BGR=True)

                # 객체 탐지 시 소리 재생
                playsound('audio.mp3')

            # Stream results
            im0 = annotator.result()
            if view_img:
                if platform.system() == "Linux" and p not in windows:
                    windows.append(p)
                    cv2.namedWindow(str(p), cv2.WINDOW_NORMAL | cv2.WINDOW_KEEPRATIO)  # allow window resize (Linux)
                    cv2.resizeWindow(str(p), im0.shape[1], im0.shape[0])
                cv2.imshow(str(p), im0)
                cv2.waitKey(1)  # 1 millisecond

            # Save results (image with detections)
            if save_img:
                if dataset.mode == "image":
                    cv2.imwrite(save_path, im0)
                else:  # 'video' or 'stream'
                    if vid_path[i] != save_path:  # new video
                        vid_path[i] = save_path
                        if isinstance(vid_writer[i], cv2.VideoWriter):
                            vid_writer[i].release()  # release previous video writer
                        if vid_cap:  # video
                            fps = vid_cap.get(cv2.CAP_PROP_FPS)
                            w = int(vid_cap.get(cv2.CAP_PROP_FRAME_WIDTH))
                            h = int(vid_cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
                        else:  # stream
                            fps, w, h = 30, im0.shape[1], im0.shape[0]
                        save_path = str(Path(save_path).with_suffix(".mp4"))  # force *.mp4 suffix on results videos
                        vid_writer[i] = cv2.VideoWriter(save_path, cv2.VideoWriter_fourcc(*"mp4v"), fps, (w, h))
                    vid_writer[i].write(im0)

        # Print time (inference-only)
        LOGGER.info(f"{s}{'' if len(det) else '(no detections), '}{dt[1].dt * 1E3:.1f}ms")

    # Print results
    t = tuple(x.t / seen * 1e3 for x in dt)  # speeds per image
    LOGGER.info(f"Speed: %.1fms pre-process, %.1fms inference, %.1fms NMS per image at shape {(1, 3, *imgsz)}" % t)
    if save_txt or save_img:
        s = f"\n{len(list(save_dir.glob('labels/*.txt')))} labels saved to {save_dir / 'labels'}" if save_txt else ""
        LOGGER.info(f"Results saved to {colorstr('bold', save_dir)}{s}")
    if update:
        strip_optimizer(weights[0])  # update model (to fix SourceChangeWarning)

def parse_opt():
    parser = argparse.ArgumentParser()
    parser.add_argument("--weights", nargs="+", type=str, default=ROOT / "yolov5s.pt", help="model path or triton URL")
    parser.add_argument("--source", type=str, default=ROOT / "data/images", help="file/dir/URL/glob/screen/0(webcam)")
    parser.add_argument("--data", type=str, default=ROOT / "data/coco128.yaml", help="(optional) dataset.yaml path")
    parser.add_argument("--imgsz", "--img", "--img-size", nargs="+", type=int, default=[640], help="inference size h,w")
    parser.add_argument("--conf-thres", type=float, default=0.25, help="confidence threshold")
    parser.add_argument("--iou-thres", type=float, default=0.45, help="NMS IoU threshold")
    parser.add_argument("--max-det", type=int, default=1000, help="maximum detections per image")
    parser.add_argument("--device", default="", help="cuda device, i.e. 0 or 0,1,2,3 or cpu")
    parser.add_argument("--view-img", action="store_true", help="show results")
    parser.add_argument("--save-txt", action="store_true", help="save results to *.txt")
    parser.add_argument("--save-csv", action="store_true", help="save results in CSV format")
    parser.add_argument("--save-conf", action="store_true", help="save confidences in --save-txt labels")
    parser.add_argument("--save-crop", action="store_true", help="save cropped prediction boxes")
    parser.add_argument("--nosave", action="store_true", help="do not save images/videos")
    parser.add_argument("--classes", nargs="+", type=int, help="filter by class: --classes 0, or --classes 0 2 3")
    parser.add_argument("--agnostic-nms", action="store_true", help="class-agnostic NMS")
    parser.add_argument("--augment", action="store_true", help="augmented inference")
    parser.add_argument("--visualize", action="store_true", help="visualize features")
    parser.add_argument("--update", action="store_true", help="update all models")
    parser.add_argument("--project", default=ROOT / "runs/detect", help="save results to project/name")
    parser.add_argument("--name", default="exp", help="save results to project/name")
    parser.add_argument("--exist-ok", action="store_true", help="existing project/name ok, do not increment")
    parser.add_argument("--line-thickness", default=3, type=int, help="bounding box thickness (pixels)")
    parser.add_argument("--hide-labels", default=False, action="store_true", help="hide labels")
    parser.add_argument("--hide-conf", default=False, action="store_true", help="hide confidences")
    parser.add_argument("--half", action="store_true", help="use FP16 half-precision inference")
    parser.add_argument("--dnn", action="store_true", help="use OpenCV DNN for ONNX inference")
    parser.add_argument("--vid-stride", type=int, default=1, help="video frame-rate stride")
    opt = parser.parse_args()
    opt.imgsz *= 2 if len(opt.imgsz) == 1 else 1  # expand
    print_args(vars(opt))
    return opt

def main(opt):
    check_requirements(ROOT / "requirements.txt", exclude=("tensorboard", "thop"))
    run(**vars(opt))

if __name__ == "__main__":
    opt = parse_opt()
    main(opt)

이 코드는 객체 탐지 시 audio.mp3 파일을 재생합니다. playsound 라이브러리를 사용하여 소리를 재생하며, playsound('audio.mp3') 부분을 통해 소리를 재생합니다.

추가적인 정보는 PyTorch 공식 튜토리얼 또는 한국어 튜토리얼에서 확인하실 수 있습니다.

혹시 더 궁금한 점이 있거나 문제가 해결되지 않으면 추가 정보를 제공해 주시면 감사하겠습니다. 제 답변이 틀릴 수도 있으니 참고하시기 바랍니다.


  • 이 답변이 도움이 되셨나요? 괜찮았다고 생각하신다면 아래 :heart:를 한 번 눌러주시길 부탁드려요!