안녕하세요!
오늘은 실시간으로 캡처된 이미지에 라벨을 달고 자세가 3번 연속 바뀌었을 때 데이터베이스에 수면이벤트가 저장되도록 해보겠습니다.
먼저 record.js에 함수를 추가해주겠습니다.
이전에 작성하지 않았던 captureAndUploadFrame 함수입니다.
// 이미지 업로드 함수
function captureAndUploadFrame() {
// HTML <canvas> 요소를 동적으로 생성합니다. 이 캔버스는 이미지를 그리기 위한 렌더링 대상이 됩니다.
const canvas = document.createElement("canvas");
// 캔버스 크기 설정
canvas.width = videoElement.videoWidth;
canvas.height = videoElement.videoHeight;
canvas
// 2D 그래픽 컨텍스트를 가져옵니다.
.getContext("2d")
// videoElement의 비디오 프레임을 캔버스에 그립니다.
.drawImage(videoElement, 0, 0, canvas.width, canvas.height);
// 캡처된 이미지를 Blob 형태로 변환
canvas.toBlob(function (blob) {
// Blob 데이터를 image(key)로 FormData에 추가
const formData = new FormData();
formData.append("image", blob, "captured_image.jpg");
console.log("formData : ", formData);
// FormData의 key 확인
for (let key of formData.keys()) {
console.log("key : ", key);
}
// FormData의 value 확인
for (let value of formData.values()) {
console.log("value : ", value);
}
// 서버로 이미지 데이터 전송 (fetch API 사용)
sendImageToServer(formData);
}, "image/jpg"); // jpg로 이미지 저장
}
바로 이어서 서버로 이미지 데이터를 전송해 주는 sendImageToServer 함수를 작성하겠습니다.
함수 안에 자세가 바뀌었을 때 조건문이 들어있습니다.
function sendImageToServer(formData) {
fetch("/record/return_posture", {
method: "POST",
body: formData,
})
.then(function (response) {
// 서버 응답이 JSON 형식일 경우
return response.json();
})
.then(function (data) {
console.log("서버에서 받은 데이터:", data);
var currentPosture = data;
console.log("현재 자세:", currentPosture);
console.log("이전 자세:", latestPosture);
// 이전 자세와 현재 자세를 비교하여 로직을 추가합니다.
if (latestPosture == null) {
// 최근 자세 정보 업데이트
latestPosture = currentPosture;
}
if (latestPosture !== null) {
if (latestPosture !== currentPosture) {
// 자세가 바뀌었을 때 처리할 코드
changedPostureCount++; // 자세 변경 횟수 증가
console.log("다른 횟수:", changedPostureCount);
if (changedPostureCount >= 3) {
// 자세가 3번 이상 변경되었을 때 처리할 코드
latestPosture = currentPosture;
changedPostureCount = 0;
callSavePostureApi(formData, data);
}
} else {
// 자세가 같을 때
changedPostureCount = 0; // 자세 변경 횟수 초기화
}
}
})
.catch(function (error) {
console.error("이미지 업로드 중 오류 발생:", error);
});
}
자세를 반환해 줄 함수를 api_record.py에 작성해 주겠습니다.
def process_image(image):
# 이미지를 캡처하고 저장합니다.
file_path = f"static/images/pose/{image.filename}"
with open(file_path, "wb") as image_file:
image_file.write(image.file.read())
# 캡처한 이미지를 읽습니다.
image = cv2.imread(file_path)
# 랜드마크를 감지합니다.
response = detect_pose(image, pose, display=False)
if response is not None:
landmarks_image, landmarks = response
frame_height, frame_width, _ = landmarks_image.shape
fps = 50
# 랜드마크를 기반으로 레이블을 분류합니다.
labeled_image, labels = classify_pose(landmarks, landmarks_image, fps, frame_height, frame_width, display=False)
# 배열을 문자열로 바꾸기
labels_str = ' '.join(labels)
# 라벨링 되기 전 이미지는 삭제합니다.
if os.path.exists(file_path):
os.remove(file_path)
return labels_str
@router.post("/record/return_posture")
async def upload_image(image: UploadFile):
# 이미지 처리 함수 호출
labels_str = process_image(image) # 라벨 문자열 반환
return labels_str
위 함수를 통해 자세 라벨을 서버로부터 넘겨받습니다.
자세가 3번 이상 변경되었을 때 불러올 callSavePostureApi 함수도 작성하겠습니다.
수면 이벤트를 저장하는 함수입니다.
// 이미지 저장 함수
function callSavePostureApi(imageData, data) {
const sleepInfoId = document.getElementById("sleep_info_id").value;
// FormData 객체를 생성합니다.
const formData = new FormData();
formData.append("sleep_info_id", sleepInfoId);
formData.append("data", data);
formData.append("image", imageData.get("image"), "captured_image.jpg");
console.log("sleep_info_id:", sleepInfoId);
console.log("data:", data);
console.log("imageData:", imageData.get("image"));
fetch("/record/event_save", {
method: "POST",
body: formData,
})
.then(function (response) {
if (response.ok) {
console.log("Image saved successfully.");
} else {
console.error("Error saving the image.");
}
})
.catch(function (error) {
console.error("Error saving the image:", error);
});
}
이미지 저장 하기 전 개인정보를 위해 얼굴 모자이크 하는 함수를 작성해서 호출합니다.
import cv2
import mediapipe as mp
# 미디어파이프 초기화
mp_face_detection = mp.solutions.face_detection
mp_drawing = mp.solutions.drawing_utils
face_detection = mp_face_detection.FaceDetection(min_detection_confidence=0.30)
def detect_face(image, factor=15):
# RGB 이미지로 변환
frame_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
# 얼굴 감지 수행
results = face_detection.process(frame_rgb)
if results.detections:
for detection in results.detections:
# 감지된 얼굴의 바운딩 박스 정보 가져오기
bboxC = detection.location_data.relative_bounding_box
ih, iw, _ = image.shape
x, y, w, h = int(bboxC.xmin * iw), int(bboxC.ymin * ih), int(bboxC.width * iw), int(bboxC.height * ih)
# 얼굴 주위에 픽셀화 적용
# 얼굴 영역 크기 조정
face_roi = image[y:y+h, x:x+w]
face_roi = cv2.resize(face_roi, (0, 0), fx=0.04, fy=0.04) # 얼굴 크기 축소
face_roi = cv2.resize(face_roi, (w, h), interpolation=cv2.INTER_NEAREST) # 원래 크기로 확대
image[y:y+h, x:x+w] = face_roi # 원본 이미지에 픽셀화된 얼굴 영역 적용
return image
수면이벤트를 저장할 때 형식과 사용할 쿼리도 작성해 줍니다.
shchemas.py
class SleepEventBase(BaseModel):
sleep_info_id: int
sleep_event: str
event_time: str
event_data_path: str
crud.py
def create_sleep_event(db: Session, sleep_event_data: schemas.SleepEventBase):
db_sleep_event = model.SleepEvent(
sleep_info_id=sleep_event_data.sleep_info_id,
sleep_event=sleep_event_data.sleep_event,
event_time=sleep_event_data.event_time,
event_data_path=sleep_event_data.event_data_path,
)
db.add(db_sleep_event)
db.commit()
db.refresh(db_sleep_event)
return db_sleep_event
이제 api_record.py에 /record/event_save를 post로 받는 함수를 작성하겠습니다.
@router.post("/record/event_save")
async def event_image_save(image: UploadFile, data: str = Form(...), sleep_info_id: int = Form(...), db: Session = Depends(get_db)):
# 현재 날짜와 시간 생성
current_date = datetime.now().strftime("%Y-%m-%d")
current_time = datetime.now().strftime("%H:%M:%S")
formatted_time = datetime.now().strftime("%H-%M-%S")
# 파일 저장 이름 정의
file_path = f"static/images/pose/{current_date}_{formatted_time}_{data}.jpg"
with open(file_path, "wb") as image_file:
image_file.write(image.file.read())
# 이미지 로드
image = cv2.imread(file_path)
# 얼굴 감지 및 픽셀화 처리 함수 호출
image = detect_face(image, factor=15)
# 픽셀화 처리한 이미지 저장
cv2.imwrite(file_path, image)
sleep_event_data = SleepEventBase(
sleep_info_id=sleep_info_id,
sleep_event=data,
event_time=current_time,
event_data_path=file_path
)
db_sleep_event = create_sleep_event(db, sleep_event_data)
return "Image saved successfully with pixelation"
이제 실제로 사용해 보면 자세가 3번 바뀌었을 때 모자이크된 이미지와 수면이벤트가 DB에 저장되는 것을 확인해 볼 수 있습니다.
'과정 > 2차 AI프로젝트 서비스 개발' 카테고리의 다른 글
프로젝트 '재움' 개발과정(5) (0) | 2023.11.07 |
---|---|
프로젝트 '재움' 개발과정(3) (0) | 2023.10.23 |
프로젝트 '재움' 개발과정(2) (0) | 2023.10.21 |
프로젝트 '재움' 개발과정(1) (1) | 2023.10.19 |
댓글