Android NDK와 OpenCV를 사용하여 갤러리에 있는 이미지를 불러와 영상처리하는 예제입니다.
바를 이용하여 Canny의 스레숄드를 변경하면 바로 결과를 볼 수 있습니다.
영상에는 코드 설명이 포함되어 있습니다.
외장 저장공간 접근 권한을 사용하기 때문에 처음 실행하면 권한 요청을 합니다.
상단에 보이는 디폴트 이미지를 클릭하면 갤러리에서 이미지를 불러올 수 있습니다.
이미지를 불러올 때 사용할 앱을 선택합니다.
갤러리에서 이미지를 선택합니다.
상단에 갤러리에서 선택한 이미지가 보입니다.
에지 검출하기를 선택하면 영상에서 에지를 검출하여 보여줍니다.
버튼 위에 보이는 두 개의 바를 사용하여 스레숄드 값을 변경할 수 있습니다.
바를 이동할때 마다 해당 스레숄드를 사용한 Canny의 에지 검출 결과를 보여줍니다.
2016.12.16 최초작성
. . . .
2019. 2. 8. 갤러리에서 이미지 불러오도록 수정
2019. 5. 5. 스레숄드 조정할 수 있는 바를 추가
2020. 9. 22 androidx 관련 수정
1. 다음 포스팅을 참고하여 안드로이드 프로젝트를 생성합니다.
2. AndroidManifest.xml 파일에서 필요없는 권한들을 제거하고 외부 저장소 접근 권한을 추가합니다.
activity 태그에 있던 옵션을 제거합니다.
3. build.gradle에서 최소 SDK을 26으로 수정한 후, Sync Now를 클릭하여 적용합니다.
SeekBar에 최소값을 지정하려면 변경해야 합니다.
4. activity_main.xml 파일을 다음 내용으로 대체합니다.
5. MainActivity.java 파일을 다음 내용으로 변경합니다.
붉은색으로 표시되는 imageprocessing 함수에 마우스 커서를 가져가 빨간 전구가 보이면 Create JNI function을 클릭합니다.
6. native-lib.cpp 파일을 다음처럼 수정합니다. 흰색은 새로 추가하고 파란색 부분은 주석처리합니다.
7. 아래 첨부된 svg 이미지를 다운로드 받습니다.
svg 이미지를 프로젝트의 drawable 폴더에 추가해야 합니다.
프로젝트 창에서 app을 선택하고 마우스 오른쪽 버튼을 클릭했을 때
보이는 메뉴에서 New > Vector Asset를 선택합니다.
다음 항목들을 선택하고 Next 버튼을 클릭합니다.
Asset Type 항목에서 Local file(SVG, PSD)를 선택합니다.
Path 항목에 있는 폴더 아이콘을 클릭하여 다운로드 받아둔 SVG 이미지 파일을 선택합니다.
Finish 버튼을 클릭하면 SVG 파일이 프로젝트에 추가됩니다.
8. 이제 폰에 올려서 확인해보면 됩니다.
'OpenCV > Android 개발 환경 및 예제' 카테고리의 다른 글
Android NDK + CMake + OpenCV 카메라 예제 및 프로젝트 생성방법(Android Camera Example with NDK, OpenCV, CMake ) (786) | 2021.04.10 |
---|---|
Android NDK + OpenCV 카메라 예제 및 프로젝트 생성방법(ndk-build 사용) (307) | 2021.04.08 |
Android 용으로 OpenCV 4.4.0 빌드하는 방법 (Build OpenCV 4.4.0 for Android ) (255) | 2020.09.27 |
Android NDK + OpenCV 이미지 로드하여 영상처리하는 예제 (136) | 2020.09.22 |
OpenCV와 NDK를 사용하여 Android에서 Face Detection(얼굴 검출) (697) | 2020.06.27 |
OpenCV 강좌 - 안드로이드 폰에서 딥러닝 네트워크(deep learning network) 실행하기 (Caffe) (10) | 2019.08.27 |
Android OpenCV 예제 - SURF를 사용한 오브젝트 검출 테스트 (57) | 2019.05.21 |
Android NDK + OpenCV 관심영역(ROI)에 영상처리하는 예제 (36) | 2019.05.13 |
포스트 작성시에는 문제 없었지만 이후 문제가 생길 수 있습니다.
질문을 남겨주면 가능한 빨리 답변드립니다.
여러분의 응원으로 좋은 컨텐츠가 만들어집니다.
지금 본 내용이 도움이 되었다면 유튜브 구독 부탁드립니다.
감사합니다 ~~
유튜브 구독하기
제가 쓴 책도 한번 검토해보세요 ^^
- 이전 댓글 더보기
-
-
천천히가는중 2019.01.15 11:49
제가 처음에 오류나서 없애두고 안된다고 하던거였네요.
cvtColor( img_input, img_input, COLOR_BGR2RGB);
CV_BGR2RGB를 COLOR_BGR2RGB로 바꾸고 해결했습니다. .
빠르게 알려주셔서 감사합니다.
항상 많은 도움 받고 있습니다. -
컴딱이 2019.03.25 21:16
정말정말정말 감사합니다 제가 원하던 빠진부분없이 모든 내용들이 알차고 그저 감사할 따름입니다.
저는 현재 자동차 번호판을 추출해서 번호판에있는 문자열 인식을 하고있는데
안드로이드 스튜디오 환경에서 opencv는 처음하는거라 너무 막막했는데 감사합니다. -
DenisKIIM 2019.05.07 16:51
선생님의 지식공유에 많은 감사를 드립니다.
안드로이드 Edge검출 부분에서 다음 과 같은 에러가 발생 합니다.
error: package R does not exist
어떤 부분의 문제로 발생하는지 알고 싶습니다.
과정은 선생님의 시킨과정대로 따라 한것 같은데 어디서 잘못했는지 잘 모르겠습니다.
고수님의 한 수를 부탁드리겠습니다.
-
발생한 이유가 한가지가 아닐거 같아서 맞는 솔루션인지 모르겠네요..
메니페스트 파일에 있는 패키지 이름과
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.tistory.webnautes.opencvimageexample">
액티비티에 있는 패키지 명이 같은지 확인해보세요.
package com.tistory.webnautes.opencvimageexample;
또는 프로젝트에 속한 파일중 에러 났다고 표시를 해주는 파일이 있는지도 확인해보세요.
-
-
DenisKIM 2019.05.08 14:52
대단히 감사합니다.
하드웨어를 전공하다보니 APP에 부조감을 많이 느낍니다.
선생님께서 일러주신 대로 package를 처리하니 동작하였습니다.
다시한번 감사함을 전합니다.(꾸뻑,꾸뻑) -
-
canny 말고 이미지 배경색상(필터)을 바꿔주고 싶은데....어디쪽을 봐야 될까요....? 아무리 뒤져봐도 잘 모르겠어서 댓글 드립니다...
-
cpp 파일의 다음 부분을 수정하세요.
Mat &img_input = *(Mat *) inputImage;
Mat &img_output = *(Mat *) outputImage;
cvtColor( img_input, img_output, COLOR_RGB2GRAY);
blur( img_output, img_output, Size(5,5) );
Canny( img_output, img_output, th1, th2);
img_input를 입력으로 img_out를 최종 결과물로 하면 됩니다.
img_out에 저장된 이미지가 최종적으로 자바코드에서 보여집니다.
-
-
김서정 2019.10.01 16:54
선생님 좋은 코드 너무감사합니다..!
제가 할때는 잘실행이 안되는 부분들이 있어서 혹시 전체 프로젝트폴더같은것을 받고싶은데
가능할까요..?
혹시 github에 올려두셨거나 하신 프로젝트들이있나요..? -
포스팅과 동영상 잘 보고 있습니다.
이 예제도 해봤는데, 처음에는 잘 뜨지만 프로그레스바나 버튼을 누르면 즉시 앱이 종료하네요.
이유가 뭘까요?
처음 뜨는 이미지를 클릭해 다른 이미지로 바꾼 다음부터는 정상적으로 작동합니다. -
-
hello 2020.06.24 22:28
어디부터 어디까지 봐야하는지를 잘 몰라서 일단 앱 종료때부터 뜨는오류 올립니다!
2020-06-24 22:26:36.101 6015-6015/com.example.colorapp E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.colorapp, PID: 6015
java.lang.NullPointerException: Attempt to invoke virtual method 'long org.opencv.core.Mat.getNativeObjAddr()' on a null object reference
at com.example.colorapp.ColoringActivity_Camera.imageprocess_and_showResult(ColoringActivity_Camera.java:340)
at com.example.colorapp.ColoringActivity_Camera.access$300(ColoringActivity_Camera.java:49)
at com.example.colorapp.ColoringActivity_Camera$7.onProgressChanged(ColoringActivity_Camera.java:261)
at android.widget.SeekBar.onProgressRefresh(SeekBar.java:98)
at android.widget.ProgressBar.doRefreshProgress(ProgressBar.java:1555)
at android.widget.ProgressBar.refreshProgress(ProgressBar.java:1655)
at android.widget.ProgressBar.setProgressInternal(ProgressBar.java:1721)
at android.widget.AbsSeekBar.trackTouchEvent(AbsSeekBar.java:1008)
at android.widget.AbsSeekBar.onTouchEvent(AbsSeekBar.java:916)
at android.view.View.dispatchTouchEvent(View.java:14207)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3022)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2745)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3022)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2745)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3022)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2745)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3022)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2745)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3022)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2745)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3022)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2745)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3022)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2745)
at com.android.internal.policy.DecorView.superDispatchTouchEvent(DecorView.java:488)
at com.android.internal.policy.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1883)
at android.app.Activity.dispatchTouchEvent(Activity.java:4122)
at android.support.v7.view.WindowCallbackWrapper.dispatchTouchEvent(WindowCallbackWrapper.java:69)
at com.android.internal.policy.DecorView.dispatchTouchEvent(DecorView.java:446)
at android.view.View.dispatchPointerEvent(View.java:14466)
at android.view.ViewRootImpl$ViewPostImeInputStage.processPointerEvent(ViewRootImpl.java:5980)
at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:5783)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:5274)
at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:5331)
at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:5297)
at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:5449)
at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:5305)
at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:5506)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:5278)
at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:5331)
at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:5297)
at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:5305)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:5278)
at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:8041)
at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:7992)
at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:7953)
at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:8170)
at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:219)
at android.view.InputEventReceiver.nativeConsumeBatchedInputEvents(Native Method)
2020-06-24 22:26:36.102 6015-6015/com.example.colorapp E/AndroidRuntime: at android.view.InputEventReceiver.consumeBatchedInputEvents(InputEventReceiver.java:199)
at android.view.ViewRootImpl.doConsumeBatchedInput(ViewRootImpl.java:8120)
at android.view.ViewRootImpl$ConsumeBatchedInputRunnable.run(ViewRootImpl.java:8210)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:972)
at android.view.Choreographer.doCallbacks(Choreographer.java:796)
at android.view.Choreographer.doFrame(Choreographer.java:724)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:957)
at android.os.Handler.handleCallback(Handler.java:907)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:223)
at android.app.ActivityThread.main(ActivityThread.java:7476)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:549)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:939)
2020-06-24 22:26:36.446 548-698/system_process E/InputDispatcher: channel '5a7b929 com.example.colorapp/com.example.colorapp.ColoringActivity_Camera (server)' ~ Channel is unrecoverably broken and will be disposed!
2020-06-24 22:26:37.704 1241-1241/com.google.android.gms E/BeaconBle: Missing BluetoothAdapter
-
jyshin 2020.09.07 16:49
처음에 native project로 안드로이드 프로젝트를 선택하면.. 무조건 CMakeLists.txt 파일이 생성되는건가요? Native Project로 프로젝트를 생성해도 ndk-build 방법으로 진행이 가능한지요?
-
jyshin 2020.09.07 18:08
아.. 그리고.. import android.support.annotation.NonNull; 요 부분이 회색처리 되면서 build시 에러나네요..
원인이 멀까요..
-
jyshin 2020.09.08 14:54
일단.. Native C++ 위저드로 프로젝트 생성하면.. CMakeLists.txt는 자동으로 생성되네요. build.gradle에도 externalNativeBuild가 cmake로 자동으로 잡히고,
억지로 build.gradle에서 cmake 부분을 주석처리해버리고, ndkBuild로 변경한후 Android.mk, Application.mk 작성해서 빌드까지 성공해봤으나,
에뮬레이터에서 App 실행이 안되네요. 먼가 될 듯 될 듯하면서.. 안되네요.. ㅎㅎ
자꾸 Native C++에서 ndk-build를 실행해보려고 하는 이유가 여기 저기 가져다 쓰는 Open Source가 ndk-build로 되어 있어서 가져다 쓰기 좋기 때문입니다...
혹시 Native C++ 위저드로 프로젝트 생성하고 ndk-build로 open CV 예제 개발해서 업로드 계획 있으신지요^^?
날로 먹으려고 하는건 아닌지 모르겠지만.. 이런 고민하는 사람이 있을 것 같아서 문의 남깁니다. -
jyshin 2020.09.09 12:43
https://webnautes.tistory.com/923 < - 요 방법을 몇주전에 따라 해서 도움을 받은 적이 있습니다.
그러나.. empty project wizard로 프로젝트를 생성하면 native c++ 파일에 break를 걸 수가 없더군요... 즉 c++ 코드에 debugger를 쓸 수 없습니다.
항상 Native c++ 위저드로 생성한 프로젝트만 break를 걸어서 debugger를 돌릴 수 있더라구요...
그래서 제가 Native C++ 위저드로 ndk-build를 시도해보려는 겁니다..
-
jyshin 2020.09.14 19:27
Native C++ 프로젝트를 예를 들어 STAR.aar로 빌드해서.. 다른 프로젝트에 import한 후 STAR.aar에 있는 STAR.cpp 파일의 sum_two_digits( )이라는 C 함수를 호출할 수 있는지요?
시도해보는데.. 호출이 안되서 질문드리는겁니다.. 먼가 제가 이해를 잘 못하고 있는건지... -
감사합니다~ 정말 잘 봤어요. PC에서 하던 것을 android에서 해보려고 하는데 쉽지 않네요. 좋은 길잡이가 되어 주셔서 감사합니다.
음..... 그런데... 왼쪽의 카테고리 보니까 dlib+android도 있던데...혹시 계획 있으신지..^^a.... -
kannu 2020.10.11 08:24
혹시 안드로이드에서 opencv는 흑백사진만 이미지 필터링이 가능한가요?
bilateral 처리 방법을 찾아봐도 다 gray로 바꾸고 시작하더라구요.. -