AnalysisPose.js 4.36 KB
//두 좌표 사이의 거리를 반환하는 함수
function distance(x1, y1, x2, y2) {
    var x = Math.abs(x1 - x2);
    var y = Math.abs(y1 - y2);
    var result = Math.hypot(x, y);
    return result;
}

//두 길이의 차이를 %비로 반환하는 함수
function difference(d1, d2) {
    if (d1 > d2) {
        return (1 - (d2 / d1)) * 100;
    } else if (d1 < d2) {
        return (1 - (d1 / d2)) * 100;
    } else if (d1 === d2) {
        return 0;
    }
}

//객체와 방향정보를 받아 자세정보를 반환하는 함수
const checkStraight = (resData, position) => { //resData: API로 받은 JSON 객체, position: 사진의 방향정보
    var trust_value = []; //17개의 신체부위 좌표에 대한 신뢰도를 저장할 배열
    var x_position = []; //17개의 신체부위의 X좌표값을 저장할 배열
    var y_position = []; //17개의 신체부위의 Y좌표값을 저장할 배열
    const neck_maximum_angle = (180 * 30) / Math.PI; //어깨-귀 각도가 30도 이상일 경우 > 거북목
    const back_minimum_angle = (180 * 70) / Math.PI; //엉덩이-어깨 각도가 70도 이하일 경우 > 굽은등
    let ear = 3;
    let shoulder = 5;
    let hip = 11;
    for (let i = 0; i < 49; i += 3) {
        x_position.push(resData[i]);
        y_position.push(resData[i + 1]);
        trust_value.push(resData[i + 2]);
    }
    if (position === 'front') { //정면 사진일 경우
        //사용할 데이터의 신뢰도가 0.4 미만이면 실행하지 않음
        if (trust_value[ear] < 0.4) {
            return 'error_low_trust_value (keypoint:left_ear:4)'
        }
        if (trust_value[ear + 1] < 0.4) {
            return 'error_low_trust_value (keypoint:right_ear:5)'
        }
        if (trust_value[shoulder] < 0.4) {
            return 'error_low_trust_value (keypoint:left_shoulder:6)'
        }
        if (trust_value[shoulder + 1] < 0.4) {
            return 'error_low_trust_value (keypoint:right_shoulder_7)'
        }

        //왼쪽귀(4)-왼쪽어깨(6) 거리와 오른쪽귀(5)-오른쪽어깨(7) 거리가 30% 이상 차이날 경우 > 좌우편향
        var d_left = distance(x_position[ear], y_position[ear], x_position[shoulder], y_position[shoulder]);
        var d_right = distance(x_position[ear + 1], y_position[ear + 1], x_position[shoulder + 1], y_position[shoulder + 1]);
        var gap = difference(d_left, d_right);

        if (gap >= 15) { //기운 각도가 15도를 넘을 경우
            if (d_left > d_right) { //오른쪽으로 기울인 경우
                return 'leaning right by ' + gap + 'percent.';
            } else if (d_left < d_right) { //왼쪽으로 기울인 경우
                return 'leaning left by ' + gap + 'percent.';
            }
        } else { //기운 각도가 15도 미만인 경우
            return 'okay';
        }


    }
    else {
        if (position === 'right') {
            ear++;
            shoulder++;
            hip++;
        }
        if (trust_value[hip] < 0.4) { //사용할 데이터의 신뢰도가 0.4 미만이면 실행하지 않음
            return `error_low_trust_value (keypoint:${position}hip)`;
        }
        if (trust_value[shoulder] < 0.4) {
            return `error_low_trust_value (keypoint:${position}shoulder)`;
        }
        if (trust_value[ear] < 0.4) {
            return `error_low_trust_value (keypoint:${position}ear)`;
        }
        //엉덩이(12)-어깨(6) 각도가 70도 이하일 경우 > 굽은등

        var back_d1 = Math.abs(x_position[hip] - x_position[shoulder]);
        var back_d2 = Math.abs(y_position[hip] - y_position[shoulder]);
        var back_angle = Math.atan(back_d2 / back_d1);
        var back_angle_rad = (180 * back_angle) / Math.PI; //라디안 > 육십분법 변환
        if (back_angle_rad <= back_minimum_angle) {
            return 'bent_back';
        }
        //어깨(6)-귀(4) 각도가 30도 이상일 경우 > 거북목
        var neck_d1 = Math.abs(y_position[ear] - y_position[shoulder]);
        var neck_d2 = Math.abs(x_position[ear] - x_position[shoulder]);
        var neck_angle = Math.atan(neck_d2 / neck_d1);
        var neck_angle_rad = (180 * neck_angle) / Math.PI; //라디안 > 육십분법 변환
        if (neck_angle_rad >= neck_maximum_angle) {
            return 'bent_neck';
        }
        //굽은등, 거북목 모두 없을 경우
        return 'okay';
    }
}

export default checkStraight;