Tuesday 3 June 2014

Configure OpenCV for Android and manipulate image HSV

Hey Guys,

Just used OpenCV in  one of my project to manipulate image Hue, Saturation and Brightness.

Here is source code:
//**************************//
In Java class:
//Image input
InputStream is;
is = this.getResources().openRawResource(R.drawable.img_test);
Bitmap bmInImg = BitmapFactory.decodeStream(is);

int[] mPhotoIntArray;
int[] mOutArray;

mPhotoIntArray = new int[bmInImg.getWidth() * bmInImg.getHeight()];
// Copy pixel data from the Bitmap into the 'intArray' array
bmInImg.getPixels(mPhotoIntArray, 0, bmInImg.getWidth(), 0, 0, bmInImg.getWidth(), bmInImg.getHeight());

// create the canny result buffer
mOutArray= new int[bmInImg.getWidth() * bmInImg.getHeight()];

hsb(bmInImg.getHeight(), bmInImg.getWidth(), h,s,b, mPhotoIntArray, mOutArray);

//use recived output
Bitmap bmOutImg = Bitmap.createBitmap(bmInImg.getWidth(), bmInImg.getHeight(), Config.ARGB_8888);
bmOutImg.setPixels(mOutArray, 0, bmInImg.getWidth(), 0, 0, bmInImg.getWidth(), bmInImg.getHeight());
img.setImageBitmap(bmOutImg);


public native boolean hsb(int width, int height, double hueEffect,double satrEffect,double brightnessEffect, int[] mPhotoIntArray, int[] mOutArray);


static
{
System.loadLibrary("first-opencv");
}

//**************************//
JNI file:

#include <jni.h>

#include <opencv/cv.h>
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc_c.h>
#include <android/log.h>
using namespace cv;

//jboolean - return type
// Java - jni notation
// com_deepapps_ui - package name of class in which method loaded/declared.
// EditorFragmentActivity - class in  the package.
// hsb - method name

extern "C" jboolean Java_com_deepapps_ui_EditorFragmentActivity_hsb(
JNIEnv* env, jobject thiz, jint width, jint height, jdouble hueEffect,
jdouble saturationEffect, jdouble brightnessEffect, jintArray in,
jintArray out) {
//get the data pointer.
IplImage *hsv, *hue, *sat, *val, *b, *r, *g, *brg;
double scale = 1;
int key = 0, depth;
CvSize size;

jint* _in = env->GetIntArrayElements(in, 0);
jint* _out = env->GetIntArrayElements(out, 0);

//Build the Mat structure for input data
Mat mSrc(height, width, CV_8UC4, (unsigned char *) _in);
//Build the Mat structure for output data
Mat mOut(height, width, CV_8UC4, (unsigned char *) _out);

//Convert Mat to IplImage
IplImage mSrcImg = mSrc;
IplImage mOutImg = mOut;

if (mSrcImg.nChannels != 3) {
printf("image is not compatible to precess!");
exit - 1;
}

size = cvGetSize(&mSrcImg);
depth = mSrcImg.depth;
hue = cvCreateImage(size, depth, 1);
sat = cvCreateImage(size, depth, 1);
val = cvCreateImage(size, depth, 1);
hsv = cvCreateImage(size, depth, 3);
cvZero(hsv);
cvZero(hue);
cvZero(sat);
cvZero(val);
b = cvCreateImage(size, depth, 1);
r = cvCreateImage(size, depth, 1);
g = cvCreateImage(size, depth, 1);
brg = cvCreateImage(size, depth, 3);
cvZero(brg);
cvZero(hue);
cvZero(sat);
cvZero(val);
IplImage *im1_a = cvCreateImage(cvGetSize(&mSrcImg), 8, 1); //hold alpha chanel
IplImage *im1_bgra = cvCreateImage(cvGetSize(&mSrcImg), 8, 4);
/* Convert from Red-Green-Blue to Hue-Saturation-Value */
cvCvtColor(&mSrcImg, im1_bgra, CV_BGR2BGRA);
cvCvtColor(&mSrcImg, hsv, CV_BGR2HSV);

/* Split hue, saturation and value of hsv on them */
cvSplit(im1_bgra, hue, sat, val, im1_a);
cvSplit(hsv, hue, sat, val, 0);

cvConvertScale(hue, hue, scale, hueEffect); //update hue // (uchar) ((double)src*scale+saturation)
cvConvertScale(sat, sat, scale, saturationEffect); //update sat

cvMerge(hue, sat, val, 0, hsv);
cvCvtColor(hsv, brg, CV_HSV2BGR);

cvSplit(brg, b, g, r, 0);
cvMerge(b, g, r, im1_a, &mOutImg);//merge b g r and orignal apha

mOut = &mOutImg
+ Scalar(brightnessEffect, brightnessEffect, brightnessEffect); //update brightness

__android_log_write(ANDROID_LOG_ERROR, "satr", "4");
//release the pointer.
env->ReleaseIntArrayElements(in, _in, 0);
env->ReleaseIntArrayElements(out, _out, 0);
return true;
}


Put this code in "open-cv.cpp" under jni folder.( jni should be in root folder of project)

Create Android.mk file in jni folder and put:

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
OPENCV_INSTALL_MODULES:=on
OPENCV_CAMERA_MODULES:=off
OPENCV_LIB_TYPE:=STATIC
include ..replacewithopencvfolderpath\sdk\native\jni\OpenCV.mk
LOCAL_MODULE    := open-cv
LOCAL_SRC_FILES := open-cv.cpp
LOCAL_LDLIBS +=  -llog -ldl
include $(BUILD_SHARED_LIBRARY)

Create Application.mk in jni folder and put:

APP_STL := gnustl_static
APP_CPPFLAGS := -frtti -fexceptions
APP_ABI := armeabi-v7a
APP_PLATFORM := android-9
APP_MODULES := open-cv





//make sure your sourcecode and opencv libs folders path must be without space in there name.

Download opencv from: http://sourceforge.net/projects/opencvlibrary/files/opencv-android/2.4.9/OpenCV-2.4.9-android-sdk.zip/download

I hope you must have android ndk configured in your eclipse.
Or follow steps: https://developer.android.com/tools/sdk/ndk/index.html


Android project properties:
-> C/C++ build
Builder setting -> build command : ndk-build

-> C/C++ General Setting
  Path and Symbol
Add:
1. ..ndkfolderpath\sources\cxx-stl\system\include
2. ..ndkfolderpath\sources\cxx-stl\gnu-libstdc++\4.6\include
3. ..ndkfolder\platforms\android-9\arch-arm\usr\include
4  ..opencvfolder\sdk\native\jni\include

Let me know if have any doubt.


keywords: opencv android, android jni, Hue , Saturation, Brightness, Image color manipulation, android NDK