본문 바로가기

CV

리얼센스 카메라를 활용한 yolov8 기반 human detection

리얼센스 카메라를 이용하여 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()

사람 탐지만 수행한 이유는 현재 프로젝트에서 사람만 탐지 후 센서로부터 사람과의 거리를 측정하기 위해서다.

 

따라서, 컬러이미지로 먼저 사람에 대한 디텍션을 수행하고, 바운딩박스의 중심점을 가지고 뎁스 이미지 픽셀에 매핑하여 뎁스값을 가져오게 된다.

 

그 뎁스값은 센서로부터 사람까지의 거리가 된다.

 

이미지 기반으로 센서와 사람간의 거리를 구하고 싶다면 밑에 깃허브를 참고하자.

 

hj-joo/Distance_from_human_with_depth_image: We calculate human distance from realsense depth camera with yolov8 (github.com)

 

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