본문 바로가기
네이버 클라우드

[네이버 클라우드] CFR(CLOVA Face Recognition)

by 썬키 2023. 3. 31.
 

CLOVA Face Recognition(CFR) 개요

 

api.ncloud-docs.com

API에 대한 자세한 설명은 위의 링크에서 확인할 수 있습니다.

 

CFR이란?

 

CFR(CLOVA Face Recognition)얼굴 감지 및 인식 기능을 이용하여 관련 정보를 제공하는

네이버 클라우드 플랫폼의 서비스이다. 이미지 속 얼굴의 윤곽, 눈, 코, 입, 표정 값을 산출할 수 있는 API를 제공한다.

 

GOAL

 

ㆍ네이버 클라우드 플랫폼에서 지난번에 생성한 Application에 CFR service를 추가한다.

ㆍ클라이언트에서 인물 사진 업로드 후, 해당 인물과 가장 닮은 유명 인물을 출력할 수 있다.

ㆍ클라이언트에서 인물 사진 업로드 후, 해당 인물 얼굴의 윤곽과 이목구비, 표정 값을 얻을 수 있다.

 

 

1. 생성했던 Application에 CFR service 추가

 

지난 포스트에서 생성한 TEST Application에서 수정 클릭

 

CLOVA Face Recognition(CFR)에 체크 후, 저장

 

2. 웹 브라우저에서 인물 사진을 업로드하고, 해당 인물과 가장 유사한 유명 인물 정보 출력

 

 

클라이언트에 위와 같은 UI가 존재한다고 가정하자.

CFR Service를 이용해서 해당 인물과 가장 유사한 유명인의 정보를 출력할 수도 있고,

이미지 속 얼굴의 윤곽과 이목구비, 표정 값을 얻을 수도 있으므로 라디오 버튼을 이용해 선택할 수 있도록 했다.

 

ㆍFRONT-END 소스

 

import React, {useState} from 'react';
import axios from 'axios';

function App() {

  const [title, setTitle] = useState('');
  const [answer, setAnswer] = useState('');

  const submitBtn = (e) => {
    e.preventDefault();
    
    let formData = new FormData();
    formData.append("title", title);
    formData.append("uploadFile", document.frm.uploadFile.files[0]);

    axios.post("http://localhost:3000/cfr_fileUpload", formData)
    .then(function(res){
      alert('success');
      setAnswer(JSON.stringify(res.data));
    })
    .catch(function(error){
      alert(error);
    })

  }

  return (
    <div align="center">
      <br />
    <form name="frm" onSubmit={submitBtn} encType='multipart/form-data'>
      <input type="radio" name="title" onChange={(e)=>setTitle(e.target.value)} value="celebrity" />유명인 얼굴 인식
      <input type="radio" name="title" onChange={(e)=>setTitle(e.target.value)} value="face" />얼굴 감지
      <br />
      <input type="file" name="uploadFile" accept='*'/>
      <input type="submit" value="이미지 전송" />
    </form>
    {
      answer !== null && answer !== ''
      ?
      <div> 
      <h3>해석</h3>
      <p>업로드 한 파일의 인물 정보는 다음과 같습니다.</p>
      <p>{answer}</p>
      </div>
      : <p></p>
    }
    </div>
  );
}

export default App;

 

라디오 버튼의 값을 저장해서 서버로 넘겨줄 title이라는 state 변수와

서버에서 비동기로 받아올 결과값을 담을 answer라는 state 변수를 생성했다.

 

서버에서 넘겨주는 결과값의 타입은 JSON인데

해당 값을 answer 변수에 담기 위해서 JSON의 stringify 메소드를 사용했다.

 

ㆍBACK-END 소스(Controller)

 

@PostMapping("cfr_fileUpload")
	public String cfrFileUpload(@RequestParam("uploadFile")MultipartFile uploadFile, HttpServletRequest req, String title) {
		
		String uploadPath = req.getServletContext().getRealPath("/upload");
		String fileName = uploadFile.getOriginalFilename();
		String filePath = uploadPath + "/" + fileName;
		System.out.println(filePath);
		
		try {
			BufferedOutputStream os = new BufferedOutputStream(new FileOutputStream(new File(filePath)));
			os.write(uploadFile.getBytes());
			os.close();
		} catch (Exception e) {
			e.printStackTrace();
			return "fail";
		}
		
		String resp = NaverCloud.cfr(filePath, title);
		return resp;
	}

 

클라이언트에서 파일을 넘겨주기 때문에, MultipartFile 타입의 uploadFile을 매개변수로 가지고

라디오 버튼의 값 또한 넘겨주므로 String 타입의 title을 매개변수로 가진 cfrFileUpload 메소드를 생성했다.

 

클라이언트로부터 전달받은 파일을 서버에 저장하고, 해당 파일이 존재하는 경로와 title을 매개변수로 가지는

NaverCloud 클래스의 static 메소드인 cfr 메소드에서 결과값을 받아오면 된다.

 

ㆍBACK-END 소스(static 메소드)

 

