Showing posts with label OpenCV. Show all posts
Showing posts with label OpenCV. Show all posts

Monday, October 29, 2018

Setup CMakeLists.txt for Android Studio and OpenCV C++ coding

If you want to develop C++ code making use of Android and OpenCV classes, then you have to configure Android Studio's CMakeLists.txt build file accordingly.

Please follow the previous post https://dominoc925.blogspot.com/2018/10/how-i-setup-opencv4android-java-sdk.html to download and setup the OpenCV4Android Java SDK with and Android project before doing the following steps.
  1. In Android Studio, open up the app's build.gradle file.

    Note: the OpenCV native libraries are under the jniLibs directory relative to the app's build.gradle file according to the source set jniLibs srcDirs parameter.
     

  2. Enter the cmake cpp flags and platform abi filters  in the android defaultConfig externalNativeBuild section, as shown below.

    externalNativeBuild {
        cmake {
          cppFlags "-frtti -fexceptions"        
    
    abiFilters 'x86', 'x86_64', 'armeabi-v7a', 'arm64-v8a'
    }
    }

  3. Next, open up the CMakeLists.txt file in the editor.

     
  4. Add in the cmake macros to add in the path to the OpenCV C++ include files e.g. /path/to/OpenCV-android-sdk/sdk/native/jni/include/

     
  5.  Then, use the macro add_library to add the OpenCV library.

  6. Next, use the macro set_target_properties to tell CMake the location of the OpenCV library.

    set_target_properties(
         lib_opencv        
    
    PROPERTIES
    IMPORTED_LOCATION
    ${CMAKE_CURRENT_SOURCE_DIR}/jniLibs/${ANDROID_ABI}/libopencv_java3.so
    )


  7. Finally, link the OpenCV library with your code with the target_link_libraries macro.

The full sample of the CMakeLists.txt file is shown below.

# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html

# Sets the minimum version of CMake required to build the native library.

cmake_minimum_required(VERSION 3.4.1)

set (OPENCV4ANDSDK_INCLUDE
        /path/to/OpenCV-android-sdk/sdk/native/jni/include)
include_directories(
    ${OPENCV4ANDSDK_INCLUDE}
)
# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK.

add_library( # Sets the name of the library.
        native-lib

        # Sets the library as a shared library.
        SHARED

        # Provides a relative path to your source file(s).
        src/main/cpp/native-lib.cpp)
add_library(
        lib_opencv
        SHARED
        IMPORTED
)
set_target_properties(
        lib_opencv
        PROPERTIES
        IMPORTED_LOCATION
        ${CMAKE_CURRENT_SOURCE_DIR}/jniLibs/${ANDROID_ABI}/libopencv_java3.so
)

# Searches for a specified prebuilt library and stores the path as a
# variable. Because CMake includes system libraries in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.

find_library( # Sets the name of the path variable.
        log-lib

        # Specifies the name of the NDK library that
        # you want CMake to locate.
        log)


# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in this
# build script, prebuilt third-party libraries, or system libraries.

target_link_libraries( # Specifies the target library.
        native-lib

        # Links the target library to the log library
        # included in the NDK.
        ${log-lib}
        lib_opencv
        )




Monday, October 22, 2018

How I setup OpenCV4Android Java SDK with a blank Android project

Setting up an Android Studio project with OpenCV3 can be a little tricky. The official documentation is still using Eclipse and has not been updated with Android Studio. So setting up OpenCV with Android Studio required some trial and error experimentation. I managed to get a template Android Studio project to load the native OpenCV library with the following steps.

Download OpenCV4AndroidSdk
  1. If you have not done so, download OpenCV4Android from this website https://sourceforge.net/projects/opencvlibrary/files/opencv-android/
  2. Extract the files into a folder e.g. /path/to/Open-CV-android-sdk/
Create an Android Project with C++ Support
  1.  Run Android Studio. Choose Create a New Project.

  2. In the Create New Project dialog box, toggle on Include C++ support.
  3. Choose appropriate options and click Next in the following screens.
  4. Click Finish.

    The new project is created.
Import the OpenCV module into Gradle
  1. In the Android Studio File menu, select File | New | Import Module.

    The Import Module from Source dialog box appears.
  2. In the Source directory field, click the ... button and browse to the downloaded OpenCV4Android files and select the java folder e.g. /path/to/OpenCV-android-sdk/sdk/java/.
  3. Optional. In the Module name field, type in a name e.g. :opencv.
  4. Click Next and Finish.

    The module is imported (with most likely error messages)
  5. Options. You can download the missing dependencies by clicking the Install missing platforms and sync project link. Or you can edit the OpenCV4Android's build.gradle file to enter the installed dependencies.
Fix OpenCV4Android configuration files
  1. In Android Studio, open up the file build.gradle from the imported module opencv module e.g. /path/to/opencv/build.gradle. It may be necessary to change the Project pane to display as project view.

  2. In the editor, changed the compiledSdkVersion to 27 (or any installed version), the targetSdkVersion to 27 (or any installed version).
  3. Then sync the gradle project.

    The project is synced but now there is an error about the manifest file.
  4. Open up the manifest file /path/to/opencv/src/main/AndroidManifest.xml in the editor.

  5. Now, comment out the uses-sdk line as shown in the screenshot above.
  6. Sync the project again.

    The OpenCV module is successfully configured.
Add the OpenCV module as a dependency to the Android App project
  1. In Android Studio, select App in the Project pane.
  2. Select File | Project Structure.

    The Project Structure dialog box appears.
  3. Select app. Then click the Dependencies tab. Click +. Choose module dependency.
  4. Choose the imported Opencv module.

    OpenCV is appended to the list.
  5. Click OK.

    The module is added the Android App project.
