본문 바로가기
멀티캠퍼스 풀스택 과정/AI

[CFR(Face Recognition)] 얼굴인식 구현하기

by 이쟝 2022. 4. 6.

https://www.ncloud.com/ 에 접속해 로그인 후(메뉴 > 서비스 > 구현할 서비스 선택 후 이용 신청)

 

메뉴 > 서비스 > AI Service CLOVA Face Recognition > 사용가이드 > CFR API v1 바로가기(API 가이드로) > 왼쪽 메뉴 탭에서 face(얼굴 감지) > API 예제에서 Java 복사하기

 

1. CLOVA_api 프로젝트 생성(springboot, gradle로)

2. home.jsp 생성

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="EUC-KR">
<title>home.jsp</title>
</head>
<body>
	<h1>Ai Service API</h1>
	<ol>
		<li><a href="/cfrform">CFRecognition:얼굴감지</a></li>
	</ol>
</body>
</html>

3. Home에서 CFRecognition으로 넘어갈 폼 생성(/cfrfrom): clova_cfr_recognition.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="EUC-KR">
<title>clova_cfr_recognition.jsp</title>
<!-- CFRecognition
입력받은 이미지로부터 얼굴을 감지하고 입력된 이미지에서 얼마나 많은 얼굴이 감지되었고 각 얼굴이
어디에 어떤 크기로 위치하며 어떤 모습을 하고 있는지 반환 -->
<script>

</script>
</head>
<body>
<form method="post" id="uploadForm" enctype="multipart/form-data" >
	이미지 선택 : <input type="file" id="image" name="image"/><br/>
	<button>확인</button>
</form><br/>
<textarea id="text" rows="10" cols="100"></textarea>
</body>
</html>
파일 업로드를 하기위해서 form의 enctype = multipart/form-data로 작성해야하고, method = post로 한다.
-> 이렇게 해야 MultipartResolver가 multipartFile객체를 컨트롤러에 전달할 수 있다.

4. Controller패키지를 만든 뒤 Controller 클래스 생성(Clova_CFR_recognition.java)

package com.campus.myapp.controller;

@Controller
public class Clova_CFR_recognition {
	
	@GetMapping("/cfrform")
	public String cfrForm() {
		return "clova_cfr_recognition";
	}
	
	@PostMapping("cfr")
	@ResponseBody 
	public void cfr_recognition() {

	}
}

5. 만들어둔 Controller 클래스에 홈페이지에서 java 코드 복사해 온 것을 붙여넣기

package com.campus.myapp.controller;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class Clova_CFR_recognition {
	
	@GetMapping("/cfrform")
	public String cfrForm() {
		return "clova_cfr_recognition";
	}
	
	@PostMapping("cfr")
	@ResponseBody 
	public void cfr_recognition() {
		    StringBuffer reqStr = new StringBuffer();
	        String clientId = "YOUR_CLIENT_ID";//애플리케이션 클라이언트 아이디값";
	        String clientSecret = "YOUR_CLIENT_SECRET";//애플리케이션 클라이언트 시크릿값";

	        try {
	            String paramName = "image"; // 파라미터명은 image로 지정
	            String imgFile = "이미지 파일 경로 ";
	            File uploadFile = new File(imgFile);
	            String 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) {
	                StringBuffer 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);
	        }
	    }
	}


6. Ajax로 이미지 파일 보내기

clova_cfr_recognition.jsp

1) Ajax를 사용하기 위해서 jquery 홈페이지에서 cdn 복사한다. 

2) 파일을 선택하지 않았을 때와 선택했을 때(Ajax로 데이터 보내기)

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>

<script>
	$(function(){
	
           // 파일을 선택하지 않았을 때
		$("#uploadForm").submit(function(){
			event.preventDefault(); // submit이 발생해서 action으로 가면 안되서 기본이벤트 제거
			
			const image = $("#image")[0];
			if(image.files.length===0){ // 데이터타입과 데이터가 같을 때(===), 데이터 타입만 같을 때는(==)
				alert("파일을 선택해주세요");
				return;
			}
			
			// 선택한 파일이 있는 경우
			let url = "http://localhost:8050/cfr";
                       // form 데이터가 객체로, form이 한 개 밖에 없어서 [0]
			let data = new FormData($("#uploadForm")[0]); 
            
			$.ajax({
				type:"post",
				dataType:"text",
				url: url, // PostMapping("/cfr")
				processData:false,
				contentType:false,
				data: data,
				success:function(data, textStatus){
                	// 콘솔에도 찍히는 지 확인
					console.log('textStatus : ', textStatus);
					$("#text").val(data); 
				},error:function(){
					console.log("fail");
				}
			});
		});
	});
</script>
</head>
<body>
<form method="post" id="uploadForm" enctype="multipart/form-data" >
	이미지 선택 : <input type="file" id="image" name="image"/><br/>
	<button>확인</button>
</form><br/>
<textarea id="text" rows="10" cols="100"></textarea>
</body>
</html>

7. 파일 업로드하는 기능을 구현하기(파일 업로드하는 클래스 생성)

1) ClovaFileUpload 클래스 생성(파일의 경로와 파일 이름(객체)을 매개변수로 받아서 구해야 한다.)

