임도현의 성장
OpenCV 얼굴인식(Face Detection) 사용해보기 본문

📻OpenCV 란?
Open Source Computer Vision의 약자로 영상 처리에 사용할 수 있는 오픈 소스 라이브러리입니다. OpenCV는 이미지와 비디오 처리, 물체 추적, 얼굴 인식, 패턴 인식 등 다양한 컴퓨터 비전 기술을 구현하는 데 필요한 강력한 도구들을 제공합니다. OpenCV는 C++로 개발되었으며, Python, Java, 그리고 여러 다른 언어 바인딩을 통해 다양한 플랫폼에서 사용할 수 있습니다.
😰 컴퓨터 비전이란?
컴퓨터 비전(Computer Vision, CV)은 인간의 시각적 능력을 모방하여 이미지를 분석하고 해석하며, 이를 바탕으로 "의사 결정을 내리는 인공지능(AI) 기술입니다." 컴퓨터 비전을 활용하면 이미지, 패턴, 객체를 감지하고 인식할 수 있습니다. 이 기술은 자율주행차, 의료 영상 분석, 온라인 쇼핑 등 다양한 분야에서 핵심적인 역할을 수행하고 있습니다.
📚얼굴 인식을 어떻게 할까?
OpenCV가 이미지만 보고 얼굴을 인식하는 원리는 "머신 러닝"과 "패턴 인식" 기술을 기반으로 합니다. 가장 일반적으로 사용되는 얼굴 인식 방법은 Haar Cascade Classifier입니다.
🍪Haar Cascade Classifier란?
Haar Cascade Classifier는 Haar 특징(Haar Features)와 기계 학습 알고리즘을 활용한 얼굴 검출 알고리즘입니다.
- Haar 특징(Haar Features) : Haar 특징은 기본적으로 이미지 내에서 특정 부분의 명도 차이를 나타내는 특징입니다. 이 특징들은 주로 사각형 형태로 나누어지고, 각 사각형의 밝기 차이를 비교하여 이미지의 패턴을 인식합니다.
- Cascade Classifier : 이미지에서 큰 특징을 찾고, 이후 단계에서 점점 더 작은 특징을 찾아가며 얼굴을 정확히 인식합니다.
즉 Haar Cascade Classifier는모델 이 수많은 얼굴을 학습하여 빠르게 얼굴의 특징, 눈, 코, 입의 배치 및 밝기 차이 등을 찾아 얼굴을 인식 할 수 있는것입니다.
👨💻IntelliJ 라이브러리 등록
build.gradle에 OpenCV를 버전에 맞게 추가해주고 OpenCV는 native library로 dll 파일을 연결해주어야 합니다. 저 같은 경우에는 ddl 파일을 libs/native/ 경로에 저장을 하고 VM Option에 네이티브 라이브러리 경로 설정을 하였습니다.
implementation 'org.openpnp:opencv:4.5.5-1'

