From 68534d70f379d5d4aa799444baedac9fda028248 Mon Sep 17 00:00:00 2001 From: Andrey Kamaev Date: Wed, 6 Apr 2011 14:31:03 +0000 Subject: [PATCH] Merged android-experimental branch back to trunk. --- 3rdparty/CMakeLists.txt | 4 - 3rdparty/lapack/CMakeLists.txt | 5 - 3rdparty/libjasper/CMakeLists.txt | 9 - 3rdparty/libjpeg/CMakeLists.txt | 6 - 3rdparty/libpng/CMakeLists.txt | 5 - 3rdparty/libtiff/tif_config.h | 2 + 3rdparty/zlib/CMakeLists.txt | 5 - CMakeLists.txt | 33 +- OpenCVConfig.cmake.in | 13 +- OpenCVModule.cmake | 24 +- OpenCVPCHSupport.cmake | 4 + android/Android.mk.in | 17 - android/Android.mk.master.in | 5 - android/Android.mk.modules.in | 2 - android/AndroidCVModule.cmake | 28 - android/AndroidManifest.xml.in | 7 - android/Application.mk.in | 6 - android/CMakeCache.android.initial.cmake | 110 +++ android/CMakeLists.txt | 93 --- android/README.android.txt | 90 ++- android/android-cmake/CMakeLists.txt | 90 --- android/android-jni/AndroidManifest.xml | 24 - android/android-jni/Makefile | 78 -- android/android-jni/README.txt | 41 -- android/android-jni/jni/Android.mk | 31 - android/android-jni/jni/Application.mk | 2 - android/android-jni/jni/cv.i | 59 -- android/android-jni/jni/yuv420sp2rgb.c | 80 -- android/android-jni/sample.local.env.mk | 10 - android/android-opencv.mk.in | 38 - android/android-opencv/AndroidManifest.xml | 29 + .../android-opencv/AndroidOpenCVConfig.cmake.in | 44 ++ android/android-opencv/CMakeLists.txt | 5 + android/android-opencv/README.txt | 13 + .../default.properties | 3 +- android/android-opencv/jni/CMakeLists.txt | 70 ++ .../jni/Calibration.cpp | 0 .../jni/Calibration.i | 0 .../jni/android-cv-typemaps.i | 0 .../jni/android-cv.i | 1 - .../{android-jni => android-opencv}/jni/buffers.i | 8 +- android/android-opencv/jni/cv.i | 156 ++++ .../jni/gl_code.cpp | 102 ++- .../{android-jni => android-opencv}/jni/glcamera.i | 1 + .../jni/image_pool.cpp | 88 ++- .../jni/image_pool.i | 13 +- .../jni/include}/Calibration.h | 0 .../android-opencv/jni/include/android_logger.h | 19 + .../jni => android-opencv/jni/include}/glcamera.h | 9 + .../jni/include}/image_pool.h | 23 +- android/android-opencv/jni/include/yuv2rgb.h | 147 ++++ .../jni/include}/yuv420sp2rgb.h | 1 - .../{android-jni => android-opencv}/jni/nocopy.i | 0 android/android-opencv/jni/yuv2rgb16tab.c | 802 +++++++++++++++++++++ .../jni/yuv2rgb_neon.c | 0 android/android-opencv/jni/yuv420rgb888.s | 379 ++++++++++ android/android-opencv/jni/yuv420rgb888c.c | 208 ++++++ android/android-opencv/jni/yuv420sp2rgb.c | 156 ++++ .../project_create.sh | 0 .../res/drawable-mdpi/cameraback.jpg | Bin 0 -> 164530 bytes .../res/layout/calibrationviewer.xml | 0 android/android-opencv/res/layout/camera.xml | 28 + .../res/layout/camerasettings.xml | 6 +- .../res/layout/chesssizer.xml | 0 .../res/values/attrs.xml | 0 .../res/values/chessnumbers.xml | 0 .../res/values/settingnumbers.xml | 0 .../res/values/strings.xml | 0 .../src/com/opencv/OpenCV.java | 4 +- .../com/opencv/calibration/CalibrationViewer.java | 0 .../src/com/opencv/calibration/Calibrator.java | 0 .../com/opencv/calibration/ChessBoardChooser.java | 0 .../calibration/services/CalibrationService.java | 0 .../src/com/opencv/camera/CameraActivity.java | 128 ++++ .../com/opencv/camera/CameraButtonsHandler.java | 83 +++ .../src/com/opencv/camera/CameraConfig.java | 2 +- .../src/com/opencv/camera/NativePreviewer.java | 26 +- .../src/com/opencv/camera/NativeProcessor.java | 0 .../src/com/opencv/opengl/GL2CameraViewer.java | 6 + .../src/com/opencv/utils/BitmapBridge.java | 34 + android/apps/CVCamera/CMakeLists.txt | 5 + android/apps/CVCamera/Makefile | 86 --- android/apps/CVCamera/build.sh | 1 - android/apps/CVCamera/clean.sh | 1 - android/apps/CVCamera/default.properties | 2 +- android/apps/CVCamera/jni/Android.mk | 21 - android/apps/CVCamera/jni/Application.mk | 2 - android/apps/CVCamera/jni/CMakeLists.txt | 62 ++ android/apps/CVCamera/sample.local.env.mk | 4 - android/apps/Calibration/default.properties | 2 +- .../res/layout/{camera.xml => calib_camera.xml} | 0 .../src/com/opencv/calibration/Calibration.java | 4 +- android/apps/OpenCV_SAMPLE/AndroidManifest.xml | 29 + android/apps/OpenCV_SAMPLE/CMakeLists.txt | 5 + .../OpenCV_SAMPLE/default.properties} | 5 +- android/apps/OpenCV_SAMPLE/jni/CMakeLists.txt | 68 ++ android/apps/OpenCV_SAMPLE/jni/OpenCV_SAMPLE.i | 48 ++ android/apps/OpenCV_SAMPLE/jni/cvsample.cpp | 27 + android/apps/OpenCV_SAMPLE/jni/cvsample.h | 11 + android/apps/OpenCV_SAMPLE/project_create.sh | 3 + .../apps/OpenCV_SAMPLE/res/drawable-hdpi/icon.png | Bin 0 -> 5760 bytes .../apps/OpenCV_SAMPLE/res/drawable-ldpi/icon.png | Bin 0 -> 2034 bytes .../apps/OpenCV_SAMPLE/res/drawable-mdpi/icon.png | Bin 0 -> 2861 bytes android/apps/OpenCV_SAMPLE/res/layout/main.xml | 12 + .../apps/OpenCV_SAMPLE/res/menu/sample_menu.xml | 8 + android/apps/OpenCV_SAMPLE/res/values/strings.xml | 5 + .../src/com/OpenCV_SAMPLE/OpenCV_SAMPLE.java | 87 +++ android/changes.Android.txt | 17 - android/changes.diff | 255 ------- android/cmake_android.sh | 4 + android/cmake_android_armeabi.sh | 4 + android/cvconfig.h.in | 161 ----- android/diff.txt | 211 ------ modules/CMakeLists.txt | 10 +- modules/haartraining/CMakeLists.txt | 2 + modules/highgui/CMakeLists.txt | 30 +- .../highgui/include/opencv2/highgui/highgui_c.h | 12 +- modules/highgui/src/cap.cpp | 13 +- modules/highgui/src/cap_android.cpp | 354 +++++++++ modules/highgui/src/precomp.hpp | 1 + 120 files changed, 3475 insertions(+), 1612 deletions(-) delete mode 100644 android/Android.mk.in delete mode 100644 android/Android.mk.master.in delete mode 100644 android/Android.mk.modules.in delete mode 100644 android/AndroidCVModule.cmake delete mode 100644 android/AndroidManifest.xml.in delete mode 100644 android/Application.mk.in create mode 100644 android/CMakeCache.android.initial.cmake delete mode 100644 android/CMakeLists.txt delete mode 100644 android/android-cmake/CMakeLists.txt delete mode 100644 android/android-jni/AndroidManifest.xml delete mode 100644 android/android-jni/Makefile delete mode 100644 android/android-jni/README.txt delete mode 100644 android/android-jni/jni/Android.mk delete mode 100644 android/android-jni/jni/Application.mk delete mode 100644 android/android-jni/jni/cv.i delete mode 100644 android/android-jni/jni/yuv420sp2rgb.c delete mode 100644 android/android-jni/sample.local.env.mk delete mode 100644 android/android-opencv.mk.in create mode 100644 android/android-opencv/AndroidManifest.xml create mode 100644 android/android-opencv/AndroidOpenCVConfig.cmake.in create mode 100644 android/android-opencv/CMakeLists.txt create mode 100644 android/android-opencv/README.txt rename android/{android-jni => android-opencv}/default.properties (94%) create mode 100644 android/android-opencv/jni/CMakeLists.txt rename android/{android-jni => android-opencv}/jni/Calibration.cpp (100%) rename android/{android-jni => android-opencv}/jni/Calibration.i (100%) rename android/{android-jni => android-opencv}/jni/android-cv-typemaps.i (100%) rename android/{android-jni => android-opencv}/jni/android-cv.i (99%) rename android/{android-jni => android-opencv}/jni/buffers.i (96%) create mode 100644 android/android-opencv/jni/cv.i rename android/{android-jni => android-opencv}/jni/gl_code.cpp (81%) rename android/{android-jni => android-opencv}/jni/glcamera.i (98%) rename android/{android-jni => android-opencv}/jni/image_pool.cpp (55%) rename android/{android-jni => android-opencv}/jni/image_pool.i (92%) rename android/{android-jni/jni => android-opencv/jni/include}/Calibration.h (100%) create mode 100644 android/android-opencv/jni/include/android_logger.h rename android/{android-jni/jni => android-opencv/jni/include}/glcamera.h (84%) rename android/{android-jni/jni => android-opencv/jni/include}/image_pool.h (67%) create mode 100644 android/android-opencv/jni/include/yuv2rgb.h rename android/{android-jni/jni => android-opencv/jni/include}/yuv420sp2rgb.h (94%) rename android/{android-jni => android-opencv}/jni/nocopy.i (100%) create mode 100644 android/android-opencv/jni/yuv2rgb16tab.c rename android/{android-jni => android-opencv}/jni/yuv2rgb_neon.c (100%) create mode 100644 android/android-opencv/jni/yuv420rgb888.s create mode 100644 android/android-opencv/jni/yuv420rgb888c.c create mode 100644 android/android-opencv/jni/yuv420sp2rgb.c rename android/{android-jni => android-opencv}/project_create.sh (100%) create mode 100644 android/android-opencv/res/drawable-mdpi/cameraback.jpg rename android/{android-jni => android-opencv}/res/layout/calibrationviewer.xml (100%) create mode 100644 android/android-opencv/res/layout/camera.xml rename android/{android-jni => android-opencv}/res/layout/camerasettings.xml (99%) rename android/{android-jni => android-opencv}/res/layout/chesssizer.xml (100%) rename android/{android-jni => android-opencv}/res/values/attrs.xml (100%) rename android/{android-jni => android-opencv}/res/values/chessnumbers.xml (100%) rename android/{android-jni => android-opencv}/res/values/settingnumbers.xml (100%) rename android/{android-jni => android-opencv}/res/values/strings.xml (100%) rename android/{android-jni => android-opencv}/src/com/opencv/OpenCV.java (98%) rename android/{android-jni => android-opencv}/src/com/opencv/calibration/CalibrationViewer.java (100%) rename android/{android-jni => android-opencv}/src/com/opencv/calibration/Calibrator.java (100%) rename android/{android-jni => android-opencv}/src/com/opencv/calibration/ChessBoardChooser.java (100%) rename android/{android-jni => android-opencv}/src/com/opencv/calibration/services/CalibrationService.java (100%) create mode 100644 android/android-opencv/src/com/opencv/camera/CameraActivity.java create mode 100644 android/android-opencv/src/com/opencv/camera/CameraButtonsHandler.java rename android/{android-jni => android-opencv}/src/com/opencv/camera/CameraConfig.java (99%) rename android/{android-jni => android-opencv}/src/com/opencv/camera/NativePreviewer.java (97%) rename android/{android-jni => android-opencv}/src/com/opencv/camera/NativeProcessor.java (100%) rename android/{android-jni => android-opencv}/src/com/opencv/opengl/GL2CameraViewer.java (99%) create mode 100644 android/android-opencv/src/com/opencv/utils/BitmapBridge.java create mode 100644 android/apps/CVCamera/CMakeLists.txt delete mode 100644 android/apps/CVCamera/Makefile delete mode 100644 android/apps/CVCamera/build.sh delete mode 100644 android/apps/CVCamera/clean.sh delete mode 100644 android/apps/CVCamera/jni/Android.mk delete mode 100644 android/apps/CVCamera/jni/Application.mk create mode 100644 android/apps/CVCamera/jni/CMakeLists.txt delete mode 100644 android/apps/CVCamera/sample.local.env.mk rename android/apps/Calibration/res/layout/{camera.xml => calib_camera.xml} (100%) create mode 100644 android/apps/OpenCV_SAMPLE/AndroidManifest.xml create mode 100644 android/apps/OpenCV_SAMPLE/CMakeLists.txt rename android/{default.properties.in => apps/OpenCV_SAMPLE/default.properties} (86%) create mode 100644 android/apps/OpenCV_SAMPLE/jni/CMakeLists.txt create mode 100644 android/apps/OpenCV_SAMPLE/jni/OpenCV_SAMPLE.i create mode 100644 android/apps/OpenCV_SAMPLE/jni/cvsample.cpp create mode 100644 android/apps/OpenCV_SAMPLE/jni/cvsample.h create mode 100755 android/apps/OpenCV_SAMPLE/project_create.sh create mode 100644 android/apps/OpenCV_SAMPLE/res/drawable-hdpi/icon.png create mode 100644 android/apps/OpenCV_SAMPLE/res/drawable-ldpi/icon.png create mode 100644 android/apps/OpenCV_SAMPLE/res/drawable-mdpi/icon.png create mode 100644 android/apps/OpenCV_SAMPLE/res/layout/main.xml create mode 100644 android/apps/OpenCV_SAMPLE/res/menu/sample_menu.xml create mode 100644 android/apps/OpenCV_SAMPLE/res/values/strings.xml create mode 100644 android/apps/OpenCV_SAMPLE/src/com/OpenCV_SAMPLE/OpenCV_SAMPLE.java delete mode 100644 android/changes.Android.txt delete mode 100644 android/changes.diff create mode 100644 android/cmake_android.sh create mode 100644 android/cmake_android_armeabi.sh delete mode 100644 android/cvconfig.h.in delete mode 100644 android/diff.txt create mode 100644 modules/highgui/src/cap_android.cpp diff --git a/3rdparty/CMakeLists.txt b/3rdparty/CMakeLists.txt index babacb3..f536e21 100644 --- a/3rdparty/CMakeLists.txt +++ b/3rdparty/CMakeLists.txt @@ -1,7 +1,3 @@ -if(ANDROID) - configure_file("${CMAKE_SOURCE_DIR}/Android.mk.modules.in" "${CMAKE_CURRENT_BINARY_DIR}/Android.mk") -endif() - add_subdirectory(lapack) add_subdirectory(zlib) if(WITH_JASPER AND NOT JASPER_FOUND) diff --git a/3rdparty/lapack/CMakeLists.txt b/3rdparty/lapack/CMakeLists.txt index b2185ee..9ccf07c 100644 --- a/3rdparty/lapack/CMakeLists.txt +++ b/3rdparty/lapack/CMakeLists.txt @@ -2,9 +2,6 @@ # CMake file for opencv_lapack. See root CMakeLists.txt # # ---------------------------------------------------------------------------- -if(ANDROID) -define_3rdparty_module(opencv_lapack) -else() project(opencv_lapack) @@ -65,5 +62,3 @@ if(NOT BUILD_SHARED_LIBS) install(TARGETS ${the_target} ARCHIVE DESTINATION share/opencv/3rdparty/lib COMPONENT main) endif() - -endif() #android diff --git a/3rdparty/libjasper/CMakeLists.txt b/3rdparty/libjasper/CMakeLists.txt index 7f1effc..d5627b3 100644 --- a/3rdparty/libjasper/CMakeLists.txt +++ b/3rdparty/libjasper/CMakeLists.txt @@ -1,10 +1,3 @@ -if(ANDROID) -set(android_defs "-DEXCLUDE_MIF_SUPPORT -DEXCLUDE_PNM_SUPPORT -DEXCLUDE_BMP_SUPPORT -DEXCLUDE_RAS_SUPPORT -DEXCLUDE_JPG_SUPPORT -DEXCLUDE_PGX_SUPPORT") -define_3rdparty_module(jasper) -set(android_defs "") -else(ANDROID) - - # ---------------------------------------------------------------------------- # CMake file for libjasper. See root CMakeLists.txt # @@ -62,5 +55,3 @@ if(NOT BUILD_SHARED_LIBS) install(TARGETS ${the_target} ARCHIVE DESTINATION share/opencv/3rdparty/lib COMPONENT main) endif() - -endif(ANDROID)#!android diff --git a/3rdparty/libjpeg/CMakeLists.txt b/3rdparty/libjpeg/CMakeLists.txt index af8e6f2..7b2b1fa 100644 --- a/3rdparty/libjpeg/CMakeLists.txt +++ b/3rdparty/libjpeg/CMakeLists.txt @@ -1,7 +1,3 @@ -if(ANDROID) -define_3rdparty_module(jpeg) -else() -#endif()#android # ---------------------------------------------------------------------------- # CMake file for libjpeg. See root CMakeLists.txt # @@ -52,5 +48,3 @@ if(NOT BUILD_SHARED_LIBS) install(TARGETS ${the_target} ARCHIVE DESTINATION share/opencv/3rdparty/lib COMPONENT main) endif() - -endif()#android diff --git a/3rdparty/libpng/CMakeLists.txt b/3rdparty/libpng/CMakeLists.txt index 0eb998b..b5d441c 100644 --- a/3rdparty/libpng/CMakeLists.txt +++ b/3rdparty/libpng/CMakeLists.txt @@ -1,6 +1,3 @@ -if(ANDROID) -define_3rdparty_module(png) -else() # ---------------------------------------------------------------------------- # CMake file for libpng. See root CMakeLists.txt # @@ -46,5 +43,3 @@ if(NOT BUILD_SHARED_LIBS) install(TARGETS ${the_target} ARCHIVE DESTINATION share/opencv/3rdparty/lib COMPONENT main) endif() - -endif()#android diff --git a/3rdparty/libtiff/tif_config.h b/3rdparty/libtiff/tif_config.h index 08d1f0d..8c8d145 100644 --- a/3rdparty/libtiff/tif_config.h +++ b/3rdparty/libtiff/tif_config.h @@ -20,8 +20,10 @@ /* Define to 1 if you have the header file. */ #define HAVE_IO_H 1 +#if !__ANDROID__ /* Define to 1 if you have the header file. */ #define HAVE_SEARCH_H 1 +#endif /* Define to 1 if you have the `setmode' function. */ #define HAVE_SETMODE 1 diff --git a/3rdparty/zlib/CMakeLists.txt b/3rdparty/zlib/CMakeLists.txt index 340a8b5..9c20f9c 100644 --- a/3rdparty/zlib/CMakeLists.txt +++ b/3rdparty/zlib/CMakeLists.txt @@ -1,6 +1,3 @@ -if(ANDROID) -define_3rdparty_module(zlib) -else() # ---------------------------------------------------------------------------- # CMake file for zlib. See root CMakeLists.txt # @@ -43,5 +40,3 @@ if(NOT BUILD_SHARED_LIBS) install(TARGETS ${the_target} ARCHIVE DESTINATION share/opencv/3rdparty/lib COMPONENT main) endif() - -endif(ANDROID) diff --git a/CMakeLists.txt b/CMakeLists.txt index ae1b220..9cf7c25 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -482,8 +482,10 @@ if(UNIX) endif() endif() - if(${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD" OR ${CMAKE_SYSTEM_NAME} MATCHES "NetBSD") + if(${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD" OR ${CMAKE_SYSTEM_NAME} MATCHES "NetBSD" AND NOT ANDROID) set(OPENCV_LINKER_LIBS m pthread) + elseif(ANDROID) + set(OPENCV_LINKER_LIBS dl m) else() set(OPENCV_LINKER_LIBS dl m pthread rt) endif() @@ -508,6 +510,18 @@ if(WITH_JASPER AND NOT JASPER_FOUND) set(JASPER_LIBRARIES libjasper) endif() +if (ANDROID) + set(NativeCamera_DIR "${CMAKE_SOURCE_DIR}/android/native-camera/build") + FIND_PACKAGE(NativeCamera QUIET) + if(NativeCamera_FOUND) + set(HAVE_ANDROID_NATIVE_CAMERA TRUE) + set(OPENCV_LINKER_LIBS ${OPENCV_LINKER_LIBS} ${NativeCamera_LIBS} log) + else() + set(HAVE_ANDROID_NATIVE_CAMERA FALSE) + message("-- Could NOT find NativeCamera for Android") + endif() +endif() + #message(STATUS "Graphic libraries: ${PNG_LIBRARIES} ${JPEG_LIBRARIES} ${TIFF_LIBRARIES} ${JASPER_LIBRARIES}") if(WITH_OPENEXR) @@ -895,7 +909,9 @@ if(CMAKE_COMPILER_IS_GNUCXX) # We need pthread's if(UNIX) + if(NOT ANDROID) set(EXTRA_C_FLAGS "${EXTRA_C_FLAGS} -pthread") + endif() endif() if(OPENCV_WARNINGS_ARE_ERRORS) @@ -1083,7 +1099,17 @@ endif() set(CMAKE_INCLUDE_DIRS_CONFIGCMAKE "\"${OPENCV_CONFIG_FILE_INCLUDE_DIR}\" \"${CMAKE_CURRENT_SOURCE_DIR}/include\" \"${CMAKE_CURRENT_SOURCE_DIR}/include/opencv\"") set(CMAKE_BASE_INCLUDE_DIRS_CONFIGCMAKE "\"${CMAKE_CURRENT_SOURCE_DIR}\"") -set(CMAKE_LIB_DIRS_CONFIGCMAKE "${LIBRARY_OUTPUT_PATH}") +set(CMAKE_LIB_DIRS_CONFIGCMAKE "${LIBRARY_OUTPUT_PATH}") + +if (ANDROID) + if (NOT BUILD_SHARED_LIBS) + set(CMAKE_LIB_DIRS_CONFIGCMAKE ${CMAKE_LIB_DIRS_CONFIGCMAKE} "${CMAKE_BINARY_DIR}/lib") + endif() + + if( HAVE_ANDROID_NATIVE_CAMERA ) + set(CMAKE_LIB_DIRS_CONFIGCMAKE ${CMAKE_LIB_DIRS_CONFIGCMAKE} ${NativeCamera_LIB_DIR}) + endif() +endif() configure_file("${CMAKE_CURRENT_SOURCE_DIR}/OpenCVConfig.cmake.in" "${CMAKE_BINARY_DIR}/OpenCVConfig.cmake" IMMEDIATE @ONLY) @@ -1367,6 +1393,9 @@ else() message(STATUS " V4L/V4L2: ${HAVE_CAMV4L}/${HAVE_CAMV4L2}") endif() message(STATUS " Xine: ${HAVE_XINE}") +if(ANDROID) +message(STATUS " AndroidNativeCamera: ${HAVE_ANDROID_NATIVE_CAMERA}") +endif() endif() #if(UNIX AND NOT APPLE) if(APPLE) diff --git a/OpenCVConfig.cmake.in b/OpenCVConfig.cmake.in index 8efd602..efe3593 100644 --- a/OpenCVConfig.cmake.in +++ b/OpenCVConfig.cmake.in @@ -52,8 +52,14 @@ LINK_DIRECTORIES(${OpenCV_LIB_DIR}) # ==================================================================== # Link libraries: e.g. opencv_core220.so, opencv_imgproc220d.lib, etc... -# ==================================================================== -set(OPENCV_LIB_COMPONENTS opencv_core opencv_imgproc opencv_features2d opencv_gpu opencv_calib3d opencv_objdetect opencv_video opencv_highgui opencv_ml opencv_legacy opencv_contrib opencv_flann) +# ==================================================================== +if(NOT ANDROID) + set(OPENCV_LIB_COMPONENTS opencv_core opencv_imgproc opencv_features2d opencv_gpu opencv_calib3d opencv_objdetect opencv_video opencv_highgui opencv_ml opencv_legacy opencv_contrib opencv_flann) +else() + #libraries order is very important because linker from Android NDK is one-pass linker + set(OPENCV_LIB_COMPONENTS opencv_calib3d opencv_objdetect opencv_features2d opencv_imgproc opencv_video opencv_highgui opencv_ml opencv_legacy opencv_flann opencv_core ) +endif() + SET(OpenCV_LIBS "") foreach(__CVLIB ${OPENCV_LIB_COMPONENTS}) # CMake>=2.6 supports the notation "debug XXd optimized XX" @@ -85,6 +91,9 @@ IF (NOT @OPENCV_BUILD_SHARED_LIB@) LINK_DIRECTORIES(@CMAKE_LIB_DIRS_CONFIGCMAKE@/../3rdparty/lib) if(WIN32) LINK_DIRECTORIES(@CMAKE_BASE_INCLUDE_DIRS_CONFIGCMAKE@/3rdparty/lib) + elseif(ANDROID) + LINK_DIRECTORIES(@CMAKE_BINARY_DIR@/3rdparty/lib) + LINK_DIRECTORIES(@CMAKE_LIB_DIRS_CONFIGCMAKE@/3rdparty/lib) else() LINK_DIRECTORIES(@CMAKE_LIB_DIRS_CONFIGCMAKE@/../share/opencv/3rdparty/lib) endif() diff --git a/OpenCVModule.cmake b/OpenCVModule.cmake index be84e19..5939ebb 100644 --- a/OpenCVModule.cmake +++ b/OpenCVModule.cmake @@ -29,18 +29,6 @@ macro(define_opencv_module name) add_library(${the_target} ${lib_srcs} ${lib_hdrs} ${lib_int_hdrs}) - if(PCHSupport_FOUND) - set(pch_header ${CMAKE_CURRENT_SOURCE_DIR}/src/precomp.hpp) - if(${CMAKE_GENERATOR} MATCHES "Visual*" OR ${CMAKE_GENERATOR} MATCHES "Xcode*") - if(${CMAKE_GENERATOR} MATCHES "Visual*") - set(${the_target}_pch "src/precomp.cpp") - endif() - add_native_precompiled_header(${the_target} ${pch_header}) - elseif(CMAKE_COMPILER_IS_GNUCXX AND ${CMAKE_GENERATOR} MATCHES ".*Makefiles") - add_precompiled_header(${the_target} ${pch_header}) - endif() - endif() - # For dynamic link numbering convenions set_target_properties(${the_target} PROPERTIES VERSION ${OPENCV_VERSION} @@ -56,6 +44,18 @@ macro(define_opencv_module name) INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/lib" ) + if(PCHSupport_FOUND) + set(pch_header ${CMAKE_CURRENT_SOURCE_DIR}/src/precomp.hpp) + if(${CMAKE_GENERATOR} MATCHES "Visual*" OR ${CMAKE_GENERATOR} MATCHES "Xcode*") + if(${CMAKE_GENERATOR} MATCHES "Visual*") + set(${the_target}_pch "src/precomp.cpp") + endif() + add_native_precompiled_header(${the_target} ${pch_header}) + elseif(CMAKE_COMPILER_IS_GNUCXX AND ${CMAKE_GENERATOR} MATCHES ".*Makefiles") + add_precompiled_header(${the_target} ${pch_header}) + endif() + endif() + # Add the required libraries for linking: target_link_libraries(${the_target} ${OPENCV_LINKER_LIBS} ${IPP_LIBS} ${ARGN}) diff --git a/OpenCVPCHSupport.cmake b/OpenCVPCHSupport.cmake index 3c38201..2fdfba5 100644 --- a/OpenCVPCHSupport.cmake +++ b/OpenCVPCHSupport.cmake @@ -34,6 +34,10 @@ ELSE() ENDIF() ENDIF(CMAKE_COMPILER_IS_GNUCXX) +#if (ANDROID) + #SET(PCHSupport_FOUND FALSE) +#endif() + MACRO(_PCH_GET_COMPILE_FLAGS _out_compile_flags) diff --git a/android/Android.mk.in b/android/Android.mk.in deleted file mode 100644 index 65d0826..0000000 --- a/android/Android.mk.in +++ /dev/null @@ -1,17 +0,0 @@ -LOCAL_PATH := ${CMAKE_CURRENT_SOURCE_DIR} - -include $(CLEAR_VARS) - -LOCAL_MODULE := ${android_module_name} - -ifeq ($(TARGET_ARCH_ABI),armeabi-v7a) -LOCAL_ARM_NEON := true -endif - -LOCAL_SRC_FILES := ${android_srcs} - -LOCAL_CFLAGS := ${android_defs} - -LOCAL_C_INCLUDES := ${include_dirs} $(LOCAL_PATH) - -include $(BUILD_STATIC_LIBRARY) diff --git a/android/Android.mk.master.in b/android/Android.mk.master.in deleted file mode 100644 index d2a0add..0000000 --- a/android/Android.mk.master.in +++ /dev/null @@ -1,5 +0,0 @@ -include android-opencv.mk -include modules/Android.mk -include 3rdparty/Android.mk -#include zlib-android/Android.mk - diff --git a/android/Android.mk.modules.in b/android/Android.mk.modules.in deleted file mode 100644 index 8338432..0000000 --- a/android/Android.mk.modules.in +++ /dev/null @@ -1,2 +0,0 @@ -include $(call all-subdir-makefiles) - diff --git a/android/AndroidCVModule.cmake b/android/AndroidCVModule.cmake deleted file mode 100644 index c7a5de0..0000000 --- a/android/AndroidCVModule.cmake +++ /dev/null @@ -1,28 +0,0 @@ -macro(define_android_manual name lib_srcs includes) -set(android_module_name ${name}) -set(android_srcs "") -set(include_dirs "${includes}") -foreach(f ${lib_srcs}) - string(REPLACE "${CMAKE_CURRENT_SOURCE_DIR}/" "" n_f ${f}) - set(android_srcs "${android_srcs} ${n_f}") -endforeach() -configure_file("${CMAKE_SOURCE_DIR}/Android.mk.in" "${CMAKE_CURRENT_BINARY_DIR}/Android.mk") -endmacro() - - -macro(define_3rdparty_module name) - file(GLOB lib_srcs "*.c" "*.cpp") - file(GLOB lib_int_hdrs "*.h*") - define_android_manual(${name} "${lib_srcs}" "$(LOCAL_PATH)/../include") -endmacro() - -macro(define_opencv_module name) - file(GLOB lib_srcs "src/*.cpp") - file(GLOB lib_int_hdrs "src/*.h*") - define_android_manual(opencv_${name} "${lib_srcs}" "$(LOCAL_PATH)/src $(OPENCV_INCLUDES)") -endmacro() - - - - - diff --git a/android/AndroidManifest.xml.in b/android/AndroidManifest.xml.in deleted file mode 100644 index 3ce558f..0000000 --- a/android/AndroidManifest.xml.in +++ /dev/null @@ -1,7 +0,0 @@ - - - - \ No newline at end of file diff --git a/android/Application.mk.in b/android/Application.mk.in deleted file mode 100644 index c504912..0000000 --- a/android/Application.mk.in +++ /dev/null @@ -1,6 +0,0 @@ -APP_BUILD_SCRIPT := $(call my-dir)/Android.mk -APP_PROJECT_PATH := $(call my-dir) -# The ARMv7 is significanly faster due to the use of the hardware FPU -APP_ABI := ${ARM_TARGETS} -APP_MODULES := png jpeg jasper zlib opencv_lapack opencv_core opencv_imgproc opencv_ml opencv_highgui opencv_features2d \ - opencv_legacy opencv_objdetect opencv_calib3d opencv_video opencv_contrib opencv_flann diff --git a/android/CMakeCache.android.initial.cmake b/android/CMakeCache.android.initial.cmake new file mode 100644 index 0000000..be8c492 --- /dev/null +++ b/android/CMakeCache.android.initial.cmake @@ -0,0 +1,110 @@ +######################## +# Initial cache settings for opencv on android +# run cmake with: +# cmake -C +######################## +#Build all examples +set(BUILD_EXAMPLES OFF CACHE BOOL "" ) + +#Build Reference Manual +set(BUILD_REFMAN OFF CACHE BOOL "" ) + +#Build LaTeX OpenCV Documentation +#set(BUILD_LATEX_DOCS OFF CACHE BOOL "" ) + +#Build with Python support +set(BUILD_NEW_PYTHON_SUPPORT OFF CACHE BOOL "" ) + +#Build a installer with the SDK +set(BUILD_PACKAGE OFF CACHE BOOL "" ) + +#Build shared libraries (.dll/.so CACHE BOOL "" ) instead of static ones (.lib/.a CACHE BOOL "" ) +set(BUILD_SHARED_LIBS OFF CACHE BOOL "" ) + +#Build 3rd party libraries +set(OPENCV_BUILD_3RDPARTY_LIBS ON CACHE BOOL "" ) + +#Build tests +set(BUILD_TESTS OFF CACHE BOOL "" ) + +#Choose the type of build, options are: None Debug Release RelWithDebInfo +# MinSizeRel. +set(CMAKE_BUILD_TYPE "Release" CACHE STRING "" ) + +#Include IEEE1394 support +set(WITH_1394 OFF CACHE BOOL "" ) + +#Include NVidia Cuda Runtime support +set(WITH_CUDA OFF CACHE BOOL "" ) + +#Include Eigen2/Eigen3 support +set(WITH_EIGEN2 OFF CACHE BOOL "" ) + +#Include FFMPEG support +set(WITH_FFMPEG OFF CACHE BOOL "" ) + +#Include Gstreamer support +set(WITH_GSTREAMER OFF CACHE BOOL "" ) + +#Include GTK support +set(WITH_GTK OFF CACHE BOOL "" ) + +#Include Intel IPP support +set(WITH_IPP OFF CACHE BOOL "" ) + +#Include JPEG2K support +set(WITH_JASPER ON CACHE BOOL "" ) + +#Include JPEG support +set(WITH_JPEG ON CACHE BOOL "" ) + +#Include ILM support via OpenEXR +set(WITH_OPENEXR OFF CACHE BOOL "" ) + +#Include OpenNI support +set(WITH_OPENNI OFF CACHE BOOL "" ) + +#Include PNG support +set(WITH_PNG ON CACHE BOOL "" ) + +#Include Prosilica GigE support +set(WITH_PVAPI OFF CACHE BOOL "" ) + +#Build with Qt Backend support +set(WITH_QT OFF CACHE BOOL "" ) + +#Add OpenGL extension to Qt +set(WITH_QT_OPENGL OFF CACHE BOOL "" ) + +#Include Intel TBB support +set(WITH_TBB OFF CACHE BOOL "" ) + +#Include TIFF support +set(WITH_TIFF ON CACHE BOOL "" ) + +#Include Unicap support (GPL CACHE BOOL "" ) +set(WITH_UNICAP OFF CACHE BOOL "" ) + +#Include Video 4 Linux support +set(WITH_V4L OFF CACHE BOOL "" ) + +#Include Xine support (GPL CACHE BOOL "" ) +set(WITH_XINE OFF CACHE BOOL "" ) + +#Enable SSE instructions +SET( ENABLE_SSE OFF CACHE BOOL "" ) + +#Enable SSE2 instructions +SET( ENABLE_SSE2 OFF CACHE BOOL "" ) + +#Enable SSE3 instructions +SET( ENABLE_SSE3 OFF CACHE BOOL "" ) + +#Enable SSE4.1 instructions +SET( ENABLE_SSE41 OFF CACHE BOOL "" ) + +#Enable SSE4.2 instructions +SET( ENABLE_SSE42 OFF CACHE BOOL "" ) + +#Enable SSSE3 instructions +SET( ENABLE_SSSE3 OFF CACHE BOOL "" ) diff --git a/android/CMakeLists.txt b/android/CMakeLists.txt deleted file mode 100644 index 302cce3..0000000 --- a/android/CMakeLists.txt +++ /dev/null @@ -1,93 +0,0 @@ -# ---------------------------------------------------------------------------- -# Root CMake file for Android Opencv Build -# -# To build with cmake -# $ mkdir build -# $ cd build -# $ cmake .. -# $ make -# Make sure to set the path in the cache for the crystax ndk available -# here: -# http://www.crystax.net/android/ndk-r4.php -# -# - initial version August 2010 Ethan Rublee ethan.ruble@gmail.com -# -# ---------------------------------------------------------------------------- - -project(android-opencv) - -cmake_minimum_required(VERSION 2.8) - -include(AndroidCVModule.cmake REQUIRED) - -set(opencv_root "${CMAKE_SOURCE_DIR}/.." CACHE STRING "opencv source root directory") -if(NOT EXISTS ${opencv_root}) -message(FATAL_ERROR "Cannot find your opencv root directory!" ) -endif() -set(ANDROID true) -set(WITH_JASPER true) -set(JASPER_FOUND false) -set(WITH_PNG true) -set(WITH_JPEG true) - -file(GLOB module_includes "${opencv_root}/modules/[a-zA-Z]*") - -list(REMOVE_ITEM module_includes ${opencv_root}/modules/CMakeLists.txt) - -set(module_includes ${module_includes} ${CMAKE_SOURCE_DIR}/../3rdparty $(OPENCV_BUILD_ROOT) ${opencv_root} ) -foreach(mdir ${module_includes}) - string(REPLACE "${opencv_root}" "$(OPENCV_ROOT)" n_f ${mdir}) - set(android_module_include_dirs "${android_module_include_dirs} ${n_f}/include") -endforeach() - -set(PossibleArmTargets - "armeabi armeabi-v7a;armeabi;armeabi-v7a") -set(ARM_TARGETS "armeabi armeabi-v7a" CACHE STRING "the arm targets for android, recommend armeabi-v7a for floating point support and neon") -set_property(CACHE ARM_TARGETS PROPERTY STRINGS ${PossibleArmTargets} ) - - - -configure_file("${CMAKE_SOURCE_DIR}/Android.mk.master.in" "${CMAKE_BINARY_DIR}/Android.mk") -configure_file("${CMAKE_SOURCE_DIR}/Application.mk.in" "${CMAKE_BINARY_DIR}/Application.mk") -configure_file("${CMAKE_SOURCE_DIR}/AndroidManifest.xml.in" "${CMAKE_BINARY_DIR}/AndroidManifest.xml") -configure_file("${CMAKE_SOURCE_DIR}/default.properties.in" "${CMAKE_BINARY_DIR}/default.properties") -configure_file("${CMAKE_SOURCE_DIR}/cvconfig.h.in" "${CMAKE_BINARY_DIR}/include/cvconfig.h") - -add_subdirectory(${opencv_root}/modules "${CMAKE_BINARY_DIR}/modules") - -add_subdirectory(${opencv_root}/3rdparty "${CMAKE_BINARY_DIR}/3rdparty") - -set(NDK_ROOT "$ENV{HOME}/android-ndk-r4-crystax" CACHE STRING "the crystax ndk directory") -if(NOT EXISTS ${NDK_ROOT}) -message(FATAL_ERROR "Cannot find your ndk root directory! please download and -unzip the android ndk from crystax to the directory specified by NDK_ROOT -You may download the crystax ndk from: - http://www.crystax.net/android/ndk-r4.php" ) -endif() -set(J "2" CACHE STRING "how many processes for make -j ") - -ADD_CUSTOM_COMMAND( -OUTPUT android-opencv -DEPENDS ${CMAKE_BINARY_DIR}/Android.mk -COMMAND "${NDK_ROOT}/ndk-build" -ARGS --directory=${CMAKE_BINARY_DIR} NDK_APPLICATION_MK=Application.mk -j${J} -) - -configure_file("${CMAKE_SOURCE_DIR}/android-opencv.mk.in" "${CMAKE_BINARY_DIR}/android-opencv.mk") - -ADD_CUSTOM_TARGET(ndk ALL echo - DEPENDS android-opencv -) - -message(STATUS "Make will use make -j${J} - for speeding up build - you may change this in the cache") -message(STATUS "The NDK directory is ${NDK_ROOT}") -message(STATUS "OpenCV source root is ${opencv_root}") -message(STATUS "just run make - and grab some coffee or tea ;)") -message(STATUS "The android opencv libs will be located in ${CMAKE_BINARY_DIR}/obj/local/armeabi*/") - - - - - - - diff --git a/android/README.android.txt b/android/README.android.txt index dec230c..99fa368 100644 --- a/android/README.android.txt +++ b/android/README.android.txt @@ -1,39 +1,77 @@ Author: Ethan Rublee email: ethan.rublee@gmail.com +######################################################## +Prerequisites: +######################################################## + android-ndk-r5b http://developer.android.com/sdk/ndk/index.html + the official ndk with standalone toolchain + android-cmake http://code.google.com/p/android-cmake/ + this is for the cmake toolchain for android + mercurial + sudo apt-get install mercurial + cmake + opencv (you should have this if you're reading this file :) - -To build with cmake: +######################################################## +Quick NDK Setup(ubuntu and bash): +######################################################## +create some working directory: + WORK=$HOME/android_dev + cd $WORK + +now get the android-cmake project with mercurial + hg clone https://android-cmake.googlecode.com/hg/ android-cmake -mkdir build -cd build -cmake .. -make +there is a convenience script in there for pulling down and setting up the +android ndk as a standalone toolchain + cd android-cmake/scripts + ./get_ndk_toolchain_linux.sh $WORK +add the cmake toolchain location to your bashrc or otherwise export it to your env + echo export ANDTOOLCHAIN=$WORK/android-cmake/toolchain/android.toolchain.cmake >> $HOME/.bashrc +######################################################## +Quick opencv build(ubuntu and bash): +######################################################## +Make sure you either source your bashrc or otherwise export the ANDTOOLCHAIN variable. -Make sure to set the path in the cache for the crystax ndk available -here: - http://www.crystax.net/android/ndk-r4.php - - -to include in an android project - -just include the generated android-opencv.mk in you android ndk project -(in an Android.mk file) -with: +There is a script in the android folder for running cmake with the proper cache +variables set. It is recommended that you use this to setup a smake build directory. + cd opencv/android + sh ./cmake_android.sh -include android-opencv.mk +You should now see a build directory, that is ready to be made. + cd build + make -j8 -this defines OPENCV_INCLUDES and OPENCV_LIBS - which you should add to your -makefiles like: +That will build most of the opencv modules, except for those that don't make sense +on android - gpu, etc.. + +To install to the toolchain: + make install +######################################################## +Using opencv in you're cmake own projects. +######################################################## +Use the cmake find script for opencv: + find_package(OpenCV REQUIRED) + +Then when you run cmake, use: + cmake -DCMAKE_TOOLCHAIN_FILE=$ANDTOOLCHAIN .. -#define OPENCV_INCLUDES and OPENCV_LIBS -include $(PATH_TO_OPENCV_ANDROID_BUILD)/android-opencv.mk +And direct your cmake cache for OpenCV_Dir to the path that you build opencv for android. + something like : opencv/android/build -LOCAL_LDLIBS += $(OPENCV_LIBS) - -LOCAL_C_INCLUDES += $(OPENCV_INCLUDES) +To avoid setting the cmake cache for OpenCV_Dir, you can just "install" opencv to your +android toolchain. Run the following from the opencv/android/build path: + make install -for now, you also need to cd to android-jni and run make -this will create the android shared library with some useful functionality -that may be reused in android projects. +######################################################## +android targets +######################################################## +You may wish to build android for multiple hardware targets. +Just change the cmake cache ARM_TARGETS to either: + "armeabi" "armeab-v7a" "armeab-v7a with NEON" + +You may install each of these to the toolchain, and they should be linked against +properly via way of the android-cmake toolchain. diff --git a/android/android-cmake/CMakeLists.txt b/android/android-cmake/CMakeLists.txt deleted file mode 100644 index 5f404fc..0000000 --- a/android/android-cmake/CMakeLists.txt +++ /dev/null @@ -1,90 +0,0 @@ -# ---------------------------------------------------------------------------- -# Root CMake file for Android Opencv Build -# -# To build with cmake -# $ mkdir build -# $ cd build -# $ cmake .. -# $ make -# Make sure to set the path in the cache for the crystax ndk available -# here: -# http://www.crystax.net/android/ndk-r4.php -# -# - initial version August 2010 Ethan Rublee ethan.rublee@gmail.com -# -# ---------------------------------------------------------------------------- - -project(android-opencv-shared) - -cmake_minimum_required(VERSION 2.8) - -set(opencv_root "$ENV{HOME}/opencv" CACHE PATH "opencv source root directory") -if(NOT EXISTS ${opencv_root}) -message(FATAL_ERROR "Cannot find your opencv root directory!" ) -endif() - -set(android_opencv_mk "${opencv_root}/android/build/android-opencv.mk" cache FILE "the generated android-opencv.mk file") -if(NOT EXISTS ${android_opencv_mk}) -message(FATAL_ERROR "please locate the cmake generated android-opencv.mk file, usually in the android/build directory...") -endif() - -set(ANDROID true) - -file(GLOB module_includes "${opencv_root}/modules/[a-zA-Z]*") - -list(REMOVE_ITEM module_includes ${opencv_root}/modules/CMakeLists.txt) - -set(module_includes ${module_includes} ${CMAKE_SOURCE_DIR}/../3rdparty $(OPENCV_BUILD_ROOT) ) -foreach(mdir ${module_includes}) - string(REPLACE "${opencv_root}" "$(OPENCV_ROOT)" n_f ${mdir}) - set(android_module_include_dirs "${android_module_include_dirs} ${n_f}/include") -endforeach() - -configure_file("${CMAKE_SOURCE_DIR}/Android.mk.master.in" "${CMAKE_BINARY_DIR}/Android.mk") -configure_file("${CMAKE_SOURCE_DIR}/Application.mk.in" "${CMAKE_BINARY_DIR}/Application.mk") -configure_file("${CMAKE_SOURCE_DIR}/AndroidManifest.xml.in" "${CMAKE_BINARY_DIR}/AndroidManifest.xml") -configure_file("${CMAKE_SOURCE_DIR}/default.properties.in" "${CMAKE_BINARY_DIR}/default.properties") - -set(NDK_ROOT "$ENV{HOME}/android-ndk-r4-crystax" CACHE STRING "the crystax ndk directory") -if(NOT EXISTS ${NDK_ROOT}) -message(FATAL_ERROR "Cannot find your ndk root directory! please download and -unzip the android ndk from crystax to the directory specified by NDK_ROOT -You may download the crystax ndk from: - http://www.crystax.net/android/ndk-r4.php" ) -endif() - -set(J "2" CACHE STRING "how many processes for make -j ") - -ADD_CUSTOM_COMMAND( -OUTPUT android-ndk -DEPENDS ${CMAKE_BINARY_DIR}/Android.mk -COMMAND "${NDK_ROOT}/ndk-build" -ARGS --directory=${CMAKE_BINARY_DIR} NDK_APPLICATION_MK=Application.mk -j${J} -) - -ADD_CUSTOM_COMMAND( -OUTPUT android-swig -DEPENDS ${SWIG_MAIN} -COMMAND "swig" -ARGS --directory=${CMAKE_BINARY_DIR} NDK_APPLICATION_MK=Application.mk -j${J} -) - - -configure_file("${CMAKE_SOURCE_DIR}/android-opencv.mk.in" "${CMAKE_BINARY_DIR}/android-opencv.mk") - -ADD_CUSTOM_TARGET(ndk ALL echo - DEPENDS android-ndk -) - -message(STATUS "Make will use make -j${J} - for speeding up build - you may change this in the cache") -message(STATUS "The NDK directory is ${NDK_ROOT}") -message(STATUS "OpenCV source root is ${opencv_root}") -message(STATUS "just run make - and grab some coffee or tea ;)") -message(STATUS "The android opencv libs will be located in ${CMAKE_BINARY_DIR}/obj/local/armeabi*/") - - - - - - - diff --git a/android/android-jni/AndroidManifest.xml b/android/android-jni/AndroidManifest.xml deleted file mode 100644 index f0a9639..0000000 --- a/android/android-jni/AndroidManifest.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - - - - - - - - - diff --git a/android/android-jni/Makefile b/android/android-jni/Makefile deleted file mode 100644 index 9aa6da4..0000000 --- a/android/android-jni/Makefile +++ /dev/null @@ -1,78 +0,0 @@ -# The path to the NDK, requires crystax version r-4 for now, due to support -# for the standard library - -# load environment from local make file -LOCAL_ENV_MK=local.env.mk -ifneq "$(wildcard $(LOCAL_ENV_MK))" "" -include $(LOCAL_ENV_MK) -else -$(shell cp sample.$(LOCAL_ENV_MK) $(LOCAL_ENV_MK)) -$(info ERROR local environement not setup! try:) -$(info gedit $(LOCAL_ENV_MK)) -$(error Please setup the $(LOCAL_ENV_MK) - the default was just created') -endif - -ifndef ARM_TARGETS -ARM_TARGETS="armeabi armeabi-v7a" -endif - -ANDROID_NDK_BASE = $(ANDROID_NDK_ROOT) - -$(info OPENCV_CONFIG = $(OPENCV_CONFIG)) - -# The name of the native library -LIBNAME = libandroid-opencv.so - -# Find all the C++ sources in the native folder -SOURCES = $(wildcard jni/*.cpp) -HEADERS = $(wildcard jni/*.h) -SWIG_IS = $(wildcard jni/*.i) - -ANDROID_MKS = $(wildcard jni/*.mk) - -SWIG_MAIN = jni/android-cv.i - -SWIG_JAVA_DIR = src/com/opencv/jni -SWIG_JAVA_OUT = $(wildcard $(SWIG_JAVA_DIR)/*.java) - -SWIG_C_DIR = jni/gen -SWIG_C_OUT = $(SWIG_C_DIR)/android_cv_wrap.cpp - -# The real native library stripped of symbols -LIB = libs/armeabi-v7a/$(LIBNAME) libs/armeabi/$(LIBNAME) - - -all: $(LIB) nogdb - - -#calls the ndk-build script, passing it OPENCV_ROOT and OPENCV_LIBS_DIR -$(LIB): $(SWIG_C_OUT) $(SOURCES) $(HEADERS) $(ANDROID_MKS) - $(ANDROID_NDK_BASE)/ndk-build OPENCV_CONFIG=$(OPENCV_CONFIG) \ - PROJECT_PATH=$(PROJECT_PATH) ARM_TARGETS=$(ARM_TARGETS) V=$(V) $(NDK_FLAGS) - - -#this creates the swig wrappers -$(SWIG_C_OUT): $(SWIG_IS) - make clean-swig &&\ - mkdir -p $(SWIG_C_DIR) &&\ - mkdir -p $(SWIG_JAVA_DIR) &&\ - swig -java -c++ -package "com.opencv.jni" \ - -outdir $(SWIG_JAVA_DIR) \ - -o $(SWIG_C_OUT) $(SWIG_MAIN) - - -#clean targets -.PHONY: clean clean-swig cleanall nogdb - -nogdb: $(LIB) - rm -f libs/armeabi*/gdb* - -#this deletes the generated swig java and the generated c wrapper -clean-swig: - rm -f $(SWIG_JAVA_OUT) $(SWIG_C_OUT) - -#does clean-swig and then uses the ndk-build clean -clean: clean-swig - $(ANDROID_NDK_BASE)/ndk-build OPENCV_CONFIG=$(OPENCV_CONFIG) \ - PROJECT_PATH=$(PROJECT_PATH) clean ARM_TARGETS=$(ARM_TARGETS) V=$(V) $(NDK_FLAGS) - diff --git a/android/android-jni/README.txt b/android/android-jni/README.txt deleted file mode 100644 index 36eb32a..0000000 --- a/android/android-jni/README.txt +++ /dev/null @@ -1,41 +0,0 @@ -android-jni - -this is an example of an android library project that has some reusable -code that exposes part of OpenCV to android. In particular this provides a -native camera interface for loading live video frames from the android camera -into native opencv functions(as cv::Mat's) - -pre-reqs: -* build the opencv/android libraries - up one directory -* you need swig in you path for android-jni - on ubuntu - sudo apt-get install swig - others: http://www.swig.org/ - -to build: - -make - -that should work... If it doesn't make sure to edit the generated local.env.mk -to reflect your machine's setup - -see the sample for how to use this in your own projects - -If you only support armeabi-v7a or armeabi your final apks will be much smaller. - -To build the class files, either start a new Android project from existing sources -in eclipse -or from the commmand line: -sh project_create.sh -ant debug - -This should be linked to in your android projects, if you would like to reuse the -code. See Calibration or CVCamera in the opencv/android/apps directory - -With cdt installed in eclipse, you may also "convert to C++ project" once you have -opened this as an android project. Select makefile project->toolchain other to do this. - -Eclipse tip of the day: -You may get build warnings when linking to the project, complainging about duplicate something -or other in you .svn directories. Right click project->settings->java build path->source->excude paths->add -.svn/ and **/.svn/ should do it ;) - diff --git a/android/android-jni/jni/Android.mk b/android/android-jni/jni/Android.mk deleted file mode 100644 index 8f38719..0000000 --- a/android/android-jni/jni/Android.mk +++ /dev/null @@ -1,31 +0,0 @@ -# date: Summer, 2010 -# author: Ethan Rublee -# contact: ethan.rublee@gmail.com -# -LOCAL_PATH := $(call my-dir) - -include $(CLEAR_VARS) - -#define OPENCV_INCLUDES and OPENCV_LIBS -include $(OPENCV_CONFIG) - -LOCAL_LDLIBS += $(OPENCV_LIBS) -llog -lGLESv2 - -LOCAL_C_INCLUDES += $(OPENCV_INCLUDES) - -LOCAL_MODULE := android-opencv - -LOCAL_SRC_FILES := gen/android_cv_wrap.cpp image_pool.cpp \ - gl_code.cpp Calibration.cpp - - -#ifeq ($(TARGET_ARCH_ABI),armeabi-v7a) -# LOCAL_CFLAGS := -DHAVE_NEON=1 -# LOCAL_SRC_FILES += yuv2rgb_neon.c.neon -#else - LOCAL_SRC_FILES += yuv420sp2rgb.c -#endif - - -include $(BUILD_SHARED_LIBRARY) - diff --git a/android/android-jni/jni/Application.mk b/android/android-jni/jni/Application.mk deleted file mode 100644 index f23b245..0000000 --- a/android/android-jni/jni/Application.mk +++ /dev/null @@ -1,2 +0,0 @@ -APP_ABI := $(ARM_TARGETS) -APP_MODULES := android-opencv diff --git a/android/android-jni/jni/cv.i b/android/android-jni/jni/cv.i deleted file mode 100644 index 3c47d0a..0000000 --- a/android/android-jni/jni/cv.i +++ /dev/null @@ -1,59 +0,0 @@ -%typemap(javaimports) Mat " -/** Wrapper for the OpenCV Mat object. Good for passing around as a pointer to a Mat. -*/" - -%typemap(javaimports) Size " -/** Wrapper for the OpenCV Size object. Good for setting dimensions of cv::Mat... -*/" - -class Mat { -public: - %immutable; - int rows; - int cols; -}; - -class Size{ -public: - Size(int width,int height); - int width; - int height; - -}; - -template class Ptr -{ -public: - //! empty constructor - Ptr(); - //! take ownership of the pointer. The associated reference counter is allocated and set to 1 - Ptr(_Tp* _obj); - //! calls release() - ~Ptr(); - //! copy constructor. Copies the members and calls addref() - Ptr(const Ptr& ptr); - //! copy operator. Calls ptr.addref() and release() before copying the members - // Ptr& operator = (const Ptr& ptr); - //! increments the reference counter - void addref(); - //! decrements the reference counter. If it reaches 0, delete_obj() is called - void release(); - //! deletes the object. Override if needed - void delete_obj(); - //! returns true iff obj==NULL - bool empty() const; - - - //! helper operators making "Ptr ptr" use very similar to "T* ptr". - _Tp* operator -> (); - // const _Tp* operator -> () const; - - // operator _Tp* (); - // operator const _Tp*() const; - -protected: - _Tp* obj; //< the object pointer. - int* refcount; //< the associated reference counter -}; - -%template(PtrMat) Ptr; \ No newline at end of file diff --git a/android/android-jni/jni/yuv420sp2rgb.c b/android/android-jni/jni/yuv420sp2rgb.c deleted file mode 100644 index 0511df3..0000000 --- a/android/android-jni/jni/yuv420sp2rgb.c +++ /dev/null @@ -1,80 +0,0 @@ -#include -#include - -#include - -/* - YUV 4:2:0 image with a plane of 8 bit Y samples followed by an interleaved - U/V plane containing 8 bit 2x2 subsampled chroma samples. - except the interleave order of U and V is reversed. - - H V - Y Sample Period 1 1 - U (Cb) Sample Period 2 2 - V (Cr) Sample Period 2 2 - */ - -/* - size of a char: - find . -name limits.h -exec grep CHAR_BIT {} \; - */ - -#ifndef max -#define max(a,b) ({typeof(a) _a = (a); typeof(b) _b = (b); _a > _b ? _a : _b; }) -#define min(a,b) ({typeof(a) _a = (a); typeof(b) _b = (b); _a < _b ? _a : _b; }) -#endif - -const int bytes_per_pixel = 2; -void color_convert_common(const unsigned char *pY, const unsigned char *pUV, int width, int height, unsigned char *buffer, int grey) -{ - - int i, j; - int nR, nG, nB; - int nY, nU, nV; - unsigned char *out = buffer; - int offset = 0; - - if (grey) - { - memcpy(out,pY,width*height*sizeof(unsigned char)); - } - else - // YUV 4:2:0 - for (i = 0; i < height; i++) - { - for (j = 0; j < width; j++) - { - nY = *(pY + i * width + j); - nV = *(pUV + (i / 2) * width + bytes_per_pixel * (j / 2)); - nU = *(pUV + (i / 2) * width + bytes_per_pixel * (j / 2) + 1); - - // Yuv Convert - nY -= 16; - nU -= 128; - nV -= 128; - - if (nY < 0) - nY = 0; - - nB = (int)(1192 * nY + 2066 * nU); - nG = (int)(1192 * nY - 833 * nV - 400 * nU); - nR = (int)(1192 * nY + 1634 * nV); - - nR = min(262143, max(0, nR)); - nG = min(262143, max(0, nG)); - nB = min(262143, max(0, nB)); - - nR >>= 10; - nR &= 0xff; - nG >>= 10; - nG &= 0xff; - nB >>= 10; - nB &= 0xff; - - out[offset++] = (unsigned char)nR; - out[offset++] = (unsigned char)nG; - out[offset++] = (unsigned char)nB; - } - } - -} diff --git a/android/android-jni/sample.local.env.mk b/android/android-jni/sample.local.env.mk deleted file mode 100644 index 6bd9240..0000000 --- a/android/android-jni/sample.local.env.mk +++ /dev/null @@ -1,10 +0,0 @@ -#location of android-opencv.mk file that was generated by the cmake build -#of opencv for android -OPENCV_CONFIG=../build/android-opencv.mk - -#the root directory of the crystax r4 ndk - ndk-build should be in this dir -#you can download the ndk from http://www.crystax.net/android/ndk-r4.php -ANDROID_NDK_ROOT=$(HOME)/android-ndk-r4-crystax - -#define only armeabi-v7a to make the final apk smaller or armeabi -ARM_TARGETS="armeabi armeabi-v7a" \ No newline at end of file diff --git a/android/android-opencv.mk.in b/android/android-opencv.mk.in deleted file mode 100644 index 5d5d446..0000000 --- a/android/android-opencv.mk.in +++ /dev/null @@ -1,38 +0,0 @@ -#you may override this if you move the build -#just define it before including this or on the command line - or with -#an environment variable -#this points to the root of the opencv trunk - where the original opencv -#sources are - with modules 3rparty ... -ifndef OPENCV_ROOT -OPENCV_ROOT := ${opencv_root} -endif - -#you may override this same as above -#this points to the actually directory that you built opencv for android from -#maybe in under opencv/android/build -ifndef OPENCV_BUILD_ROOT -OPENCV_BUILD_ROOT := ${CMAKE_BINARY_DIR} -endif - -OPENCV_INCLUDES := ${android_module_include_dirs} - -ANDROID_OPENCV_INCLUDES := $(OPENCV_ROOT)/android/android-jni/jni - -ARMOBJS := local/armeabi -ARMOBJS_V7A := local/armeabi-v7a - -OPENCV_LIB_DIRS := -L$(OPENCV_BUILD_ROOT)/obj/$(ARMOBJS_V7A) \ - -L$(OPENCV_BUILD_ROOT)/obj/$(ARMOBJS) -L$(OPENCV_BUILD_ROOT)/bin/ndk/$(ARMOBJS) \ - -L$(OPENCV_BUILD_ROOT)/bin/ndk/$(ARMOBJS_V7A) - -ANDROID_OPENCV_LIB_DIRS := -L$(OPENCV_ROOT)/android/android-jni/libs/armeabi-v7a \ - -L$(OPENCV_ROOT)/android/android-jni/libs/armeabi - -#order of linking very important ---- may have stuff out of order here, but -#important that modules that are more dependent come first... - -OPENCV_LIBS := $(OPENCV_LIB_DIRS) -lopencv_calib3d -lopencv_features2d -lopencv_objdetect -lopencv_imgproc \ - -lopencv_video -lopencv_highgui -lopencv_ml -lopencv_legacy -lopencv_core -lopencv_lapack -lopencv_flann \ - -lzlib -lpng -ljpeg -ljasper -ANDROID_OPENCV_LIBS := -landroid-opencv $(ANDROID_OPENCV_LIB_DIRS) - diff --git a/android/android-opencv/AndroidManifest.xml b/android/android-opencv/AndroidManifest.xml new file mode 100644 index 0000000..8d3efb0 --- /dev/null +++ b/android/android-opencv/AndroidManifest.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/android/android-opencv/AndroidOpenCVConfig.cmake.in b/android/android-opencv/AndroidOpenCVConfig.cmake.in new file mode 100644 index 0000000..53cdfc2 --- /dev/null +++ b/android/android-opencv/AndroidOpenCVConfig.cmake.in @@ -0,0 +1,44 @@ +# ============================================================================ +# The AndroidOpenCV CMake configuration file +# +# ** File generated automatically, do not modify ** +# +# Usage from an external project: +# In your CMakeLists.txt, add these lines: +# +# FIND_PACKAGE(AndroidOpenCV REQUIRED ) +# TARGET_LINK_LIBRARIES(MY_TARGET_NAME ${AndroidOpenCV_LIBS}) +# +# This file will define the following variables: +# - AndroidOpenCV_LIBS : The list of libraries to links against. +# - AndroidOpenCV_LIB_DIR : The directory where lib files are. +# Calling LINK_DIRECTORIES with this path +# is NOT needed. +# - AndroidOpenCV_INCLUDE_DIRS : The AndroidOpenCV include directories. +# - AndroidOpenCV_SWIG_DIR : The swig path +# +# =========================================================================== + + +# ====================================================== +# Include directories to add to the user project: +# ====================================================== + +# Provide the include directories to the caller +SET(AndroidOpenCV_INCLUDE_DIRS @CMAKE_INCLUDE_DIRS_CONFIGCMAKE@) +INCLUDE_DIRECTORIES(${AndroidOpenCV_INCLUDE_DIRS}) + +# ====================================================== +# Link directories to add to the user project: +# ====================================================== + +# Provide the libs directory anyway, it may be needed in some cases. +SET(AndroidOpenCV_LIB_DIR @CMAKE_LIB_DIRS_CONFIGCMAKE@) +LINK_DIRECTORIES(${AndroidOpenCV_LIB_DIR}) + +# ====================================================== +# Libraries to add to the user project: +# ====================================================== +SET(AndroidOpenCV_LIBS @CMAKE_LIBS_CONFIGCMAKE@) + +SET(AndroidOpenCV_SWIG_DIR @CMAKE_SWIG_DIR_CONFIGCMAKE@) diff --git a/android/android-opencv/CMakeLists.txt b/android/android-opencv/CMakeLists.txt new file mode 100644 index 0000000..2737766 --- /dev/null +++ b/android/android-opencv/CMakeLists.txt @@ -0,0 +1,5 @@ +cmake_minimum_required(VERSION 2.8) + +project(android-jni) + +add_subdirectory(jni) diff --git a/android/android-opencv/README.txt b/android/android-opencv/README.txt new file mode 100644 index 0000000..c7f2195 --- /dev/null +++ b/android/android-opencv/README.txt @@ -0,0 +1,13 @@ +========================================= +CMake Build +========================================= +mkdir build +cd build +cmake -DCMAKE_TOOLCHAIN_FILE=$ANDTOOLCHAIN .. + +========================================= +Android Build +========================================= +sh project_create.sh +ant compile +ant install diff --git a/android/android-jni/default.properties b/android/android-opencv/default.properties similarity index 94% rename from android/android-jni/default.properties rename to android/android-opencv/default.properties index b586c76..b308918 100644 --- a/android/android-jni/default.properties +++ b/android/android-opencv/default.properties @@ -7,6 +7,7 @@ # "build.properties", and override values to adapt the script to your # project structure. -android.library=true +#android.library=true # Project target. target=android-7 +android.library=true diff --git a/android/android-opencv/jni/CMakeLists.txt b/android/android-opencv/jni/CMakeLists.txt new file mode 100644 index 0000000..1f26f0d --- /dev/null +++ b/android/android-opencv/jni/CMakeLists.txt @@ -0,0 +1,70 @@ +######################################################### +# Find opencv and android-opencv +######################################################### + +set(OpenCV_DIR ${CMAKE_SOURCE_DIR}/../build + CACHE PATH "The path where you built opencv for android") +find_package(OpenCV REQUIRED) + +######################################################### +#c flags, included, and lib dependencies +######################################################### +#notice the "recycling" of CMAKE_C_FLAGS +#this is necessary to pick up android flags +set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -pedantic -fPIC" ) + +INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/include) + +set( LIBRARY_DEPS ${OpenCV_LIBS} ) +if(ANDROID) + set( LIBRARY_DEPS ${LIBRARY_DEPS} log dl GLESv2) +endif(ANDROID) + +######################################################### +#SWIG STUFF +######################################################### +#the java package to place swig generated java files in +set(MY_PACKAGE com.opencv.jni) + +if(NOT ANDROID) + #non android swig and jni + #jni is available by default on android + find_package(JNI REQUIRED) + include_directories(${JNI_INCLUDE_DIRS}) + FIND_PACKAGE(SWIG) +endif() + +INCLUDE(${SWIG_USE_FILE}) #on android this is found by the cmake toolchain + +if(ANDROID) + #this will set the output path for the java package + #and properly create the package declarations in generated java sources + SET_SWIG_JAVA_PACKAGE( ${MY_PACKAGE} ) #defined in the android toolchain +endif(ANDROID) + +SET_SOURCE_FILES_PROPERTIES(android-cv.i PROPERTIES CPLUSPLUS ON) + +SWIG_ADD_MODULE(android-opencv java + android-cv.i + Calibration.cpp + gl_code.cpp + image_pool.cpp + yuv420sp2rgb.c + #yuv420rgb888c.c + #yuv420rgb888.s + yuv2rgb16tab.c + ) + +target_link_libraries(android-opencv ${LIBRARY_DEPS} ) + +################################################################### +# Setup the configure file for other's to link against. +################################################################### +set(CMAKE_INCLUDE_DIRS_CONFIGCMAKE ${CMAKE_CURRENT_SOURCE_DIR}/include) +set(CMAKE_LIB_DIRS_CONFIGCMAKE ${LIBRARY_OUTPUT_PATH}) +set(CMAKE_LIBS_CONFIGCMAKE android-opencv) +set(CMAKE_SWIG_DIR_CONFIGCMAKE ${CMAKE_CURRENT_SOURCE_DIR}) +configure_file( "${CMAKE_SOURCE_DIR}/AndroidOpenCVConfig.cmake.in" + "${CMAKE_BINARY_DIR}/AndroidOpenCVConfig.cmake" + IMMEDIATE @ONLY) diff --git a/android/android-jni/jni/Calibration.cpp b/android/android-opencv/jni/Calibration.cpp similarity index 100% rename from android/android-jni/jni/Calibration.cpp rename to android/android-opencv/jni/Calibration.cpp diff --git a/android/android-jni/jni/Calibration.i b/android/android-opencv/jni/Calibration.i similarity index 100% rename from android/android-jni/jni/Calibration.i rename to android/android-opencv/jni/Calibration.i diff --git a/android/android-jni/jni/android-cv-typemaps.i b/android/android-opencv/jni/android-cv-typemaps.i similarity index 100% rename from android/android-jni/jni/android-cv-typemaps.i rename to android/android-opencv/jni/android-cv-typemaps.i diff --git a/android/android-jni/jni/android-cv.i b/android/android-opencv/jni/android-cv.i similarity index 99% rename from android/android-jni/jni/android-cv.i rename to android/android-opencv/jni/android-cv.i index 54eba06..f6661aa 100644 --- a/android/android-jni/jni/android-cv.i +++ b/android/android-opencv/jni/android-cv.i @@ -8,7 +8,6 @@ before loading any lib that depends on this. %{ #include "image_pool.h" #include "glcamera.h" - using namespace cv; %} #ifndef SWIGIMPORTED diff --git a/android/android-jni/jni/buffers.i b/android/android-opencv/jni/buffers.i similarity index 96% rename from android/android-jni/jni/buffers.i rename to android/android-opencv/jni/buffers.i index d601120..42cca9c 100644 --- a/android/android-jni/jni/buffers.i +++ b/android/android-opencv/jni/buffers.i @@ -51,7 +51,7 @@ return $jnicall; } %typemap(in) CTYPE* LABEL { - $1 = (*jenv)->GetDirectBufferAddress(jenv, $input); + $1 = (CTYPE*)(jenv)->GetDirectBufferAddress( $input); if ($1 == NULL) { SWIG_JavaThrowException(jenv, SWIG_JavaRuntimeException, "Unable to get address of direct buffer. Buffer must be allocated direct."); } @@ -92,7 +92,7 @@ NIO_BUFFER_TYPEMAP(double, BUFF, java.nio.DoubleBuffer); return $jnicall; } %typemap(in) CTYPE* INBUFF { - $1 = (*jenv)->GetDirectBufferAddress(jenv, $input); + $1 = (jenv)->GetDirectBufferAddress($input); if ($1 == NULL) { SWIG_JavaThrowException(jenv, SWIG_JavaRuntimeException, "Unable to get address of direct buffer. Buffer must be allocated direct."); } @@ -116,7 +116,7 @@ NIO_BUFFER_TYPEMAP(double, BUFF, java.nio.DoubleBuffer); return $jnicall; } %typemap(in) CTYPE* OUTBUFF { - $1 = (*jenv)->GetDirectBufferAddress(jenv, $input); + $1 = (jenv)->GetDirectBufferAddress( $input); if ($1 == NULL) { SWIG_JavaThrowException(jenv, SWIG_JavaRuntimeException, "Unable to get address of direct buffer. Buffer must be allocated direct."); } @@ -147,7 +147,7 @@ UNSIGNED_NIO_BUFFER_TYPEMAP(unsigned long, 4, java.nio.LongBuffer, permafrost.hd return $jnicall; } %typemap(in) unsigned char* BUFF { - $1 = (*jenv)->GetDirectBufferAddress(jenv, $input); + $1 = (const char*)(jenv)->GetDirectBufferAddress( $input); if ($1 == NULL) { SWIG_JavaThrowException(jenv, SWIG_JavaRuntimeException, "Unable to get address of direct buffer. Buffer must be allocated direct."); } diff --git a/android/android-opencv/jni/cv.i b/android/android-opencv/jni/cv.i new file mode 100644 index 0000000..167d55d --- /dev/null +++ b/android/android-opencv/jni/cv.i @@ -0,0 +1,156 @@ +%typemap(javaimports) Mat " +/** Wrapper for the OpenCV Mat object. Good for passing around as a pointer to a Mat. +*/" + +%typemap(javaimports) Size " +/** Wrapper for the OpenCV Size object. Good for setting dimensions of cv::Mat... +*/" + + +class Size{ +public: + Size(); + Size(int width,int height); + ~Size(); + int width; + int height; +}; + +#define CV_CN_MAX 512 +#define CV_CN_SHIFT 3 +#define CV_DEPTH_MAX (1 << CV_CN_SHIFT) + +#define CV_8U 0 +#define CV_8S 1 +#define CV_16U 2 +#define CV_16S 3 +#define CV_32S 4 +#define CV_32F 5 +#define CV_64F 6 +#define CV_USRTYPE1 7 + +#define CV_MAT_DEPTH_MASK (CV_DEPTH_MAX - 1) +#define CV_MAT_DEPTH(flags) ((flags) & CV_MAT_DEPTH_MASK) + +#define CV_MAKETYPE(depth,cn) (CV_MAT_DEPTH(depth) + (((cn)-1) << CV_CN_SHIFT)) +#define CV_MAKE_TYPE CV_MAKETYPE + +#define CV_8UC1 CV_MAKETYPE(CV_8U,1) +#define CV_8UC2 CV_MAKETYPE(CV_8U,2) +#define CV_8UC3 CV_MAKETYPE(CV_8U,3) +#define CV_8UC4 CV_MAKETYPE(CV_8U,4) +#define CV_8UC(n) CV_MAKETYPE(CV_8U,(n)) + +#define CV_8SC1 CV_MAKETYPE(CV_8S,1) +#define CV_8SC2 CV_MAKETYPE(CV_8S,2) +#define CV_8SC3 CV_MAKETYPE(CV_8S,3) +#define CV_8SC4 CV_MAKETYPE(CV_8S,4) +#define CV_8SC(n) CV_MAKETYPE(CV_8S,(n)) + +#define CV_16UC1 CV_MAKETYPE(CV_16U,1) +#define CV_16UC2 CV_MAKETYPE(CV_16U,2) +#define CV_16UC3 CV_MAKETYPE(CV_16U,3) +#define CV_16UC4 CV_MAKETYPE(CV_16U,4) +#define CV_16UC(n) CV_MAKETYPE(CV_16U,(n)) + +#define CV_16SC1 CV_MAKETYPE(CV_16S,1) +#define CV_16SC2 CV_MAKETYPE(CV_16S,2) +#define CV_16SC3 CV_MAKETYPE(CV_16S,3) +#define CV_16SC4 CV_MAKETYPE(CV_16S,4) +#define CV_16SC(n) CV_MAKETYPE(CV_16S,(n)) + +#define CV_32SC1 CV_MAKETYPE(CV_32S,1) +#define CV_32SC2 CV_MAKETYPE(CV_32S,2) +#define CV_32SC3 CV_MAKETYPE(CV_32S,3) +#define CV_32SC4 CV_MAKETYPE(CV_32S,4) +#define CV_32SC(n) CV_MAKETYPE(CV_32S,(n)) + +#define CV_32FC1 CV_MAKETYPE(CV_32F,1) +#define CV_32FC2 CV_MAKETYPE(CV_32F,2) +#define CV_32FC3 CV_MAKETYPE(CV_32F,3) +#define CV_32FC4 CV_MAKETYPE(CV_32F,4) +#define CV_32FC(n) CV_MAKETYPE(CV_32F,(n)) + +#define CV_64FC1 CV_MAKETYPE(CV_64F,1) +#define CV_64FC2 CV_MAKETYPE(CV_64F,2) +#define CV_64FC3 CV_MAKETYPE(CV_64F,3) +#define CV_64FC4 CV_MAKETYPE(CV_64F,4) +#define CV_64FC(n) CV_MAKETYPE(CV_64F,(n)) + +#define CV_AUTO_STEP 0x7fffffff +#define CV_WHOLE_ARR cvSlice( 0, 0x3fffffff ) + +#define CV_MAT_CN_MASK ((CV_CN_MAX - 1) << CV_CN_SHIFT) +#define CV_MAT_CN(flags) ((((flags) & CV_MAT_CN_MASK) >> CV_CN_SHIFT) + 1) +#define CV_MAT_TYPE_MASK (CV_DEPTH_MAX*CV_CN_MAX - 1) +#define CV_MAT_TYPE(flags) ((flags) & CV_MAT_TYPE_MASK) +#define CV_MAT_CONT_FLAG_SHIFT 14 +#define CV_MAT_CONT_FLAG (1 << CV_MAT_CONT_FLAG_SHIFT) +#define CV_IS_MAT_CONT(flags) ((flags) & CV_MAT_CONT_FLAG) +#define CV_IS_CONT_MAT CV_IS_MAT_CONT +#define CV_SUBMAT_FLAG_SHIFT 15 +#define CV_SUBMAT_FLAG (1 << CV_SUBMAT_FLAG_SHIFT) +#define CV_IS_SUBMAT(flags) ((flags) & CV_MAT_SUBMAT_FLAG) + +#define CV_MAGIC_MASK 0xFFFF0000 +#define CV_MAT_MAGIC_VAL 0x42420000 +#define CV_TYPE_NAME_MAT "opencv-matrix" + +class Mat { +public: + Mat(); + ~Mat(); + void create(Size size, int type); + int channels() const; + %immutable; + int rows; + int cols; +}; + +template class Ptr +{ +public: + //! empty constructor + Ptr(); + //! take ownership of the pointer. The associated reference counter is allocated and set to 1 + Ptr(_Tp* _obj); + //! calls release() + ~Ptr(); + //! copy constructor. Copies the members and calls addref() + Ptr(const Ptr& ptr); + //! copy operator. Calls ptr.addref() and release() before copying the members + // Ptr& operator = (const Ptr& ptr); + //! increments the reference counter + void addref(); + //! decrements the reference counter. If it reaches 0, delete_obj() is called + void release(); + //! deletes the object. Override if needed + void delete_obj(); + //! returns true iff obj==NULL + bool empty() const; + + + //! helper operators making "Ptr ptr" use very similar to "T* ptr". + _Tp* operator -> (); + // const _Tp* operator -> () const; + + // operator _Tp* (); + // operator const _Tp*() const; + +protected: + _Tp* obj; //< the object pointer. + int* refcount; //< the associated reference counter +}; + + + +%template(PtrMat) Ptr; + +void imwrite(const char* image_name, const Mat& image); +Mat imread(const char* image_name); + + %include "buffers.i" + %apply char* BUFF {const char* buffer} + %apply char* BUFF {char* buffer} +void copyMatToBuffer(char* buffer, const Mat& mat); +void copyBufferToMat(Mat& mat, const char* buffer); \ No newline at end of file diff --git a/android/android-jni/jni/gl_code.cpp b/android/android-opencv/jni/gl_code.cpp similarity index 81% rename from android/android-jni/jni/gl_code.cpp rename to android/android-opencv/jni/gl_code.cpp index 4512b9d..358b448 100644 --- a/android/android-jni/jni/gl_code.cpp +++ b/android/android-opencv/jni/gl_code.cpp @@ -17,14 +17,18 @@ // OpenGL ES 2.0 code #include +#if __ANDROID__ +#include +#include +#else +#include +#endif + +#include "android_logger.h" -#include #include #include -#include -#include - #include #include #include @@ -33,9 +37,6 @@ #include "glcamera.h" #include "image_pool.h" using namespace cv; -#define LOG_TAG "libandroid-opencv" -#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__) -#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__) static void printGLString(const char *name, GLenum s) { @@ -68,18 +69,12 @@ static const char gFragmentShader[] = "precision mediump float; " gl_FragColor = texture2D( s_texture, v_texCoord );\n" "} \n"; -const GLfloat gTriangleVertices[] = {0.0f, 0.5f, -0.5f, -0.5f, 0.5f, -0.5f}; -GLubyte testpixels[4 * 3] = {255, 0, 0, // Red - 0, 255, 0, // Green - 0, 0, 255, // Blue - 255, 255, 0 // Yellow - }; GLuint glcamera::createSimpleTexture2D(GLuint _textureid, GLubyte* pixels, int width, int height, int channels) { // Bind the texture - glActiveTexture( GL_TEXTURE0); + glActiveTexture(GL_TEXTURE0); checkGlError("glActiveTexture"); // Bind the texture object glBindTexture(GL_TEXTURE_2D, _textureid); @@ -89,7 +84,11 @@ GLuint glcamera::createSimpleTexture2D(GLuint _textureid, GLubyte* pixels, int w switch (channels) { case 3: +#if ANDROID format = GL_RGB; +#else + format = GL_BGR; +#endif break; case 1: format = GL_LUMINANCE; @@ -102,9 +101,15 @@ GLuint glcamera::createSimpleTexture2D(GLuint _textureid, GLubyte* pixels, int w glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, pixels); checkGlError("glTexImage2D"); +#if ANDROID // Set the filtering mode glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); +#else + /* Linear Filtering */ + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); +#endif return _textureid; @@ -112,7 +117,9 @@ GLuint glcamera::createSimpleTexture2D(GLuint _textureid, GLubyte* pixels, int w GLuint glcamera::loadShader(GLenum shaderType, const char* pSource) { - GLuint shader = glCreateShader(shaderType); + GLuint shader = 0; +#if __ANDROID__ + shader = glCreateShader(shaderType); if (shader) { glShaderSource(shader, 1, &pSource, NULL); @@ -138,11 +145,13 @@ GLuint glcamera::loadShader(GLenum shaderType, const char* pSource) } } } +#endif return shader; } GLuint glcamera::createProgram(const char* pVertexSource, const char* pFragmentSource) { +#if __ANDROID__ GLuint vertexShader = loadShader(GL_VERTEX_SHADER, pVertexSource); if (!vertexShader) { @@ -184,27 +193,32 @@ GLuint glcamera::createProgram(const char* pVertexSource, const char* pFragmentS } } return program; +#else + return 0; +#endif +} +void glcamera::clear(){ + nimg = Mat(); } - //GLuint textureID; bool glcamera::setupGraphics(int w, int h) { - printGLString("Version", GL_VERSION); - printGLString("Vendor", GL_VENDOR); - printGLString("Renderer", GL_RENDERER); - printGLString("Extensions", GL_EXTENSIONS); +// printGLString("Version", GL_VERSION); +// printGLString("Vendor", GL_VENDOR); +// printGLString("Renderer", GL_RENDERER); +// printGLString("Extensions", GL_EXTENSIONS); - LOGI("setupGraphics(%d, %d)", w, h); +#if __ANDROID__ gProgram = createProgram(gVertexShader, gFragmentShader); if (!gProgram) { LOGE("Could not create program."); return false; } + gvPositionHandle = glGetAttribLocation(gProgram, "a_position"); gvTexCoordHandle = glGetAttribLocation(gProgram, "a_texCoord"); - gvSamplerHandle = glGetAttribLocation(gProgram, "s_texture"); // Use tightly packed data @@ -212,28 +226,24 @@ bool glcamera::setupGraphics(int w, int h) // Generate a texture object glGenTextures(1, &textureID); - textureID = createSimpleTexture2D(textureID, testpixels, 2, 2, 3); - - checkGlError("glGetAttribLocation"); - LOGI("glGetAttribLocation(\"vPosition\") = %d\n", - gvPositionHandle); glViewport(0, 0, w, h); - checkGlError("glViewport"); +#endif return true; } void glcamera::renderFrame() { +#if __ANDROID__ GLfloat vVertices[] = {-1.0f, 1.0f, 0.0f, // Position 0 0.0f, 0.0f, // TexCoord 0 -1.0f, -1.0f, 0.0f, // Position 1 - 0.0f, 1.0f, // TexCoord 1 + 0.0f, img_h, // TexCoord 1 1.0f, -1.0f, 0.0f, // Position 2 - 1.0f, 1.0f, // TexCoord 2 + img_w, img_h, // TexCoord 2 1.0f, 1.0f, 0.0f, // Position 3 - 1.0f, 0.0f // TexCoord 3 + img_w, 0.0f // TexCoord 3 }; GLushort indices[] = {0, 1, 2, 0, 2, 3}; GLsizei stride = 5 * sizeof(GLfloat); // 3 for position, 2 for texture @@ -244,6 +254,8 @@ void glcamera::renderFrame() glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); checkGlError("glClear"); + if(nimg.empty())return; + glUseProgram(gProgram); checkGlError("glUseProgram"); @@ -256,14 +268,14 @@ void glcamera::renderFrame() glEnableVertexAttribArray(gvTexCoordHandle); // Bind the texture - glActiveTexture( GL_TEXTURE0); + glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, textureID); // Set the sampler texture unit to 0 glUniform1i(gvSamplerHandle, 0); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices); - +#endif //checkGlError("glVertexAttribPointer"); //glEnableVertexAttribArray(gvPositionHandle); //checkGlError("glEnableVertexAttribArray"); @@ -284,17 +296,35 @@ void glcamera::step() if (newimage && !nimg.empty()) { - textureID = createSimpleTexture2D(textureID, nimg.ptr (0), nimg.rows, nimg.cols, nimg.channels()); + textureID = createSimpleTexture2D(textureID, nimg.ptr (0), nimg.cols, nimg.rows, nimg.channels()); newimage = false; } renderFrame(); } -#define NEAREST_POW2(x)((int)(0.5 + std::log(x)/0.69315) ) +#define NEAREST_POW2(x)( std::ceil(std::log(x)/0.69315) ) void glcamera::setTextureImage(const Mat& img) { + int p = NEAREST_POW2(img.cols/2); //subsample by 2 + //int sz = std::pow(2, p); + + // Size size(sz, sz); Size size(256, 256); - resize(img, nimg, size, cv::INTER_NEAREST); + img_w = 1; + img_h = 1; + if (nimg.cols != size.width) + LOGI_STREAM( "using texture of size: (" << size.width << " , " << size.height << ") image size is: (" << img.cols << " , " << img.rows << ")"); + nimg.create(size, img.type()); +#if SUBREGION_NPO2 + cv::Rect roi(0, 0, img.cols/2, img.rows/2); + cv::Mat nimg_sub = nimg(roi); + //img.copyTo(nimg_sub); + img_w = (img.cols/2)/float(sz); + img_h = (img.rows/2)/float(sz); + cv::resize(img,nimg_sub,nimg_sub.size(),0,0,CV_INTER_NN); +#else + cv::resize(img, nimg, nimg.size(), 0, 0, CV_INTER_NN); +#endif newimage = true; } diff --git a/android/android-jni/jni/glcamera.i b/android/android-opencv/jni/glcamera.i similarity index 98% rename from android/android-jni/jni/glcamera.i rename to android/android-opencv/jni/glcamera.i index 0a4a059..2fd2a53 100644 --- a/android/android-jni/jni/glcamera.i +++ b/android/android-opencv/jni/glcamera.i @@ -39,5 +39,6 @@ public: void init(int width, int height); void step(); void drawMatToGL(int idx, image_pool* pool); + void clear(); }; diff --git a/android/android-jni/jni/image_pool.cpp b/android/android-opencv/jni/image_pool.cpp similarity index 55% rename from android/android-jni/jni/image_pool.cpp rename to android/android-opencv/jni/image_pool.cpp index 4e70a28..c7a6720 100644 --- a/android/android-jni/jni/image_pool.cpp +++ b/android/android-opencv/jni/image_pool.cpp @@ -2,14 +2,31 @@ #include "yuv420sp2rgb.h" -#include +#include "android_logger.h" + #include + +#include #include -using namespace cv; +#ifdef __cplusplus +extern "C" +{ +#endif + +JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved); +// +//JNIEXPORT jobject JNICALL Java_com_opencv_jni_opencvJNI_getBitmapBuffer( +// JNIEnv *jenv, jclass jcls, jlong jarg1, jobject jarg1_); -#define LOG_TAG "libandroid-opencv" -#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__) -#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__) + +JNIEXPORT void JNICALL Java_com_opencv_jni_opencvJNI_addYUVtoPool(JNIEnv *, jclass, jlong, jobject, jbyteArray, jint, + jint, jint, jboolean); + +#ifdef __cplusplus +} +#endif + +using namespace cv; JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) { @@ -19,49 +36,36 @@ JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) } JNIEXPORT void JNICALL Java_com_opencv_jni_opencvJNI_addYUVtoPool(JNIEnv * env, jclass thiz, jlong ppool, - jobject _jpool, jbyteArray jbuffer, jint jidx, - jint jwidth, jint jheight, jboolean jgrey) + jobject _jpool, jbyteArray jbuffer, jint jidx, + jint jwidth, jint jheight, jboolean jgrey) { int buff_height = jheight + (jheight / 2); Size buff_size(jwidth, buff_height); image_pool *pool = (image_pool *)ppool; Mat mat = pool->getYUV(jidx); - - if (mat.empty() || mat.size() != buff_size) + //create is smart and only copies if the buffer size is different + mat.create(buff_size, CV_8UC1); { - mat.create(buff_size, CV_8UC1); + uchar* buff = mat.ptr (0); + jsize sz = env->GetArrayLength(jbuffer); + //http://elliotth.blogspot.com/2007/03/optimizing-jni-array-access.html + env->GetByteArrayRegion(jbuffer, 0, sz, (jbyte*)buff); } - - jsize sz = env->GetArrayLength(jbuffer); - uchar* buff = mat.ptr (0); - - env->GetByteArrayRegion(jbuffer, 0, sz, (jbyte*)buff); - pool->addYUVMat(jidx, mat); - Mat color = pool->getImage(jidx); - - if (!jgrey) - { - - if (color.cols != jwidth || color.rows != jheight || color.channels() != 3) - { - color.create(jheight, jwidth, CV_8UC3); - } - //doesn't work unfortunately.. - //TODO cvtColor(mat,color, CV_YCrCb2RGB); - color_convert_common(buff, buff + jwidth * jheight, jwidth, jheight, color.ptr (0), false); - } - + Mat color; if (jgrey) { Mat grey = pool->getGrey(jidx); color = grey; } - + else + { + color = pool->getImage(jidx); + pool->convertYUVtoColor(jidx, color); + } pool->addImage(jidx, color); - } image_pool::image_pool() @@ -71,7 +75,7 @@ image_pool::image_pool() image_pool::~image_pool() { - __android_log_print(ANDROID_LOG_INFO, "image_pool", "destructor called"); + } Mat image_pool::getImage(int i) @@ -100,9 +104,7 @@ void image_pool::addImage(int i, Mat mat) void image_pool::convertYUVtoColor(int i, cv::Mat& out) { - Mat yuv = getYUV(i); - if (yuv.empty()) return; int width = yuv.cols; @@ -110,7 +112,19 @@ void image_pool::convertYUVtoColor(int i, cv::Mat& out) out.create(height, width, CV_8UC3); const unsigned char* buff = yuv.ptr (0); unsigned char* out_buff = out.ptr (0); - //doesn't work unfortunately.. - //TODO cvtColor(mat,color, CV_YCrCb2RGB); color_convert_common(buff, buff + width * height, width, height, out_buff, false); } + +void copyMatToBuffer(char* buffer, const cv::Mat& mat) +{ + memcpy(buffer, mat.data, mat.rows * mat.cols * mat.step1()); +} +void copyBufferToMat(cv::Mat& mat, const char* buffer) +{ + memcpy(mat.data, buffer, mat.rows * mat.cols * mat.step1()); +} + +void RGB2BGR(const Mat& in, Mat& out) +{ + cvtColor(in, out, CV_RGB2BGR); +} diff --git a/android/android-jni/jni/image_pool.i b/android/android-opencv/jni/image_pool.i similarity index 92% rename from android/android-jni/jni/image_pool.i rename to android/android-opencv/jni/image_pool.i index c1b3c6d..b81e64a 100644 --- a/android/android-jni/jni/image_pool.i +++ b/android/android-opencv/jni/image_pool.i @@ -40,17 +40,12 @@ references them by an index. It allows one to get a pointer to an underlying ma %feature("director") image_pool; class image_pool { - public: - image_pool(); - ~image_pool(); - - + Mat getGrey(int i); Mat getImage(int i); void addImage(int i, Mat mat); - - - - + void convertYUVtoColor(int i, Mat& out); }; +void RGB2BGR(const Mat& in, Mat& out); + diff --git a/android/android-jni/jni/Calibration.h b/android/android-opencv/jni/include/Calibration.h similarity index 100% rename from android/android-jni/jni/Calibration.h rename to android/android-opencv/jni/include/Calibration.h diff --git a/android/android-opencv/jni/include/android_logger.h b/android/android-opencv/jni/include/android_logger.h new file mode 100644 index 0000000..09f8dc3 --- /dev/null +++ b/android/android-opencv/jni/include/android_logger.h @@ -0,0 +1,19 @@ +#pragma once +#include +#include + +#define LOG_TAG "libopencv" +#if ANDROID +#include +#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__) +#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__) +#else +#include +#define LOGI(...) printf("info:");printf("%s:",LOG_TAG); fprintf(stdout,__VA_ARGS__);printf("\n"); +#define LOGE(...) printf("error:");printf("%s:",LOG_TAG); fprintf(stderr,__VA_ARGS__);printf("\n"); +#endif + +#ifndef LOGI_STREAM +#define LOGI_STREAM(x) {std::stringstream ss; ss << x; LOGI("%s",ss.str().c_str());} +#endif +#define LOGE_STREAM(x) {std::stringstream ss; ss << x; LOGE("%s",ss.str().c_str());} diff --git a/android/android-jni/jni/glcamera.h b/android/android-opencv/jni/include/glcamera.h similarity index 84% rename from android/android-jni/jni/glcamera.h rename to android/android-opencv/jni/include/glcamera.h index 923fc53..e7c021a 100644 --- a/android/android-jni/jni/glcamera.h +++ b/android/android-opencv/jni/include/glcamera.h @@ -2,8 +2,13 @@ #define GLCAMERA_H_ #include +#ifdef __ANDROID__ #include #include +#else +#include +#include +#endif #include "image_pool.h" @@ -17,8 +22,11 @@ public: void step(); void drawMatToGL(int idx, image_pool* pool); + void drawMatToGL(const cv::Mat& img); void setTextureImage(const cv::Mat& img); + void clear(); + private: GLuint createSimpleTexture2D(GLuint _textureid, GLubyte* pixels, int width, int height, int channels); GLuint loadShader(GLenum shaderType, const char* pSource); @@ -35,5 +43,6 @@ private: GLuint gvTexCoordHandle; GLuint gvSamplerHandle; + float img_w, img_h; }; #endif diff --git a/android/android-jni/jni/image_pool.h b/android/android-opencv/jni/include/image_pool.h similarity index 67% rename from android/android-jni/jni/image_pool.h rename to android/android-opencv/jni/include/image_pool.h index 8ce13cb..d32eb47 100644 --- a/android/android-jni/jni/image_pool.h +++ b/android/android-opencv/jni/include/image_pool.h @@ -3,27 +3,8 @@ #include #include -#if ANDROID -#include - -#ifdef __cplusplus -extern "C" -{ -#endif - -JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved); -// -//JNIEXPORT jobject JNICALL Java_com_opencv_jni_opencvJNI_getBitmapBuffer( -// JNIEnv *jenv, jclass jcls, jlong jarg1, jobject jarg1_); -JNIEXPORT void JNICALL Java_com_opencv_jni_opencvJNI_addYUVtoPool(JNIEnv *, jclass, jlong, jobject, jbyteArray, jint, - jint, jint, jboolean); - -#ifdef __cplusplus -} -#endif -#endif class image_pool { @@ -63,4 +44,8 @@ private: std::map yuvImagesMap; }; + +void copyMatToBuffer(char* buffer, const cv::Mat& mat); +void copyBufferToMat(cv::Mat& mat, const char* buffer); +void RGB2BGR(const cv::Mat& in, cv::Mat& out); #endif diff --git a/android/android-opencv/jni/include/yuv2rgb.h b/android/android-opencv/jni/include/yuv2rgb.h new file mode 100644 index 0000000..9b7535c --- /dev/null +++ b/android/android-opencv/jni/include/yuv2rgb.h @@ -0,0 +1,147 @@ +/* YUV-> RGB conversion code. + * + * Copyright (C) 2008-9 Robin Watts (robin@wss.co.uk) for Pinknoise + * Productions Ltd. + * + * Licensed under the GNU GPL. If you need it under another license, contact + * me and ask. + * + * This program is free software ; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation ; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY ; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program ; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef YUV2RGB_H + +#define YUV2RGB_H + +/* Define these to something appropriate in your build */ +typedef unsigned int uint32_t; +typedef signed int int32_t; +typedef unsigned short uint16_t; +typedef unsigned char uint8_t; + +extern const uint32_t yuv2rgb565_table[]; +extern const uint32_t yuv2bgr565_table[]; + +void yuv420_2_rgb565(uint8_t *dst_ptr, + const uint8_t *y_ptr, + const uint8_t *u_ptr, + const uint8_t *v_ptr, + int32_t width, + int32_t height, + int32_t y_span, + int32_t uv_span, + int32_t dst_span, + const uint32_t *tables, + int32_t dither); + +void yuv422_2_rgb565(uint8_t *dst_ptr, + const uint8_t *y_ptr, + const uint8_t *u_ptr, + const uint8_t *v_ptr, + int32_t width, + int32_t height, + int32_t y_span, + int32_t uv_span, + int32_t dst_span, + const uint32_t *tables, + int32_t dither); + +void yuv444_2_rgb565(uint8_t *dst_ptr, + const uint8_t *y_ptr, + const uint8_t *u_ptr, + const uint8_t *v_ptr, + int32_t width, + int32_t height, + int32_t y_span, + int32_t uv_span, + int32_t dst_span, + const uint32_t *tables, + int32_t dither); + +void yuv420_2_rgb888(uint8_t *dst_ptr, + const uint8_t *y_ptr, + const uint8_t *u_ptr, + const uint8_t *v_ptr, + int32_t width, + int32_t height, + int32_t y_span, + int32_t uv_span, + int32_t dst_span, + const uint32_t *tables, + int32_t dither); + +void yuv422_2_rgb888(uint8_t *dst_ptr, + const uint8_t *y_ptr, + const uint8_t *u_ptr, + const uint8_t *v_ptr, + int32_t width, + int32_t height, + int32_t y_span, + int32_t uv_span, + int32_t dst_span, + const uint32_t *tables, + int32_t dither); + +void yuv444_2_rgb888(uint8_t *dst_ptr, + const uint8_t *y_ptr, + const uint8_t *u_ptr, + const uint8_t *v_ptr, + int32_t width, + int32_t height, + int32_t y_span, + int32_t uv_span, + int32_t dst_span, + const uint32_t *tables, + int32_t dither); + +void yuv420_2_rgb8888(uint8_t *dst_ptr, + const uint8_t *y_ptr, + const uint8_t *u_ptr, + const uint8_t *v_ptr, + int32_t width, + int32_t height, + int32_t y_span, + int32_t uv_span, + int32_t dst_span, + const uint32_t *tables, + int32_t dither); + +void yuv422_2_rgb8888(uint8_t *dst_ptr, + const uint8_t *y_ptr, + const uint8_t *u_ptr, + const uint8_t *v_ptr, + int32_t width, + int32_t height, + int32_t y_span, + int32_t uv_span, + int32_t dst_span, + const uint32_t *tables, + int32_t dither); + +void yuv444_2_rgb8888(uint8_t *dst_ptr, + const uint8_t *y_ptr, + const uint8_t *u_ptr, + const uint8_t *v_ptr, + int32_t width, + int32_t height, + int32_t y_span, + int32_t uv_span, + int32_t dst_span, + const uint32_t *tables, + int32_t dither); + + +#endif /* YUV2RGB_H */ diff --git a/android/android-jni/jni/yuv420sp2rgb.h b/android/android-opencv/jni/include/yuv420sp2rgb.h similarity index 94% rename from android/android-jni/jni/yuv420sp2rgb.h rename to android/android-opencv/jni/include/yuv420sp2rgb.h index dfe9b5f..fcfc49c 100644 --- a/android/android-jni/jni/yuv420sp2rgb.h +++ b/android/android-opencv/jni/include/yuv420sp2rgb.h @@ -1,4 +1,3 @@ -//yuv420sp2rgb.h #ifndef YUV420SP2RGB_H #define YUV420SP2RGB_H diff --git a/android/android-jni/jni/nocopy.i b/android/android-opencv/jni/nocopy.i similarity index 100% rename from android/android-jni/jni/nocopy.i rename to android/android-opencv/jni/nocopy.i diff --git a/android/android-opencv/jni/yuv2rgb16tab.c b/android/android-opencv/jni/yuv2rgb16tab.c new file mode 100644 index 0000000..f9f6a14 --- /dev/null +++ b/android/android-opencv/jni/yuv2rgb16tab.c @@ -0,0 +1,802 @@ +/* YUV-> RGB conversion code. + * + * Copyright (C) 2008-9 Robin Watts (robin@wss.co.uk) for Pinknoise + * Productions Ltd. + * + * Licensed under the GNU GPL. If you need it under another license, contact + * me and ask. + * + * This program is free software ; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation ; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY ; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program ; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* For BREW or Symbian you might need to make this static const rather than + * just const, and introduce a function to get the address. */ + +#include "yuv2rgb.h" + +const uint32_t yuv2rgb565_table[256*3] = +{ + /* y_table */ + 0x7FFFFFEDU, + 0x7FFFFFEFU, + 0x7FFFFFF0U, + 0x7FFFFFF1U, + 0x7FFFFFF2U, + 0x7FFFFFF3U, + 0x7FFFFFF4U, + 0x7FFFFFF6U, + 0x7FFFFFF7U, + 0x7FFFFFF8U, + 0x7FFFFFF9U, + 0x7FFFFFFAU, + 0x7FFFFFFBU, + 0x7FFFFFFDU, + 0x7FFFFFFEU, + 0x7FFFFFFFU, + 0x80000000U, + 0x80400801U, + 0x80A01002U, + 0x80E01803U, + 0x81202805U, + 0x81803006U, + 0x81C03807U, + 0x82004008U, + 0x82604809U, + 0x82A0500AU, + 0x82E0600CU, + 0x8340680DU, + 0x8380700EU, + 0x83C0780FU, + 0x84208010U, + 0x84608811U, + 0x84A09813U, + 0x8500A014U, + 0x8540A815U, + 0x8580B016U, + 0x85E0B817U, + 0x8620C018U, + 0x8660D01AU, + 0x86C0D81BU, + 0x8700E01CU, + 0x8740E81DU, + 0x87A0F01EU, + 0x87E0F81FU, + 0x88210821U, + 0x88811022U, + 0x88C11823U, + 0x89012024U, + 0x89412825U, + 0x89A13026U, + 0x89E14028U, + 0x8A214829U, + 0x8A81502AU, + 0x8AC1582BU, + 0x8B01602CU, + 0x8B61682DU, + 0x8BA1782FU, + 0x8BE18030U, + 0x8C418831U, + 0x8C819032U, + 0x8CC19833U, + 0x8D21A034U, + 0x8D61B036U, + 0x8DA1B837U, + 0x8E01C038U, + 0x8E41C839U, + 0x8E81D03AU, + 0x8EE1D83BU, + 0x8F21E83DU, + 0x8F61F03EU, + 0x8FC1F83FU, + 0x90020040U, + 0x90420841U, + 0x90A21042U, + 0x90E22044U, + 0x91222845U, + 0x91823046U, + 0x91C23847U, + 0x92024048U, + 0x92624849U, + 0x92A2504AU, + 0x92E2604CU, + 0x9342684DU, + 0x9382704EU, + 0x93C2784FU, + 0x94228050U, + 0x94628851U, + 0x94A29853U, + 0x9502A054U, + 0x9542A855U, + 0x9582B056U, + 0x95E2B857U, + 0x9622C058U, + 0x9662D05AU, + 0x96C2D85BU, + 0x9702E05CU, + 0x9742E85DU, + 0x97A2F05EU, + 0x97E2F85FU, + 0x98230861U, + 0x98831062U, + 0x98C31863U, + 0x99032064U, + 0x99632865U, + 0x99A33066U, + 0x99E34068U, + 0x9A434869U, + 0x9A83506AU, + 0x9AC3586BU, + 0x9B23606CU, + 0x9B63686DU, + 0x9BA3786FU, + 0x9BE38070U, + 0x9C438871U, + 0x9C839072U, + 0x9CC39873U, + 0x9D23A074U, + 0x9D63B076U, + 0x9DA3B877U, + 0x9E03C078U, + 0x9E43C879U, + 0x9E83D07AU, + 0x9EE3D87BU, + 0x9F23E87DU, + 0x9F63F07EU, + 0x9FC3F87FU, + 0xA0040080U, + 0xA0440881U, + 0xA0A41082U, + 0xA0E42084U, + 0xA1242885U, + 0xA1843086U, + 0xA1C43887U, + 0xA2044088U, + 0xA2644889U, + 0xA2A4588BU, + 0xA2E4608CU, + 0xA344688DU, + 0xA384708EU, + 0xA3C4788FU, + 0xA4248090U, + 0xA4649092U, + 0xA4A49893U, + 0xA504A094U, + 0xA544A895U, + 0xA584B096U, + 0xA5E4B897U, + 0xA624C098U, + 0xA664D09AU, + 0xA6C4D89BU, + 0xA704E09CU, + 0xA744E89DU, + 0xA7A4F09EU, + 0xA7E4F89FU, + 0xA82508A1U, + 0xA88510A2U, + 0xA8C518A3U, + 0xA90520A4U, + 0xA96528A5U, + 0xA9A530A6U, + 0xA9E540A8U, + 0xAA4548A9U, + 0xAA8550AAU, + 0xAAC558ABU, + 0xAB2560ACU, + 0xAB6568ADU, + 0xABA578AFU, + 0xAC0580B0U, + 0xAC4588B1U, + 0xAC8590B2U, + 0xACE598B3U, + 0xAD25A0B4U, + 0xAD65B0B6U, + 0xADA5B8B7U, + 0xAE05C0B8U, + 0xAE45C8B9U, + 0xAE85D0BAU, + 0xAEE5D8BBU, + 0xAF25E8BDU, + 0xAF65F0BEU, + 0xAFC5F8BFU, + 0xB00600C0U, + 0xB04608C1U, + 0xB0A610C2U, + 0xB0E620C4U, + 0xB12628C5U, + 0xB18630C6U, + 0xB1C638C7U, + 0xB20640C8U, + 0xB26648C9U, + 0xB2A658CBU, + 0xB2E660CCU, + 0xB34668CDU, + 0xB38670CEU, + 0xB3C678CFU, + 0xB42680D0U, + 0xB46690D2U, + 0xB4A698D3U, + 0xB506A0D4U, + 0xB546A8D5U, + 0xB586B0D6U, + 0xB5E6B8D7U, + 0xB626C8D9U, + 0xB666D0DAU, + 0xB6C6D8DBU, + 0xB706E0DCU, + 0xB746E8DDU, + 0xB7A6F0DEU, + 0xB7E6F8DFU, + 0xB82708E1U, + 0xB88710E2U, + 0xB8C718E3U, + 0xB90720E4U, + 0xB96728E5U, + 0xB9A730E6U, + 0xB9E740E8U, + 0xBA4748E9U, + 0xBA8750EAU, + 0xBAC758EBU, + 0xBB2760ECU, + 0xBB6768EDU, + 0xBBA778EFU, + 0xBC0780F0U, + 0xBC4788F1U, + 0xBC8790F2U, + 0xBCE798F3U, + 0xBD27A0F4U, + 0xBD67B0F6U, + 0xBDC7B8F7U, + 0xBE07C0F8U, + 0xBE47C8F9U, + 0xBEA7D0FAU, + 0xBEE7D8FBU, + 0xBF27E8FDU, + 0xBF87F0FEU, + 0xBFC7F8FFU, + 0xC0080100U, + 0xC0480901U, + 0xC0A81102U, + 0xC0E82104U, + 0xC0E82104U, + 0xC0E82104U, + 0xC0E82104U, + 0xC0E82104U, + 0xC0E82104U, + 0xC0E82104U, + 0xC0E82104U, + 0xC0E82104U, + 0xC0E82104U, + 0xC0E82104U, + 0xC0E82104U, + 0xC0E82104U, + 0xC0E82104U, + 0xC0E82104U, + 0xC0E82104U, + 0xC0E82104U, + /* u_table */ + 0x0C400103U, + 0x0C200105U, + 0x0C200107U, + 0x0C000109U, + 0x0BE0010BU, + 0x0BC0010DU, + 0x0BA0010FU, + 0x0BA00111U, + 0x0B800113U, + 0x0B600115U, + 0x0B400117U, + 0x0B400119U, + 0x0B20011BU, + 0x0B00011DU, + 0x0AE0011FU, + 0x0AE00121U, + 0x0AC00123U, + 0x0AA00125U, + 0x0A800127U, + 0x0A600129U, + 0x0A60012BU, + 0x0A40012DU, + 0x0A20012FU, + 0x0A000131U, + 0x0A000132U, + 0x09E00134U, + 0x09C00136U, + 0x09A00138U, + 0x09A0013AU, + 0x0980013CU, + 0x0960013EU, + 0x09400140U, + 0x09400142U, + 0x09200144U, + 0x09000146U, + 0x08E00148U, + 0x08C0014AU, + 0x08C0014CU, + 0x08A0014EU, + 0x08800150U, + 0x08600152U, + 0x08600154U, + 0x08400156U, + 0x08200158U, + 0x0800015AU, + 0x0800015CU, + 0x07E0015EU, + 0x07C00160U, + 0x07A00162U, + 0x07A00164U, + 0x07800166U, + 0x07600168U, + 0x0740016AU, + 0x0720016CU, + 0x0720016EU, + 0x07000170U, + 0x06E00172U, + 0x06C00174U, + 0x06C00176U, + 0x06A00178U, + 0x0680017AU, + 0x0660017CU, + 0x0660017EU, + 0x06400180U, + 0x06200182U, + 0x06000184U, + 0x05E00185U, + 0x05E00187U, + 0x05C00189U, + 0x05A0018BU, + 0x0580018DU, + 0x0580018FU, + 0x05600191U, + 0x05400193U, + 0x05200195U, + 0x05200197U, + 0x05000199U, + 0x04E0019BU, + 0x04C0019DU, + 0x04C0019FU, + 0x04A001A1U, + 0x048001A3U, + 0x046001A5U, + 0x044001A7U, + 0x044001A9U, + 0x042001ABU, + 0x040001ADU, + 0x03E001AFU, + 0x03E001B1U, + 0x03C001B3U, + 0x03A001B5U, + 0x038001B7U, + 0x038001B9U, + 0x036001BBU, + 0x034001BDU, + 0x032001BFU, + 0x032001C1U, + 0x030001C3U, + 0x02E001C5U, + 0x02C001C7U, + 0x02A001C9U, + 0x02A001CBU, + 0x028001CDU, + 0x026001CFU, + 0x024001D1U, + 0x024001D3U, + 0x022001D5U, + 0x020001D7U, + 0x01E001D8U, + 0x01E001DAU, + 0x01C001DCU, + 0x01A001DEU, + 0x018001E0U, + 0x016001E2U, + 0x016001E4U, + 0x014001E6U, + 0x012001E8U, + 0x010001EAU, + 0x010001ECU, + 0x00E001EEU, + 0x00C001F0U, + 0x00A001F2U, + 0x00A001F4U, + 0x008001F6U, + 0x006001F8U, + 0x004001FAU, + 0x004001FCU, + 0x002001FEU, + 0x00000200U, + 0xFFE00202U, + 0xFFC00204U, + 0xFFC00206U, + 0xFFA00208U, + 0xFF80020AU, + 0xFF60020CU, + 0xFF60020EU, + 0xFF400210U, + 0xFF200212U, + 0xFF000214U, + 0xFF000216U, + 0xFEE00218U, + 0xFEC0021AU, + 0xFEA0021CU, + 0xFEA0021EU, + 0xFE800220U, + 0xFE600222U, + 0xFE400224U, + 0xFE200226U, + 0xFE200228U, + 0xFE000229U, + 0xFDE0022BU, + 0xFDC0022DU, + 0xFDC0022FU, + 0xFDA00231U, + 0xFD800233U, + 0xFD600235U, + 0xFD600237U, + 0xFD400239U, + 0xFD20023BU, + 0xFD00023DU, + 0xFCE0023FU, + 0xFCE00241U, + 0xFCC00243U, + 0xFCA00245U, + 0xFC800247U, + 0xFC800249U, + 0xFC60024BU, + 0xFC40024DU, + 0xFC20024FU, + 0xFC200251U, + 0xFC000253U, + 0xFBE00255U, + 0xFBC00257U, + 0xFBC00259U, + 0xFBA0025BU, + 0xFB80025DU, + 0xFB60025FU, + 0xFB400261U, + 0xFB400263U, + 0xFB200265U, + 0xFB000267U, + 0xFAE00269U, + 0xFAE0026BU, + 0xFAC0026DU, + 0xFAA0026FU, + 0xFA800271U, + 0xFA800273U, + 0xFA600275U, + 0xFA400277U, + 0xFA200279U, + 0xFA20027BU, + 0xFA00027CU, + 0xF9E0027EU, + 0xF9C00280U, + 0xF9A00282U, + 0xF9A00284U, + 0xF9800286U, + 0xF9600288U, + 0xF940028AU, + 0xF940028CU, + 0xF920028EU, + 0xF9000290U, + 0xF8E00292U, + 0xF8E00294U, + 0xF8C00296U, + 0xF8A00298U, + 0xF880029AU, + 0xF860029CU, + 0xF860029EU, + 0xF84002A0U, + 0xF82002A2U, + 0xF80002A4U, + 0xF80002A6U, + 0xF7E002A8U, + 0xF7C002AAU, + 0xF7A002ACU, + 0xF7A002AEU, + 0xF78002B0U, + 0xF76002B2U, + 0xF74002B4U, + 0xF74002B6U, + 0xF72002B8U, + 0xF70002BAU, + 0xF6E002BCU, + 0xF6C002BEU, + 0xF6C002C0U, + 0xF6A002C2U, + 0xF68002C4U, + 0xF66002C6U, + 0xF66002C8U, + 0xF64002CAU, + 0xF62002CCU, + 0xF60002CEU, + 0xF60002CFU, + 0xF5E002D1U, + 0xF5C002D3U, + 0xF5A002D5U, + 0xF5A002D7U, + 0xF58002D9U, + 0xF56002DBU, + 0xF54002DDU, + 0xF52002DFU, + 0xF52002E1U, + 0xF50002E3U, + 0xF4E002E5U, + 0xF4C002E7U, + 0xF4C002E9U, + 0xF4A002EBU, + 0xF48002EDU, + 0xF46002EFU, + 0xF46002F1U, + 0xF44002F3U, + 0xF42002F5U, + 0xF40002F7U, + 0xF3E002F9U, + 0xF3E002FBU, + /* v_table */ + 0x1A09A000U, + 0x19E9A800U, + 0x19A9B800U, + 0x1969C800U, + 0x1949D000U, + 0x1909E000U, + 0x18C9E800U, + 0x18A9F800U, + 0x186A0000U, + 0x182A1000U, + 0x180A2000U, + 0x17CA2800U, + 0x17AA3800U, + 0x176A4000U, + 0x172A5000U, + 0x170A6000U, + 0x16CA6800U, + 0x168A7800U, + 0x166A8000U, + 0x162A9000U, + 0x160AA000U, + 0x15CAA800U, + 0x158AB800U, + 0x156AC000U, + 0x152AD000U, + 0x14EAE000U, + 0x14CAE800U, + 0x148AF800U, + 0x146B0000U, + 0x142B1000U, + 0x13EB2000U, + 0x13CB2800U, + 0x138B3800U, + 0x134B4000U, + 0x132B5000U, + 0x12EB6000U, + 0x12CB6800U, + 0x128B7800U, + 0x124B8000U, + 0x122B9000U, + 0x11EBA000U, + 0x11ABA800U, + 0x118BB800U, + 0x114BC000U, + 0x112BD000U, + 0x10EBE000U, + 0x10ABE800U, + 0x108BF800U, + 0x104C0000U, + 0x100C1000U, + 0x0FEC2000U, + 0x0FAC2800U, + 0x0F8C3800U, + 0x0F4C4000U, + 0x0F0C5000U, + 0x0EEC5800U, + 0x0EAC6800U, + 0x0E6C7800U, + 0x0E4C8000U, + 0x0E0C9000U, + 0x0DEC9800U, + 0x0DACA800U, + 0x0D6CB800U, + 0x0D4CC000U, + 0x0D0CD000U, + 0x0CCCD800U, + 0x0CACE800U, + 0x0C6CF800U, + 0x0C4D0000U, + 0x0C0D1000U, + 0x0BCD1800U, + 0x0BAD2800U, + 0x0B6D3800U, + 0x0B2D4000U, + 0x0B0D5000U, + 0x0ACD5800U, + 0x0AAD6800U, + 0x0A6D7800U, + 0x0A2D8000U, + 0x0A0D9000U, + 0x09CD9800U, + 0x098DA800U, + 0x096DB800U, + 0x092DC000U, + 0x090DD000U, + 0x08CDD800U, + 0x088DE800U, + 0x086DF800U, + 0x082E0000U, + 0x07EE1000U, + 0x07CE1800U, + 0x078E2800U, + 0x076E3800U, + 0x072E4000U, + 0x06EE5000U, + 0x06CE5800U, + 0x068E6800U, + 0x064E7800U, + 0x062E8000U, + 0x05EE9000U, + 0x05CE9800U, + 0x058EA800U, + 0x054EB800U, + 0x052EC000U, + 0x04EED000U, + 0x04AED800U, + 0x048EE800U, + 0x044EF000U, + 0x042F0000U, + 0x03EF1000U, + 0x03AF1800U, + 0x038F2800U, + 0x034F3000U, + 0x030F4000U, + 0x02EF5000U, + 0x02AF5800U, + 0x028F6800U, + 0x024F7000U, + 0x020F8000U, + 0x01EF9000U, + 0x01AF9800U, + 0x016FA800U, + 0x014FB000U, + 0x010FC000U, + 0x00EFD000U, + 0x00AFD800U, + 0x006FE800U, + 0x004FF000U, + 0x00100000U, + 0xFFD01000U, + 0xFFB01800U, + 0xFF702800U, + 0xFF303000U, + 0xFF104000U, + 0xFED05000U, + 0xFEB05800U, + 0xFE706800U, + 0xFE307000U, + 0xFE108000U, + 0xFDD09000U, + 0xFD909800U, + 0xFD70A800U, + 0xFD30B000U, + 0xFD10C000U, + 0xFCD0D000U, + 0xFC90D800U, + 0xFC70E800U, + 0xFC30F000U, + 0xFBF10000U, + 0xFBD11000U, + 0xFB911800U, + 0xFB712800U, + 0xFB313000U, + 0xFAF14000U, + 0xFAD14800U, + 0xFA915800U, + 0xFA516800U, + 0xFA317000U, + 0xF9F18000U, + 0xF9D18800U, + 0xF9919800U, + 0xF951A800U, + 0xF931B000U, + 0xF8F1C000U, + 0xF8B1C800U, + 0xF891D800U, + 0xF851E800U, + 0xF831F000U, + 0xF7F20000U, + 0xF7B20800U, + 0xF7921800U, + 0xF7522800U, + 0xF7123000U, + 0xF6F24000U, + 0xF6B24800U, + 0xF6925800U, + 0xF6526800U, + 0xF6127000U, + 0xF5F28000U, + 0xF5B28800U, + 0xF5729800U, + 0xF552A800U, + 0xF512B000U, + 0xF4F2C000U, + 0xF4B2C800U, + 0xF472D800U, + 0xF452E800U, + 0xF412F000U, + 0xF3D30000U, + 0xF3B30800U, + 0xF3731800U, + 0xF3532800U, + 0xF3133000U, + 0xF2D34000U, + 0xF2B34800U, + 0xF2735800U, + 0xF2336800U, + 0xF2137000U, + 0xF1D38000U, + 0xF1B38800U, + 0xF1739800U, + 0xF133A800U, + 0xF113B000U, + 0xF0D3C000U, + 0xF093C800U, + 0xF073D800U, + 0xF033E000U, + 0xF013F000U, + 0xEFD40000U, + 0xEF940800U, + 0xEF741800U, + 0xEF342000U, + 0xEEF43000U, + 0xEED44000U, + 0xEE944800U, + 0xEE745800U, + 0xEE346000U, + 0xEDF47000U, + 0xEDD48000U, + 0xED948800U, + 0xED549800U, + 0xED34A000U, + 0xECF4B000U, + 0xECD4C000U, + 0xEC94C800U, + 0xEC54D800U, + 0xEC34E000U, + 0xEBF4F000U, + 0xEBB50000U, + 0xEB950800U, + 0xEB551800U, + 0xEB352000U, + 0xEAF53000U, + 0xEAB54000U, + 0xEA954800U, + 0xEA555800U, + 0xEA156000U, + 0xE9F57000U, + 0xE9B58000U, + 0xE9958800U, + 0xE9559800U, + 0xE915A000U, + 0xE8F5B000U, + 0xE8B5C000U, + 0xE875C800U, + 0xE855D800U, + 0xE815E000U, + 0xE7F5F000U, + 0xE7B60000U, + 0xE7760800U, + 0xE7561800U, + 0xE7162000U, + 0xE6D63000U, + 0xE6B64000U, + 0xE6764800U, + 0xE6365800U +}; diff --git a/android/android-jni/jni/yuv2rgb_neon.c b/android/android-opencv/jni/yuv2rgb_neon.c similarity index 100% rename from android/android-jni/jni/yuv2rgb_neon.c rename to android/android-opencv/jni/yuv2rgb_neon.c diff --git a/android/android-opencv/jni/yuv420rgb888.s b/android/android-opencv/jni/yuv420rgb888.s new file mode 100644 index 0000000..570ccc7 --- /dev/null +++ b/android/android-opencv/jni/yuv420rgb888.s @@ -0,0 +1,379 @@ +; YUV-> RGB conversion code Copyright (C) 2008 Robin Watts (robin;wss.co.uk). +; +; Licensed under the GPL. If you need it under another license, contact me +; and ask. +; +; This program is free software ; you can redistribute it and/or modify +; it under the terms of the GNU General Public License as published by +; the Free Software Foundation ; either version 2 of the License, or +; (at your option) any later version. +; +; This program is distributed in the hope that it will be useful, +; but WITHOUT ANY WARRANTY ; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +; GNU General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this program ; if not, write to the Free Software +; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +; +; +; The algorithm used here is based heavily on one created by Sophie Wilson +; of Acorn/e-14/Broadcomm. Many thanks. +; +; Additional tweaks (in the fast fixup code) are from Paul Gardiner. +; +; The old implementation of YUV -> RGB did: +; +; R = CLAMP((Y-16)*1.164 + 1.596*V) +; G = CLAMP((Y-16)*1.164 - 0.391*U - 0.813*V) +; B = CLAMP((Y-16)*1.164 + 2.018*U ) +; +; We're going to bend that here as follows: +; +; R = CLAMP(y + 1.596*V) +; G = CLAMP(y - 0.383*U - 0.813*V) +; B = CLAMP(y + 1.976*U ) +; +; where y = 0 for Y <= 16, +; y = ( Y-16)*1.164, for 16 < Y <= 239, +; y = (239-16)*1.164, for 239 < Y +; +; i.e. We clamp Y to the 16 to 239 range (which it is supposed to be in +; anyway). We then pick the B_U factor so that B never exceeds 511. We then +; shrink the G_U factor in line with that to avoid a colour shift as much as +; possible. +; +; We're going to use tables to do it faster, but rather than doing it using +; 5 tables as as the above suggests, we're going to do it using just 3. +; +; We do this by working in parallel within a 32 bit word, and using one +; table each for Y U and V. +; +; Source Y values are 0 to 255, so 0.. 260 after scaling +; Source U values are -128 to 127, so -49.. 49(G), -253..251(B) after +; Source V values are -128 to 127, so -204..203(R), -104..103(G) after +; +; So total summed values: +; -223 <= R <= 481, -173 <= G <= 431, -253 <= B < 511 +; +; We need to pack R G and B into a 32 bit word, and because of Bs range we +; need 2 bits above the valid range of B to detect overflow, and another one +; to detect the sense of the overflow. We therefore adopt the following +; representation: +; +; osGGGGGgggggosBBBBBbbbosRRRRRrrr +; +; Each such word breaks down into 3 ranges. +; +; osGGGGGggggg osBBBBBbbb osRRRRRrrr +; +; Thus we have 8 bits for each B and R table entry, and 10 bits for G (good +; as G is the most noticable one). The s bit for each represents the sign, +; and o represents the overflow. +; +; For R and B we pack the table by taking the 11 bit representation of their +; values, and toggling bit 10 in the U and V tables. +; +; For the green case we calculate 4*G (thus effectively using 10 bits for the +; valid range) truncate to 12 bits. We toggle bit 11 in the Y table. + +; Theorarm library +; Copyright (C) 2009 Robin Watts for Pinknoise Productions Ltd + + AREA |.text|, CODE, READONLY + + EXPORT yuv420_2_rgb888 + EXPORT yuv420_2_rgb888_PROFILE + +; void yuv420_2_rgb565 +; uint8_t *dst_ptr +; uint8_t *y_ptr +; uint8_t *u_ptr +; uint8_t *v_ptr +; int width +; int height +; int y_span +; int uv_span +; int dst_span +; int *tables +; int dither + +CONST_flags + DCD 0x40080100 +yuv420_2_rgb888 + ; r0 = dst_ptr + ; r1 = y_ptr + ; r2 = u_ptr + ; r3 = v_ptr + ; <> = width + ; <> = height + ; <> = y_span + ; <> = uv_span + ; <> = dst_span + ; <> = y_table + ; <> = dither + STMFD r13!,{r4-r11,r14} + + LDR r8, [r13,#10*4] ; r8 = height + LDR r10,[r13,#11*4] ; r10= y_span + LDR r9, [r13,#13*4] ; r9 = dst_span + LDR r14,[r13,#14*4] ; r14= y_table + LDR r5, CONST_flags + LDR r11,[r13,#9*4] ; r11= width + ADD r4, r14, #256*4 + SUBS r8, r8, #1 + BLT end + BEQ trail_row1 +yloop1 + SUB r8, r8, r11,LSL #16 ; r8 = height-(width<<16) + ADDS r8, r8, #1<<16 ; if (width == 1) + BGE trail_pair1 ; just do 1 column +xloop1 + LDRB r11,[r2], #1 ; r11 = u = *u_ptr++ + LDRB r12,[r3], #1 ; r12 = v = *v_ptr++ + LDRB r7, [r1, r10] ; r7 = y2 = y_ptr[stride] + LDRB r6, [r1], #1 ; r6 = y0 = *y_ptr++ + ADD r12,r12,#512 + LDR r11,[r4, r11,LSL #2] ; r11 = u = u_table[u] + LDR r12,[r14,r12,LSL #2] ; r12 = v = v_table[v] + LDR r7, [r14,r7, LSL #2] ; r7 = y2 = y_table[y2] + LDR r6, [r14,r6, LSL #2] ; r6 = y0 = y_table[y0] + ADD r11,r11,r12 ; r11 = uv = u+v + + ADD r7, r7, r11 ; r7 = y2 + uv + ADD r6, r6, r11 ; r6 = y0 + uv + ANDS r12,r7, r5 + TSTEQ r6, r5 + BNE fix101 +return101 + ; Store the bottom one first + ADD r12,r0, r9 + STRB r7,[r12],#1 ; Store R + MOV r7, r7, ROR #22 + STRB r7,[r12],#1 ; Store G + MOV r7, r7, ROR #21 + STRB r7,[r12],#1 ; Store B + + ; Then store the top one + STRB r6,[r0], #1 ; Store R + MOV r6, r6, ROR #22 + STRB r6,[r0], #1 ; Store G + + LDRB r7, [r1, r10] ; r7 = y3 = y_ptr[stride] + LDRB r12,[r1], #1 ; r12= y1 = *y_ptr++ + MOV r6, r6, ROR #21 + LDR r7, [r14, r7, LSL #2] ; r7 = y3 = y_table[y2] + LDR r12,[r14, r12,LSL #2] ; r12= y1 = y_table[y0] + STRB r6,[r0], #1 ; Store B + + ADD r7, r7, r11 ; r7 = y3 + uv + ADD r6, r12,r11 ; r6 = y1 + uv + ANDS r12,r7, r5 + TSTEQ r6, r5 + BNE fix102 +return102 + ; Store the bottom one first + ADD r12,r0, r9 + STRB r7,[r12],#1 ; Store R + MOV r7, r7, ROR #22 + STRB r7,[r12],#1 ; Store G + MOV r7, r7, ROR #21 + STRB r7,[r12],#1 ; Store B + + ; Then store the top one + STRB r6,[r0], #1 ; Store R + MOV r6, r6, ROR #22 + STRB r6,[r0], #1 ; Store G + MOV r6, r6, ROR #21 + STRB r6,[r0], #1 ; Store B + + ADDS r8, r8, #2<<16 + BLT xloop1 + MOVS r8, r8, LSL #16 ; Clear the top 16 bits of r8 + MOV r8, r8, LSR #16 ; If the C bit is clear we still have + BCC trail_pair1 ; 1 more pixel pair to do +end_xloop1 + LDR r11,[r13,#9*4] ; r11= width + LDR r12,[r13,#12*4] ; r12= uv_stride + ADD r0, r0, r9, LSL #1 + SUB r0, r0, r11,LSL #1 + SUB r0, r0, r11 + ADD r1, r1, r10,LSL #1 + SUB r1, r1, r11 + SUB r2, r2, r11,LSR #1 + SUB r3, r3, r11,LSR #1 + ADD r2, r2, r12 + ADD r3, r3, r12 + + SUBS r8, r8, #2 + BGT yloop1 + + LDMLTFD r13!,{r4-r11,pc} +trail_row1 + ; We have a row of pixels left to do + SUB r8, r8, r11,LSL #16 ; r8 = height-(width<<16) + ADDS r8, r8, #1<<16 ; if (width == 1) + BGE trail_pix1 ; just do 1 pixel +xloop12 + LDRB r11,[r2], #1 ; r11 = u = *u_ptr++ + LDRB r12,[r3], #1 ; r12 = v = *v_ptr++ + LDRB r6, [r1], #1 ; r6 = y0 = *y_ptr++ + LDRB r7, [r1], #1 ; r7 = y1 = *y_ptr++ + ADD r12,r12,#512 + LDR r11,[r4, r11,LSL #2] ; r11 = u = u_table[u] + LDR r12,[r14,r12,LSL #2] ; r12 = v = v_table[v] + LDR r7, [r14,r7, LSL #2] ; r7 = y1 = y_table[y1] + LDR r6, [r14,r6, LSL #2] ; r6 = y0 = y_table[y0] + ADD r11,r11,r12 ; r11 = uv = u+v + + ADD r6, r6, r11 ; r6 = y0 + uv + ADD r7, r7, r11 ; r7 = y1 + uv + ANDS r12,r7, r5 + TSTEQ r6, r5 + BNE fix104 +return104 + ; Store the bottom one first + STRB r6,[r0], #1 ; Store R + MOV r6, r6, ROR #22 + STRB r6,[r0], #1 ; Store G + MOV r6, r6, ROR #21 + STRB r6,[r0], #1 ; Store B + + ; Then store the top one + STRB r7,[r0], #1 ; Store R + MOV r7, r7, ROR #22 + STRB r7,[r0], #1 ; Store G + MOV r7, r7, ROR #21 + STRB r7,[r0], #1 ; Store B + + ADDS r8, r8, #2<<16 + BLT xloop12 + MOVS r8, r8, LSL #16 ; Clear the top 16 bits of r8 + MOV r8, r8, LSR #16 ; If the C bit is clear we still have + BCC trail_pix1 ; 1 more pixel pair to do +end + LDMFD r13!,{r4-r11,pc} +trail_pix1 + ; We have a single extra pixel to do + LDRB r11,[r2], #1 ; r11 = u = *u_ptr++ + LDRB r12,[r3], #1 ; r12 = v = *v_ptr++ + LDRB r6, [r1], #1 ; r6 = y0 = *y_ptr++ + ADD r12,r12,#512 + LDR r11,[r4, r11,LSL #2] ; r11 = u = u_table[u] + LDR r12,[r14,r12,LSL #2] ; r12 = v = v_table[v] + LDR r6, [r14,r6, LSL #2] ; r6 = y0 = y_table[y0] + ADD r11,r11,r12 ; r11 = uv = u+v + + ADD r6, r6, r11 ; r6 = y0 + uv + ANDS r12,r6, r5 + BNE fix105 +return105 + STRB r6,[r0], #1 ; Store R + MOV r6, r6, ROR #22 + STRB r6,[r0], #1 ; Store G + MOV r6, r6, ROR #21 + STRB r6,[r0], #1 ; Store B + + LDMFD r13!,{r4-r11,pc} + +trail_pair1 + ; We have a pair of pixels left to do + LDRB r11,[r2] ; r11 = u = *u_ptr++ + LDRB r12,[r3] ; r12 = v = *v_ptr++ + LDRB r7, [r1, r10] ; r7 = y2 = y_ptr[stride] + LDRB r6, [r1], #1 ; r6 = y0 = *y_ptr++ + ADD r12,r12,#512 + LDR r11,[r4, r11,LSL #2] ; r11 = u = u_table[u] + LDR r12,[r14,r12,LSL #2] ; r12 = v = v_table[v] + LDR r7, [r14,r7, LSL #2] ; r7 = y2 = y_table[y2] + LDR r6, [r14,r6, LSL #2] ; r6 = y0 = y_table[y0] + ADD r11,r11,r12 ; r11 = uv = u+v + + ADD r7, r7, r11 ; r7 = y2 + uv + ADD r6, r6, r11 ; r6 = y0 + uv + ANDS r12,r7, r5 + TSTEQ r6, r5 + BNE fix103 +return103 + ; Store the bottom one first + ADD r12,r0, r9 + STRB r7,[r12],#1 ; Store R + MOV r7, r7, ROR #22 + STRB r7,[r12],#1 ; Store G + MOV r7, r7, ROR #21 + STRB r7,[r12],#1 ; Store B + + ; Then store the top one + STRB r6,[r0], #1 ; Store R + MOV r6, r6, ROR #22 + STRB r6,[r0], #1 ; Store G + MOV r6, r6, ROR #21 + STRB r6,[r0], #1 ; Store B + B end_xloop1 +fix101 + ; r7 and r6 are the values, at least one of which has overflowed + ; r12 = r7 & mask = .s......s......s...... + SUB r12,r12,r12,LSR #8 ; r12 = ..SSSSSS.SSSSSS.SSSSSS + ORR r7, r7, r12 ; r7 |= ..SSSSSS.SSSSSS.SSSSSS + BIC r12,r5, r7, LSR #1 ; r12 = .o......o......o...... + ADD r7, r7, r12,LSR #8 ; r7 = fixed value + + AND r12, r6, r5 ; r12 = .S......S......S...... + SUB r12,r12,r12,LSR #8 ; r12 = ..SSSSSS.SSSSSS.SSSSSS + ORR r6, r6, r12 ; r6 |= ..SSSSSS.SSSSSS.SSSSSS + BIC r12,r5, r6, LSR #1 ; r12 = .o......o......o...... + ADD r6, r6, r12,LSR #8 ; r6 = fixed value + B return101 +fix102 + ; r7 and r6 are the values, at least one of which has overflowed + ; r12 = r7 & mask = .s......s......s...... + SUB r12,r12,r12,LSR #8 ; r12 = ..SSSSSS.SSSSSS.SSSSSS + ORR r7, r7, r12 ; r7 |= ..SSSSSS.SSSSSS.SSSSSS + BIC r12,r5, r7, LSR #1 ; r12 = .o......o......o...... + ADD r7, r7, r12,LSR #8 ; r7 = fixed value + + AND r12, r6, r5 ; r12 = .S......S......S...... + SUB r12,r12,r12,LSR #8 ; r12 = ..SSSSSS..SSSSS.SSSSSS + ORR r6, r6, r12 ; r6 |= ..SSSSSS..SSSSS.SSSSSS + BIC r12,r5, r6, LSR #1 ; r12 = .o......o......o...... + ADD r6, r6, r12,LSR #8 ; r6 = fixed value + B return102 +fix103 + ; r7 and r6 are the values, at least one of which has overflowed + ; r12 = r7 & mask = .s......s......s...... + SUB r12,r12,r12,LSR #8 ; r12 = ..SSSSSS.SSSSSS.SSSSSS + ORR r7, r7, r12 ; r7 |= ..SSSSSS.SSSSSS.SSSSSS + BIC r12,r5, r7, LSR #1 ; r12 = .o......o......o...... + ADD r7, r7, r12,LSR #8 ; r7 = fixed value + + AND r12, r6, r5 ; r12 = .S......S......S...... + SUB r12,r12,r12,LSR #8 ; r12 = ..SSSSSS.SSSSSS.SSSSSS + ORR r6, r6, r12 ; r6 |= ..SSSSSS.SSSSSS.SSSSSS + BIC r12,r5, r6, LSR #1 ; r12 = .o......o......o...... + ADD r6, r6, r12,LSR #8 ; r6 = fixed value + B return103 +fix104 + ; r7 and r6 are the values, at least one of which has overflowed + ; r12 = r7 & mask = .s......s......s...... + SUB r12,r12,r12,LSR #8 ; r12 = ..SSSSSS.SSSSSS.SSSSSS + ORR r7, r7, r12 ; r7 |= ..SSSSSS.SSSSSS.SSSSSS + BIC r12,r5, r7, LSR #1 ; r12 = .o......o......o...... + ADD r7, r7, r12,LSR #8 ; r7 = fixed value + + AND r12, r6, r5 ; r12 = .S......S......S...... + SUB r12,r12,r12,LSR #8 ; r12 = ..SSSSSS.SSSSSS.SSSSSS + ORR r6, r6, r12 ; r6 |= ..SSSSSS.SSSSSS.SSSSSS + BIC r12,r5, r6, LSR #1 ; r12 = .o......o......o...... + ADD r6, r6, r12,LSR #8 ; r6 = fixed value + B return104 +fix105 + ; r6 is the value, which has has overflowed + ; r12 = r7 & mask = .s......s......s...... + SUB r12,r12,r12,LSR #8 ; r12 = ..SSSSSS.SSSSSS.SSSSSS + ORR r6, r6, r12 ; r6 |= ..SSSSSS.SSSSSS.SSSSSS + BIC r12,r5, r6, LSR #1 ; r12 = .o......o......o...... + ADD r6, r6, r12,LSR #8 ; r6 = fixed value + B return105 + + END diff --git a/android/android-opencv/jni/yuv420rgb888c.c b/android/android-opencv/jni/yuv420rgb888c.c new file mode 100644 index 0000000..c7ec52e --- /dev/null +++ b/android/android-opencv/jni/yuv420rgb888c.c @@ -0,0 +1,208 @@ +/* YUV-> RGB conversion code. (YUV420 to RGB565) + * + * Copyright (C) 2008-9 Robin Watts (robin@wss.co.uk) for Pinknoise + * Productions Ltd. + * + * Licensed under the GNU GPL. If you need it under another license, contact + * me and ask. + * + * This program is free software ; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation ; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY ; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program ; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * The algorithm used here is based heavily on one created by Sophie Wilson + * of Acorn/e-14/Broadcomm. Many thanks. + * + * Additional tweaks (in the fast fixup code) are from Paul Gardiner. + * + * The old implementation of YUV -> RGB did: + * + * R = CLAMP((Y-16)*1.164 + 1.596*V) + * G = CLAMP((Y-16)*1.164 - 0.391*U - 0.813*V) + * B = CLAMP((Y-16)*1.164 + 2.018*U ) + * + * We're going to bend that here as follows: + * + * R = CLAMP(y + 1.596*V) + * G = CLAMP(y - 0.383*U - 0.813*V) + * B = CLAMP(y + 1.976*U ) + * + * where y = 0 for Y <= 16, + * y = ( Y-16)*1.164, for 16 < Y <= 239, + * y = (239-16)*1.164, for 239 < Y + * + * i.e. We clamp Y to the 16 to 239 range (which it is supposed to be in + * anyway). We then pick the B_U factor so that B never exceeds 511. We then + * shrink the G_U factor in line with that to avoid a colour shift as much as + * possible. + * + * We're going to use tables to do it faster, but rather than doing it using + * 5 tables as as the above suggests, we're going to do it using just 3. + * + * We do this by working in parallel within a 32 bit word, and using one + * table each for Y U and V. + * + * Source Y values are 0 to 255, so 0.. 260 after scaling + * Source U values are -128 to 127, so -49.. 49(G), -253..251(B) after + * Source V values are -128 to 127, so -204..203(R), -104..103(G) after + * + * So total summed values: + * -223 <= R <= 481, -173 <= G <= 431, -253 <= B < 511 + * + * We need to pack R G and B into a 32 bit word, and because of Bs range we + * need 2 bits above the valid range of B to detect overflow, and another one + * to detect the sense of the overflow. We therefore adopt the following + * representation: + * + * osGGGGGgggggosBBBBBbbbosRRRRRrrr + * + * Each such word breaks down into 3 ranges. + * + * osGGGGGggggg osBBBBBbbb osRRRRRrrr + * + * Thus we have 8 bits for each B and R table entry, and 10 bits for G (good + * as G is the most noticable one). The s bit for each represents the sign, + * and o represents the overflow. + * + * For R and B we pack the table by taking the 11 bit representation of their + * values, and toggling bit 10 in the U and V tables. + * + * For the green case we calculate 4*G (thus effectively using 10 bits for the + * valid range) truncate to 12 bits. We toggle bit 11 in the Y table. + */ + +#include "yuv2rgb.h" + +enum +{ + FLAGS = 0x40080100 +}; + +#define READUV(U,V) (tables[256 + (U)] + tables[512 + (V)]) +#define READY(Y) tables[Y] +#define FIXUP(Y) \ +do { \ + int tmp = (Y) & FLAGS; \ + if (tmp != 0) \ + { \ + tmp -= tmp>>8; \ + (Y) |= tmp; \ + tmp = FLAGS & ~(Y>>1); \ + (Y) += tmp>>8; \ + } \ +} while (0 == 1) + +#define STORE(Y,DSTPTR) \ +do { \ + uint32_t Y2 = (Y); \ + uint8_t *DSTPTR2 = (DSTPTR); \ + (DSTPTR2)[0] = (Y2); \ + (DSTPTR2)[1] = (Y2)>>22; \ + (DSTPTR2)[2] = (Y2)>>11; \ +} while (0 == 1) + +void yuv420_2_rgb888(uint8_t *dst_ptr, + const uint8_t *y_ptr, + const uint8_t *u_ptr, + const uint8_t *v_ptr, + int32_t width, + int32_t height, + int32_t y_span, + int32_t uv_span, + int32_t dst_span, + const uint32_t *tables, + int32_t dither) +{ + height -= 1; + while (height > 0) + { + height -= width<<16; + height += 1<<16; + while (height < 0) + { + /* Do 2 column pairs */ + uint32_t uv, y0, y1; + + uv = READUV(*u_ptr++,*v_ptr++); + y1 = uv + READY(y_ptr[y_span]); + y0 = uv + READY(*y_ptr++); + FIXUP(y1); + FIXUP(y0); + STORE(y1, &dst_ptr[dst_span]); + STORE(y0, dst_ptr); + dst_ptr += 3; + y1 = uv + READY(y_ptr[y_span]); + y0 = uv + READY(*y_ptr++); + FIXUP(y1); + FIXUP(y0); + STORE(y1, &dst_ptr[dst_span]); + STORE(y0, dst_ptr); + dst_ptr += 3; + height += (2<<16); + } + if ((height>>16) == 0) + { + /* Trailing column pair */ + uint32_t uv, y0, y1; + + uv = READUV(*u_ptr,*v_ptr); + y1 = uv + READY(y_ptr[y_span]); + y0 = uv + READY(*y_ptr++); + FIXUP(y1); + FIXUP(y0); + STORE(y0, &dst_ptr[dst_span]); + STORE(y1, dst_ptr); + dst_ptr += 3; + } + dst_ptr += dst_span*2-width*3; + y_ptr += y_span*2-width; + u_ptr += uv_span-(width>>1); + v_ptr += uv_span-(width>>1); + height = (height<<16)>>16; + height -= 2; + } + if (height == 0) + { + /* Trail row */ + height -= width<<16; + height += 1<<16; + while (height < 0) + { + /* Do a row pair */ + uint32_t uv, y0, y1; + + uv = READUV(*u_ptr++,*v_ptr++); + y1 = uv + READY(*y_ptr++); + y0 = uv + READY(*y_ptr++); + FIXUP(y1); + FIXUP(y0); + STORE(y1, dst_ptr); + dst_ptr += 3; + STORE(y0, dst_ptr); + dst_ptr += 3; + height += (2<<16); + } + if ((height>>16) == 0) + { + /* Trailing pix */ + uint32_t uv, y0; + + uv = READUV(*u_ptr++,*v_ptr++); + y0 = uv + READY(*y_ptr++); + FIXUP(y0); + STORE(y0, dst_ptr); + dst_ptr += 3; + } + } +} diff --git a/android/android-opencv/jni/yuv420sp2rgb.c b/android/android-opencv/jni/yuv420sp2rgb.c new file mode 100644 index 0000000..ef2eea3 --- /dev/null +++ b/android/android-opencv/jni/yuv420sp2rgb.c @@ -0,0 +1,156 @@ +#include +#include + +#include +#include + +/* + YUV 4:2:0 image with a plane of 8 bit Y samples followed by an interleaved + U/V plane containing 8 bit 2x2 subsampled chroma samples. + except the interleave order of U and V is reversed. + + H V + Y Sample Period 1 1 + U (Cb) Sample Period 2 2 + V (Cr) Sample Period 2 2 + */ + +/* + size of a char: + find . -name limits.h -exec grep CHAR_BIT {} \; + */ + +#ifndef max +#define max(a,b) (a > b ? a : b ) +#define min(a,b) (a < b ? a : b ) +#endif +enum +{ + FLAGS = 0x40080100 +}; + +#define READUV(U,V) (tables[256 + (U)] + tables[512 + (V)]) +#define READY(Y) tables[Y] +#define FIXUP(Y) \ +do { \ + int tmp = (Y) & FLAGS; \ + if (tmp != 0) \ + { \ + tmp -= tmp>>8; \ + (Y) |= tmp; \ + tmp = FLAGS & ~(Y>>1); \ + (Y) += tmp>>8; \ + } \ +} while (0 == 1) + +#define STORE(Y,DSTPTR) \ +do { \ + uint32_t Y2 = (Y); \ + uint8_t *DSTPTR2 = (DSTPTR); \ + (DSTPTR2)[2] = (Y2); \ + (DSTPTR2)[1] = (Y2)>>22; \ + (DSTPTR2)[0] = (Y2)>>11; \ +} while (0 == 1) + +typedef unsigned char byte; +const int bytes_per_pixel = 2; +void color_convert_common(const unsigned char *pY, const unsigned char *pUV, int width, int height, + unsigned char *buffer, int grey) +{ +#define LOOKUP 1 +#if ! LOOKUP + int nR, nG, nB; +#endif + int dest_span = 3 * width; + unsigned char *out = buffer; + if (grey) + { + memcpy(out, pY, width * height * sizeof(unsigned char)); + } + else + { + +#if LOOKUP + const uint32_t* tables = yuv2rgb565_table; + const byte* nY = pY; + const byte* nUV = pUV; + int idx = 0; + while (nY+width < pUV) + { + int y = (idx / width); + int x = (idx % width); + byte Y = *nY; + byte Y2 = nY[width]; + byte V = *nUV; + byte U = *(nUV + 1); + /* Do 2 row pairs */ + uint32_t uv, y0, y1; + + uv = READUV(U,V); + y1 = uv + READY(Y); + y0 = uv + READY(Y2); + FIXUP(y1); + FIXUP(y0); + STORE(y1, &out[dest_span]); + STORE(y0, out); + out += 3; + Y = *(++nY); + Y2 = nY[width]; + y1 = uv + READY(Y); + y0 = uv + READY(Y2); + FIXUP(y1); + FIXUP(y0); + STORE(y1, &out[dest_span]); + STORE(y0, out); + out += 3; + height += (2 << 16); + ++nY; + nUV = pUV + (y / 2) * width + 2 * (x / 2); + idx+=2; + } +#else + const byte* nY = pY; + const byte* nUV = pUV; + int idx = 0; + while (nY < pUV) + { + + int y = (idx / width); + int x = (idx % width); + int Y = *nY; + int V = *nUV; + int U = *(nUV + 1); + + Y -= 16; + V -= 128; + U -= 128; + if (y < 0) + y = 0; + + nB = (int)(1192 * Y + 2066 * U); + nG = (int)(1192 * Y - 833 * V - 400 * U); + nR = (int)(1192 * Y + 1634 * V); + + nR = min(262143, max(0, nR)); + nG = min(262143, max(0, nG)); + nB = min(262143, max(0, nB)); + + nR >>= 10; + nR &= 0xff; + nG >>= 10; + nG &= 0xff; + nB >>= 10; + nB &= 0xff; + + *(out++) = (unsigned char)nR; + *(out++) = (unsigned char)nG; + *(out++) = (unsigned char)nB; + nY += 1; + nUV = pUV + (y / 2) * width + 2 * (x / 2); + ++idx; + } +#endif + } + + +} diff --git a/android/android-jni/project_create.sh b/android/android-opencv/project_create.sh similarity index 100% rename from android/android-jni/project_create.sh rename to android/android-opencv/project_create.sh diff --git a/android/android-opencv/res/drawable-mdpi/cameraback.jpg b/android/android-opencv/res/drawable-mdpi/cameraback.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b53ffd48914da75f62c83c4578ceff67b2d25914 GIT binary patch literal 164530 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%0D8kaD7Poz&;QG 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 z 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 + + + + + + + + + + diff --git a/android/android-jni/res/layout/camerasettings.xml b/android/android-opencv/res/layout/camerasettings.xml similarity index 99% rename from android/android-jni/res/layout/camerasettings.xml rename to android/android-opencv/res/layout/camerasettings.xml index 5583014..4366ad3 100644 --- a/android/android-jni/res/layout/camerasettings.xml +++ b/android/android-opencv/res/layout/camerasettings.xml @@ -27,7 +27,7 @@ android:prompt="@string/camera_mode_prompt" android:entries="@array/camera_mode"> - + @@ -37,7 +37,7 @@ android:layout_height="wrap_content" android:saveEnabled="true" android:prompt="@string/whitebalance_prompt" android:entries="@array/whitebalance"> - - + + diff --git a/android/android-jni/res/layout/chesssizer.xml b/android/android-opencv/res/layout/chesssizer.xml similarity index 100% rename from android/android-jni/res/layout/chesssizer.xml rename to android/android-opencv/res/layout/chesssizer.xml diff --git a/android/android-jni/res/values/attrs.xml b/android/android-opencv/res/values/attrs.xml similarity index 100% rename from android/android-jni/res/values/attrs.xml rename to android/android-opencv/res/values/attrs.xml diff --git a/android/android-jni/res/values/chessnumbers.xml b/android/android-opencv/res/values/chessnumbers.xml similarity index 100% rename from android/android-jni/res/values/chessnumbers.xml rename to android/android-opencv/res/values/chessnumbers.xml diff --git a/android/android-jni/res/values/settingnumbers.xml b/android/android-opencv/res/values/settingnumbers.xml similarity index 100% rename from android/android-jni/res/values/settingnumbers.xml rename to android/android-opencv/res/values/settingnumbers.xml diff --git a/android/android-jni/res/values/strings.xml b/android/android-opencv/res/values/strings.xml similarity index 100% rename from android/android-jni/res/values/strings.xml rename to android/android-opencv/res/values/strings.xml diff --git a/android/android-jni/src/com/opencv/OpenCV.java b/android/android-opencv/src/com/opencv/OpenCV.java similarity index 98% rename from android/android-jni/src/com/opencv/OpenCV.java rename to android/android-opencv/src/com/opencv/OpenCV.java index d3e9248..0fced80 100644 --- a/android/android-jni/src/com/opencv/OpenCV.java +++ b/android/android-opencv/src/com/opencv/OpenCV.java @@ -107,7 +107,7 @@ public class OpenCV extends Activity { FrameLayout frame = new FrameLayout(getApplication()); // Create our Preview view and set it as the content of our activity. - mPreview = new NativePreviewer(getApplication(), 400, 300); + mPreview = new NativePreviewer(getApplication(), 640, 480); LayoutParams params = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); @@ -154,4 +154,4 @@ public class OpenCV extends Activity { } -} \ No newline at end of file +} diff --git a/android/android-jni/src/com/opencv/calibration/CalibrationViewer.java b/android/android-opencv/src/com/opencv/calibration/CalibrationViewer.java similarity index 100% rename from android/android-jni/src/com/opencv/calibration/CalibrationViewer.java rename to android/android-opencv/src/com/opencv/calibration/CalibrationViewer.java diff --git a/android/android-jni/src/com/opencv/calibration/Calibrator.java b/android/android-opencv/src/com/opencv/calibration/Calibrator.java similarity index 100% rename from android/android-jni/src/com/opencv/calibration/Calibrator.java rename to android/android-opencv/src/com/opencv/calibration/Calibrator.java diff --git a/android/android-jni/src/com/opencv/calibration/ChessBoardChooser.java b/android/android-opencv/src/com/opencv/calibration/ChessBoardChooser.java similarity index 100% rename from android/android-jni/src/com/opencv/calibration/ChessBoardChooser.java rename to android/android-opencv/src/com/opencv/calibration/ChessBoardChooser.java diff --git a/android/android-jni/src/com/opencv/calibration/services/CalibrationService.java b/android/android-opencv/src/com/opencv/calibration/services/CalibrationService.java similarity index 100% rename from android/android-jni/src/com/opencv/calibration/services/CalibrationService.java rename to android/android-opencv/src/com/opencv/calibration/services/CalibrationService.java diff --git a/android/android-opencv/src/com/opencv/camera/CameraActivity.java b/android/android-opencv/src/com/opencv/camera/CameraActivity.java new file mode 100644 index 0000000..ddb35a5 --- /dev/null +++ b/android/android-opencv/src/com/opencv/camera/CameraActivity.java @@ -0,0 +1,128 @@ +package com.opencv.camera; + +import java.util.LinkedList; + +import android.app.Activity; +import android.content.pm.ActivityInfo; +import android.os.Bundle; +import android.view.KeyEvent; +import android.view.MotionEvent; +import android.view.Window; +import android.view.WindowManager; +import android.widget.LinearLayout; + +import com.opencv.camera.CameraButtonsHandler.CaptureListener; +import com.opencv.opengl.GL2CameraViewer; + +public abstract class CameraActivity extends Activity implements CaptureListener { + + /** Called when the activity is first created. */ + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setFullscreen(); + setOrientation(); + disableScreenTurnOff(); + setContentView(com.opencv.R.layout.camera); + cameraButtonHandler = new CameraButtonsHandler(this,this); + mPreview = (NativePreviewer) findViewById(com.opencv.R.id.nativepreviewer); + LinearLayout glview_layout = (LinearLayout) findViewById(com.opencv.R.id.glview_layout); + glview = new GL2CameraViewer(getApplication(), true, 0, 0); + glview_layout.addView(glview); + } + + /** + * Handle the capture button as follows... + */ + @Override + public boolean onKeyUp(int keyCode, KeyEvent event) { + + switch (keyCode) { + case KeyEvent.KEYCODE_CAMERA: + case KeyEvent.KEYCODE_SPACE: + case KeyEvent.KEYCODE_DPAD_CENTER: + cameraButtonHandler.setIsCapture(true); + return true; + + default: + return super.onKeyUp(keyCode, event); + } + + } + + /** + * Handle the capture button as follows... On some phones there is no + * capture button, only trackball + */ + @Override + public boolean onTrackballEvent(MotionEvent event) { + if (event.getAction() == MotionEvent.ACTION_UP) { + cameraButtonHandler.setIsCapture(true); + return true; + } + return super.onTrackballEvent(event); + } + + /** + * Avoid that the screen get's turned off by the system. + */ + public void disableScreenTurnOff() { + getWindow().setFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON, + WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); + } + + /** + * Set's the orientation to landscape, as this is needed by AndAR. + */ + public void setOrientation() { + setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); + } + + /** + * Maximize the application. + */ + public void setFullscreen() { + requestWindowFeature(Window.FEATURE_NO_TITLE); + getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, + WindowManager.LayoutParams.FLAG_FULLSCREEN); + } + + @Override + protected void onPause() { + super.onPause(); + mPreview.onPause(); + glview.onPause(); + } + + @Override + protected void onResume() { + super.onResume(); + mPreview.setParamsFromPrefs(getApplicationContext()); + glview.onResume(); + mPreview.onResume(); + setCallbackStack(); + } + + protected void setCallbackStack() { + LinkedList callbackstack = getCallBackStack(); + if (callbackstack == null){ + callbackstack = new LinkedList(); + callbackstack.add(glview.getDrawCallback()); + } + mPreview.addCallbackStack(callbackstack); + } + + /** + * Overide this and provide your processors to the camera + * + * @return null for default drawing + */ + protected abstract LinkedList getCallBackStack(); + public void onCapture(){ + + } + + protected NativePreviewer mPreview; + protected GL2CameraViewer glview; + protected CameraButtonsHandler cameraButtonHandler; +} diff --git a/android/android-opencv/src/com/opencv/camera/CameraButtonsHandler.java b/android/android-opencv/src/com/opencv/camera/CameraButtonsHandler.java new file mode 100644 index 0000000..bbf5c2d --- /dev/null +++ b/android/android-opencv/src/com/opencv/camera/CameraButtonsHandler.java @@ -0,0 +1,83 @@ +package com.opencv.camera; + +import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.view.View; +import android.view.View.OnClickListener; +import android.widget.ImageButton; + +public class CameraButtonsHandler { + /** Constructs a buttons handler, will register with the capture button + * and the camera settings button. + * @param a The activity that has inflated the com.opencv.R.layout.camera + * as its layout. + */ + public CameraButtonsHandler(Activity a, CaptureListener l) { + ImageButton capture = (ImageButton) a + .findViewById(com.opencv.R.id.button_capture); + ImageButton settings = (ImageButton) a + .findViewById(com.opencv.R.id.button_camera_settings); + capture.setOnClickListener(capture_listener); + settings.setOnClickListener(settings_listener); + captureListener = l; + ctx = a; + } + + public CameraButtonsHandler(Activity a) { + ImageButton capture = (ImageButton) a + .findViewById(com.opencv.R.id.button_capture); + ImageButton settings = (ImageButton) a + .findViewById(com.opencv.R.id.button_camera_settings); + capture.setOnClickListener(capture_listener); + settings.setOnClickListener(settings_listener); + ctx = a; + } + + + /** Check if the capture button has been pressed + * @return true if the capture button has been pressed + */ + synchronized public boolean isCapture(){ + return capture_flag; + } + + /** Reset the capture flag + */ + synchronized public void resetIsCapture(){ + capture_flag = false; + } + + /** Manually set the flag - call this on any event that should trigger + * a capture + * @param isCapture true if a capture should take place + */ + synchronized public void setIsCapture(boolean isCapture){ + capture_flag = isCapture; + if(capture_flag && captureListener != null){ + captureListener.onCapture(); + } + } + + private OnClickListener capture_listener = new View.OnClickListener() { + @Override + public void onClick(View v) { + setIsCapture(true); + } + }; + private OnClickListener settings_listener = new View.OnClickListener() { + @Override + public void onClick(View v) { + Intent configurer = new Intent(ctx, + CameraConfig.class); + ctx.startActivity(configurer); + } + }; + + interface CaptureListener{ + public void onCapture(); + } + private CaptureListener captureListener; + private Context ctx; + private boolean capture_flag = false; +} diff --git a/android/android-jni/src/com/opencv/camera/CameraConfig.java b/android/android-opencv/src/com/opencv/camera/CameraConfig.java similarity index 99% rename from android/android-jni/src/com/opencv/camera/CameraConfig.java rename to android/android-opencv/src/com/opencv/camera/CameraConfig.java index 6f522ed..fcedd1b 100644 --- a/android/android-jni/src/com/opencv/camera/CameraConfig.java +++ b/android/android-opencv/src/com/opencv/camera/CameraConfig.java @@ -171,7 +171,7 @@ public class CameraConfig extends Activity { } }); - + whitebalance_spinner.setOnItemSelectedListener(new OnItemSelectedListener() { @Override diff --git a/android/android-jni/src/com/opencv/camera/NativePreviewer.java b/android/android-opencv/src/com/opencv/camera/NativePreviewer.java similarity index 97% rename from android/android-jni/src/com/opencv/camera/NativePreviewer.java rename to android/android-opencv/src/com/opencv/camera/NativePreviewer.java index fc2ad3c..4554d49 100644 --- a/android/android-jni/src/com/opencv/camera/NativePreviewer.java +++ b/android/android-opencv/src/com/opencv/camera/NativePreviewer.java @@ -29,7 +29,7 @@ public class NativePreviewer extends SurfaceView implements * Constructor useful for defining a NativePreviewer in android layout xml * * @param context - * @param attributes + * @param attributes */ public NativePreviewer(Context context, AttributeSet attributes) { super(context, attributes); @@ -47,7 +47,7 @@ public class NativePreviewer extends SurfaceView implements "preview_width", 600); preview_height = attributes.getAttributeIntValue("opencv", "preview_height", 600); - + Log.d("NativePreviewer", "Trying to use preview size of " + preview_width + " " + preview_height); @@ -92,17 +92,17 @@ public class NativePreviewer extends SurfaceView implements * @param height * desired height */ - public void setPreviewSize(int width, int height) { + public void setPreviewSize(int width, int height){ preview_width = width; preview_height = height; - + Log.d("NativePreviewer", "Trying to use preview size of " + preview_width + " " + preview_height); } - - public void setParamsFromPrefs(Context ctx) { - int size[] = { 0, 0 }; + + public void setParamsFromPrefs(Context ctx){ + int size[] ={0,0}; CameraConfig.readImageSize(ctx, size); int mode = CameraConfig.readCameraMode(ctx); setPreviewSize(size[0], size[1]); @@ -146,7 +146,7 @@ public class NativePreviewer extends SurfaceView implements } preview_width = best_width; preview_height = best_height; - + Log.d("NativePreviewer", "Determined compatible preview size is: (" + preview_width + "," + preview_height + ")"); @@ -159,10 +159,10 @@ public class NativePreviewer extends SurfaceView implements if (parameters.getSupportedWhiteBalance().contains(whitebalance_mode)) { parameters.setWhiteBalance(whitebalance_mode); } - if (parameters.getSupportedAntibanding().contains( - Camera.Parameters.ANTIBANDING_OFF)) { - parameters.setAntibanding(Camera.Parameters.ANTIBANDING_OFF); - } +// if (parameters.getSupportedAntibanding().contains( +// Camera.Parameters.ANTIBANDING_OFF)) { +// parameters.setAntibanding(Camera.Parameters.ANTIBANDING_OFF); +// } List fmodes = mCamera.getParameters().getSupportedFocusModes(); // for(String x: fmodes){ @@ -476,7 +476,7 @@ public class NativePreviewer extends SurfaceView implements public void setGrayscale(boolean b) { processor.setGrayscale(b); - + } } \ No newline at end of file diff --git a/android/android-jni/src/com/opencv/camera/NativeProcessor.java b/android/android-opencv/src/com/opencv/camera/NativeProcessor.java similarity index 100% rename from android/android-jni/src/com/opencv/camera/NativeProcessor.java rename to android/android-opencv/src/com/opencv/camera/NativeProcessor.java diff --git a/android/android-jni/src/com/opencv/opengl/GL2CameraViewer.java b/android/android-opencv/src/com/opencv/opengl/GL2CameraViewer.java similarity index 99% rename from android/android-jni/src/com/opencv/opengl/GL2CameraViewer.java rename to android/android-opencv/src/com/opencv/opengl/GL2CameraViewer.java index 2498ad7..237ae82 100644 --- a/android/android-jni/src/com/opencv/opengl/GL2CameraViewer.java +++ b/android/android-opencv/src/com/opencv/opengl/GL2CameraViewer.java @@ -361,6 +361,12 @@ public class GL2CameraViewer extends GLSurfaceView{ else Log.e("android-opencv", "null glcamera!!!!"); } + public void clear(){ + if(mglcamera != null) + mglcamera.clear(); + else + Log.e("android-opencv", "null glcamera!!!!"); + } private class Renderer implements GLSurfaceView.Renderer { diff --git a/android/android-opencv/src/com/opencv/utils/BitmapBridge.java b/android/android-opencv/src/com/opencv/utils/BitmapBridge.java new file mode 100644 index 0000000..573e7ae --- /dev/null +++ b/android/android-opencv/src/com/opencv/utils/BitmapBridge.java @@ -0,0 +1,34 @@ +package com.opencv.utils; + +import java.nio.ByteBuffer; + +import com.opencv.jni.Mat; +import com.opencv.jni.Size; +import com.opencv.jni.opencv; + +import android.graphics.Bitmap; +import android.graphics.Bitmap.Config; + +public class BitmapBridge { + static void copyBitmap(Bitmap bmap, Mat mat) throws Exception { + if ((bmap.getConfig() == null) || bmap.getConfig() == Config.ARGB_8888) + throw new Exception("bad config"); + Size sz = new Size(bmap.getWidth(), bmap.getHeight()); + mat.create(sz, opencv.CV_8UC4); + ByteBuffer buffer = ByteBuffer.allocate(4 * bmap.getWidth() + * bmap.getHeight()); + bmap.copyPixelsToBuffer(buffer); + opencv.copyBufferToMat(mat, buffer); + + } + + static Bitmap matToBitmap(Mat mat) { + Bitmap bmap = Bitmap.createBitmap(mat.getCols(), mat.getRows(), + Config.ARGB_8888); + ByteBuffer buffer = ByteBuffer.allocate(4 * bmap.getWidth() + * bmap.getHeight()); + opencv.copyMatToBuffer(buffer, mat); + bmap.copyPixelsFromBuffer(buffer); + return bmap; + } +} diff --git a/android/apps/CVCamera/CMakeLists.txt b/android/apps/CVCamera/CMakeLists.txt new file mode 100644 index 0000000..e82fbdf --- /dev/null +++ b/android/apps/CVCamera/CMakeLists.txt @@ -0,0 +1,5 @@ +cmake_minimum_required(VERSION 2.8) + +project(CVCamera) + +add_subdirectory(jni) diff --git a/android/apps/CVCamera/Makefile b/android/apps/CVCamera/Makefile deleted file mode 100644 index 7beb94c..0000000 --- a/android/apps/CVCamera/Makefile +++ /dev/null @@ -1,86 +0,0 @@ -# The path to the NDK, requires crystax version r-4 for now, due to support -# for the standard library - -# load environment from local make file -LOCAL_ENV_MK=local.env.mk -ifneq "$(wildcard $(LOCAL_ENV_MK))" "" -include $(LOCAL_ENV_MK) -else -$(shell cp sample.$(LOCAL_ENV_MK) $(LOCAL_ENV_MK)) -$(info ERROR local environement not setup! try:) -$(info gedit $(LOCAL_ENV_MK)) -$(error Please setup the $(LOCAL_ENV_MK) - the default was just created') -endif -ifndef ARM_TARGETS -ARM_TARGETS="armeabi armeabi-v7a" -endif -ANDROID_NDK_BASE = $(ANDROID_NDK_ROOT) - -$(info OPENCV_CONFIG = $(OPENCV_CONFIG)) - -ifndef PROJECT_PATH -$(info PROJECT_PATH defaulting to this directory) -PROJECT_PATH=. -endif - - -# The name of the native library -LIBNAME = libcvcamera.so - - -# Find all the C++ sources in the native folder -SOURCES = $(wildcard jni/*.cpp) -HEADERS = $(wildcard jni/*.h) - -ANDROID_MKS = $(wildcard jni/*.mk) - -SWIG_IS = $(wildcard jni/*.i) - -SWIG_MAIN = jni/cvcamera.i - -SWIG_JAVA_DIR = src/com/theveganrobot/cvcamera/jni -SWIG_JAVA_OUT = $(wildcard $(SWIG_JAVA_DIR)/*.java) - - -SWIG_C_DIR = jni/gen -SWIG_C_OUT = $(SWIG_C_DIR)/cvcamera_swig.cpp - -BUILD_DEFS=OPENCV_CONFIG=$(OPENCV_CONFIG) \ - PROJECT_PATH=$(PROJECT_PATH) \ - V=$(V) \ - $(NDK_FLAGS) \ - ARM_TARGETS=$(ARM_TARGETS) - -# The real native library stripped of symbols -LIB = libs/armeabi-v7a/$(LIBNAME) libs/armeabi/$(LIBNAME) - - -all: $(LIB) - - -#calls the ndk-build script, passing it OPENCV_ROOT and OPENCV_LIBS_DIR -$(LIB): $(SWIG_C_OUT) $(SOURCES) $(HEADERS) $(ANDROID_MKS) - $(ANDROID_NDK_BASE)/ndk-build $(BUILD_DEFS) - - -#this creates the swig wrappers -$(SWIG_C_OUT): $(SWIG_IS) - make clean-swig &&\ - mkdir -p $(SWIG_C_DIR) &&\ - mkdir -p $(SWIG_JAVA_DIR) &&\ - swig -java -c++ -I../../android-jni/jni -package "com.theveganrobot.cvcamera.jni" \ - -outdir $(SWIG_JAVA_DIR) \ - -o $(SWIG_C_OUT) $(SWIG_MAIN) - - -#clean targets -.PHONY: clean clean-swig cleanall - -#this deletes the generated swig java and the generated c wrapper -clean-swig: - rm -f $(SWIG_JAVA_OUT) $(SWIG_C_OUT) - -#does clean-swig and then uses the ndk-build clean -clean: clean-swig - $(ANDROID_NDK_BASE)/ndk-build clean $(BUILD_DEFS) - diff --git a/android/apps/CVCamera/build.sh b/android/apps/CVCamera/build.sh deleted file mode 100644 index 1497a39..0000000 --- a/android/apps/CVCamera/build.sh +++ /dev/null @@ -1 +0,0 @@ -make V=0 diff --git a/android/apps/CVCamera/clean.sh b/android/apps/CVCamera/clean.sh deleted file mode 100644 index 121e391..0000000 --- a/android/apps/CVCamera/clean.sh +++ /dev/null @@ -1 +0,0 @@ -make OPENCV_ROOT=../../opencv V=0 clean diff --git a/android/apps/CVCamera/default.properties b/android/apps/CVCamera/default.properties index 66148fe..248b9a0 100644 --- a/android/apps/CVCamera/default.properties +++ b/android/apps/CVCamera/default.properties @@ -7,6 +7,6 @@ # "build.properties", and override values to adapt the script to your # project structure. -android.library.reference.1=../../android-jni +android.library.reference.1=../../android-opencv # Project target. target=android-7 diff --git a/android/apps/CVCamera/jni/Android.mk b/android/apps/CVCamera/jni/Android.mk deleted file mode 100644 index f5aa1b1..0000000 --- a/android/apps/CVCamera/jni/Android.mk +++ /dev/null @@ -1,21 +0,0 @@ -# date: Summer, 2010 -# author: Ethan Rublee -# contact: ethan.rublee@gmail.com -# -LOCAL_PATH := $(call my-dir) - -include $(CLEAR_VARS) - -#define OPENCV_INCLUDES and OPENCV_LIBS -include $(OPENCV_CONFIG) - -LOCAL_LDLIBS += $(OPENCV_LIBS) $(ANDROID_OPENCV_LIBS) -llog -lGLESv2 - -LOCAL_C_INCLUDES += $(OPENCV_INCLUDES) $(ANDROID_OPENCV_INCLUDES) - -LOCAL_MODULE := cvcamera - -LOCAL_SRC_FILES := Processor.cpp gen/cvcamera_swig.cpp - -include $(BUILD_SHARED_LIBRARY) - diff --git a/android/apps/CVCamera/jni/Application.mk b/android/apps/CVCamera/jni/Application.mk deleted file mode 100644 index 0bbce43..0000000 --- a/android/apps/CVCamera/jni/Application.mk +++ /dev/null @@ -1,2 +0,0 @@ -# The ARMv7 is significanly faster due to the use of the hardware FPU -APP_ABI := $(ARM_TARGETS) \ No newline at end of file diff --git a/android/apps/CVCamera/jni/CMakeLists.txt b/android/apps/CVCamera/jni/CMakeLists.txt new file mode 100644 index 0000000..3ea00cb --- /dev/null +++ b/android/apps/CVCamera/jni/CMakeLists.txt @@ -0,0 +1,62 @@ +######################################################### +# Find opencv and android-opencv +######################################################### + +set(OpenCV_DIR ${CMAKE_SOURCE_DIR}/../../build + CACHE PATH "The path where you built opencv for android") +set(AndroidOpenCV_DIR ${CMAKE_SOURCE_DIR}/../../android-opencv/build + CACHE PATH "The path where you built android-opencv") + +find_package(OpenCV REQUIRED) +FIND_PACKAGE(AndroidOpenCV REQUIRED ) + +######################################################### +#c flags, included, and lib dependencies +######################################################### + +#notice the "recycling" of CMAKE_C_FLAGS +#this is necessary to pick up android flags +set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -pedantic -fPIC" ) + +INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) + +set( LIBRARY_DEPS ${AndroidOpenCV_LIBS} ${OpenCV_LIBS} ) +if(ANDROID) + set( LIBRARY_DEPS ${LIBRARY_DEPS} log dl) +endif(ANDROID) + +######################################################### +#SWIG STUFF +######################################################### +#the java package to place swig generated java files in +set(MY_PACKAGE com.theveganrobot.cvcamera.jni) + +if(NOT ANDROID) + #non android swig and jni + #jni is available by default on android + find_package(JNI REQUIRED) + include_directories(${JNI_INCLUDE_DIRS}) + FIND_PACKAGE(SWIG) +endif() + +INCLUDE(${SWIG_USE_FILE}) #on android this is found by the cmake toolchain + +if(ANDROID) + #this will set the output path for the java package + #and properly create the package declarations in generated java sources + SET_SWIG_JAVA_PACKAGE( ${MY_PACKAGE} ) #defined in the android toolchain +endif(ANDROID) + +#this add's the swig path for the opencv wrappers +SET(CMAKE_SWIG_FLAGS ${CMAKE_SWIG_FLAGS} "-I${AndroidOpenCV_SWIG_DIR}" ) + +SET_SOURCE_FILES_PROPERTIES(cvcamera.i PROPERTIES CPLUSPLUS ON) + +#add the swig module, giving it the name, java, and then all of the source files +SWIG_ADD_MODULE(cvcamera java + cvcamera.i #swig file + Processor.cpp #cpp files can be compiled to + ) + +#link the module like any other +target_link_libraries(cvcamera ${LIBRARY_DEPS} ) diff --git a/android/apps/CVCamera/sample.local.env.mk b/android/apps/CVCamera/sample.local.env.mk deleted file mode 100644 index b0cf78f..0000000 --- a/android/apps/CVCamera/sample.local.env.mk +++ /dev/null @@ -1,4 +0,0 @@ -#location of android-opencv port of OpenCV to android -OPENCV_CONFIG=../../build/android-opencv.mk -ANDROID_NDK_ROOT=$(HOME)/android-ndk-r4-crystax -ARM_TARGETS="armeabi armeabi-v7a" diff --git a/android/apps/Calibration/default.properties b/android/apps/Calibration/default.properties index 66148fe..7f801f9 100644 --- a/android/apps/Calibration/default.properties +++ b/android/apps/Calibration/default.properties @@ -7,6 +7,6 @@ # "build.properties", and override values to adapt the script to your # project structure. -android.library.reference.1=../../android-jni +android.library.reference.1=../../android-opencv/ # Project target. target=android-7 diff --git a/android/apps/Calibration/res/layout/camera.xml b/android/apps/Calibration/res/layout/calib_camera.xml similarity index 100% rename from android/apps/Calibration/res/layout/camera.xml rename to android/apps/Calibration/res/layout/calib_camera.xml diff --git a/android/apps/Calibration/src/com/opencv/calibration/Calibration.java b/android/apps/Calibration/src/com/opencv/calibration/Calibration.java index ce9cd4c..64217fb 100644 --- a/android/apps/Calibration/src/com/opencv/calibration/Calibration.java +++ b/android/apps/Calibration/src/com/opencv/calibration/Calibration.java @@ -204,9 +204,9 @@ public class Calibration extends Activity implements CalibrationCallback { setFullscreen(); disableScreenTurnOff(); - setContentView(R.layout.camera); + setContentView(R.layout.calib_camera); mPreview = (NativePreviewer) findViewById(R.id.nativepreviewer); - mPreview.setPreviewSize(1000, 500); + mPreview.setPreviewSize(800, 400); mPreview.setGrayscale(true); LinearLayout glview_layout = (LinearLayout) findViewById(R.id.glview_layout); glview = new GL2CameraViewer(getApplication(), false, 0, 0); diff --git a/android/apps/OpenCV_SAMPLE/AndroidManifest.xml b/android/apps/OpenCV_SAMPLE/AndroidManifest.xml new file mode 100644 index 0000000..c129d81 --- /dev/null +++ b/android/apps/OpenCV_SAMPLE/AndroidManifest.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/android/apps/OpenCV_SAMPLE/CMakeLists.txt b/android/apps/OpenCV_SAMPLE/CMakeLists.txt new file mode 100644 index 0000000..954ba5b --- /dev/null +++ b/android/apps/OpenCV_SAMPLE/CMakeLists.txt @@ -0,0 +1,5 @@ +cmake_minimum_required(VERSION 2.8) + +project(OpenCV_SAMPLE) + +add_subdirectory(jni) diff --git a/android/default.properties.in b/android/apps/OpenCV_SAMPLE/default.properties similarity index 86% rename from android/default.properties.in rename to android/apps/OpenCV_SAMPLE/default.properties index 9d135cb..5d6911a 100644 --- a/android/default.properties.in +++ b/android/apps/OpenCV_SAMPLE/default.properties @@ -1,11 +1,12 @@ # This file is automatically generated by Android Tools. # Do not modify this file -- YOUR CHANGES WILL BE ERASED! -# +# # This file must be checked in Version Control Systems. -# +# # To customize properties used by the Ant build system use, # "build.properties", and override values to adapt the script to your # project structure. # Project target. target=android-7 +android.library.reference.1=../../android-opencv/ diff --git a/android/apps/OpenCV_SAMPLE/jni/CMakeLists.txt b/android/apps/OpenCV_SAMPLE/jni/CMakeLists.txt new file mode 100644 index 0000000..823101c --- /dev/null +++ b/android/apps/OpenCV_SAMPLE/jni/CMakeLists.txt @@ -0,0 +1,68 @@ +######################################################### +# Find opencv and android-opencv +######################################################### + +set(OpenCV_DIR ${CMAKE_SOURCE_DIR}/../../build + CACHE PATH "The path where you built opencv for android") +set(AndroidOpenCV_DIR ${CMAKE_SOURCE_DIR}/../../android-opencv/build + CACHE PATH "The path where you built android-opencv") + +find_package(OpenCV REQUIRED) +FIND_PACKAGE(AndroidOpenCV REQUIRED ) + +######################################################### +#c flags, included, and lib dependencies +######################################################### + +#notice the "recycling" of CMAKE_C_FLAGS +#this is necessary to pick up android flags +set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -pedantic -fPIC" ) + +INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) + +set( LIBRARY_DEPS ${AndroidOpenCV_LIBS} ${OpenCV_LIBS} ) +if(ANDROID) + set( LIBRARY_DEPS ${LIBRARY_DEPS} log dl) +endif(ANDROID) + +######################################################### +#SWIG STUFF +######################################################### +#the java package to place swig generated java files in +set(MY_PACKAGE com.OpenCV_SAMPLE.jni ) +set(MY_MODULE OpenCV_SAMPLE ) +set(MY_SWIG + OpenCV_SAMPLE.i #swig file + ) +set(MY_SRCS + cvsample.cpp #cpp files can be compiled to + ) + +if(NOT ANDROID) + #non android swig and jni + #jni is available by default on android + find_package(JNI REQUIRED) + include_directories(${JNI_INCLUDE_DIRS}) + FIND_PACKAGE(SWIG) +endif() + +INCLUDE(${SWIG_USE_FILE}) #on android this is found by the cmake toolchain + +if(ANDROID) + #this will set the output path for the java package + #and properly create the package declarations in generated java sources + SET_SWIG_JAVA_PACKAGE( ${MY_PACKAGE} ) #defined in the android toolchain +endif(ANDROID) + +#this add's the swig path for the opencv wrappers +SET(CMAKE_SWIG_FLAGS ${CMAKE_SWIG_FLAGS} "-I${AndroidOpenCV_SWIG_DIR}" ) + +SET_SOURCE_FILES_PROPERTIES(${MY_SWIG} PROPERTIES CPLUSPLUS ON) + +#add the swig module, giving it the name, java, and then all of the source files +SWIG_ADD_MODULE(${MY_MODULE} java + ${MY_SWIG} + ${MY_SRCS} + ) +#link the module like any other +target_link_libraries(${MY_MODULE} ${LIBRARY_DEPS} ) diff --git a/android/apps/OpenCV_SAMPLE/jni/OpenCV_SAMPLE.i b/android/apps/OpenCV_SAMPLE/jni/OpenCV_SAMPLE.i new file mode 100644 index 0000000..93b6c89 --- /dev/null +++ b/android/apps/OpenCV_SAMPLE/jni/OpenCV_SAMPLE.i @@ -0,0 +1,48 @@ +/* File : foobar.i */ +%module OpenCV_SAMPLE + +/* + * the java import code muse be included for the opencv jni wrappers + * this means that the android project must reference opencv/android as a project + * see the default.properties for how this is done + */ +%pragma(java) jniclassimports=%{ +import com.opencv.jni.*; //import the android-opencv jni wrappers +%} + +%pragma(java) jniclasscode=%{ + static { + try { + //load up our shared libraries + System.loadLibrary("android-opencv"); + System.loadLibrary("OpenCV_SAMPLE"); + } catch (UnsatisfiedLinkError e) { + //badness + throw e; + } + } + +%} + +//import the android-cv.i file so that swig is aware of all that has been previous defined +//notice that it is not an include.... +%import "android-cv.i" + +%{ +#include "cvsample.h" +using cv::Mat; +%} + +//make sure to import the image_pool as it is +//referenced by the Processor java generated +//class +%typemap(javaimports) CVSample " +import com.opencv.jni.*;// import the opencv java bindings +" +class CVSample +{ +public: + void canny(const Mat& input, Mat& output, int edgeThresh); + void invert(Mat& inout); + void blur(Mat& inout, int half_kernel_size); +}; diff --git a/android/apps/OpenCV_SAMPLE/jni/cvsample.cpp b/android/apps/OpenCV_SAMPLE/jni/cvsample.cpp new file mode 100644 index 0000000..0f9eea9 --- /dev/null +++ b/android/apps/OpenCV_SAMPLE/jni/cvsample.cpp @@ -0,0 +1,27 @@ +#include "cvsample.h" +#include + +void CVSample::canny(const cv::Mat& input, cv::Mat& output, int edgeThresh) +{ + if (input.empty()) + return; + cv::Mat gray; + if (input.channels() == 3) + { + cv::cvtColor(input, gray, CV_RGB2GRAY); + } + else + gray = input; + cv::Canny(gray, output, edgeThresh, edgeThresh * 3, 3); +} + +void CVSample::invert(cv::Mat& inout) +{ + cv::bitwise_not(inout, inout); +} +void CVSample::blur(cv::Mat& inout, int half_kernel_size) +{ + int ksz = half_kernel_size*2 + 1; + cv::Size kernel(ksz,ksz); + cv::blur(inout,inout,kernel); +} diff --git a/android/apps/OpenCV_SAMPLE/jni/cvsample.h b/android/apps/OpenCV_SAMPLE/jni/cvsample.h new file mode 100644 index 0000000..345a35c --- /dev/null +++ b/android/apps/OpenCV_SAMPLE/jni/cvsample.h @@ -0,0 +1,11 @@ +#pragma once + +#include + +class CVSample +{ +public: + void canny(const cv::Mat& input, cv::Mat& output, int edgeThresh); + void invert(cv::Mat& inout); + void blur(cv::Mat& inout, int half_kernel_size); +}; diff --git a/android/apps/OpenCV_SAMPLE/project_create.sh b/android/apps/OpenCV_SAMPLE/project_create.sh new file mode 100755 index 0000000..c058d19 --- /dev/null +++ b/android/apps/OpenCV_SAMPLE/project_create.sh @@ -0,0 +1,3 @@ +#this generates an ant based cli build of the android-jni project +android update project --name OpenCV_SAMPLE \ +--path . diff --git a/android/apps/OpenCV_SAMPLE/res/drawable-hdpi/icon.png b/android/apps/OpenCV_SAMPLE/res/drawable-hdpi/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..4e828bafd86aae740c6d4da0af6cc67653b535a5 GIT binary patch literal 5760 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 V9}r2j|9cq#=xN{7s@8Of{2yTISoHt^ literal 0 HcmV?d00001 diff --git a/android/apps/OpenCV_SAMPLE/res/drawable-ldpi/icon.png b/android/apps/OpenCV_SAMPLE/res/drawable-ldpi/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..5e11406cb22ee31db3e88479d0dc73ee54e77127 GIT binary patch literal 2034 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 + + + diff --git a/android/apps/OpenCV_SAMPLE/res/menu/sample_menu.xml b/android/apps/OpenCV_SAMPLE/res/menu/sample_menu.xml new file mode 100644 index 0000000..8cf02d7 --- /dev/null +++ b/android/apps/OpenCV_SAMPLE/res/menu/sample_menu.xml @@ -0,0 +1,8 @@ + +

