Ask Your Question

Revision history [back]

click to hide/show revision 1
initial version

Accessing to OpenCv cell values of Mat from native c++ function of android app

:) I'm programming an algorithm for detect symmetric radial center of an image, to detect eyes position into face framePicture. I know that already exist a project of public domain that do this work, but i would base my work about another kind of studies.

This is the scenario:

Doing by hand this manipulation frame by frame, i have seen that writting code on java layer, like this:

private Mat mGray = new Mat(height,width,CvType.CV_8U);
private Mat mOut = new Mat(height,width,CvType.CV_8U);
private Mat mIntermediateMat = Mat.zeros(height,width,CvType.CV_32F);   

[...common methods of opencv app...]

public Mat onCameraFrame(CvCameraViewFrame inputFrame) {

    switch (ImageManipulationsActivity.viewMode) {
    case ImageManipulationsActivity.VIEW_MODE_RGBA:
        mOut = inputFrame.rgba();
        break;

    case ImageManipulationsActivity.VIEW_MODE_MODIFY:
        mGray = inputFrame.gray();

        int h = mGray.rows();
        int w = mGray.cols();

        int sobxVal,sobyVal;    

        /** 
        * Appling manually sobel filtering to calculate dx and dy image, 
        * moreover calculate magnitudo matrix and cosValue and sinValue
        * matrices for computing, using lut techniques.
        */
        for(int i = 1; i < h-1; i++)
            for(int j = 1; j < w-1; j++) {
                sobxVal = (int) (
                        ((int)mGray.get(i-1,j)[0] << 1) +
                        mGray.get(i-1,j-1)[0] +
                        mGray.get(i-1,j+1)[0] - (
                        ((int)mGray.get(i+1,j)[0] << 1) +
                        mGray.get(i+1,j-1)[0] +
                        mGray.get(i+1,j+1)[0] ) );
                sobyVal = (int) (
                        ((int)mGray.get(i,j-1)[0] << 1) +
                        mGray.get(i-1,j-1)[0] +
                        mGray.get(i+1,j-1)[0] - (
                        ((int)mGray.get(i,j+1)[0] << 1) +
                        mGray.get(i-1,j+1)[0] +
                        mGray.get(i+1,j+1)[0] ) );
//      compute magnitudo and atan2
            }

//      ...other calculations...

        Core.convertScaleAbs(mIntermediateMat, mOut);

    }

    return mOut;
}

is not all efficient! So I decided to write c++ for a native function to manipulate matrix in this way:

Code by c++ side

#include <jni.h>
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/features2d/features2d.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <math.h>
#include <vector>

#include <android/log.h>

#define LOG_TAG "Example Filter"
#define LOGD(...) ((void)__android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__))

#define RADIUS 10
#define _K      9.9
#define _A      2   //radial strictness parameter, found experimentally
using namespace std;

using namespace cv;

extern "C" {
JNIEXPORT void JNICALL Java_org_opencv_samples_tutorial2_Tutorial2Activity_FindFeatures(
        JNIEnv* env, 
        jobject, 
        jlong addrGray, 
        jlong addrRgba, 
        jlong addrlutCosSin,
        jlong addrlutM );

JNIEXPORT void JNICALL Java_org_opencv_samples_tutorial2_Tutorial2Activity_FindFeatures(
        JNIEnv* env, 
        jobject, 
        jlong addrGray, 
        jlong addrOut, 
        jlong addrlutCosSin,
        jlong addrlutM )
{
    Mat& mGr  = *(Mat*)addrGray;
    Mat& mOut = *(Mat*)addrOut;
    Mat& lutCosSin = *(Mat*)addrlutCosSin;
    Mat& lutM = *(Mat*)addrlutM;
    int w = mGr.cols;
    int h = mGr.rows;
    double sobelxVal,sobelyVal,angle;

    Mat magnitudo(h,w,CV_32F,Scalar(0));
    Mat xMat(h,w,CV_8S,Scalar(0));
    Mat yMat(h,w,CV_8S,Scalar(0));
    Mat oMat(h,w,CV_32F,Scalar(0));
    Mat mMat(h,w,CV_32F,Scalar(0));
    /*
     * Convolves Matrix with Sobel ky kernel and Sobel kx kernel
     *ky = [ 1  2  1 ;
     *       0  0  0 ;
     *      -1 -2 -1 ]
     *
     *kx = [ 1  0 -1 ;
     *       2  0 -2 ;
     *       1  0 -1 ]
     *
     * doing dedicated computation 
     */
    for( int i = 1; i < h-1; i++ )
    {
        for (int j = 1; j < w-1; j++ )
        {
            sobelxVal = (mGr.at<int>(i-1,j) << 1) +
                    mGr.at<int>(i-1,j-1) +
                    mGr.at<int>(i-1,j+1) - (
                    (mGr.at<int>(i+1,j) << 1) +
                    mGr.at<int>(i+1,j-1) +
                    mGr.at<int>(i+1,j+1) );
            sobelyVal = (mGr.at<int>(i,j-1) << 1) +
                    mGr.at<int>(i-1,j-1) +
                    mGr.at<int>(i+1,j-1) - (
                    (mGr.at<int>(i,j+1) << 1) +
                    mGr.at<int>(i-1,j+1) +
                    mGr.at<int>(i+1,j+1) );
            magnitudo.at<double>(i,j) = lutM.at<double>((int)sobelxVal+255/4,(int)sobelxVal+255/4);
            angle = floor(atan2(sobelyVal,sobelxVal)*180/M_PI);
            xMat.at<double>(i,j) = lutCosSin.at<double>(0,angle);
            yMat.at<double>(i,j) = lutCosSin.at<double>(1,angle);
        }
    }

// other code calculation to determine mOut matrix values

}
}