package com.campus.myapp.controller;

import java.io.File;

import org.springframework.web.multipart.MultipartFile;

public class ClovaFileUpload { // 파일 업로드 하는 기능 구현
	
	public static String fileUpload(String path, MultipartFile f) { // 파일의 경로와 파일
		String org = f.getOriginalFilename();
		try {
			f.transferTo(new File(path, org));
		}catch(Exception e) {
			
		}
		return org; 
	}
}
transferTo(File dest) : 업로드한 파일 데이터를 지정한 파일에 저장한다.

8. 위에서 만든 controller 수정하기

1. 애플리케이션 클라이언트 아이디값과 시크릿값 가져오기

(홈페이지 > 콘솔 > Products&Services(처음인 경우) > AI-NAVER-API(클릭) > Recently Viewed에 AI-NAVER API > Application > App 이름에서 인증정보 클릭 > Client ID와 Client Secret값을 복사해서 코드에 붙여놓기)

package com.campus.myapp.controller;

@Controller
public class Clova_CFR_recognition {
	
	@GetMapping("/cfrform")
	public String cfrForm() {
		return "clova_cfr_recognition";
	}
	
	@PostMapping("cfr")
	@ResponseBody 
	public void cfr_recognition() {
		    StringBuffer reqStr = new StringBuffer();
	        String clientId = "애플리케이션 클라이언트 아이디값";
	        String clientSecret = "애플리케이션 클라이언트 시크릿값";
	}

2. 파일 업로드할 코드 작성하기

1) @RequestParam 어노테이션과 MultipartFile 타입의 파라미터를 이용해서 업로드 파일 데이터를 전달받고, 절대주소를 구하기 위해서 session을 파라미터로 받는다.

(@RequestParam의 image는 jsp파일에서의 input 파일에서의 name)

package com.campus.myapp.controller;

@Controller
public class Clova_CFR_recognition {
	
	@GetMapping("/cfrform")
	public String cfrForm() {
		return "clova_cfr_recognition";
	}
	
	@PostMapping("cfr")
	@ResponseBody 
	public void cfr_recognition(@ReqeustParam("image") MultipartFile file, HttpSession session) {
		    StringBuffer reqStr = new StringBuffer();
	        String clientId = "애플리케이션 클라이언트 아이디값";
	        String clientSecret = "애플리케이션 클라이언트 시크릿값";
	}

2) 파일을 업로드할 경로와 파일이름을 적는다. 

package com.campus.myapp.controller;

@Controller
public class Clova_CFR_recognition {
	
	@GetMapping("/cfrform")
	public String cfrForm() {
		return "clova_cfr_recognition";
	}
	
	@PostMapping("cfr")
	@ResponseBody 
	public void cfr_recognition(@ReqeustParam("image") MultipartFile file, HttpSession session) {
	    StringBuffer reqStr = new StringBuffer();
	    String clientId = "애플리케이션 클라이언트 아이디값";
	    String clientSecret = "애플리케이션 클라이언트 시크릿값";
            String path = session.getServletContext().getRealPath("/file"); // 업로드할 곳
            String filename = null;
            
            try{
            	//업로드 실행(메서드)
            filename = ClovaFileUpload.fileUpload(path, file); 
            
            String paramName = "image"; // 파라미터명은 image로 지정
            String imgFile = path + "/" + filename; // 이미지 파일에 대한 경로
	}

3) fileUpload()에서 넘어온 데이터는 response 객체 안에 있다.

- 지역변수에 있던것을 전역변수로 변경하고(return값으로 주기 위해서)

- return값을 toString()으로 하기 위해서 return 타입을 void -> String으로 변경

package com.campus.myapp.controller;

@Controller
public class Clova_CFR_recognition {
	
	@PostMapping("/cfr")
	@ResponseBody 
	public String cfr_recognition(@RequestParam("image") MultipartFile file, HttpSession session) { // 이미지이니까 MultipartFile 객체로, 절대주소를 구하기 위해 session
	    StringBuffer reqStr = new StringBuffer();
	    String clientId = "애플리케이션 클라이언트 아이디값";
	    String clientSecret = "애플리케이션 클라이언트 시크릿값";
            String path = session.getServletContext().getRealPath("/file"); // 업로드할 곳
            String filename = null;
            
            try{
            	//업로드 실행(메서드)
            filename = ClovaFileUpload.fileUpload(path, file); 
            
            String paramName = "image"; // 파라미터명은 image로 지정
            String imgFile = path + "/" + filename; // 이미지 파일에 대한 경로
	        	
	            String paramName = "image"; // 파라미터명은 image로 지정
	            String imgFile = path+"/"+filename; // 이미지 파일에 대한 경로
	            File uploadFile = new File(imgFile);
	            String 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) {
	            	//StringBuffer response = new StringBuffer(); // response를 전역변수로!
	            	while ((inputLine = br.readLine()) != null) {
	                    response.append(inputLine);
	                }
	                br.close();
	                System.out.println(response.toString()); // 서버에서 넘어온 데이터가 response 객체 안에 
	            } 
	        } catch (Exception e) {
	            System.out.println(e);
	        }
        return response.toString();
    }
}

 파일 실행