리얼센스 카메라를 이용하여 yolov8을 활용하여 실시간 object detection을 진행하는 과정을 보여준다.
리얼센스 제품은 L515이다.
우선 리얼센스 L515 카메라 셋팅 먼저 진행하겠다.
# Create a config and configure the pipeline to stream for Realsense-L515
pipeline = rs.pipeline()
config = rs.config()
# Get device product line for setting a supporting resolution
pipeline_wrapper = rs.pipeline_wrapper(pipeline)
pipeline_profile = config.resolve(pipeline_wrapper)
device = pipeline_profile.get_device()
device_product_line = str(device.get_info(rs.camera_info.product_line))
found_rgb = False
for s in device.sensors:
if s.get_info(rs.camera_info.name) == 'RGB Camera':
found_rgb = True
break
if not found_rgb:
print("The demo requires Depth camera with Color sensor")
exit(0)
# Depth 이미지 스트리밍을 위한 config
config.enable_stream(rs.stream.depth, 640, 480, rs.format.z16, 30)
# RGB 이미지 스트리밍을 위한 config
if device_product_line == 'L500':
config.enable_stream(rs.stream.color, 960, 540, rs.format.bgr8, 30)
else:
config.enable_stream(rs.stream.color, 640, 480, rs.format.bgr8, 30)
# Start streaming
profile = pipeline.start(config)
# Create an align object
# rs.align allows us to perform alignment of depth frames to others frames
# The "align_to" is the stream type to which we plan to align depth frames.
align_to = rs.stream.color
align = rs.align(align_to)
이렇게 Realsense L515의 카메라 세팅이 완료되었다. 만약 스트리밍을 진행하고싶다면 While문을 통해 계속해서 frame을 가져오면 된다.
이제 yolov8을 활용하여 detection을 수행해보자.
먼저 패키지 설치 및 yolov8의 모델 다운로드가 필요하다.
# 패키지 설치
pip install ultralytics
# pretrained 모델
wget https://github.com/ultralytics/assets/releases/download/v0.0.0/yolo8l.pt
이렇게 패키지 및 yolov8 모델이 다운된다면, 바로 학습된 모델을 사용하여 이미지에 대한 결과를 얻을 수 있다.
from ultralytics import YOLO
from ultralytics.yolo.utils.checks import check_yaml
from ultralytics.yolo.utils import ROOT, yaml_load
# 모델 가져오기
model = YOLO('yolov8n.pt')
# 클래스 이름 가져오기
CLASSES = yaml_load(check_yaml('coco128.yaml'))['names']
이제 모델 기반으로 이미지에 대한 결과를 확인해보자!
yolov8은 api를 제공하기 때문에, model 결과를 기반으로 쉽게 여러가지 정보들을 받아올 수 있다.
https://docs.ultralytics.com/modes/predict/
Predict - YOLOv8 Docs
Predict YOLOv8 predict mode can generate predictions for various tasks, returning either a list of Results objects or a memory-efficient generator of Results objects when using the streaming mode. Enable streaming mode by passing stream=True in the predict
docs.ultralytics.com
# 이미지 불러오기 (실시간이면 strema=True)
results= model(color_image, stream=True)
class_ids = []
confidences = []
bboxes = []
for result in results:
boxes = result.boxes
for box in boxes:
confidence = box.conf
if confidence > 0.5:
xyxy = box.xyxy.tolist()[0]
bboxes.append(xyxy)
confidences.append(float(confidence))
class_ids.append(box.cls.tolist())
class_ids는 클래스 별로 instance id를 가져올 수 있도록 한다.
bboxes는 각 객체별로의 바운딩박스이며 confidences는 확률이다. 따라서 0.5이상일 때 result에 저장하도록한다.
# NMSBoxes
result_boxes = cv2.dnn.NMSBoxes(bboxes, confidences, 0.25, 0.45, 0.5)
# print(result_boxes)
for i in range(len(bboxes)):
label = str(CLASSES[int(class_ids[i][0])])
# 사람에 대해서만 detection, 만약 모든 물체에 대해서 하고싶다면 밑에 if문을 지우면 됨.
if label == 'person':
if i in result_boxes:
bbox = list(map(int, bboxes[i]))
x, y, x2, y2 = bbox
depth = depth_image_scaled[cy, cx]
cv2.rectangle(color_image, (x, y), (x2, y2), color, 2)
cv2.rectangle(depth_image_scaled, (x, y), (x2, y2), color, 2)
cv2.putText(color_image, label, (x, y + 30), font, 3, color, 3)
cv2.imshow("Bgr frame", color_image)
cv2.imshow("Depth frame", depth_image_scaled)
NMS는 여러개의 바운딩박스를 단일 바운딩 박스로 변환해주는 작업이다. 자세한 내용은 아래를 참고하자.
3) NMS (Non-Maximum Suppression) & Anchor box - 한땀한땀 딥러닝 컴퓨터 비전 백과사전 (wikidocs.net)
3) NMS (Non-Maximum Suppression) & Anchor box
## 서론 앞서 [1) General process of object detection](https://wikidocs.net/152376) 에서 언급했듯, 대다수의 objec…
wikidocs.net
다음 코드를 기반으로 컬러 이미지로부터 yolov8을 수행하여 사람 탐지를 할 수 있게 된다. 전체 코드는 다음과 같다.
import pyrealsense2 as rs
import numpy as np
import cv2
from ultralytics import YOLO
from ultralytics.yolo.utils.checks import check_yaml
from ultralytics.yolo.utils import ROOT, yaml_load
# parameters
WITDH = 1280
HEIGHT = 720
model = YOLO('yolov8n.pt')
CLASSES = yaml_load(check_yaml('coco128.yaml'))['names']
colors = np.random.uniform(0, 255, size=(len(CLASSES), 3))
# Create a config and configure the pipeline to stream for Realsense-L515
pipeline = rs.pipeline()
config = rs.config()
# Get device product line for setting a supporting resolution
pipeline_wrapper = rs.pipeline_wrapper(pipeline)
pipeline_profile = config.resolve(pipeline_wrapper)
device = pipeline_profile.get_device()
device_product_line = str(device.get_info(rs.camera_info.product_line))
found_rgb = False
for s in device.sensors:
if s.get_info(rs.camera_info.name) == 'RGB Camera':
found_rgb = True
break
if not found_rgb:
print("The demo requires Depth camera with Color sensor")
exit(0)
config.enable_stream(rs.stream.depth, 640, 480, rs.format.z16, 30)
if device_product_line == 'L500':
config.enable_stream(rs.stream.color, 960, 540, rs.format.bgr8, 30)
else:
config.enable_stream(rs.stream.color, 640, 480, rs.format.bgr8, 30)
# Start streaming
profile = pipeline.start(config)
# Create an align object
# rs.align allows us to perform alignment of depth frames to others frames
# The "align_to" is the stream type to which we plan to align depth frames.
align_to = rs.stream.color
align = rs.align(align_to)
# Streaming loop
try:
while True:
# Get frameset of color and depth
frames = pipeline.wait_for_frames()
# Align the depth frame to color frame
aligned_frames = align.process(frames)
# Get aligned frames
aligned_depth_frame = aligned_frames.get_depth_frame() # aligned_depth_frame is a 640x480 depth image
color_frame = aligned_frames.get_color_frame()
# Validate that both frames are valid
if not aligned_depth_frame or not color_frame:
continue
depth_image = np.asanyarray(aligned_depth_frame.get_data())
color_image = np.asanyarray(color_frame.get_data())
depth_image = cv2.resize(depth_image, (WITDH, HEIGHT))
color_image = cv2.resize(color_image, (WITDH, HEIGHT))
# # Render images:
# # depth align to color on left
# # depth on right
# 뎁스 이미지 스케일링
depth_image_scaled = cv2.convertScaleAbs(depth_image, alpha=0.025)
results= model(color_image, stream=True)
class_ids = []
confidences = []
bboxes = []
for result in results:
boxes = result.boxes
for box in boxes:
confidence = box.conf
if confidence > 0.5:
xyxy = box.xyxy.tolist()[0]
bboxes.append(xyxy)
confidences.append(float(confidence))
class_ids.append(box.cls.tolist())
result_boxes = cv2.dnn.NMSBoxes(bboxes, confidences, 0.25, 0.45, 0.5)
# print(result_boxes)
font = cv2.FONT_HERSHEY_PLAIN
depth_list = list()
person_id_list = list()
for i in range(len(bboxes)):
label = str(CLASSES[int(class_ids[i][0])])
if label == 'person':
if i in result_boxes:
bbox = list(map(int, bboxes[i]))
x, y, x2, y2 = bbox
color = colors[i]
color = (int(color[0]), int(color[1]), int(color[2]))
cv2.rectangle(color_image, (x, y), (x2, y2), color, 2)
cv2.rectangle(depth_image_scaled, (x, y), (x2, y2), color, 2)
cv2.putText(color_image, label, (x, y + 30), font, 3, color, 3)
cv2.imshow("Bgr frame", color_image)
cv2.imshow("Depth frame", depth_image_scaled)
key = cv2.waitKey(1)
# Press esc or 'q' to close the image window
if key & 0xFF == ord('q') or key == 27:
cv2.destroyAllWindows()
break
finally:
pipeline.stop()
사람 탐지만 수행한 이유는 현재 프로젝트에서 사람만 탐지 후 센서로부터 사람과의 거리를 측정하기 위해서다.
따라서, 컬러이미지로 먼저 사람에 대한 디텍션을 수행하고, 바운딩박스의 중심점을 가지고 뎁스 이미지 픽셀에 매핑하여 뎁스값을 가져오게 된다.
그 뎁스값은 센서로부터 사람까지의 거리가 된다.
이미지 기반으로 센서와 사람간의 거리를 구하고 싶다면 밑에 깃허브를 참고하자.
GitHub - hj-joo/Distance_from_human_with_depth_image: We calculate human distance from realsense depth camera with yolov8
We calculate human distance from realsense depth camera with yolov8 - GitHub - hj-joo/Distance_from_human_with_depth_image: We calculate human distance from realsense depth camera with yolov8
github.com