By java code side

private Mat mRgba;
private Mat mGray;
/*
 * Matrix of 360 cols and 2 rows
 * row[0] cos values
 * row[1] sin values
 */
private static Mat lutCosSin;

/*
 * Matrix 510 x 510 
 * where lutM(i,j) = atan2(i,j)
 */
private static Mat lutMagnitudo

// common methods and declarations...

public Mat onCameraFrame(CvCameraViewFrame inputFrame) {
    final int viewMode = mViewMode;
    switch (viewMode) {
    case VIEW_MODE_RGBA:
        // input frame has RBGA format
        mRgba = inputFrame.rgba();
        break;
    case VIEW_MODE_FEATURES:
        // input frame has RGBA format
        mGray = inputFrame.gray();
        mRgba = Mat.zeros(mGray.rows(), mGray.cols(), mGray.type());
        FindFeatures(
        mGray.getNativeObjAddr(), 
        mRgba.getNativeObjAddr(), 
        lutCosSin.getNativeObjAddr(), 
        lutMagnitudo.getNativeObjAddr()
        );

        //Core.convertScaleAbs(mRgba, mRgba);
//            Log.d(TAG, "Called native function :"+mRgba.submat(new Range(0,5), new Range(0,5)).toString()+
//                  "\nAngles matrix:"+mGray);
        break;
    }

    return mRgba;
}

public native void FindFeatures(long matAddrGr, long matAddrRgba, long matAddrlutCS, long matAddrlutM);

the first important issue of this snipped code is that on accessing to mGr cells with "at" method in this way:

mGr.at<int>(i,j)

previus check that mGr type is int, the returned values isn't the effective gray level pixel of gray frame (i saw it by log).

I suppose that there are linkin bug of matrix from java code to c++ code, but i'm not sure for this.

I hope may anyone help me to solve this issue XD !!

click to hide/show revision 2
retagged

updated 2013-09-20 09:28:53 -0600

berak gravatar image

Accessing to OpenCv cell values of Mat from native c++ function of android app

:) I'm programming an algorithm for detect symmetric radial center of an image, to detect eyes position into face framePicture. I know that already exist a project of public domain that do this work, but i would base my work about another kind of studies.

This is the scenario:

Doing by hand this manipulation frame by frame, i have seen that writting code on java layer, like this:

private Mat mGray = new Mat(height,width,CvType.CV_8U);
private Mat mOut = new Mat(height,width,CvType.CV_8U);
private Mat mIntermediateMat = Mat.zeros(height,width,CvType.CV_32F);   

[...common methods of opencv app...]

public Mat onCameraFrame(CvCameraViewFrame inputFrame) {

    switch (ImageManipulationsActivity.viewMode) {
    case ImageManipulationsActivity.VIEW_MODE_RGBA:
        mOut = inputFrame.rgba();
        break;

    case ImageManipulationsActivity.VIEW_MODE_MODIFY:
        mGray = inputFrame.gray();

        int h = mGray.rows();
        int w = mGray.cols();

        int sobxVal,sobyVal;    

        /** 
        * Appling manually sobel filtering to calculate dx and dy image, 
        * moreover calculate magnitudo matrix and cosValue and sinValue
        * matrices for computing, using lut techniques.
        */
        for(int i = 1; i < h-1; i++)
            for(int j = 1; j < w-1; j++) {
                sobxVal = (int) (
                        ((int)mGray.get(i-1,j)[0] << 1) +
                        mGray.get(i-1,j-1)[0] +
                        mGray.get(i-1,j+1)[0] - (
                        ((int)mGray.get(i+1,j)[0] << 1) +
                        mGray.get(i+1,j-1)[0] +
                        mGray.get(i+1,j+1)[0] ) );
                sobyVal = (int) (
                        ((int)mGray.get(i,j-1)[0] << 1) +
                        mGray.get(i-1,j-1)[0] +
                        mGray.get(i+1,j-1)[0] - (
                        ((int)mGray.get(i,j+1)[0] << 1) +
                        mGray.get(i-1,j+1)[0] +
                        mGray.get(i+1,j+1)[0] ) );
//      compute magnitudo and atan2
            }

//      ...other calculations...

        Core.convertScaleAbs(mIntermediateMat, mOut);

    }

    return mOut;
}

is not all efficient! So I decided to write c++ for a native function to manipulate matrix in this way:

Code by c++ side