public static String cfr(String filePath, String title) {
		StringBuffer reqStr = new StringBuffer();
        String clientId = "Application Client ID";             // Application Client ID";
        String clientSecret = "Application Client Secret";";     // Application Client Secret";
        StringBuffer response = null;

        try {
            String paramName = "image"; // 파라미터명은 image로 지정
            String imgFile = filePath;
            File uploadFile = new File(imgFile);
            
            String apiURL = "";
            if(title.equals("celebrity")) {
            	apiURL = "https://naveropenapi.apigw.ntruss.com/vision/v1/celebrity"; // 유명인 얼굴 인식
            } else {
            	apiURL = "https://naveropenapi.apigw.ntruss.com/vision/v1/face"; // 유명인 얼굴 인식
            }
            
            URL url = new URL(apiURL);
            HttpURLConnection con = (HttpURLConnection)url.openConnection();
            con.setUseCaches(false);
            con.setDoOutput(true);
            con.setDoInput(true);
            // multipart request
            String boundary = "---" + System.currentTimeMillis() + "---";
            con.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
            con.setRequestProperty("X-NCP-APIGW-API-KEY-ID", clientId);
            con.setRequestProperty("X-NCP-APIGW-API-KEY", clientSecret);
            OutputStream outputStream = con.getOutputStream();
            PrintWriter writer = new PrintWriter(new OutputStreamWriter(outputStream, "UTF-8"), true);
            String LINE_FEED = "\r\n";
            // file 추가
            String fileName = uploadFile.getName();
            writer.append("--" + boundary).append(LINE_FEED);
            writer.append("Content-Disposition: form-data; name=\"" + paramName + "\"; filename=\"" + fileName + "\"").append(LINE_FEED);
            writer.append("Content-Type: "  + URLConnection.guessContentTypeFromName(fileName)).append(LINE_FEED);
            writer.append(LINE_FEED);
            writer.flush();
            FileInputStream inputStream = new FileInputStream(uploadFile);
            byte[] buffer = new byte[4096];
            int bytesRead = -1;
            while ((bytesRead = inputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, bytesRead);
            }
            outputStream.flush();
            inputStream.close();
            writer.append(LINE_FEED).flush();
            writer.append("--" + boundary + "--").append(LINE_FEED);
            writer.close();
            BufferedReader br = null;
            int responseCode = con.getResponseCode();
            if(responseCode==200) { // 정상 호출
                br = new BufferedReader(new InputStreamReader(con.getInputStream()));
            } else {  // 오류 발생
                System.out.println("error!!!!!!! responseCode= " + responseCode);
                br = new BufferedReader(new InputStreamReader(con.getInputStream()));
            }
            String inputLine;
            if(br != null) {
            	response = new StringBuffer();
                while ((inputLine = br.readLine()) != null) {
                    response.append(inputLine);
                }
                br.close();
                System.out.println(response.toString());
            } else {
                System.out.println("error !!!");
            }
        } catch (Exception e) {
            System.out.println(e);
        }
        return response.toString();
	}

 

clientIdclientSecret에 발급 받았던 값들을 입력한다.

 

매개변수의 title 값이 "celebrity" 일 때는, 이미지 속 인물과 가장 유사한 유명 인물을 출력하는 API를 호출하고

그게 아닐 때에는 이미지 속 인물의 얼굴 윤곽, 이목구비, 표정 값을 출력하는 API를 호출하는 메소드이다.

 

 

필자는 유재석의 이미지를 업로드 해보았는데 다음과 같이 인물 정보가 출력되는 것을 확인할 수 있다.

 

출처 : 네이버 클라우드 플랫폼

 

서버에서 던져주는 응답값의 필드에 대한 설명은 위와 같다.

 

3. 웹 브라우저에서 인물 사진을 업로드하고, 해당 인물의 윤곽, 이목구비, 표정값 출력

 

 

얼굴 감지 API 또한 유재석의 사진을 이용해봤는데 위와 같은 JSON 데이터를 출력할 수 있다.

가독성이 떨어지므로, prettier를 이용해서 정렬을 해보면 다음과 같다.

 

{
  "info": {
    "size": {
      "width": 220,
      "height": 307
    },
    "faceCount": 1
  },
  "faces": [
    {
      "roi": {
        "x": 55,
        "y": 63,
        "width": 79,
        "height": 79
      },
      "landmark": {
        "leftEye": {
          "x": 74,
          "y": 82
        },
        "rightEye": {
          "x": 106,
          "y": 78
        },
        "nose": {
          "x": 84,
          "y": 103
        },
        "leftMouth": {
          "x": 76,
          "y": 122
        },
        "rightMouth": {
          "x": 108,
          "y": 118
        }
      },
      "gender": {
        "value": "male",
        "confidence": 0.997746
      },
      "age": {
        "value": "35~39",
        "confidence": 0.149178
      },
      "emotion": {
        "value": "neutral",
        "confidence": 0.554271
      },
      "pose": {
        "value": "frontal_face",
        "confidence": 0.691971
      }
    }
  ]
}

 

출처 - 네이버 클라우드 플랫폼

 

이 API의 응답 값은 위와 같다고 한다.

 

마치며

 

한 때, 이런 애플리케이션이 유행했던 적이 있었는데 이런식으로 만들어졌겠구나..! 하고 신기해했다.

댓글