1. YOLO Camera 객체탐지
◇ 데이터 읽어들이기
○ 웹캠 신호 받기
- 어떤 카메라를 사용할지 채널 선택
- 여러개의 카메라가 있으면, 카메라 별로 번호가 부여된다
- 내 PC에 1개만 연결되어있다면, 0번 카메라 번호가 부여된다.
#웹캠 신호받기
VidioSignal = cv2.VideoCapture(0)
VidioSignal
< cv2.VideoCapture 0000019962AF2190>
◇ YOLO 모델 생성하기
YOLO_net = cv2.dnn.readNet('./yolo/config/yolov2-tiny.weights', './yolo/config/yolov2-tiny.cfg')
YOLO_net
< cv2.dnn.Net 000001996774F110>
◇ 라벨링 명칭 데이터 읽어들이기
with open('./yolo/config/coco.names', 'r') as f:
classes = [line.strip() for line in f.readlines()]
print(classes)
['person', 'bicycle', 'car', 'motorbike', 'aeroplane', 'bus', 'train', 'truck', 'boat', 'traffic light', 'fire hydrant', 'stop sign', 'parking meter', 'bench', 'bird', 'cat', 'dog', 'horse', 'sheep', 'cow', 'elephant', 'bear', 'zebra', 'giraffe', 'backpack', 'umbrella', 'handbag', 'tie', 'suitcase', 'frisbee', 'skis', 'snowboard', 'sports ball', 'kite', 'baseball bat', 'baseball glove', 'skateboard', 'surfboard', 'tennis racket', 'bottle', 'wine glass', 'cup', 'fork', 'knife', 'spoon', 'bowl', 'banana', 'apple', 'sandwich', 'orange', 'broccoli', 'carrot', 'hot dog', 'pizza', 'donut', 'cake', 'chair', 'sofa', 'pottedplant', 'bed', 'diningtable', 'toilet', 'tvmonitor', 'laptop', 'mouse', 'remote', 'keyboard', 'cell phone', 'microwave', 'oven', 'toaster', 'sink', 'refrigerator', 'book', 'clock', 'vase', 'scissors', 'teddy bear', 'hair drier', 'toothbrush']
◇ 출력 계층 이름 추출하기
# YOLO 레이어 전체 이름 추출
layer_names = YOLO_net.getLayerNames()
# YOLO 출력 계층만 이름 추출
output_layer = [layer_names[i-1] for i in YOLO_net.getUnconnectedOutLayers()]
output_layer
['detection_out']
◇ 윈도우 창 관리 영역 : 카메라 영상 처리 영역
- 윈도우 창 관리는 이름으로 한다.
- 카메라를 통한 영상처리시에는 윈도우 창을 계속 띄워놓아야한다
- 정지옵션(윈도우 창닫기) 필수
- 웹캠신호객체.read() : 카메라에서 영상 읽어들이기
- 영상파일 또는 카메라로부터 프레임을 읽어오는 역할 수행
* ret : 읽어들이는 프레임이 있는지 여부 판단(True or False)
: 더 이상 읽어들일 프레임이 없으면 False가 됨
* frame : 실제로 읽어들인 프레임(이미지) 자체
: 더 이상 읽어들일 프레임이 없으면 None이 됨
: 우리가 사용할 변수
- waitKey() : 괄호 안의 숫자 밀리초 만큼 기다린 후 사용자가 키보드의 키를 누르면
해당하는 키의 아스키값을 반환( 누른 키값이 없으면 -1 반환)
- 0xFF == ord('q') : 0xFF 는 키의 아스키값 얻기 위함 , ord('q') 는 'q'의 아스키 값 반환함
이 둘을 비교하여 같을때 조건 만족
- 윈도우 종료 후 재실행 안되는 경우가 발생할 수 있음
- 이때는 주피터가 실행된 프롬프트 창에서 ctrl + c 정지 후, 다시 주피터 실행하면됨
- 웹캠에 연결하여 frame 가져오는 것 외에 인식 데이터 처리 및 바운딩 박스 그리기는
Yolo image detection과 동일함
[ 전체 코드 ]
import cv2
import numpy as np
VidioSignal = cv2.VideoCapture(0)
Yolo_net = cv2.dnn.readNet('./yolo/config/yolov2-tiny.weights', './yolo/config/yolov2-tiny.cfg')
with open('./yolo/config/coco.names', 'r') as f:
classes = [line.strip() for line in f.readlines()]
layer_names = YOLO_net.getLayerNames()
output_layer = [layer_names[i-1] for i in YOLO_net.getUnconnectedOutLayers()]
cv2.namedWindow('YOLO3_CM_01')
while True:
# 카메라에서 영상 읽어들이기
ret, frame = VidioSignal.read()
# frame 정보에서 높이, 너비, 채널(흑백 또는 컬러)추출하기
h,w,c = frame.shape
# ---------------------
# Blob 데이터 구조화
blob = cv2.dnn.blobFromImage(
# 카메라에서 읽어들인 frame(이미지) 데이터
image = frame,
# 이미지 픽셀 값 정규화(스케일링)
scalefactor = 1/255.0,
# Yolo 모델이 사용할 크기로 조정
size=(416,416),
# BGR,RGB 선택
# - True 이면 OpenCV의 기본 BGR 색상 순서를 RGB로 변경
swapRB = True,
# 위에 size로 조정 후 어떻게 할지 결정
# - True : 잘라내기
# - False : size로 전체 조정하기
crop = False
)
# YOLO 입력 데이터로 넣어주기
YOLO_net.setInput(blob)
# YOLO 모델에 출력계층 이름을 알려주고 출력결과 받아오기
outs = YOLO_net.forward(output_layer)
# 라벨명칭 담을 리스트 변수
class_ids = []
# 정확도 담을 리스트 변수
confidences = []
# 바운딩 박스의 좌표를 담을 리스트 변수
boxes = []
# 출력 결과 여러개(인식된 객체 여러개)
for out in outs:
# 실제 객체 인식 데이터 처리
for detection in out:
# 인식 데이터의 인식률(정밀도)
scores = detection[5:]
# 인식률(정밀도)가 가장 높은 인덱스 위치 얻기 : 라벨의 위치값
class_id = np.argmax(scores)
# 인식률 값 추출하기 : class_id의 인덱스번호 위치값이 정밀도
confidence = scores[class_id]
# 정밀도가 50% 이상인 경우만 처리 : 기준은 자유롭게 정의
if confidence > 0.5:
# 중앙값의 좌표 비율에 실제 너비로 연산하여 중앙 x값 추출
center_x = int(detection[0] * w)
# 중앙값의 좌표 비율에 실제 높이로 연산하여 중앙 y값 추출
center_y = int(detection[1] * h)
# 바운딩 박스의 실제 너비와 높이 계산하기
dw = int(detection[2] * w)
dh = int(detection[3] * h)
# 바운딩 박스의 시작좌표(x,y)계산하기
x = int(center_x - dw / 2)
y = int(center_y - dh / 2)
boxes.append([x,y,dw,dh])
class_ids.append(class_id)
confidences.append(float(confidence))
# 중복된 바운딩 박스 제거하기
# - 정확도가 0.45보다 작으면 제거하기
indexes = cv2.dnn.NMSBoxes(boxes,confidences,0.45,0.4)
# 바운딩 박스 처리하기
for i in range (len(boxes)):
# 중복 제거 이후 남은 바운딩 박스의 정보만 이용
if i in indexes:
# 해당 객체에 대한 좌표값
x,y,w,h = boxes[i]
# 해당 객체에 대한 라벨값
label = str(classes[class_ids[i]])
# 해당 객체에 대한 정확도
score = confidences[i]
# 바운딩 박스 그리기
cv2.rectangle(frame,(x,y),(x+w,y+h),(0,0,255),5)
# 라벨, 정확도 이미지에 그리기
cv2.putText(
# 지금까지 그려진 frame 이미지
img = frame,
# 추가할 텍스트(문자열타입으로)
text = label,
# 텍스트 시작 위치 지정
org=(x,y-20),
# 텍스트 font 스타일
fontFace = cv2.FONT_ITALIC,
# font 크기
fontScale = 0.5,
# font 색상
color = (255,255,255),
# font 선굵기
thickness =1)
# 윈도우 창 open하기
cv2.imshow('YOLO3_CM_01',frame)
# 윈도우 창 크기 조절하기
cv2.resizeWindow('YOLO3_CM_01',650,500)
# 키보드에서 아무키 눌리면 while문 종료하기
if cv2.waitKey(100) > 0:
# 윈도우 무조건 종료
cv2.destroyAllWindows()
break
# 키보드에서 q 입력시 종료시키기
if cv2.waitKey(1) & 0xFF == ord('q'):
cv2.destroyAllWindows()
break
▶ 코드 실행하면 웹캠 창이 뜨게되며 사람, 책을 인식하여 바운딩박스와 라벨이름이
표시되는 것을 확인하였다.
2. YOLO Camera 객체탐지 이미지로 추출하기
인식된 객체 이미지로 저장
- 이미지 파일 저장시 파일명에 번호 붙이기
이미지로 저장
- 이미지 저장함수 imwrite() 함수 사용
import cv2
import numpy as np
VidioSignal = cv2.VideoCapture(0)
YOLO_net = cv2.dnn.readNet('./yolo/config/yolov2-tiny.weights', './yolo/config/yolov2-tiny.cfg')
with open('./yolo/config/coco.names', 'r') as f:
classes = [line.strip() for line in f.readlines()]
layer_names = YOLO_net.getLayerNames()
output_layer = [layer_names[i-1] for i in YOLO_net.getUnconnectedOutLayers()]
cv2.namedWindow('YOLO3_CM_01')
# -----------------------------
# 인식된 객체 이미지로 저장
img_cnt = 1
# -----------------------------
while True:
# 카메라에서 영상 읽어들이기
ret, frame = VidioSignal.read()
# frame 정보에서 높이, 너비, 채널(흑백 또는 컬러)추출하기
h,w,c = frame.shape
# ---------------------
# Blob 데이터 구조화
blob = cv2.dnn.blobFromImage(
# 카메라에서 읽어들인 frame(이미지) 데이터
image = frame,
# 이미지 픽셀 값 정규화(스케일링)
scalefactor = 1/255.0,
# Yolo 모델이 사용할 크기로 조정
size=(416,416),
# BGR,RGB 선택
# - True 이면 OpenCV의 기본 BGR 색상 순서를 RGB로 변경
swapRB = True,
# 위에 size로 조정 후 어떻게 할지 결정
# - True : 잘라내기
# - False : size로 전체 조정하기
crop = False
)
# YOLO 입력 데이터로 넣어주기
YOLO_net.setInput(blob)
# YOLO 모델에 출력계층 이름을 알려주고 출력결과 받아오기
outs = YOLO_net.forward(output_layer)
# 라벨명칭 담을 리스트 변수
class_ids = []
# 정확도 담을 리스트 변수
confidences = []
# 바운딩 박스의 좌표를 담을 리스트 변수
boxes = []
# 출력 결과 여러개(인식된 객체 여러개)
for out in outs:
# 실제 객체 인식 데이터 처리
for detection in out:
# 인식 데이터의 인식률(정밀도)
scores = detection[5:]
# 인식률(정밀도)가 가장 높은 인덱스 위치 얻기 : 라벨의 위치값
class_id = np.argmax(scores)
# 인식률 값 추출하기 : class_id의 인덱스번호 위치값이 정밀도
confidence = scores[class_id]
# 정밀도가 50% 이상인 경우만 처리 : 기준은 자유롭게 정의
if confidence > 0.5:
# 중앙값의 좌표 비율에 실제 너비로 연산하여 중앙 x값 추출
center_x = int(detection[0] * w)
# 중앙값의 좌표 비율에 실제 높이로 연산하여 중앙 y값 추출
center_y = int(detection[1] * h)
# 바운딩 박스의 실제 너비와 높이 계산하기
dw = int(detection[2] * w)
dh = int(detection[3] * h)
# 바운딩 박스의 시작좌표(x,y)계산하기
x = int(center_x - dw / 2)
y = int(center_y - dh / 2)
boxes.append([x,y,dw,dh])
class_ids.append(class_id)
confidences.append(float(confidence))
# 중복된 바운딩 박스 제거하기
# - 정확도가 0.45보다 작으면 제거하기
indexes = cv2.dnn.NMSBoxes(boxes,confidences,0.45,0.4)
# 바운딩 박스 처리하기
for i in range (len(boxes)):
# 중복 제거 이후 남은 바운딩 박스의 정보만 이용
if i in indexes:
# 해당 객체에 대한 좌표값
x,y,w,h = boxes[i]
# 해당 객체에 대한 라벨값
label = str(classes[class_ids[i]])
# 해당 객체에 대한 정확도
score = confidences[i]
# 바운딩 박스 그리기
cv2.rectangle(frame,(x,y),(x+w,y+h),(0,0,255),5)
# 라벨, 정확도 이미지에 그리기
cv2.putText(
# 지금까지 그려진 frame 이미지
img = frame,
# 추가할 텍스트(문자열타입으로)
text = label,
# 텍스트 시작 위치 지정
org=(x,y-20),
# 텍스트 font 스타일
fontFace = cv2.FONT_ITALIC,
# font 크기
fontScale = 0.5,
# font 색상
color = (255,255,255),
# font 선굵기
thickness =1)
# 윈도우 창 open하기
cv2.imshow('YOLO3_CM_01',frame)
# 윈도우 창 크기 조절하기
cv2.resizeWindow('YOLO3_CM_01',650,500)
# -----------------------------
# 이미지로 저장하기
print(f">>>>>> 정확도 평균 : {np.mean(confidences)}")
# 정확도 평균이 0.8 이상인 경우만 저장시키기
if np.mean(confidences)>=0.8:
# 이미지 저장함수 : imwrite() 함수 사용
cv2.imwrite(f"./yolo/images_new/img_{img_cnt}.jpg",frame)
# 파일 끝에 넣을 번호 1씩 증가
img_cnt +=1
# -----------------------------
# 키보드에서 아무키 눌리면 while문 종료하기
if cv2.waitKey(100) > 0:
# 윈도우 무조건 종료
cv2.destroyAllWindows()
break
# 키보드에서 q 입력시 종료시키기
if cv2.waitKey(1) & 0xFF == ord('q'):
cv2.destroyAllWindows()
break
3.이미지 증식 테스트
◇ 라이브러리
# 이미지 증식에 사용되는 라이브러리
from keras.preprocessing.image import ImageDataGenerator
# numpy 배열을 이미지로 변환하는 라이브러리
from keras.preprocessing.image import array_to_img
# 이미지를 numpy배열로 변환하는 라이브러리
from keras.preprocessing.image import img_to_array
# 이미지 읽어들이는 라이브러리
from keras.preprocessing.image import load_img
# 시각화
import matplotlib.pyplot as plt
◇ 이미지 증식 객체 생성하기
* 이미지 증식을 하는 이유
- 이미지를 이용하여 모델 훈련 시 데이터 확보가 어려운 경우 수행
- 기존 이미지 훈련모델의 성능이 낮은 경우에 데이터를 증가 시키고자 할 때 사용
- 이미지 증식은 하나의 원본 이미지의 형태를 랜덤하게 변형시켜서
많은 양의 이미지를 생성가능
- rescale : 이미지 데이터를 0과 1사이의 값으로 정규화
- rotation_range : 이미지 회전시키기, 0~ 90 사이로 랜덤하게 회전
- width_shift_range : 수평 이동시키기 , 0~1 사이의 비율에 따라 랜덤하게 이동
: 0.1 = 10% , 10%의 비율로 좌/우 랜덤하게 이동
- height_shift_range : 수직 이동 시키기
- shear_range : 이미지 형태 변환(반시계방향)
- zoom_range=[0.8,2.0] : 이미지 확대/축소 , 0.8~2.0 사이의 값으로 랜덤하게 확대/축소
- horizontal_flip=True : 수평방향으로 뒤집기 여부
- vertical_flip=True : 수직방향으로 뒤집기 여부
- fill_mode : 이미지 변형시 발생하는 빈 공간의 픽셀값 처리 방법 지정
- nearest : 가까운 곳의 픽셀값으로 채우기(기본값, 생략가능) , 주로 사용됨
- reflect : 빈공간만큼의 영역을 근처 공간의 반전된 픽셀값으로 채우기
- wrap : 빈공간을 이동하면서 잘려나간 이미지로 채우기
- constant : 빈공간을 검정 또는 흰색으로 채우기
imgGen = ImageDataGenerator(rescale=1./255,
rotation_range=15,
width_shift_range=0.1,
height_shift_range=0.1,
shear_range=0.5,
zoom_range=[0.8,2.0],
horizontal_flip=True,
vertical_flip=True,
fill_mode='nearest'
)
◇ 원본 이미지 불러오기
img = load_img('./yolo/new_img/penimg.jpg')
img
◇ 이미지를 데이터화 시키기
이미지를 array 배열 데이터로 변환하기
- 3차원 데이터로 반환됨
- ( 높이 , 너비 , 채널 )
img_array = img_to_array(img)
print(img_array.shape)
img_array
(400, 400, 3)
array([[[102., 105., 112.],
[103., 106., 113.],
[105., 108., 113.],
...,
○ 이미지 데이터 4차원으로 변환
# 이미지 증식을 위한 데이터는 4차원 데이터
img_array = img_array.reshape((1,)+img_array.shape)
img_array.shape
(1, 400, 400, 3)
◇ 이미지 증식하기
* imgGen.flow() : imgGen 객체를 이용해서 랜덤하게 만들어진 이미지를 저장시키는 함수
- save_to_dir : 저장할 폴더 위치
- save_to_prefix : 저장할 파일명에 사용할 이니셜
: 이니셜 뒤에 자동으로 이름이 부여된다
- save_formats : 저장할 파일의 포멧, 파일명 뒤에 확장자 정의
- i > cnt 외에
반복하면서 이미지를 보여주는 경우에는 show()를 사용해야한다
- 그렇지 않으면 1개의 이미지만 보이게 된다
- show() 이미지를 보여주고, 자원을 반환하는 역할도 같이 수행됨
- 자원이 반환되어 다음이미지를 plt를 통해서 사용가능
# 반복을 종료하기 위한 count 값으로 사용
i = 0
# 생성할 이미지 개수
cnt = 100
# 이미지를 반복해서 생성
for new_img in imgGen.flow(
img_array,
save_to_dir='./new_img/new',
save_prefix='train',
save_format='png'):
# 생성할 이미지 개수까지만 반복시키고 반복을 종료시키기
if i > cnt:
break
# 생성된 이미지 출력하기
# plt.imshow(new_img[0])
plt.imshow(new_img[0])
# x,y축 그래프 숨기기
plt.axis("off")
plt.show()
# 반복을 위한 count값 증가
i += 1
print(">>>>>>>>> 이미지 증식이 종료되었습니다 >>>>>>>>>")
▶ 증식된 이미지들이 잘 저장되어있는것을 확인할 수 있다
'머신러닝&딥러닝' 카테고리의 다른 글
[시계열분석] Prophet , Arima Model (1) | 2024.01.17 |
---|---|
사람이미지 증식 및 4차원 독립변수와 종속변수(라벨링) 생성하기 (0) | 2024.01.11 |
[딥러닝] YOLO 설치 및 객체 탐지 Image 사용 (0) | 2024.01.10 |
[머신러닝&딥러닝] 실습 - 에너지 사용 패턴 확인을 통한 부하 타입 분류 (1) | 2024.01.09 |
[딥러닝] 합성곱신경망(CNN)을 이용한 이미지 분류 (1) | 2024.01.08 |