#include <jni.h>
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/features2d/features2d.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <math.h>
#include <vector>

#include <android/log.h>

#define LOG_TAG "Example Filter"
#define LOGD(...) ((void)__android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__))

#define RADIUS 10
#define _K      9.9
#define _A      2   //radial strictness parameter, found experimentally
using namespace std;

using namespace cv;

extern "C" {
JNIEXPORT void JNICALL Java_org_opencv_samples_tutorial2_Tutorial2Activity_FindFeatures(
        JNIEnv* env, 
        jobject, 
        jlong addrGray, 
        jlong addrRgba, 
        jlong addrlutCosSin,
        jlong addrlutM );

JNIEXPORT void JNICALL Java_org_opencv_samples_tutorial2_Tutorial2Activity_FindFeatures(
        JNIEnv* env, 
        jobject, 
        jlong addrGray, 
        jlong addrOut, 
        jlong addrlutCosSin,
        jlong addrlutM )
{
    Mat& mGr  = *(Mat*)addrGray;
    Mat& mOut = *(Mat*)addrOut;
    Mat& lutCosSin = *(Mat*)addrlutCosSin;
    Mat& lutM = *(Mat*)addrlutM;
    int w = mGr.cols;
    int h = mGr.rows;
    double sobelxVal,sobelyVal,angle;

    Mat magnitudo(h,w,CV_32F,Scalar(0));
    Mat xMat(h,w,CV_8S,Scalar(0));
    Mat yMat(h,w,CV_8S,Scalar(0));
    Mat oMat(h,w,CV_32F,Scalar(0));
    Mat mMat(h,w,CV_32F,Scalar(0));
    /*
     * Convolves Matrix with Sobel ky kernel and Sobel kx kernel
     *ky = [ 1  2  1 ;
     *       0  0  0 ;
     *      -1 -2 -1 ]
     *
     *kx = [ 1  0 -1 ;
     *       2  0 -2 ;
     *       1  0 -1 ]
     *
     * doing dedicated computation 
     */
    for( int i = 1; i < h-1; i++ )
    {
        for (int j = 1; j < w-1; j++ )
        {
            sobelxVal = (mGr.at<int>(i-1,j) << 1) +
                    mGr.at<int>(i-1,j-1) +
                    mGr.at<int>(i-1,j+1) - (
                    (mGr.at<int>(i+1,j) << 1) +
                    mGr.at<int>(i+1,j-1) +
                    mGr.at<int>(i+1,j+1) );
            sobelyVal = (mGr.at<int>(i,j-1) << 1) +
                    mGr.at<int>(i-1,j-1) +
                    mGr.at<int>(i+1,j-1) - (
                    (mGr.at<int>(i,j+1) << 1) +
                    mGr.at<int>(i-1,j+1) +
                    mGr.at<int>(i+1,j+1) );
            magnitudo.at<double>(i,j) = lutM.at<double>((int)sobelxVal+255/4,(int)sobelxVal+255/4);
            angle = floor(atan2(sobelyVal,sobelxVal)*180/M_PI);
            xMat.at<double>(i,j) = lutCosSin.at<double>(0,angle);
            yMat.at<double>(i,j) = lutCosSin.at<double>(1,angle);
        }
    }

// other code calculation to determine mOut matrix values

}
}

By java code side

private Mat mRgba;
private Mat mGray;
/*
 * Matrix of 360 cols and 2 rows
 * row[0] cos values
 * row[1] sin values
 */
private static Mat lutCosSin;

/*
 * Matrix 510 x 510 
 * where lutM(i,j) = atan2(i,j)
 */
private static Mat lutMagnitudo

// common methods and declarations...

public Mat onCameraFrame(CvCameraViewFrame inputFrame) {
    final int viewMode = mViewMode;
    switch (viewMode) {
    case VIEW_MODE_RGBA:
        // input frame has RBGA format
        mRgba = inputFrame.rgba();
        break;
    case VIEW_MODE_FEATURES:
        // input frame has RGBA format
        mGray = inputFrame.gray();
        mRgba = Mat.zeros(mGray.rows(), mGray.cols(), mGray.type());
        FindFeatures(
        mGray.getNativeObjAddr(), 
        mRgba.getNativeObjAddr(), 
        lutCosSin.getNativeObjAddr(), 
        lutMagnitudo.getNativeObjAddr()
        );

        //Core.convertScaleAbs(mRgba, mRgba);
//            Log.d(TAG, "Called native function :"+mRgba.submat(new Range(0,5), new Range(0,5)).toString()+
//                  "\nAngles matrix:"+mGray);
        break;
    }

    return mRgba;
}

public native void FindFeatures(long matAddrGr, long matAddrRgba, long matAddrlutCS, long matAddrlutM);

the first important issue of this snipped code is that on accessing to mGr cells with "at" method in this way:

mGr.at<int>(i,j)

previus check that mGr type is int, the returned values isn't the effective gray level pixel of gray frame (i saw it by log).

I suppose that there are linkin bug of matrix from java code to c++ code, but i'm not sure for this.

I hope may anyone help me to solve this issue XD !!