opencv (얼굴인식) + RN "react-native-vision-camera 4번째 시도

Seokhyun Yoon·2023년 9월 14일

카메라 권한 네이티브 모듈 개발 & webview태그 내에 얼굴 인식시에 백엔드로 데이터 전송하는 로직 구현

네이티브 모듈을 개발하다가 깨닫게 된 것이 있다.

개념

ReactNative는 javascript와 네이티브 코드가 합쳐져 앱 환경에서 작동할 수 있도록 하는 라이브러리라고 생각한다.

네이티브 코드

  • C, C++처럼 (JVM 같은)인터프리터 없이 운영체제가 읽을 수 있는 형태로 컴파일해 사용 가능한 코드

내 생각

  • 네이티브 코드가 필요한 이유는 Android 환경에서는 Java언어가 필요하고 ios 환경에서는 C,C++ 같은 언어들이 필요하다고 생각했다.

  • 예를들어 직접 네이티브 모듈을 구현할 때 모든 기능들, 하드웨어 접근 권한을 하기 위해서는 네이티브 코드로 된 모듈을 구현한다음 브릿지로 javascript 코드에서 사용할 수 있는 형태로 바꿔주었기 때문.

  • 아래 코드는 beanlove97님의 글을 참조했다.
    Native Module 만들어서 사용하기

React Native를 사용하면 웹 개발자들이 JavaScript를 사용하여 네이티브 기능(java나 c#, c++로 구현된 하드웨어 권한 기능이나 그 외 여럿 모든 기능들)을 활용하는 모바일 앱을 빌드할 수 있습니다. 이로써 기존에 웹 개발자들이 익숙한 언어와 도구를 활용하여 모바일 앱을 개발할 수 있게 되었습니다.

개발

첫 번째: 웹뷰 내에서 카메라 권한 얻기

카메라 권한을 웹뷰 내에서 사용하기 위해서는 네이티브 모듈을 작성하여 React Native 앱과 웹뷰 간의 통신을 확립해야 합니다.

  • CameraModule.java
    package com.okeydokeycontest;
    
    import com.facebook.react.bridge.ReactApplicationContext;
    import com.facebook.react.bridge.ReactContextBaseJavaModule;
    import com.facebook.react.bridge.ReactMethod;
    import android.hardware.Camera;
    public class CameraModule extends ReactContextBaseJavaModule {
        private ReactApplicationContext reactContext;
    
        public CameraModule(ReactApplicationContext reactContext) {
            super(reactContext);
            this.reactContext = reactContext;
        }
    
        @Override
        public String getName() {
            return "CameraModule"; // 모듈의 이름을 반환
        }
    
        private Camera camera;
    
        @ReactMethod
        public void startCamera() {
            try {
                camera = Camera.open();
                camera.startPreview();
                system.out.println("hi");
            } catch (Exception e) {
                e.printStackTrace();
                system.out.println("error");
            }
        }
        
        @ReactMethod
        public void stopCamera() {
            try {
                camera.stopPreview();
                camera.release();
                system.out.println("hi");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
  • CameraModulePackage.java
    package com.okeydokeycontest;
    
    import com.facebook.react.bridge.NativeModule;
    import com.facebook.react.bridge.ReactApplicationContext;
    import com.facebook.react.uimanager.ViewManager;
    import com.facebook.react.ReactPackage;
    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.List;
    
    public class CameraModulePackage implements ReactPackage {
        @Override
        public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
            return Collections.emptyList();
        }
    
        @Override
        public List<NativeModule> createNativeModules(
                ReactApplicationContext reactContext) {
            List<NativeModule> modules = new ArrayList<>();
            modules.add(new CameraModule(reactContext));
            return modules;
        }
    }
  • CameraModule.js
    // CameraModule.js
    import { NativeModules } from 'react-native';
    
    const CameraModule = NativeModules.CameraModule;
    
    export const startCamera = () => {
      if (CameraModule && CameraModule.startCamera) {
        CameraModule.startCamera();
      }
    };
    
    export const stopCamera = () => {
      if (CameraModule && CameraModule.stopCamera) {
        CameraModule.stopCamera();
      }
    };
    
    export default {
      startCamera,
      stopCamera,
    };
  • MyWebViewScreen.js
    // MyWebViewScreen.js
    import React, { useRef } from 'react';
    import { WebView } from 'react-native-webview';
    import { startCamera, stopCamera } from './CameraModule'; // 모듈 파일 경로를 적절하게 수정
    
    const MyWebViewScreen = () => {
      const webViewRef = useRef();
    
      // WebView로부터 메시지를 받아서 처리하는 함수
      const handleMessage = (event) => {
        const message = event.nativeEvent.data; // 메시지 추출
        if (message === 'startCamera') {
          startCamera(); // 카메라 시작 함수 호출
        } else if (message === 'stopCamera') {
          stopCamera(); // 카메라 정지 함수 호출
        }
      };
    
      return (
        <WebView
          ref={webViewRef}
          source={{ uri: 'http://wifiIp 혹은 netlify배포:5500/keyosk_camera-main/index.html' }}
          onMessage={handleMessage} // WebView로부터 메시지를 받는 핸들러 함수 설정
        />
      );
    };
    
    export default MyWebViewScreen;
  • postmessage로 javascript 코드에 네이티브 모듈을 노출시켜서 웹뷰에서 카메라 권한을 얻을 수 있도록 진행해보겠음.
  • opencv 폴더의 비디오 스트림을 얻는 index.html에 노출 시켰음.
    <script type='text/javascript'>
         window.addEventListener('message', (event) => {
        const message = JSON.parse(event.data);
        if (message.type === 'requestCameraPermission') {
          requestCameraPermissionFromWebView();
        }
      });

두 번째: 사진 촬영 및 서버로 전송 기능 구현

  • 웹뷰 내에서 카메라가 동작하고 얼굴 인식이 성공하면 사진을 촬영하고 서버로 전송하는 로직을 구현해야 합니다. 이 부분은 크게 네이티브 모듈과 웹뷰 내 JavaScript 코드로 구현될 수 있습니다.

  • 결론 : 위의 방법을 시도하려다가 카메라의 권한을 대체해주면 될 것 같았던
    videoStream을 얻고 처리하는 부분이 대체되지 않았고 실패
    대안책으로 팀장이 얼굴을 자동촬영하여 백엔드 서버로 보내고 하는 것을 실시간 반복해서 인식 시키겠다고 함. (서버에 python opencv로 만든 코드를 이용해)

현재 이 방법은 성공함, 하지만 앞의 시도들에 대해 분명 해결책이 있었을 것인데 공부가 부족하다고 생각되어 더 공부를 해봐야 할 것 같다고 결론을 내림.

profile
Web과 Cloud에 관심이 있습니다.

0개의 댓글