diff --git a/.cproject b/.cproject index d3c1f726..28fe6c0f 100755 --- a/.cproject +++ b/.cproject @@ -5,9 +5,9 @@ + - @@ -45,10 +45,8 @@ - - - - + + diff --git a/.project b/.project index d9aa1e51..99cf38f4 100644 --- a/.project +++ b/.project @@ -55,7 +55,7 @@ org.eclipse.cdt.make.core.useDefaultBuildCmd - true + false diff --git a/.settings/org.eclipse.cdt.core.prefs b/.settings/org.eclipse.cdt.core.prefs index 59692068..44f85a9e 100644 --- a/.settings/org.eclipse.cdt.core.prefs +++ b/.settings/org.eclipse.cdt.core.prefs @@ -1,6 +1,6 @@ eclipse.preferences.version=1 environment/project/com.android.toolchain.gcc.1245095277/PATH/delimiter=\: environment/project/com.android.toolchain.gcc.1245095277/PATH/operation=replace -environment/project/com.android.toolchain.gcc.1245095277/PATH/value=/usr/lib/lightdm/lightdm\:/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/usr/games\:/usr/local/games\:/home/sergey/android_tools/android-ndk-r10d +environment/project/com.android.toolchain.gcc.1245095277/PATH/value=/usr/lib/lightdm/lightdm\:/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/usr/games\:/usr/local/games\:/home/ivan/Android/android-ndk-r12b environment/project/com.android.toolchain.gcc.1245095277/append=true environment/project/com.android.toolchain.gcc.1245095277/appendContributed=true diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 05859d26..fa4be149 100755 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -2,17 +2,17 @@ + android:versionCode="123" + android:versionName="1.0"> --> - - - - - @@ -122,26 +122,26 @@ - + @@ -164,5 +164,5 @@ --> + android:targetSdkVersion="24"/> diff --git a/assets/opencamera_modes.xml b/assets/opencamera_modes.xml index 1a5a9c5b..6e9169d3 100755 --- a/assets/opencamera_modes.xml +++ b/assets/opencamera_modes.xml @@ -72,7 +72,7 @@ - + + + + + + + + + + + + + + +          + +     + +          +     @@ -276,6 +302,6 @@ - + \ No newline at end of file diff --git a/jni/Android.mk b/jni/Android.mk index 5e7dd1a5..388bb231 100755 --- a/jni/Android.mk +++ b/jni/Android.mk @@ -92,6 +92,9 @@ include $(MY_CORE_PATH)/bestshot/Android.mk # Night plugin include $(MY_CORE_PATH)/nightprocessing/Android.mk +# FocusStacking plugin +include $(MY_CORE_PATH)/focusstacking/Android.mk + # HDR plugin include $(MY_CORE_PATH)/hdrprocessing/Android.mk @@ -122,5 +125,8 @@ include $(MY_CORE_PATH)/histogram/Android.mk # yuvimage helper include $(MY_CORE_PATH)/yuvimage/Android.mk +# yuvbitmap helper +include $(MY_CORE_PATH)/yuvbitmap/Android.mk + # swapheap helper (move data between native and java heaps) include $(MY_CORE_PATH)/swapheap/Android.mk diff --git a/jni/almashot/armeabi-v7a/libalmalib_eval.a b/jni/almashot/armeabi-v7a/libalmalib_eval.a index b8784eba..812e093e 100644 Binary files a/jni/almashot/armeabi-v7a/libalmalib_eval.a and b/jni/almashot/armeabi-v7a/libalmalib_eval.a differ diff --git a/jni/almashot/x86/libalmalib_eval.a b/jni/almashot/x86/libalmalib_eval.a index 94542057..815a14f9 100644 Binary files a/jni/almashot/x86/libalmalib_eval.a and b/jni/almashot/x86/libalmalib_eval.a differ diff --git a/jni/focusstacking/Android.mk b/jni/focusstacking/Android.mk new file mode 100755 index 00000000..14d2bb95 --- /dev/null +++ b/jni/focusstacking/Android.mk @@ -0,0 +1,13 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +include $(LOCAL_PATH)/../Flags.mk + +LOCAL_MODULE := almashot-fstacking +LOCAL_SRC_FILES := almashot-fstacking.cpp +LOCAL_CFLAGS += -DLOG_ON +LOCAL_STATIC_LIBRARIES := almalib gomp +LOCAL_LDLIBS := -ldl -lz -llog + +include $(BUILD_SHARED_LIBRARY) diff --git a/jni/focusstacking/almashot-fstacking.cpp b/jni/focusstacking/almashot-fstacking.cpp new file mode 100755 index 00000000..cd584f95 --- /dev/null +++ b/jni/focusstacking/almashot-fstacking.cpp @@ -0,0 +1,441 @@ +/* + The contents of this file are subject to the Mozilla Public License + Version 1.1 (the "License"); you may not use this file except in + compliance with the License. You may obtain a copy of the License at + http://www.mozilla.org/MPL/ + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + License for the specific language governing rights and limitations + under the License. + + The Original Code is collection of files collectively known as Open Camera. + + The Initial Developer of the Original Code is Almalence Inc. + Portions created by Initial Developer are Copyright (C) 2013 + by Almalence Inc. All Rights Reserved. + */ + +#include +#include +#include +#include + +#include "almashot.h" +#include "fstacking.h" + +#ifdef LOG_ON +#define LOG_TAG "AlmalenceFocusStacking" +#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG,__VA_ARGS__) +#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__ ) +#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__ ) +#define LOGW(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__ ) +#else +#define LOG_TAG +#define LOGD(...) +#define LOGE(...) +#define LOGI(...) +#define LOGW(...) +#endif + +// This triggers openmp constructors and destructors to be called upon library load/unload +void __attribute__((constructor)) initialize_openmp() { +} +void __attribute__((destructor)) release_openmp() { +} + +#include "fstacking-utils.h" + +#define MAX_FFRAMES 8 + +static int iInputWidth = 0; +static int iInputHeight = 0; +static int iImageAmount = 0; + +static unsigned char *inputFrame[MAX_FFRAMES] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; +static unsigned char *alignedFrame[MAX_FFRAMES] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; + +static float focusDistances[MAX_FFRAMES] = {0, 0, 0, 0, 0, 0, 0, 0}; +static unsigned char* focusMap = NULL; + +static void *instance = NULL; +static int almashot_inited = 0; +static unsigned char *OutPic = NULL; + +/* + * Initialize Almashot engine. Must be called first + */ +extern "C" JNIEXPORT jstring JNICALL Java_com_almalence_focusstacking_AlmaShotFocusStacking_AlmaShotInitialize +( + JNIEnv* env, + jobject thiz +) +{ + LOGE("Initialize - start"); + char status[1024]; + int err=0; + + if (almashot_inited == 0) + { + err = AlmaShot_Initialize(1); + + if (err == ALMA_ALL_OK) + almashot_inited = 1; + } + + sprintf (status, " init status: %d\n", err); + + LOGE("Initialize - end"); + return env->NewStringUTF(status); +} + + +/* + * Initialize focus stacking instance + * @in - array of pointers to input frames + * @focusDist - array of focus distance for each input frame (in diopter) + * @nFrames - number of input frames + * @sx - width of input frames + * @sy - height of input frames + * @fmap - byte array that represents focus areas map (read doc for details) + */ +extern "C" JNIEXPORT jint JNICALL Java_com_almalence_focusstacking_AlmaShotFocusStacking_FStackingInitialize +( + JNIEnv* env, + jobject thiz, + jintArray in, + jfloatArray focusDist, + jint nFrames, + jint sx, + jint sy, + jbyteArray fmap +) +{ + LOGE("FStackingInitialize - start"); + int i; + unsigned char **yuv; + float* focus; + char status[1024]; + + iInputWidth = sx; + iInputHeight = sy; + iImageAmount = nFrames; + + yuv = (unsigned char**)env->GetIntArrayElements(in, NULL); + int yuv_length = sx*sy+2*((sx+1)/2)*((sy+1)/2); + + focus = (float*)env->GetFloatArrayElements(focusDist, NULL); + + if(fmap != NULL) + focusMap = (unsigned char *)env->GetByteArrayElements(fmap, NULL); + else + focusMap = NULL; + + for (i = 0; i < iImageAmount; ++i) + { + inputFrame[i] = yuv[i]; + focusDistances[i] = focus[i]; + } + +// __android_log_print(ANDROID_LOG_ERROR, "CameraTest", "START INPUT SAVE"); +// for (int i=0; iReleaseIntArrayElements(in, (jint*)yuv, JNI_ABORT); + env->ReleaseFloatArrayElements(focusDist, (jfloat*)focus, JNI_ABORT); + + if(fmap != NULL) + env->ReleaseByteArrayElements(fmap, (jbyte*)focusMap, JNI_ABORT); + + LOGE("FStacking_Initialize. Frames total: %d\n", (int)nFrames); + return nFrames; +} + + +/* + * Finalize Almashot engine + */ +extern "C" JNIEXPORT jint JNICALL Java_com_almalence_focusstacking_AlmaShotFocusStacking_AlmaShotRelease +( + JNIEnv* env, + jobject +) +{ + LOGE("Release - start"); + + if (almashot_inited == 1) + { + AlmaShot_Release(); + almashot_inited = 0; + } + + LOGE("Release - end"); + return 0; +} + + +/* + * Free FocusStacking instance and memory for the output frame + */ +extern "C" JNIEXPORT jint JNICALL Java_com_almalence_focusstacking_AlmaShotFocusStacking_FStackingFreeInstance +( + JNIEnv* env, + jobject +) +{ + LOGE("FreeInstance - start"); + if (OutPic) + { +// LOGE("free(OutPic) - start"); + free(OutPic); + OutPic = NULL; +// LOGE("free(OutPic) - end"); + } + + if (instance) + { + FStacking_FreeInstance(instance, 1); + instance = NULL; + } + + LOGE("FreeInstance - end"); + return 0; +} + + +/* + * Get one input frame by index + */ +extern "C" JNIEXPORT jint JNICALL Java_com_almalence_focusstacking_AlmaShotFocusStacking_GetInputFrame +( + JNIEnv* env, + jobject thiz, + jint index +) +{ + return (jint)inputFrame[index]; +} + + +/* + * Get one input frame by index in byteArray format + * @in - input frames + * @index - index of desired frame + * @orientation - desired rotation degrees of frame + * @mirror - flip frame horizontally + */ +extern "C" JNIEXPORT jbyteArray JNICALL Java_com_almalence_focusstacking_AlmaShotFocusStacking_GetInputByteFrameNative +( + JNIEnv* env, + jobject thiz, + jintArray in, + jint index, + jint orientation, + jboolean mirror +) +{ +// LOGE("GetInputByteFrame - start"); + + unsigned char** yuv = (unsigned char**)env->GetIntArrayElements(in, NULL); + + unsigned char *data; + jbyteArray jdata = env->NewByteArray(iInputWidth * iInputHeight * 2); + data = (unsigned char*)env->GetByteArrayElements(jdata, NULL); + + int flipLeftRight, flipUpDown; + int rotate90 = orientation == 90 || orientation == 270; + if (mirror) + flipUpDown = flipLeftRight = orientation == 180 || orientation == 90; + else + flipUpDown = flipLeftRight = orientation == 180 || orientation == 270; + +// LOGE("TransformNV21 - start"); + TransformNV21(yuv[index], data, iInputWidth, iInputHeight, NULL, flipLeftRight, flipUpDown, rotate90); +// LOGE("TransformNV21 - end"); + + env->ReleaseByteArrayElements(jdata, (jbyte*)data, 0); + env->ReleaseIntArrayElements(in, (jint*)yuv, 0); + +// LOGE("GetInputByteFrame - end"); + + return jdata; +} + + +/* + * Get pointer to aligned frame by index + * NOTE: Aligned frames is available only after FStackingProcess method successfully done + * @index - requested frame index + */ +extern "C" JNIEXPORT jint JNICALL Java_com_almalence_focusstacking_AlmaShotFocusStacking_GetAlignedFrame +( + JNIEnv* env, + jobject thiz, + jint index +) +{ + return (jint)alignedFrame[index]; +} + + +/* + * Get all aligned frames from Focus stacking instance + */ +extern "C" JNIEXPORT jintArray JNICALL Java_com_almalence_focusstacking_AlmaShotFocusStacking_GetAlignedFrames +( + JNIEnv* env, + jobject thiz +) +{ +// LOGE("Get aligned frames - start. iInputWidth = %d, iInputHeight = %d, iImageAmount = %d", iInputWidth, iInputHeight, iImageAmount); + //Store aligned input frames + FStacking_GetAlignedFrames(instance, + alignedFrame, + iInputWidth, + iInputHeight, + iImageAmount); +// LOGE("Get aligned frames - end"); + +// __android_log_print(ANDROID_LOG_ERROR, "CameraTest", "START ALIGNED SAVE"); +// for (int i = 0; i < iImageAmount; ++i) +// { +// char str[256]; +// sprintf(str, "/sdcard/DCIM/fstacking_aligned%02d.yuv", i); +// FILE *f = fopen (str, "wb"); +// fwrite(alignedFrame[i], iInputWidth * iInputHeight + 2 * ((iInputWidth + 1)/2) * ((iInputHeight + 1)/2), 1, f); +// fclose(f); +// } +// __android_log_print(ANDROID_LOG_ERROR, "CameraTest", "ALIGNED SAVCED"); + + jintArray jalign = env->NewIntArray(iImageAmount); + env->SetIntArrayRegion(jalign, 0, iImageAmount, (jint*)alignedFrame); + +// LOGE("Create aligned frames array - end"); + + return jalign; +} + + +/* + * Main process function. Calls an Almalence's focus stacking feature + * This method can be called only after FStackingInitialize function + * @orientation - desired rotation degrees of result frame + * @mirror - flip result frame horizontally + * @transform - true if it's need to transform result according above two arguments + * + * @return - 'All-In-Focus' frame as byte array in NV21 format + */ +extern "C" JNIEXPORT jbyteArray JNICALL Java_com_almalence_focusstacking_AlmaShotFocusStacking_FStackingProcess +( + JNIEnv* env, + jobject thiz, + jint orientation, + jboolean mirror, + jboolean transform +) +{ + FStacking_Align(&instance, + inputFrame, + focusMap, + NULL, + 655, // gain (sensor specific, might need adjustment) + iInputWidth, iInputHeight, + iImageAmount, + iImageAmount/2, // base frame (from which to take background) + 256, // do not use pre-filter + 256, // do not use post-filter + 1, // re-scale output + 1 + ); + +// for(int i = 0; i < iInputWidth/16*iInputHeight/16; i++) +// LOGE("focusMap[i] = %d", (int)focusMap[i]); + + LOGE("Focus stacking processing - start"); + + unsigned char *OutNV21; + unsigned char *data; +// LOGE("JBYTEARRAY - start new size 0"); + jbyteArray jdata = env->NewByteArray(0); +// LOGE("JBYTEARRAY - end new size 0"); + + int x0_out, y0_out, w_out, h_out; + + if(OutPic) + { + free(OutPic); + LOGE("old OutPic free"); + } + +// jbyteArray jdata = env->NewByteArray(iInputWidth * iInputHeight * 2); +// OutPic = (unsigned char*)env->GetByteArrayElements(jdata, NULL); + OutPic = (unsigned char *)malloc(iInputWidth * iInputHeight * 2); +// LOGE("OutPic malloced"); + + if (FStacking_Process(instance, + &OutPic, + &x0_out, &y0_out, + &w_out, &h_out) == ALMA_ALL_OK) + { + LOGE("Focus stacking processing - ok. x0_out = %d y0_out = %d width = %d height = %d", x0_out, y0_out, w_out, h_out); + } + else + { + LOGE("Focus stacking processing - error"); + return NULL; + } + + +// char str[256]; +// sprintf(str, "/sdcard/DCIM/fstacking_android_res.yuv"); +// FILE *f = fopen (str, "wb"); +// fwrite(OutPic, sx*sy+2*((sx+1)/2)*((sy+1)/2), 1, f); +// fclose(f); + + if(transform) + { +// LOGE("Focus stacking processing - transform start"); + int flipLeftRight, flipUpDown; + int rotate90 = orientation == 90 || orientation == 270; + if (mirror) + flipUpDown = flipLeftRight = orientation == 180 || orientation == 90; + else + flipUpDown = flipLeftRight = orientation == 180 || orientation == 270; + + OutNV21 = OutPic; + if (rotate90) + OutNV21 = (unsigned char *)malloc(iInputWidth * iInputHeight * 2); + + TransformNV21(OutPic, OutNV21, iInputWidth, iInputHeight, NULL, flipLeftRight, flipUpDown, rotate90); + + if (rotate90) + { + free(OutPic); + OutPic = OutNV21; + } +// LOGE("Focus stacking processing - transform end"); + } + +// LOGE("Focus stacking processing - new ouput byte array start"); + jdata = env->NewByteArray(iInputWidth * iInputHeight * 2); + data = (unsigned char*)env->GetByteArrayElements(jdata, NULL); + +// data = (unsigned char *)malloc(iInputWidth * iInputHeight * 2); + memcpy (data, OutPic, iInputWidth * iInputHeight * 2); + + env->ReleaseByteArrayElements(jdata, (jbyte*)data, 0); +// LOGE("Focus stacking processing - new ouput byte array end"); +// free(OutPic); +// OutPic = NULL; + + return jdata; +// return (jint)data; +// return (jint) OutPic; +} diff --git a/jni/focusstacking/fstacking-utils.h b/jni/focusstacking/fstacking-utils.h new file mode 100755 index 00000000..76c22131 --- /dev/null +++ b/jni/focusstacking/fstacking-utils.h @@ -0,0 +1,223 @@ +/* +The contents of this file are subject to the Mozilla Public License +Version 1.1 (the "License"); you may not use this file except in +compliance with the License. You may obtain a copy of the License at +http://www.mozilla.org/MPL/ + +Software distributed under the License is distributed on an "AS IS" +basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +License for the specific language governing rights and limitations +under the License. + +The Original Code is collection of files collectively known as Open Camera. + +The Initial Developer of the Original Code is Almalence Inc. +Portions created by Initial Developer are Copyright (C) 2013 +by Almalence Inc. All Rights Reserved. +*/ + +#include +#include + +void TransformPlane8bit +( + unsigned char * In, + unsigned char * Out, + int sx, + int sy, + int flipLeftRight, + int flipUpDown, + int rotate90 +) +{ + int y; + int osx, osy; + + // no transform case + if ((!flipLeftRight) && (!flipUpDown) && (!rotate90)) + { + if (In!=Out) + memcpy (Out, In, sx*sy*sizeof(unsigned char)); + return; + } + + // can't rotate in-place + if (rotate90 && (In == Out)) + return; + + if (rotate90) {osx = sy; osy = sx;} + else {osx = sx; osy = sy;} + + // processing 4 mirrored locations at once + // +1 here to cover case when image dimensions are odd + #pragma omp parallel for schedule(guided) + for (y=0; y<(sy+1)/2; ++y) + { + int x; + int ox, oy; + unsigned char t1, t2, t3, t4; + + for (x=0; x<(sx+1)/2; ++x) + { + if (rotate90) + { + if (flipLeftRight) ox = y; + else ox = osx-1-y; + if (flipUpDown) oy = osy-1-x; + else oy = x; + + t1 = In[x + y*sx]; + t2 = In[sx-1-x + y*sx]; + t3 = In[x + (sy-1-y)*sx]; + t4 = In[sx-1-x + (sy-1-y)*sx]; + + Out[ox + oy*osx] = t1; + Out[osx-1-ox + oy*osx] = t3; + Out[ox + (osy-1-oy)*osx] = t2; + Out[osx-1-ox + (osy-1-oy)*osx] = t4; + } + else + { + if (flipLeftRight) ox = sx-1-x; + else ox = x; + if (flipUpDown) oy = sy-1-y; + else oy = y; + + t1 = In[x + y*sx]; + t2 = In[sx-1-x + y*sx]; + t3 = In[x + (sy-1-y)*sx]; + t4 = In[sx-1-x + (sy-1-y)*sx]; + + Out[ox + oy*osx] = t1; + Out[osx-1-ox + oy*osx] = t2; + Out[ox + (osy-1-oy)*osx] = t3; + Out[osx-1-ox + (osy-1-oy)*osx] = t4; + } + } + } +} + + +void TransformPlane16bit +( + unsigned short * In, + unsigned short * Out, + int sx, + int sy, + int flipLeftRight, + int flipUpDown, + int rotate90 +) +{ + int y; + int osx, osy; + + // no transform case + if ((!flipLeftRight) && (!flipUpDown) && (!rotate90)) + { + if (In!=Out) + memcpy (Out, In, sx*sy*sizeof(unsigned short)); + return; + } + + // can't rotate in-place + if (rotate90 && (In == Out)) + return; + + if (rotate90) {osx = sy; osy = sx;} + else {osx = sx; osy = sy;} + + // processing 4 mirrored locations at once + #pragma omp parallel for schedule(guided) + for (y=0; y<(sy+1)/2; ++y) + { + int x; + int ox, oy; + unsigned short t1, t2, t3, t4; + + for (x=0; x<(sx+1)/2; ++x) + { + if (rotate90) + { + if (flipLeftRight) ox = y; + else ox = osx-1-y; + if (flipUpDown) oy = osy-1-x; + else oy = x; + + t1 = In[x + y*sx]; + t2 = In[sx-1-x + y*sx]; + t3 = In[x + (sy-1-y)*sx]; + t4 = In[sx-1-x + (sy-1-y)*sx]; + + Out[ox + oy*osx] = t1; + Out[osx-1-ox + oy*osx] = t3; + Out[ox + (osy-1-oy)*osx] = t2; + Out[osx-1-ox + (osy-1-oy)*osx] = t4; + } + else + { + if (flipLeftRight) ox = sx-1-x; + else ox = x; + if (flipUpDown) oy = sy-1-y; + else oy = y; + + t1 = In[x + y*sx]; + t2 = In[sx-1-x + y*sx]; + t3 = In[x + (sy-1-y)*sx]; + t4 = In[sx-1-x + (sy-1-y)*sx]; + + Out[ox + oy*osx] = t1; + Out[osx-1-ox + oy*osx] = t2; + Out[ox + (osy-1-oy)*osx] = t3; + Out[osx-1-ox + (osy-1-oy)*osx] = t4; + } + } + } +} + + +// mirror and/or rotate NV21 image +// +// Note: +// - mirroring can be performed in-place, rotation can not +// - rotation is 90 degree clockwise +// - if need to rotate 180 degree - call with flipLeftRight=1, flipUpDown=1 +// - if need to rotate 90 degree counter-clockwise - call with flipLeftRight=1, flipUpDown=1, rotate90=1 +// - it is assumed that image width is even and image height is even +// - crop coordinates are also transformed if given, but no cropping is performed +// +void TransformNV21 +( + unsigned char * InNV21, + unsigned char * OutNV21, + int sx, + int sy, + int *crop, + int flipLeftRight, + int flipUpDown, + int rotate90 +) +{ + int tmp; + + TransformPlane8bit(InNV21, OutNV21, sx, sy, flipLeftRight, flipUpDown, rotate90); + + // treat UV as a single 16bit entity - makes transform faster + TransformPlane16bit((unsigned short*)(InNV21+sx*sy), (unsigned short*)(OutNV21+sx*sy), sx/2, sy/2, flipLeftRight, flipUpDown, rotate90); + + if (crop) + { + if (rotate90) + { + tmp = crop[0]; crop[0] = crop[1]; crop[1] = tmp; + tmp = crop[2]; crop[2] = crop[3]; crop[3] = tmp; + if (!flipLeftRight) crop[0] = sy-(crop[0]+crop[2]); + if (flipUpDown) crop[1] = sx-(crop[1]+crop[3]); + } + else + { + if (flipLeftRight) crop[0] = sx-(crop[0]+crop[2]); + if (flipUpDown) crop[1] = sy-(crop[1]+crop[3]); + } + } +} diff --git a/jni/groupshot/Android.mk b/jni/groupshot/Android.mk index bf9bc4b3..7618fee3 100755 --- a/jni/groupshot/Android.mk +++ b/jni/groupshot/Android.mk @@ -116,11 +116,12 @@ LOCAL_C_INCLUDES += \ $(LOCAL_PATH)/FaceRecEm/common/src/b_FDSDK/ LOCAL_SHARED_LIBRARIES := \ - libandroid_runtime \ libnativehelper \ libutils \ libskia \ libcutils + +# libandroid_runtime \ LOCAL_MODULE:= libFFTEm diff --git a/jni/include/almashot/filters.h b/jni/include/almashot/filters.h index 245ac1ca..27a0ba88 100644 --- a/jni/include/almashot/filters.h +++ b/jni/include/almashot/filters.h @@ -384,6 +384,8 @@ void Filters_FilterMoving int stride ); +void Filters_RefBlur(Uint8 *in, Uint8 *out, Uint8 *nMov, + int mstride, int sx, int sy, int stride, int mod); #if defined __cplusplus } diff --git a/jni/include/almashot/fstacking.h b/jni/include/almashot/fstacking.h index a2c9a2fc..2412d817 100644 --- a/jni/include/almashot/fstacking.h +++ b/jni/include/almashot/fstacking.h @@ -68,6 +68,24 @@ int FStacking_Align int fastMode ); +int FStacking_GetAlignedFrames +( + void *instance, + Uint8 **out, + int sx, + int sy, + int nFrames +); + + +int FStacking_GetFocusAreaMap +( + void *instance, + Uint8 *out, + int sx, + int sy +); + int FStacking_Process ( diff --git a/jni/include/almashot/supersensor.h b/jni/include/almashot/supersensor.h index 97931d95..be365764 100644 --- a/jni/include/almashot/supersensor.h +++ b/jni/include/almashot/supersensor.h @@ -63,11 +63,9 @@ int Super_Process int syo, int nFrames, int SensorGain, - int DeGhostGain, - int DeGhostFrames, int postFilter, int postSharpen, - int gamma, + float gamma, int cameraIndex, int externalBuffers ); diff --git a/jni/nightprocessing/almashot-night.cpp b/jni/nightprocessing/almashot-night.cpp index 300ae0a7..49d44256 100755 --- a/jni/nightprocessing/almashot-night.cpp +++ b/jni/nightprocessing/almashot-night.cpp @@ -192,87 +192,87 @@ extern "C" JNIEXPORT jint JNICALL Java_com_almalence_plugins_processing_night_Al } } - if (fgamma && (iso>0)) + if (fgamma != 0.0f && (iso > 0) && cameraIndex != 903) { // iso 100 = +0.1 // iso 800 = -0.05 - fgamma += 0.1f - ( logf(iso) * 3.321928095f-6.644f)*0.15f/3.f; - if (fgamma < 0.45f) fgamma = 0.45f; - if (fgamma > 0.6f) fgamma = 0.6f; + fgamma += 0.09f - (logf(iso) * 3.321928095f - 6.644f) * 0.165f/3.0f;//log2f replaced with logf(iso) * 3.321928095f for android <4.3 } - // for SR-only fgamma = 0, gamma will evaluate to 0 also - int gamma = (int)(fgamma * 256 + 0.5f); + if (fgamma != 0.0f) + { + if (fgamma < 0.43f) fgamma = 0.43f; + if (fgamma > 0.6f) fgamma = 0.6f; + } - // threshold at which profiles are switched (about 1.5x zoom) int zoomAbove15x = sxo >= 3*(sx_zoom-2*SIZE_GUARANTEE_BORDER)/2; int zoomAbove30x = sxo >= 3*sx_zoom; + float zoom = sxo / float(sx_zoom); + + int filter = 256; + int sharpen = 1; + if (zoomAbove30x) sharpen = 0x80; // fine edge enhancement instead of primitive sharpen at high zoom levels + +// +// +// +// if (fgamma && (iso>0)) +// { +// // iso 100 = +0.1 +// // iso 800 = -0.05 +// fgamma += 0.1f - ( logf(iso) * 3.321928095f-6.644f)*0.15f/3.f; +// if (fgamma < 0.45f) fgamma = 0.45f; +// if (fgamma > 0.6f) fgamma = 0.6f; +// } +// +// // for SR-only fgamma = 0, gamma will evaluate to 0 also +// int gamma = (int)(fgamma * 256 + 0.5f); +// +// // threshold at which profiles are switched (about 1.5x zoom) +// int zoomAbove15x = sxo >= 3*(sx_zoom-2*SIZE_GUARANTEE_BORDER)/2; +// int zoomAbove30x = sxo >= 3*sx_zoom; - int sensorGain, deGhostGain, filter, sharpen; - switch (cameraIndex) { - case 100: // Nexus 5 - deGhostGain = 256*80/100; - sensorGain = (int)( 256*powf((float)iso/100, 0.5f) ); + case 103:// Nexus 6 + case 507:// LG G Flex2 + case 1900:// Cyanogen 0 + case 2201: + break; + case 100: // Nexus 5 // slightly more sharpening and less filtering at low zooms sharpen = 2; - filter = 384; // 320; // 256; - if (zoomAbove30x) sharpen = 0x80; // fine edge enhancement instead of primitive sharpen at high zoom levels - else if (zoomAbove15x) sharpen = 1; - else filter = 192; - break; - case 103: // Nexus 6 - deGhostGain = 256*50/100; - sensorGain = (int)( 107*256/100*powf((float)iso/100, 0.7f) ); - - sharpen = 1; - if (!zoomAbove15x) sharpen = 0x80; // slightly more filtering at low zooms (noise interpolation artefacts are evident otherwise) - filter = 256; + if (zoomAbove15x) filter = 384; + else filter = 192; break; - case 105: // Nexus 5X - case 106: // Nexus 6P - deGhostGain = (256 * (60 - 0.015f * iso) / 100); - if (deGhostGain < 56) deGhostGain = 56; - sensorGain = (int)(1.7f * 256 * powf(((float)iso) / 100, 0.45f)); + case 105:// Nexus 5X - same camera module as in Nexus 6p + case 106:// Nexus 6P sharpen = 2; - if (zoomAbove30x) sharpen = 0x80;// fine edge enhancement instead of primitive sharpen at high zoom levels if (zoomAbove15x) filter = 256; else filter = 192; break; - case 507: // LG G Flex2 - deGhostGain = 256*60/100; - sensorGain = (int)( 2*256*powf((float)iso/100, 0.45f) ); - sharpen = 1; - if (zoomAbove30x) sharpen = 0x80;// fine edge enhancement instead of primitive sharpen at high zoom levels - filter = 300; - if (!zoomAbove15x) filter = 192;// slightly less filtering at low zooms (somehow sr processing is creating less sharp images here) + case 903:// HTC10 + // use both edge enhancement and sharpening at high zoom levels + sharpen |= 1; break; - case 1006:// Galaxy S7 - deGhostGain = (100 - (int)(iso * 0.0004167f)) * 256 / 100; - sensorGain = (int)(1.05f * 256 * powf(((float)iso) / 100, 0.5f)); - sharpen = 1; + case 1005:// Galaxy S6 // do not use fine edge enhancement (looks too plastic on S6) - //if (zoomAbove30x) sharpen = 0x80;// fine edge enhancement instead of primitive sharpen at high zoom levels - filter = 256; - //if (!zoomAbove15x) filter = 320;// slightly more filtering at low zooms + sharpen = 1; + filter = 288; // 256; break; - case 2000:// OnePlus 2 - deGhostGain = (256 * (50 - 0.01f * iso) / 100); - if (deGhostGain < 54) deGhostGain = 54; - sensorGain = (int)(1.4f * 256 * powf(((float)iso) / 100, 0.45f)); + case 1006:// Galaxy S7 + // do not use fine edge enhancement (looks too plastic on S6) sharpen = 1; - if (zoomAbove30x) sharpen = 0x80;// fine edge enhancement instead of primitive sharpen at high zoom levels + break; - filter = 256; + case 2000:// OnePlus 2 if (zoomAbove15x) filter = 160; - break; default: __android_log_print(ANDROID_LOG_INFO, "CameraTest", "Error: Unknown camera"); @@ -286,12 +286,10 @@ extern "C" JNIEXPORT jint JNICALL Java_com_almalence_plugins_processing_night_Al int err = Super_Process( yuv, NULL, &OutPic, sx_zoom, sy_zoom, sx_zoom, sxo, syo, nImages, - sensorGain, - deGhostGain*deghostTable[DeGhostPref]/256, - 1, // deghostFrames + iso, filter, sharpen, - gamma, + fgamma, cameraIndex, 0); // externalBuffers diff --git a/jni/utils/Android.mk b/jni/utils/Android.mk index 7d836f2b..ed8131b3 100755 --- a/jni/utils/Android.mk +++ b/jni/utils/Android.mk @@ -6,6 +6,6 @@ LOCAL_MODULE := utils-image LOCAL_SRC_FILES := ImageConversionUtils.cpp LOCAL_STATIC_LIBRARIES := jpeg gomp LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH) -LOCAL_LDLIBS := -ldl -llog +LOCAL_LDLIBS := -ldl -llog -landroid -ljnigraphics include $(BUILD_SHARED_LIBRARY) diff --git a/jni/utils/ImageConversionUtils.cpp b/jni/utils/ImageConversionUtils.cpp index f25de2a9..099501b2 100755 --- a/jni/utils/ImageConversionUtils.cpp +++ b/jni/utils/ImageConversionUtils.cpp @@ -20,6 +20,7 @@ by Almalence Inc. All Rights Reserved. #include #include #include +#include #include #include "jpeglib.h" @@ -952,3 +953,87 @@ extern "C" JNIEXPORT jintArray JNICALL Java_com_almalence_util_ImageConversion_N return jpixels; } + + +extern "C" JNIEXPORT jintArray JNICALL Java_com_almalence_util_ImageConversion_NV21ByteArraytoARGB +( + JNIEnv* env, + jobject thiz, + jbyteArray inptr, + jint srcW, + jint srcH, + jobject rect, + jint dstW, + jint dstH +) +{ + LOGD("NV21toARGB - start"); + + Uint32 * pixels; + jintArray jpixels = NULL; + + jclass class_rect = env->GetObjectClass(rect); + jfieldID id_left = env->GetFieldID(class_rect, "left", "I"); + jint left = env->GetIntField(rect,id_left); + jfieldID id_top = env->GetFieldID(class_rect, "top", "I"); + jint top = env->GetIntField(rect,id_top); + jfieldID id_right = env->GetFieldID(class_rect, "right", "I"); + jint right = env->GetIntField(rect,id_right); + jfieldID id_bottom = env->GetFieldID(class_rect, "bottom", "I"); + jint bottom = env->GetIntField(rect,id_bottom); + + jpixels = env->NewIntArray(dstW*dstH); + LOGD("Memory alloc size = %d * %d", dstW, dstH); + pixels = (Uint32 *)env->GetIntArrayElements(jpixels, NULL); + + Uint8 *inpxls = (Uint8 *)env->GetByteArrayElements(inptr, NULL);; + + NV21_to_RGB_scaled(inpxls, srcW, srcH, left, top, right - left, bottom - top, dstW, dstH, 4, (Uint8 *)pixels); + + env->ReleaseIntArrayElements(jpixels, (jint*)pixels, 0); + env->ReleaseByteArrayElements(inptr, (jbyte*)inpxls, 0); + + LOGD("NV21toARGB - end"); + + return jpixels; +} + +extern "C" JNIEXPORT jboolean JNICALL Java_com_almalence_util_ImageConversion_BitmapFromNV21ByteArray +( + JNIEnv* env, + jobject thiz, + jobject bitmap, + jbyteArray inptr, + jint srcW, + jint srcH, + jobject rect, + jint dstW, + jint dstH +) +{ + int ret; + Uint32 * bitmap_data; + + if ((ret = AndroidBitmap_lockPixels(env, bitmap, ((void**)&bitmap_data))) < 0) + return false; + + jclass class_rect = env->GetObjectClass(rect); + jfieldID id_left = env->GetFieldID(class_rect, "left", "I"); + jint left = env->GetIntField(rect,id_left); + jfieldID id_top = env->GetFieldID(class_rect, "top", "I"); + jint top = env->GetIntField(rect,id_top); + jfieldID id_right = env->GetFieldID(class_rect, "right", "I"); + jint right = env->GetIntField(rect,id_right); + jfieldID id_bottom = env->GetFieldID(class_rect, "bottom", "I"); + jint bottom = env->GetIntField(rect,id_bottom); + + Uint8 *inpxls = (Uint8 *)env->GetByteArrayElements(inptr, NULL); + + NV21_to_RGB_scaled(inpxls, srcW, srcH, left, top, right - left, bottom - top, dstW, dstH, 4, (Uint8 *)bitmap_data); + + AndroidBitmap_unlockPixels(env, bitmap); + + env->ReleaseByteArrayElements(inptr, (jbyte*)inpxls, 0); + + return true; +} diff --git a/jni/yuvbitmap/Android.mk b/jni/yuvbitmap/Android.mk new file mode 100755 index 00000000..c140fd84 --- /dev/null +++ b/jni/yuvbitmap/Android.mk @@ -0,0 +1,13 @@ +LOCAL_PATH := $(call my-dir) + +include $(LOCAL_PATH)/../Flags.mk + +LOCAL_MODULE := YuvBitmap +LOCAL_SRC_FILES := YuvBitmap.cpp +LOCAL_LDLIBS := \ + -L. -Ljni/$(TARGET_ARCH_ABI) \ + -llog \ + -landroid \ + -ljnigraphics + +include $(BUILD_SHARED_LIBRARY) \ No newline at end of file diff --git a/jni/yuvbitmap/YuvBitmap.cpp b/jni/yuvbitmap/YuvBitmap.cpp new file mode 100644 index 00000000..585d71bd --- /dev/null +++ b/jni/yuvbitmap/YuvBitmap.cpp @@ -0,0 +1,124 @@ +#include + +#include + +#include +#include + +#define get_Ysz(in, sx, sy, crop_x, crop_y, x, y) ((in)[(crop_x)+(crop_y)*(sx)+(x)+(y)*(sx)]) +#define get_Usz(in, sx, sy, crop_x, crop_y, x, y) ((in)[(sx)*(sy)+(crop_x)+((crop_y)/2)*(sx)+((x)|1)+((y)/2)*(sx)]) +#define get_Vsz(in, sx, sy, crop_x, crop_y, x, y) ((in)[(sx)*(sy)+(crop_x)+((crop_y)/2)*(sx)+((x)&~1)+((y)/2)*(sx)]) + +#define CLIP8(x) ( (x)<0 ? 0 : (x)>255 ? 255 : (x) ) +#define CSC_R(Y,V) CLIP8((128*(Y)+176*((V)-128)) >> 7 ) +#define CSC_B(Y,U) CLIP8((128*(Y)+222*((U)-128)) >> 7 ) +#define CSC_G(Y,U,V) CLIP8((128*(Y)-89*((V)-128)-43*((U)-128)) >> 7 ) + +extern "C" +{ + +inline int min(int a, int b) +{ + return (a < b ? a : b); +} + +void NV21_to_RGB +( + unsigned char * in, + int * out, + int sx, + int sy, + int crop_x, + int crop_y, + int crop_w, + int crop_h, + int crop_w_abs +) +{ + int x, y; + short Y1, Y2, u, v, vp, up, va, ua; + unsigned int R, G, B; + + for (y=0; yGetByteArrayElements(inputArray, NULL); + + NV21_to_RGB((uint8_t*)inputFrame, bitmap_data, input_w, input_h, crop_x, crop_y, actual_crop_w, actual_crop_h, crop_w); + + AndroidBitmap_unlockPixels(env, bitmap); + + env->ReleaseByteArrayElements(inputArray, (jbyte*)inputFrame, 0); + + return true; +} + +} diff --git a/jni/yuvimage/Android.mk b/jni/yuvimage/Android.mk index 12d8caab..f454cdf3 100755 --- a/jni/yuvimage/Android.mk +++ b/jni/yuvimage/Android.mk @@ -5,7 +5,8 @@ include $(LOCAL_PATH)/../Flags.mk LOCAL_MODULE := yuvimage LOCAL_SRC_FILES := yuvimage.cpp YuvToJpegEncoderMT.cpp LOCAL_STATIC_LIBRARIES := almalib jpeg gomp -LOCAL_LDLIBS := -llog \ - $(call host-path, $(LOCAL_PATH)/../prebuilt/$(TARGET_ARCH_ABI)/libandroid_runtime.so) +LOCAL_LDLIBS := -llog +#\ +# $(call host-path, $(LOCAL_PATH)/../prebuilt/$(TARGET_ARCH_ABI)/libandroid_runtime.so) include $(BUILD_SHARED_LIBRARY) \ No newline at end of file diff --git a/res/drawable-hdpi/icon.png b/res/drawable-hdpi/icon.png old mode 100755 new mode 100644 index a9dc4537..15f6e1b2 Binary files a/res/drawable-hdpi/icon.png and b/res/drawable-hdpi/icon.png differ diff --git a/res/drawable-large-hdpi/icon.png b/res/drawable-large-hdpi/icon.png old mode 100755 new mode 100644 index a9dc4537..15f6e1b2 Binary files a/res/drawable-large-hdpi/icon.png and b/res/drawable-large-hdpi/icon.png differ diff --git a/res/drawable-mdpi/icon.png b/res/drawable-mdpi/icon.png old mode 100755 new mode 100644 index c9874140..4688de55 Binary files a/res/drawable-mdpi/icon.png and b/res/drawable-mdpi/icon.png differ diff --git a/res/drawable-xhdpi/icon.png b/res/drawable-xhdpi/icon.png old mode 100755 new mode 100644 index 485c3c3f..5c547a6e Binary files a/res/drawable-xhdpi/icon.png and b/res/drawable-xhdpi/icon.png differ diff --git a/res/drawable-xlarge-hdpi/icon.png b/res/drawable-xlarge-hdpi/icon.png old mode 100755 new mode 100644 index a9dc4537..15f6e1b2 Binary files a/res/drawable-xlarge-hdpi/icon.png and b/res/drawable-xlarge-hdpi/icon.png differ diff --git a/res/drawable/icon.png b/res/drawable/icon.png old mode 100755 new mode 100644 index c9874140..4688de55 Binary files a/res/drawable/icon.png and b/res/drawable/icon.png differ diff --git a/res/layout-large/gui_almalence_layout.xml b/res/layout-large/gui_almalence_layout.xml index 78e62919..6ca07888 100755 --- a/res/layout-large/gui_almalence_layout.xml +++ b/res/layout-large/gui_almalence_layout.xml @@ -152,7 +152,7 @@ + + + + +