+ + + + + diff --git a/android/apps/OpenCV_SAMPLE/res/values/strings.xml b/android/apps/OpenCV_SAMPLE/res/values/strings.xml new file mode 100644 index 0000000..1b7d2e7 --- /dev/null +++ b/android/apps/OpenCV_SAMPLE/res/values/strings.xml @@ -0,0 +1,5 @@ + + + Hello World, OpenCV_SAMPLE! + OpenCV SAMPLE + diff --git a/android/apps/OpenCV_SAMPLE/src/com/OpenCV_SAMPLE/OpenCV_SAMPLE.java b/android/apps/OpenCV_SAMPLE/src/com/OpenCV_SAMPLE/OpenCV_SAMPLE.java new file mode 100644 index 0000000..7002cee --- /dev/null +++ b/android/apps/OpenCV_SAMPLE/src/com/OpenCV_SAMPLE/OpenCV_SAMPLE.java @@ -0,0 +1,87 @@ +package com.OpenCV_SAMPLE; + +import java.util.LinkedList; + +import android.os.Bundle; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; + +import com.OpenCV_SAMPLE.jni.CVSample; +import com.opencv.camera.CameraActivity; +import com.opencv.camera.NativeProcessor; +import com.opencv.camera.NativeProcessor.PoolCallback; +import com.opencv.jni.Mat; +import com.opencv.jni.image_pool; + +public class OpenCV_SAMPLE extends CameraActivity { + + private int do_what = R.id.cv_menu_nothing; + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + MenuInflater menu_flater = new MenuInflater(this); + menu_flater.inflate(R.menu.sample_menu, menu); + return true; + } + + @Override + public boolean onMenuItemSelected(int featureId, MenuItem item) { + switch (item.getItemId()) { + case R.id.cv_menu_blur: + case R.id.cv_menu_canny: + case R.id.cv_menu_invert: + case R.id.cv_menu_nothing: + do_what = item.getItemId(); + break; + default: + return false; + + } + return true; + } + + /** Called when the activity is first created. */ + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + } + + @Override + protected LinkedList getCallBackStack() { + LinkedList list = new LinkedList(); + list.add(samplePoolCallback); + return list; + } + + CVSample cvsample = new CVSample(); + Mat canny = new Mat(); + PoolCallback samplePoolCallback = new PoolCallback() { + + @Override + public void process(int idx, image_pool pool, long timestamp, + NativeProcessor nativeProcessor) { + Mat grey = pool.getGrey(idx); + Mat color = pool.getImage(idx); + Mat draw_img = color; + switch (do_what) { + case R.id.cv_menu_blur: + cvsample.blur(draw_img, 5); + break; + case R.id.cv_menu_canny: + cvsample.canny(grey, canny, 15); + draw_img = canny; + break; + case R.id.cv_menu_invert: + cvsample.invert(draw_img); + break; + case R.id.cv_menu_nothing: + break; + } + pool.addImage(idx + 1, draw_img); + glview.getDrawCallback().process(idx + 1, pool, timestamp, + nativeProcessor); + } + }; + +} \ No newline at end of file diff --git a/android/changes.Android.txt b/android/changes.Android.txt deleted file mode 100644 index 8741a44..0000000 --- a/android/changes.Android.txt +++ /dev/null @@ -1,17 +0,0 @@ -changes -added some specific CMakeLists.txt changes see the changes.diff for these - -basically see -mbstowcs is not supported - so see had to -#ifndef ANDROID -string fromUtf16(const WString& str) -WString toUtf16(const string& str) -#endif - -ANDROID is always defined when building with the ndk - -_S is a bad variable name for android... - -added the zlib-android - because i couldn't figure out how to configure the -existing zlib in 3rdparty - diff --git a/android/changes.diff b/android/changes.diff deleted file mode 100644 index 801c472..0000000 --- a/android/changes.diff +++ /dev/null @@ -1,255 +0,0 @@ -Index: modules/highgui/CMakeLists.txt -=================================================================== ---- modules/highgui/CMakeLists.txt (revision 3454) -+++ modules/highgui/CMakeLists.txt (working copy) -@@ -1,3 +1,21 @@ -+if(ANDROID) -+ -+set(high_gui_android_srcs src/bitstrm.cpp -+ src/cap.cpp -+ src/grfmt_base.cpp -+ src/grfmt_bmp.cpp -+ src/grfmt_jpeg.cpp -+ src/grfmt_png.cpp -+ src/grfmt_tiff.cpp -+ src/loadsave.cpp -+ src/precomp.cpp -+ src/utils.cpp -+ src/grfmt_sunras.cpp -+ src/grfmt_pxm.cpp -+ src/window.cpp ) -+define_android_manual(highgui "${high_gui_android_srcs}" "$(LOCAL_PATH)/src $(OPENCV_INCLUDES)") -+ -+else() - # ---------------------------------------------------------------------------- - # CMake file for highgui. See root CMakeLists.txt - # Some parts taken from version of Hartmut Seichter, HIT Lab NZ. -@@ -332,3 +350,5 @@ - install(FILES ${highgui_ext_hdrs} - DESTINATION include/opencv2/highgui - COMPONENT main) -+ -+endif()#android -Index: modules/core/src/persistence.cpp -=================================================================== ---- modules/core/src/persistence.cpp (revision 3454) -+++ modules/core/src/persistence.cpp (working copy) -@@ -114,12 +114,12 @@ - - namespace cv - { -- -+#ifndef ANDROID - string fromUtf16(const WString& str) - { - cv::AutoBuffer _buf(str.size()*4 + 1); - char* buf = _buf; -- -+ - size_t sz = wcstombs(buf, str.c_str(), str.size()); - if( sz == (size_t)-1 ) - return string(); -@@ -131,14 +131,14 @@ - { - cv::AutoBuffer _buf(str.size() + 1); - wchar_t* buf = _buf; -- -+ - size_t sz = mbstowcs(buf, str.c_str(), str.size()); - if( sz == (size_t)-1 ) - return WString(); - buf[sz] = '\0'; - return WString(buf); - } -- -+#endif - } -Index: modules/features2d/src/sift.cpp -=================================================================== ---- modules/features2d/src/sift.cpp (revision 3454) -+++ modules/features2d/src/sift.cpp (working copy) -@@ -172,6 +172,7 @@ - typedef Keypoints::iterator KeypointsIter ; ///< Keypoint list iter datatype - typedef Keypoints::const_iterator KeypointsConstIter ; ///< Keypoint list const iter datatype - -+#undef _S - /** @brief Constructors and destructors */ - /*@{*/ - Sift(const pixel_t* _im_pt, int _width, int _height, -Index: modules/features2d/CMakeLists.txt -=================================================================== ---- modules/features2d/CMakeLists.txt (revision 3454) -+++ modules/features2d/CMakeLists.txt (working copy) -@@ -1 +1,2 @@ --define_opencv_module(features2d opencv_core opencv_imgproc opencv_calib3d opencv_highgui) -\ No newline at end of file -+define_opencv_module(features2d opencv_core opencv_imgproc opencv_calib3d opencv_highgui) -+ -Index: modules/CMakeLists.txt -=================================================================== ---- modules/CMakeLists.txt (revision 3454) -+++ modules/CMakeLists.txt (working copy) -@@ -1,3 +1,7 @@ -+if(ANDROID) -+ configure_file("${CMAKE_SOURCE_DIR}/Android.mk.modules.in" "${CMAKE_CURRENT_BINARY_DIR}/Android.mk") -+endif() -+ - add_subdirectory(calib3d) - add_subdirectory(core) - add_subdirectory(features2d) -@@ -20,8 +24,11 @@ - endif() - - add_subdirectory(video) -+ -+if(!ANDROID) - add_subdirectory(haartraining) - add_subdirectory(traincascade) -+endif() - - - #add_subdirectory(gpu) -Index: 3rdparty/zlib/CMakeLists.txt -=================================================================== ---- 3rdparty/zlib/CMakeLists.txt (revision 3503) -+++ 3rdparty/zlib/CMakeLists.txt (working copy) -@@ -35,3 +35,5 @@ - DEBUG_POSTFIX "${OPENCV_DEBUG_POSTFIX}" - ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/3rdparty/lib" - ) -+ -+endif() -Index: 3rdparty/lapack/CMakeLists.txt -=================================================================== ---- 3rdparty/lapack/CMakeLists.txt (revision 3503) -+++ 3rdparty/lapack/CMakeLists.txt (working copy) -@@ -2,6 +2,10 @@ - # CMake file for opencv_lapack. See root CMakeLists.txt - # - # ---------------------------------------------------------------------------- -+if(ANDROID) -+define_3rdparty_module(opencv_lapack) -+else() -+ - project(opencv_lapack) - - # List of C++ files: -@@ -57,3 +61,4 @@ - DEBUG_POSTFIX "${OPENCV_DEBUG_POSTFIX}" - ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/3rdparty/lib - ) -+endif() #android -Index: 3rdparty/libjasper/CMakeLists.txt -=================================================================== ---- 3rdparty/libjasper/CMakeLists.txt (revision 3503) -+++ 3rdparty/libjasper/CMakeLists.txt (working copy) -@@ -1,3 +1,8 @@ -+if(ANDROID) -+define_3rdparty_module(jasper) -+else() -+ -+ - # ---------------------------------------------------------------------------- - # CMake file for libjasper. See root CMakeLists.txt - # -@@ -4,6 +9,7 @@ - # ---------------------------------------------------------------------------- - project(libjasper) - -+ - add_definitions(-DEXCLUDE_MIF_SUPPORT -DEXCLUDE_PNM_SUPPORT -DEXCLUDE_BMP_SUPPORT -DEXCLUDE_RAS_SUPPORT -DEXCLUDE_JPG_SUPPORT -DEXCLUDE_PGX_SUPPORT) - - # List of C++ files: -@@ -41,6 +47,8 @@ - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-implicit-function-declaration -Wno-unused") - endif() - -+endif()#!android -+ - set_target_properties(${the_target} - PROPERTIES - OUTPUT_NAME "${the_target}" -Index: 3rdparty/libpng/CMakeLists.txt -=================================================================== ---- 3rdparty/libpng/CMakeLists.txt (revision 3503) -+++ 3rdparty/libpng/CMakeLists.txt (working copy) -@@ -1,3 +1,7 @@ -+if(ANDROID) -+define_3rdparty_module(png) -+else() -+#endif()#android - # ---------------------------------------------------------------------------- - # CMake file for libpng. See root CMakeLists.txt - # -@@ -38,3 +42,4 @@ - DEBUG_POSTFIX "${OPENCV_DEBUG_POSTFIX}" - ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/3rdparty/lib" - ) -+endif()#android -Index: 3rdparty/libjpeg/CMakeLists.txt -=================================================================== ---- 3rdparty/libjpeg/CMakeLists.txt (revision 3503) -+++ 3rdparty/libjpeg/CMakeLists.txt (working copy) -@@ -1,3 +1,7 @@ -+if(ANDROID) -+define_3rdparty_module(jpeg) -+else() -+#endif()#android - # ---------------------------------------------------------------------------- - # CMake file for libjpeg. See root CMakeLists.txt - # -@@ -39,3 +43,4 @@ - DEBUG_POSTFIX "${OPENCV_DEBUG_POSTFIX}" - ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/3rdparty/lib - ) -+endif()#android -Index: 3rdparty/CMakeLists.txt -=================================================================== ---- 3rdparty/CMakeLists.txt (revision 3503) -+++ 3rdparty/CMakeLists.txt (working copy) -@@ -1,6 +1,22 @@ -+if(ANDROID) -+ configure_file("${CMAKE_SOURCE_DIR}/Android.mk.modules.in" "${CMAKE_CURRENT_BINARY_DIR}/Android.mk") -+ add_subdirectory(libpng) -+ add_subdirectory(libjpeg) -+ add_subdirectory(libjasper) -+ add_subdirectory(flann) -+ add_subdirectory(lapack) -+ -+ #zlib is special? look in zlib-android -+ #couldn't get the other one to compile for some reason... -+ #config issue -+ #add_subdirectory(zlib-android) -+ -+else() -+ - add_subdirectory(flann) - add_subdirectory(lapack) - add_subdirectory(zlib) -+ - if(WITH_JASPER AND NOT JASPER_FOUND) - add_subdirectory(libjasper) - endif() -@@ -13,3 +29,5 @@ - if(WITH_TIFF AND NOT TIFF_FOUND) - add_subdirectory(libtiff) - endif() -+ -+endif()#android -Index: 3rdparty/flann/CMakeLists.txt -=================================================================== ---- 3rdparty/flann/CMakeLists.txt (revision 3503) -+++ 3rdparty/flann/CMakeLists.txt (working copy) -@@ -1,3 +1,7 @@ -+if(ANDROID) -+file(GLOB_RECURSE flann_sources_cpp *.cpp) -+define_android_manual(flann "${flann_sources_cpp}" "$(LOCAL_PATH)/../include $(LOCAL_PATH)/../include/flann $(LOCAL_PATH)/nn $(LOCAL_PATH)/algorithms $(LOCAL_PATH)/util") -+else() - if (DEFINED OPENCV_VERSION) - - # ---------------------------------------------------------------------------- -@@ -105,3 +109,4 @@ - ) - - ENDIF() -+endif()#android diff --git a/android/cmake_android.sh b/android/cmake_android.sh new file mode 100644 index 0000000..b94b9d8 --- /dev/null +++ b/android/cmake_android.sh @@ -0,0 +1,4 @@ +mkdir build +cd build +cmake -C ../CMakeCache.android.initial.cmake -DCMAKE_TOOLCHAIN_FILE=$ANDTOOLCHAIN ../.. + diff --git a/android/cmake_android_armeabi.sh b/android/cmake_android_armeabi.sh new file mode 100644 index 0000000..cce096d --- /dev/null +++ b/android/cmake_android_armeabi.sh @@ -0,0 +1,4 @@ +mkdir build_armeabi +cd build_armeabi +cmake -C ../CMakeCache.android.initial.cmake -DARM_TARGETS=armeabi -DCMAKE_TOOLCHAIN_FILE=$ANDTOOLCHAIN ../.. + diff --git a/android/cvconfig.h.in b/android/cvconfig.h.in deleted file mode 100644 index 2499bd2..0000000 --- a/android/cvconfig.h.in +++ /dev/null @@ -1,161 +0,0 @@ -/* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP - systems. This function is required for `alloca.c' support on those systems. - */ -/* #undef CRAY_STACKSEG_END */ - -/* Define to 1 if using `alloca.c'. */ -/* #undef C_ALLOCA */ - -/* Define to 1 if you have `alloca', as a function or macro. */ -/* #undef HAVE_ALLOCA */ - -/* Define to 1 if you have and it should be used (not on Ultrix). - */ -#define HAVE_ALLOCA_H 1 - -/* V4L capturing support */ -//#define HAVE_CAMV4L - -/* V4L2 capturing support */ -//#define HAVE_CAMV4L2 - -/* Carbon windowing environment */ -/* #undef HAVE_CARBON */ - -/* IEEE1394 capturing support */ -/* #undef HAVE_DC1394 */ - -/* libdc1394 0.9.4 or 0.9.5 */ -/* #undef HAVE_DC1394_095 */ - -/* IEEE1394 capturing support - libdc1394 v2.x */ -//#define HAVE_DC1394_2 - -/* ffmpeg in Gentoo */ -/* #undef HAVE_GENTOO_FFMPEG */ - -/* FFMpeg video library */ -/* #undef HAVE_FFMPEG */ - -/* ffmpeg's libswscale */ -/* #undef HAVE_FFMPEG_SWSCALE */ - -/* GStreamer multimedia framework */ -/* #undef HAVE_GSTREAMER */ - -/* GStreamer with gstappsink & gstappsrc */ -/* #undef HAVE_GSTREAMER_APP */ - -/* GTK+ 2.0 Thread support */ -//#define HAVE_GTHREAD - -/* GTK+ 2.x toolkit */ -//#define HAVE_GTK - -/* OpenEXR codec */ -/* #undef HAVE_ILMIMF */ - -/* Apple ImageIO Framework */ -/* #undef HAVE_IMAGEIO */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_INTTYPES_H */ - -/* JPEG-2000 codec */ -#define HAVE_JASPER - -/* IJG JPEG codec */ -#define HAVE_JPEG - -/* Define to 1 if you have the `dl' library (-ldl). */ -/* #undef HAVE_LIBDL */ - -/* Define to 1 if you have the `gomp' library (-lgomp). */ -/* #undef HAVE_LIBGOMP */ - -/* Define to 1 if you have the `m' library (-lm). */ -/* #undef HAVE_LIBM */ - -/* libpng/png.h needs to be included */ -#undef HAVE_LIBPNG_PNG_H - -/* Define to 1 if you have the `pthread' library (-lpthread). */ -//#define HAVE_LIBPTHREAD 1 - -/* Define to 1 if you have the `lrint' function. */ -/* #undef HAVE_LRINT */ - -/* PNG codec */ -#define HAVE_PNG - -/* Define to 1 if you have the `png_get_valid' function. */ -/* #undef HAVE_PNG_GET_VALID */ - -/* png.h needs to be included */ -#define HAVE_PNG_H - -/* Define to 1 if you have the `png_set_tRNS_to_alpha' function. */ -/* #undef HAVE_PNG_SET_TRNS_TO_ALPHA */ - -/* QuickTime video libraries */ -/* #undef HAVE_QUICKTIME */ - -/* TIFF codec */ -/* #undef HAVE_TIFF */ - -/* Unicap video capture library */ -/* #undef HAVE_UNICAP */ - -/* Define to 1 if you have the header file. */ -#define HAVE_UNISTD_H 1 - -/* Xine video library */ -/* #undef HAVE_XINE */ - -/* LZ77 compression/decompression library (used for PNG) */ -/* #undef HAVE_ZLIB */ - -/* Intel Integrated Performance Primitives */ -/* #undef HAVE_IPP */ - -/* OpenCV compiled as static or dynamic libs */ -//#define OPENCV_BUILD_SHARED_LIB - -/* Name of package */ -#define PACKAGE "opencv" - -/* Define to the address where bug reports for this package should be sent. */ -//#define PACKAGE_BUGREPORT "opencvlibrary-devel@lists.sourceforge.net" - -/* Define to the full name of this package. */ -#define PACKAGE_NAME "opencv" - -/* Define to the full name and version of this package. */ -#define PACKAGE_STRING "opencv 2.2.0" - -/* Define to the one symbol short name of this package. */ -#define PACKAGE_TARNAME "opencv" - -/* Define to the version of this package. */ -#define PACKAGE_VERSION "2.2.0" - -/* If using the C implementation of alloca, define if you know the - direction of stack growth for your system; otherwise it will be - automatically deduced at runtime. - STACK_DIRECTION > 0 => grows toward higher addresses - STACK_DIRECTION < 0 => grows toward lower addresses - STACK_DIRECTION = 0 => direction of growth unknown */ -/* #undef STACK_DIRECTION */ - -/* Version number of package */ -#define VERSION "2.2.0" - -/* Define to 1 if your processor stores words with the most significant byte - first (like Motorola and SPARC, unlike Intel and VAX). */ -/* #undef WORDS_BIGENDIAN */ - -/* Intel Threading Building Blocks */ -/* #undef HAVE_TBB */ - -/*the android ndk defines this somewhere and it messes with some variables*/ -#undef _S diff --git a/android/diff.txt b/android/diff.txt deleted file mode 100644 index cf12e57..0000000 --- a/android/diff.txt +++ /dev/null @@ -1,211 +0,0 @@ -Index: modules/highgui/CMakeLists.txt -=================================================================== ---- modules/highgui/CMakeLists.txt (revision 3454) -+++ modules/highgui/CMakeLists.txt (working copy) -@@ -1,3 +1,21 @@ -+if(ANDROID) -+ -+set(high_gui_android_srcs src/bitstrm.cpp -+ src/cap.cpp -+ src/grfmt_base.cpp -+ src/grfmt_bmp.cpp -+ src/grfmt_jpeg.cpp -+ src/grfmt_png.cpp -+ src/grfmt_tiff.cpp -+ src/loadsave.cpp -+ src/precomp.cpp -+ src/utils.cpp -+ src/grfmt_sunras.cpp -+ src/grfmt_pxm.cpp -+ src/window.cpp ) -+define_android_manual(highgui "${high_gui_android_srcs}" "$(OpenCVInclude) $(LOCAL_PATH)/include") -+ -+else() - # ---------------------------------------------------------------------------- - # CMake file for highgui. See root CMakeLists.txt - # Some parts taken from version of Hartmut Seichter, HIT Lab NZ. -@@ -332,3 +350,5 @@ - install(FILES ${highgui_ext_hdrs} - DESTINATION include/opencv2/highgui - COMPONENT main) -+ -+endif()#android -Index: modules/features2d/src/sift.cpp -=================================================================== ---- modules/features2d/src/sift.cpp (revision 3454) -+++ modules/features2d/src/sift.cpp (working copy) -@@ -172,6 +172,7 @@ - typedef Keypoints::iterator KeypointsIter ; ///< Keypoint list iter datatype - typedef Keypoints::const_iterator KeypointsConstIter ; ///< Keypoint list const iter datatype - -+#undef _S - /** @brief Constructors and destructors */ - /*@{*/ - Sift(const pixel_t* _im_pt, int _width, int _height, -Index: modules/features2d/CMakeLists.txt -=================================================================== ---- modules/features2d/CMakeLists.txt (revision 3454) -+++ modules/features2d/CMakeLists.txt (working copy) -@@ -1 +1,2 @@ --define_opencv_module(features2d opencv_core opencv_imgproc opencv_calib3d opencv_highgui) -\ No newline at end of file -+define_opencv_module(features2d opencv_core opencv_imgproc opencv_calib3d opencv_highgui) -+ -Index: modules/CMakeLists.txt -=================================================================== ---- modules/CMakeLists.txt (revision 3454) -+++ modules/CMakeLists.txt (working copy) -@@ -1,3 +1,7 @@ -+if(ANDROID) -+ configure_file("${CMAKE_SOURCE_DIR}/Android.mk.modules.in" "${CMAKE_CURRENT_BINARY_DIR}/Android.mk") -+endif() -+ - add_subdirectory(calib3d) - add_subdirectory(core) - add_subdirectory(features2d) -@@ -20,8 +24,11 @@ - endif() - - add_subdirectory(video) -+ -+if(!ANDROID) - add_subdirectory(haartraining) - add_subdirectory(traincascade) -+endif() - - - #add_subdirectory(gpu) -Index: 3rdparty/zlib/CMakeLists.txt -=================================================================== ---- 3rdparty/zlib/CMakeLists.txt (revision 3454) -+++ 3rdparty/zlib/CMakeLists.txt (working copy) -@@ -1,3 +1,7 @@ -+if(ANDROID) -+define_3rdparty_module(zlib) -+else() -+ - # ---------------------------------------------------------------------------- - # CMake file for zlib. See root CMakeLists.txt - # -@@ -35,3 +39,5 @@ - DEBUG_POSTFIX "${OPENCV_DEBUG_POSTFIX}" - ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/3rdparty/lib" - ) -+ -+endif() -Index: 3rdparty/lapack/CMakeLists.txt -=================================================================== ---- 3rdparty/lapack/CMakeLists.txt (revision 3454) -+++ 3rdparty/lapack/CMakeLists.txt (working copy) -@@ -2,6 +2,10 @@ - # CMake file for opencv_lapack. See root CMakeLists.txt - # - # ---------------------------------------------------------------------------- -+if(ANDROID) -+define_3rdparty_module(opencv_lapack) -+else() -+ - project(opencv_lapack) - - # List of C++ files: -@@ -57,3 +61,4 @@ - DEBUG_POSTFIX "${OPENCV_DEBUG_POSTFIX}" - ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/3rdparty/lib - ) -+endif() #android -Index: 3rdparty/libjasper/CMakeLists.txt -=================================================================== ---- 3rdparty/libjasper/CMakeLists.txt (revision 3454) -+++ 3rdparty/libjasper/CMakeLists.txt (working copy) -@@ -1,3 +1,8 @@ -+if(ANDROID) -+define_3rdparty_module(jasper) -+else() -+ -+ - # ---------------------------------------------------------------------------- - # CMake file for libjasper. See root CMakeLists.txt - # -@@ -4,6 +9,7 @@ - # ---------------------------------------------------------------------------- - project(libjasper) - -+ - add_definitions(-DEXCLUDE_MIF_SUPPORT -DEXCLUDE_PNM_SUPPORT -DEXCLUDE_BMP_SUPPORT -DEXCLUDE_RAS_SUPPORT -DEXCLUDE_JPG_SUPPORT -DEXCLUDE_PGX_SUPPORT) - - # List of C++ files: -@@ -41,6 +47,8 @@ - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-implicit-function-declaration -Wno-unused") - endif() - -+endif()#!android -+ - set_target_properties(${the_target} - PROPERTIES - OUTPUT_NAME "${the_target}" -Index: 3rdparty/libpng/CMakeLists.txt -=================================================================== ---- 3rdparty/libpng/CMakeLists.txt (revision 3454) -+++ 3rdparty/libpng/CMakeLists.txt (working copy) -@@ -1,3 +1,7 @@ -+if(ANDROID) -+define_3rdparty_module(png) -+else() -+#endif()#android - # ---------------------------------------------------------------------------- - # CMake file for libpng. See root CMakeLists.txt - # -@@ -38,3 +42,4 @@ - DEBUG_POSTFIX "${OPENCV_DEBUG_POSTFIX}" - ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/3rdparty/lib" - ) -+endif()#android -Index: 3rdparty/libjpeg/CMakeLists.txt -=================================================================== ---- 3rdparty/libjpeg/CMakeLists.txt (revision 3454) -+++ 3rdparty/libjpeg/CMakeLists.txt (working copy) -@@ -1,3 +1,7 @@ -+if(ANDROID) -+define_3rdparty_module(jpeg) -+else() -+#endif()#android - # ---------------------------------------------------------------------------- - # CMake file for libjpeg. See root CMakeLists.txt - # -@@ -39,3 +43,4 @@ - DEBUG_POSTFIX "${OPENCV_DEBUG_POSTFIX}" - ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/3rdparty/lib - ) -+endif()#android -Index: 3rdparty/CMakeLists.txt -=================================================================== ---- 3rdparty/CMakeLists.txt (revision 3454) -+++ 3rdparty/CMakeLists.txt (working copy) -@@ -1,3 +1,10 @@ -+if(ANDROID) -+ configure_file("${CMAKE_SOURCE_DIR}/Android.mk.modules.in" "${CMAKE_CURRENT_BINARY_DIR}/Android.mk") -+ add_subdirectory(libpng) -+ add_subdirectory(libjpeg) -+ add_subdirectory(libjasper) -+endif() -+ - add_subdirectory(flann) - add_subdirectory(lapack) - add_subdirectory(zlib) -Index: 3rdparty/flann/CMakeLists.txt -=================================================================== ---- 3rdparty/flann/CMakeLists.txt (revision 3454) -+++ 3rdparty/flann/CMakeLists.txt (working copy) -@@ -1,3 +1,7 @@ -+if(ANDROID) -+file(GLOB_RECURSE flann_sources_cpp *.cpp) -+define_android_manual(flann "${flann_sources_cpp}" "$(LOCAL_PATH)/../include $(LOCAL_PATH)/../include/flann $(LOCAL_PATH)/nn $(LOCAL_PATH)/algorithms $(LOCAL_PATH)/util") -+else() - if (DEFINED OPENCV_VERSION) - - # ---------------------------------------------------------------------------- -@@ -105,3 +109,4 @@ - ) - - ENDIF() -+endif()#android diff --git a/modules/CMakeLists.txt b/modules/CMakeLists.txt index ce50df3..c5bcc50 100644 --- a/modules/CMakeLists.txt +++ b/modules/CMakeLists.txt @@ -1,7 +1,3 @@ -if(ANDROID) - configure_file("${CMAKE_SOURCE_DIR}/Android.mk.modules.in" "${CMAKE_CURRENT_BINARY_DIR}/Android.mk") -endif() - add_subdirectory(calib3d) add_subdirectory(core) add_subdirectory(features2d) @@ -13,7 +9,9 @@ if(MSVC OR MINGW) endif() endif() +if(NOT ANDROID) add_subdirectory(ts) +endif() add_subdirectory(highgui) add_subdirectory(imgproc) add_subdirectory(legacy) @@ -26,10 +24,10 @@ if(PYTHONLIBS_FOUND AND BUILD_NEW_PYTHON_SUPPORT) endif() add_subdirectory(video) +add_subdirectory(traincascade) +add_subdirectory(haartraining) if(NOT ANDROID) -add_subdirectory(haartraining) -add_subdirectory(traincascade) add_subdirectory(gpu) endif() diff --git a/modules/haartraining/CMakeLists.txt b/modules/haartraining/CMakeLists.txt index d092808..74d021d 100644 --- a/modules/haartraining/CMakeLists.txt +++ b/modules/haartraining/CMakeLists.txt @@ -39,6 +39,7 @@ set(cvhaartraining_lib_src add_library(opencv_haartraining_engine STATIC ${cvhaartraining_lib_src}) +if(NOT ANDROID) # ----------------------------------------------------------- # haartraining # ----------------------------------------------------------- @@ -75,3 +76,4 @@ set_target_properties(opencv_performance PROPERTIES install(TARGETS opencv_haartraining RUNTIME DESTINATION bin COMPONENT main) install(TARGETS opencv_createsamples RUNTIME DESTINATION bin COMPONENT main) install(TARGETS opencv_performance RUNTIME DESTINATION bin COMPONENT main) +endif() diff --git a/modules/highgui/CMakeLists.txt b/modules/highgui/CMakeLists.txt index 00171cf..f4d9458 100644 --- a/modules/highgui/CMakeLists.txt +++ b/modules/highgui/CMakeLists.txt @@ -3,7 +3,6 @@ # Some parts taken from version of Hartmut Seichter, HIT Lab NZ. # Jose Luis Blanco, 2008 # ---------------------------------------------------------------------------- -if(NOT ANDROID) project(opencv_highgui) if(WITH_JPEG) @@ -204,6 +203,11 @@ if(APPLE) endif() endif(APPLE) +if(HAVE_ANDROID_NATIVE_CAMERA) + set(highgui_srcs ${highgui_srcs} src/cap_android.cpp) + add_definitions(-DHAVE_ANDROID_NATIVE_CAMERA) +endif() + source_group("Src" FILES ${highgui_srcs} ${highgui_hdrs}) source_group("Include" FILES ${highgui_ext_hdrs}) @@ -296,7 +300,6 @@ if( OPENNI_LIBRARY ) target_link_libraries(${the_target} ${OPENNI_LIBRARY}) endif() - if(APPLE) target_link_libraries(${the_target} "-lbz2 -framework Cocoa -framework QuartzCore") if(WITH_CARBON) @@ -317,25 +320,4 @@ install(TARGETS ${the_target} install(FILES ${highgui_ext_hdrs} DESTINATION include/opencv2/highgui - COMPONENT main) - -endif() - -if(ANDROID) -set(high_gui_android_srcs src/bitstrm.cpp - src/cap.cpp - src/grfmt_base.cpp - src/grfmt_bmp.cpp - src/grfmt_jpeg.cpp - src/grfmt_jpeg2000.cpp - src/grfmt_png.cpp - src/grfmt_tiff.cpp - src/loadsave.cpp - src/precomp.cpp - src/utils.cpp - src/grfmt_sunras.cpp - src/grfmt_pxm.cpp - src/window.cpp - src/cap_images.cpp ) -define_android_manual(opencv_highgui "${high_gui_android_srcs}" "$(LOCAL_PATH)/src $(OPENCV_INCLUDES)") -endif() + COMPONENT main) \ No newline at end of file diff --git a/modules/highgui/include/opencv2/highgui/highgui_c.h b/modules/highgui/include/opencv2/highgui/highgui_c.h index ecf8d27..3c861f5 100644 --- a/modules/highgui/include/opencv2/highgui/highgui_c.h +++ b/modules/highgui/include/opencv2/highgui/highgui_c.h @@ -290,7 +290,9 @@ enum CV_CAP_PVAPI =800, // PvAPI, Prosilica GigE SDK - CV_CAP_OPENNI =900 // OpenNI (for Kinect) + CV_CAP_OPENNI =900, // OpenNI (for Kinect) + + CV_CAP_ANDROID =1000 // Android }; /* start capturing frames from camera: index = camera_index + domain_offset (CV_CAP_*) */ @@ -387,6 +389,14 @@ enum CV_CAP_OPENNI_SXGA_15HZ = 1 }; +//supported by Android camera output formats +enum +{ + CV_CAP_ANDROID_COLOR_FRAME = 1, //TODO: check RGB or BGR? + CV_CAP_ANDROID_GREY_FRAME = 0, + CV_CAP_ANDROID_YUV_FRAME = 2 +}; + /* retrieve or set capture properties */ CVAPI(double) cvGetCaptureProperty( CvCapture* capture, int property_id ); CVAPI(int) cvSetCaptureProperty( CvCapture* capture, int property_id, double value ); diff --git a/modules/highgui/src/cap.cpp b/modules/highgui/src/cap.cpp index f7cedc1..807502e 100644 --- a/modules/highgui/src/cap.cpp +++ b/modules/highgui/src/cap.cpp @@ -124,6 +124,7 @@ CV_IMPL CvCapture * cvCreateCameraCapture (int index) CV_CAP_QT, CV_CAP_UNICAP, CV_CAP_OPENNI, + CV_CAP_ANDROID, -1 }; @@ -143,7 +144,7 @@ CV_IMPL CvCapture * cvCreateCameraCapture (int index) defined(HAVE_CAMV4L) || defined (HAVE_CAMV4L2) || defined(HAVE_GSTREAMER) || \ defined(HAVE_DC1394_2) || defined(HAVE_DC1394) || defined(HAVE_CMU1394) || \ defined(HAVE_GSTREAMER) || defined(HAVE_MIL) || defined(HAVE_QUICKTIME) || \ - defined(HAVE_UNICAP) || defined(HAVE_PVAPI) || defined(HAVE_OPENNI) + defined(HAVE_UNICAP) || defined(HAVE_PVAPI) || defined(HAVE_OPENNI) || defined(HAVE_ANDROID_NATIVE_CAMERA) // local variable to memorize the captured device CvCapture *capture; #endif @@ -250,7 +251,15 @@ CV_IMPL CvCapture * cvCreateCameraCapture (int index) return capture; break; #endif - + + #ifdef HAVE_ANDROID_NATIVE_CAMERA + case CV_CAP_ANDROID: + capture = cvCreateCameraCapture_Android (index); + if (capture) + return capture; + break; + #endif + } } diff --git a/modules/highgui/src/cap_android.cpp b/modules/highgui/src/cap_android.cpp new file mode 100644 index 0000000..8559652 --- /dev/null +++ b/modules/highgui/src/cap_android.cpp @@ -0,0 +1,354 @@ + /*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +#include "precomp.hpp" + +#ifdef HAVE_ANDROID_NATIVE_CAMERA + +#include +#include +#include +#include "camera_activity.h" + +#define LOG_TAG "CV_CAP" +#define LOGD(...) ((void)__android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)) +#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)) +#define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)) + +class HighguiAndroidCameraActivity; + +class CvCapture_Android : public CvCapture +{ +public: + CvCapture_Android(); + virtual ~CvCapture_Android(); + + virtual double getProperty(int propIdx); + virtual bool setProperty(int probIdx, double propVal); + virtual bool grabFrame(); + virtual IplImage* retrieveFrame(int outputType); + virtual int getCaptureDomain() { return CV_CAP_ANDROID; } + + bool isOpened() const; + +protected: + struct OutputMap + { + public: + cv::Mat mat; + IplImage* getIplImagePtr(); + private: + IplImage iplHeader; + }; + + CameraActivity* m_activity; + +private: + bool m_isOpened; + + OutputMap *m_frameYUV; + OutputMap *m_frameYUVnext; + OutputMap m_frameGray; + OutputMap m_frameColor; + bool m_hasGray; + bool m_hasColor; + + pthread_mutex_t m_nextFrameMutex; + pthread_cond_t m_nextFrameCond; + volatile bool m_waitingNextFrame; + + int m_framesGrabbed; + + friend class HighguiAndroidCameraActivity; + + void onFrame(const void* buffer, int bufferSize); + + void convertBufferToYUV(const void* buffer, int size, int width, int height); + static bool convertYUVToGrey(const cv::Mat& yuv, cv::Mat& resmat); + static bool convertYUVToColor(const cv::Mat& yuv, cv::Mat& resmat); +}; + + +class HighguiAndroidCameraActivity : public CameraActivity +{ + public: + HighguiAndroidCameraActivity(CvCapture_Android* capture) + { + m_capture = capture; + m_framesReceived = 0; + } + + virtual bool onFrameBuffer(void* buffer, int bufferSize) + { + LOGD("buffer addr:%p size:%d",buffer, bufferSize); + if(isConnected() && buffer != 0 && bufferSize > 0) + { + m_framesReceived++; + if (m_capture->m_waitingNextFrame) + { + m_capture->onFrame(buffer, bufferSize); + pthread_mutex_lock(&m_capture->m_nextFrameMutex); + m_capture->m_waitingNextFrame = false;//set flag that no more frames required at this moment + pthread_cond_broadcast(&m_capture->m_nextFrameCond); + pthread_mutex_unlock(&m_capture->m_nextFrameMutex); + } + return true; + } + return false; + } + + void LogFramesRate() + { + LOGI("FRAMES received: %d grabbed: %d", m_framesReceived, m_capture->m_framesGrabbed); + } + + private: + CvCapture_Android* m_capture; + int m_framesReceived; +}; + +IplImage* CvCapture_Android::OutputMap::getIplImagePtr() +{ + if( mat.empty() ) + return 0; + + iplHeader = IplImage(mat); + return &iplHeader; +} + +bool CvCapture_Android::isOpened() const +{ + return m_isOpened; +} + +CvCapture_Android::CvCapture_Android() +{ + //defaults + m_activity = 0; + m_isOpened = false; + m_frameYUV = 0; + m_frameYUVnext = 0; + m_hasGray = false; + m_hasColor = false; + m_waitingNextFrame = false; + m_framesGrabbed = 0; + + //try connect to camera + m_activity = new HighguiAndroidCameraActivity(this); + + if (m_activity == 0) return; + pthread_mutex_init(&m_nextFrameMutex, NULL); + pthread_cond_init (&m_nextFrameCond, NULL); + + CameraActivity::ErrorCode errcode = m_activity->connect(); + if(errcode == CameraActivity::NO_ERROR) + { + m_isOpened = true; + m_frameYUV = new OutputMap(); + m_frameYUVnext = new OutputMap(); + } + else + { + LOGE("Native_camera returned opening error: %d", errcode); + delete m_activity; + m_activity = 0; + } +} + +CvCapture_Android::~CvCapture_Android() +{ + if (m_activity) + { + ((HighguiAndroidCameraActivity*)m_activity)->LogFramesRate(); + + //m_activity->disconnect() will be automatically called inside destructor; + delete m_activity; + delete m_frameYUV; + delete m_frameYUVnext; + m_activity = 0; + m_frameYUV = 0; + m_frameYUVnext = 0; + + pthread_mutex_destroy(&m_nextFrameMutex); + pthread_cond_destroy(&m_nextFrameCond); + } +} + +double CvCapture_Android::getProperty( int propIdx ) +{ + switch ( propIdx ) + { + case CV_CAP_PROP_FRAME_WIDTH: + return (double)CameraActivity::getFrameWidth(); + case CV_CAP_PROP_FRAME_HEIGHT: + return (double)CameraActivity::getFrameHeight(); + default: + CV_Error( CV_StsError, "Failed attempt to GET unsupported camera property." ); + break; + } + return -1.0; +} + +bool CvCapture_Android::setProperty( int propIdx, double propValue ) +{ + bool res = false; + if( isOpened() ) + { + switch ( propIdx ) + { + default: + CV_Error( CV_StsError, "Failed attempt to SET unsupported camera property." ); + break; + } + } + + return res; +} + +bool CvCapture_Android::grabFrame() +{ + if( !isOpened() ) + return false; + + pthread_mutex_lock(&m_nextFrameMutex); + m_waitingNextFrame = true; + pthread_cond_wait(&m_nextFrameCond, &m_nextFrameMutex); + pthread_mutex_unlock(&m_nextFrameMutex); + m_framesGrabbed++; + return true; +} + +void CvCapture_Android::onFrame(const void* buffer, int bufferSize) +{ + LOGD("Buffer available: %p + %d", buffer, bufferSize); + + convertBufferToYUV(buffer, bufferSize, CameraActivity::getFrameWidth(), CameraActivity::getFrameHeight()); + + //swap current and new frames + OutputMap* tmp = m_frameYUV; + m_frameYUV = m_frameYUVnext; + m_frameYUVnext = tmp; + + //discard cached frames + m_hasGray = false; + m_hasColor = false; +} + +IplImage* CvCapture_Android::retrieveFrame( int outputType ) +{ + IplImage* image = 0; + if (0 != m_frameYUV && !m_frameYUV->mat.empty()) + { + switch(outputType) + { + case CV_CAP_ANDROID_YUV_FRAME: + image = m_frameYUV->getIplImagePtr(); + break; + case CV_CAP_ANDROID_GREY_FRAME: + if (!m_hasGray) + if (!(m_hasGray = convertYUVToGrey(m_frameYUV->mat, m_frameGray.mat))) + image = 0; + image = m_frameGray.getIplImagePtr(); + break; + case CV_CAP_ANDROID_COLOR_FRAME: + if (!m_hasColor) + if (!(m_hasColor = convertYUVToColor(m_frameYUV->mat, m_frameColor.mat))) + image = 0; + image = m_frameColor.getIplImagePtr(); + break; + default: + LOGE("Unsupported frame output format: %d", outputType); + image = 0; + break; + } + } + return image; +} + + +void CvCapture_Android::convertBufferToYUV(const void* buffer, int size, int width, int height) +{ + cv::Size buffSize(width, height + (height / 2)); + if (buffSize.area() != size) + { + LOGE("ERROR convertBufferToYuv_Mat: width=%d, height=%d, buffSize=%d x %d, buffSize.area()=%d, size=%d", + width, height, buffSize.width, buffSize.height, buffSize.area(), size); + + return; + } + + m_frameYUVnext->mat.create(buffSize, CV_8UC1); + uchar* matBuff = m_frameYUVnext->mat.ptr (0); + memcpy(matBuff, buffer, size); +} + +bool CvCapture_Android::convertYUVToGrey(const cv::Mat& yuv, cv::Mat& resmat) +{ + if (yuv.empty()) + return false; + + resmat = yuv(cv::Range(0, yuv.rows * (2.0f / 3)), cv::Range::all()); + + return !resmat.empty(); +} + +bool CvCapture_Android::convertYUVToColor(const cv::Mat& yuv, cv::Mat& resmat) +{ + if (yuv.empty()) + return false; + + cv::cvtColor(yuv, resmat, CV_YUV2RGB); + return !resmat.empty(); +} + + +CvCapture* cvCreateCameraCapture_Android( int /*index*/ ) +{ + CvCapture_Android* capture = new CvCapture_Android(); + + if( capture->isOpened() ) + return capture; + + delete capture; + return 0; +} + +#endif diff --git a/modules/highgui/src/precomp.hpp b/modules/highgui/src/precomp.hpp index 931a168..50b41fd 100644 --- a/modules/highgui/src/precomp.hpp +++ b/modules/highgui/src/precomp.hpp @@ -122,6 +122,7 @@ CvVideoWriter* cvCreateVideoWriter_VFW( const char* filename, int fourcc, double fps, CvSize frameSize, int is_color ); CvCapture* cvCreateCameraCapture_DShow( int index ); CvCapture* cvCreateCameraCapture_OpenNI( int index ); +CvCapture* cvCreateCameraCapture_Android( int index ); CVAPI(int) cvHaveImageReader(const char* filename); CVAPI(int) cvHaveImageWriter(const char* filename); -- 2.7.4