🌐OpenCV 샘플 확인
https://github.com/opencv/opencv/blob/4.x/samples/java/eclipse/HelloCV/src/Main.java
OpenCV 설치를 하고 깃허브에서 샘플을 찾아 실행 보면 응답 값을 확인 할 수 있다. native library로 dll 파일을 연결해두지 않았으면 loadLibrary가 파일을 찾지 못해 에러가 난다.
public class Main {
public static void main(String[] args) {
System.out.println("Welcome to OpenCV " + Core.VERSION);
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
Mat m = Mat.eye(3, 3, CvType.CV_8UC1);
System.out.println("m = " + m.dump());
}
}
결과 값 :
Welcome to OpenCV 4.5.5
m = [ 1, 0, 0;
0, 1, 0;
0, 0, 1]
🚨예제 코드
face detection을 java로 사용하는 코드는 아래 사이트를 참고 하였다.
https://www.tutorialspoint.com/opencv/opencv_face_detection_in_picture.htm
💫Controller Layer
클라이언트가 file이라는 이름으로 보낸 이미지를 MultipartFile 객체로 받아 faceDetectionService. detectFaces() 메서드 함수에 전달하여 OpenCV를 활용하여 얼굴을 찾아서 처리된 이미지를 반환 받아 응답하는 데이터가 PNG이미지임을 명시합니다.
@PostMapping("/face")
public ResponseEntity<byte[]> facesDetect(@RequestParam("file") MultipartFile file) {
try {
byte[] processedImage = faceDetectionService.detectFaces(file);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.IMAGE_PNG);
return new ResponseEntity<>(processedImage, headers, HttpStatus.OK);
} catch (IOException e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(null);
}
}
📜Service Layer
이미지를 디스크에 저정하지 않고 메모리에서 직접 처리 할 수 있도록 하기 위해 byte[] 형식으로 변환 즉, 파일을 저장하는 추가적인 과정 없이 바로 클라이언트에 응답 할 수 있도록 하기 위함입니다.
public byte[] detectFaces(MultipartFile file) throws IOException {
Mat image = Imgcodecs.imdecode(new MatOfByte(file.getBytes()), Imgcodecs.IMREAD_COLOR);
Mat processedImage = faceDetectionProcessor.detectFaces(image);
MatOfByte buffer = new MatOfByte();
Imgcodecs.imencode(".png", processedImage, buffer);
return buffer.toArray();
}
- file.getBytes() : 이미지 파일을 byte[]로 변환
- new MatOfByte(file.getBytes()) : OpenCV에서 사용할 수 있도록 byte[] 을 MatOfByte 객체로 래핑
- Imgcodecs.imdecode() : 바이트 데이터를 OpenCV Mat 객체로 변환 Imgcodecs.IMREAD_COLOR: 컬러 이미지로 로드
Mat image = Imgcodecs.imdecode(new MatOfByte(file.getBytes()), Imgcodecs.IMREAD_COLOR);
Mat processedImage = faceDetectionProcessor.detectFaces(image);
- MatOfByte buffer : 이미지를 바이트 배열로 변환하기 위한 OpenCV 객체
- Imgcodecs.imencode(".png", processedImage, buffer) : Mat 객체를 PNG 파일 형식으로 변환 변환된 데이터는 buffer에 저장
- buffer.toArray() : MatOfByte 객체를 byte[] 형태로 변환하여 반환 즉, 얼굴을 검출한 후 처리된 이미지를 PNG 형식의 바이트 배열로 반환하는 역할
MatOfByte buffer = new MatOfByte();
Imgcodecs.imencode(".png", processedImage, buffer);
return buffer.toArray();
🛠OpenCVUtil Layer
init()은 native library가 잘 등록 되어있는지 확인 하는 메서드입니다.
loadCascade()는 LBP Cascade XML파일을 로드 하는 메서드입니다다. cascadePath는 Haar Cascade XML 파일 또는 LBP Cascade XML 파일을 저장하여 파일 경로를 읽도록합니다. 저는 깃허브에서 LBP 형식을 사용하였습니다.
@Slf4j
@Component
public class OpenCVUtil implements FaceDetectionProcessor{
private CascadeClassifier faceCascade;
@PostConstruct
public void init() {
try {
log.info("=================== OpenCV 라이브러리 로드 시작 ===================");
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
log.info("=================== OpenCV 라이브러리 로드 성공 = {} ============", Core.VERSION);
} catch (UnsatisfiedLinkError e) {
throw new RuntimeException("OpenCV 라이브러리를 로드할 수 없습니다. 환경 변수를 확인하세요.", e);
}
}
@PostConstruct
public void loadCascade() {
try {
String cascadePath = "C:/Class/MyOpencv/src/main/java/com/opencv/global/LbpCascade.xml";
faceCascade = new CascadeClassifier(cascadePath);
if (faceCascade.empty()) {
throw new IOException("LBP Cascade 파일을 로드할 수 없습니다.");
}
} catch (IOException e) {
throw new RuntimeException("Error loading LBP Cascade file", e);
}
}
@Override
public Mat detectFaces(Mat image) {
Mat grayImage = new Mat();
Imgproc.cvtColor(image, grayImage, Imgproc.COLOR_BGR2GRAY);
MatOfRect faces = new MatOfRect();
faceCascade.detectMultiScale(grayImage, faces, 1.1, 3, 0, new Size(30, 30), new Size());
log.info("찾은 얼굴 수 = {}",faces.toArray().length);
for (Rect face : faces.toArray()) {
Imgproc.rectangle(image, face.tl(), face.br(), new Scalar(0, 0, 255), 2);
}
return image;
}
}
📈detectFaces 메서드 상세 설명
- Mat grayImage : OpenCV에서는 얼굴 검출을 할 때 흑백 이미지가 성능이 더 좋기 때문에 그레이스케일 변환된 이미지를 저장할 Mat객체 생성
- Imgproc.cvtColor() : 컬러 이미지를 그레이스케일(흑백)로 변환하는 OpenCV 메서드입니다.
- MatOfRect faces : 검출된 얼굴 영역들을 저장하는 OpenCV 객체, 여러 개의 얼굴을 검출할 수 있으므로 배열 형태로 저장
- faceCascade.detectMultiScale() : 얼굴을 검출하는 OpenCV의 주요 메서드입니다. faceCascade는 CascadeClassifier 객체로, LBP 또는 Haar Cascade 알고리즘을 사용해 얼굴을 찾습니다.
- grayImage: 그레이스케일 변환된 이미지를 사용 (컬러보다 정확도가 높음)
- faces: 얼굴이 감지된 위치를 저장할 객체 (MatOfRect)
- 1.1: 이미지 스케일 팩터 (1.1배씩 이미지 크기를 줄여가면서 얼굴을 찾음)
- 3: 최소 이웃 수 (이 값이 클수록 더 정확한 얼굴만 검출, 작은 값이면 오탐 가능성 증가)
- 0: 추가적인 옵션 플래그 (일반적으로 0을 사용)
- new Size(30, 30): 최소 얼굴 크기 (너무 작은 얼굴은 무시함, 적절하게 조절)
- new Size(): 최대 얼굴 크기 (비워두면 제한 없음)
- for (Rect face : faces.toArray()) : 감지된 얼굴들의 리스트를 배열로 변환 한 후 Rect face에 사각형 좌표 정보를 저장 (x, y, width, height) 형식으로 얼굴의 위치를 나타냄]
- Imgproc.rectangle() : 검출된 얼굴 위치에 사각형을 그리는 메서드
- image: 얼굴을 감지한 원본 이미지 (사각형을 이 이미지에 그림)
- face.tl(): 사각형의 좌상단(top-left) 좌표
- face.br(): 사각형의 우하단(bottom-right) 좌표
- new Scalar(0, 0, 255): 빨간색(RED) 사각형 (BGR 형식으로 0,0,255는 빨간색)
- 2: 사각형의 두께(픽셀 단위)
🥳얼굴 인식 과정
- 이미지 전처리 (그레이스케일 변환)
- LBP Cascade 분류기 로딩
- 얼굴 검출 (DetectMultiScale)
- 검출된 얼굴 영역 표시
🏆실행 결과
프로그램을 실행시키면 주어진 이미지 파일에서 얼굴을 자동으로 인식하여 인식된 얼굴 위치에 빨간색 사각형을 그린 후, 결과 이미지를 저장하는 라이브러리를 사용해 보았습니다. 이제 이 방식을 기반으로 다양한 프로젝트에 활용할 수 있을거 같습니다.


'Spring Boot' 카테고리의 다른 글
[Spring-Boot] 객체 지향적 중심 설계 공부 (0) | 2025.04.06 |
---|---|
[Spring-Boot] JUnit & Mockito기반테스트 코드 작성 (0) | 2025.03.22 |
[Spring-Boot] Promtail + Loki + Logback 모니터링 (0) | 2025.03.09 |
[Spring-Boot] 객체 지향 설계 원칙 SOLID (0) | 2025.02.25 |
[Spring-Boot] QueryDsl 적용해보기 (0) | 2025.02.17 |