Copy over the OpenCV native platform binaries to the Android App project
  1.  Open up a File Explorer. Select all the native platform folders under the /path/to/OpenCV-android-sdk/sdk/native/libs/*.

  2. Right click and select Copy.
  3. In Android Studio, right click on the app folder (in project view). Choose Paste.

    The Copy dialog box appears.
  4. In the To directory field, change the text to /path/to/myandroid/app/jniLibs/.
  5. Click OK.

    The native binaries are copied to the project.
  6. To enable the Android project to know where the native binaries are, open up the app's build.gradle file in the editor.

  7. Add in the android class, add in the following sourceSets lines:

    Note: 'jniLibs' means the jniLibs directory relative to this build.gradle file location.
    sourceSets {
        main {
            jniLibs.srcDirs = ['jniLibs']
        }
    }
  8. Sync the project.
Load the native library
  1.  In the MainActivity Kotlin class, type in the following to load in the OpenCV library.

    System.loadLibrary("opencv_java3")
  2. If everything is configured properly, then the Android app can be launched successfully.

    Now you can make any java/Kotlin calls to the built in OpenCV interfaces.

Monday, April 4, 2016

Using EmguCV/OpenCV to correct optical distortions from photos

After calibrating a camera and obtaining the camera matrix and optical distortion coefficient matrix of the camera, the calculated matrices can be used to perform correction of photo images captured using the same camera. The open source libraries EmguCV and OpenCV have the methods and functions to undistort images given the parameters determined previously. The following snippets show how to perform the correction.

The following code C# snippet extends the EmguCV Mat class to enable us to get and set values in the matrix by row and column indices.
// Source: http://stackoverflow.com/questions/32255440/how-can-i-get-and-set-pixel-values-of-an-emgucv-mat-image
// Extends the EmguCV Mat class with Get and Set matrix values
    // by row and column indices
    public static class MatExtension
    {
        public static dynamic GetValue(this Mat mat, int row, int col)
        {
            var value = CreateElement(mat.Depth);
            Marshal.Copy(mat.DataPointer + (row * mat.Cols + col) * mat.ElementSize, value, 0, 1);
            return value[0];
        }

        public static void SetValue(this Mat mat, int row, int col, dynamic value)
        {
            var target = CreateElement(mat.Depth, value);
            Marshal.Copy(target, 0, mat.DataPointer + (row * mat.Cols + col) * mat.ElementSize, 1);
        }
        private static dynamic CreateElement(DepthType depthType, dynamic value)
        {
            var element = CreateElement(depthType);
            element[0] = value;
            return element;
        }

        private static dynamic CreateElement(DepthType depthType)
        {
            if (depthType == DepthType.Cv8S)
            {
                return new sbyte[1];
            }
            if (depthType == DepthType.Cv8U)
            {
                return new byte[1];
            }
            if (depthType == DepthType.Cv16S)
            {
                return new short[1];
            }
            if (depthType == DepthType.Cv16U)
            {
                return new ushort[1];
            }
            if (depthType == DepthType.Cv32S)
            {
                return new int[1];
            }
            if (depthType == DepthType.Cv32F)
            {
                return new float[1];
            }
            if (depthType == DepthType.Cv64F)
            {
                return new double[1];
            }
            return new float[1];
        }

The following code snippet is an example function that performs the correction to a list of JPEG images in a folder D:\Temp\.

public static void Undistort()
        {
            Mat cameraMatrix = new Mat(3, 3, DepthType.Cv64F, 1);
            Mat distCoeffs = new Mat(5, 1, DepthType.Cv64F, 1);
            Mat image = null;

            //Camera matrix values
            double fx = 3388.49;
            double fy = 3390.57;
            double cx = 2096.43;
            double cy = 1566.23;
            double skew = 1.11273;
            
            //Optical distortion coefficient values
            double k1 = 0.17352;
            double k2 = -0.484226;
            double k3 = 0.344761;
            double p1 = 0.00075256;
            double p2 = -0.000269617;

            //Set the camera matrix
            cameraMatrix.SetValue(0, 0, fx);
            cameraMatrix.SetValue(1, 1, fy);
            cameraMatrix.SetValue(0, 1, skew);
            cameraMatrix.SetValue(0, 2, cx);
            cameraMatrix.SetValue(1, 2, cy);
            cameraMatrix.SetValue(2, 2, 1);

            //Set the distortion matrix
            distCoeffs.SetValue(0, 0, k1);
            distCoeffs.SetValue(1, 0, k2);
            distCoeffs.SetValue(2, 0, p1);
            distCoeffs.SetValue(3, 0, p2);
            distCoeffs.SetValue(4, 0, k3);

            // get paths to image files
            string[] imageFiles = Directory.GetFiles(@"d:\temp\", "IMG_*.jpg");

            // for every image
            foreach (string imageFile in imageFiles)
            {
                // create new image object from file path.
                // append Und.jpg to the input filename for the output 
                string outFile = Path.Combine(Path.GetDirectoryName(imageFile), 
                    Path.GetFileNameWithoutExtension(imageFile) + "Und.jpg");

                Console.WriteLine("Processing {0}->{1}...", imageFile, outFile);
                
                //Read the input image
                image = CvInvoke.Imread(imageFile, LoadImageType.AnyColor);

                //Correct the input image
                Mat outFrame = image.Clone();
                CvInvoke.Undistort(image, outFrame, cameraMatrix, distCoeffs);
                
                //save the corrected image
                image = outFrame.Clone();
                image.Save(outFile);
                image.Dispose();
                outFrame.Dispose();
            }
        }