parent
a5eeb722a7
commit
dd280ec86a
@ -0,0 +1,9 @@
|
|||||||
|
*.iml
|
||||||
|
.gradle
|
||||||
|
/local.properties
|
||||||
|
/.idea/*
|
||||||
|
.DS_Store
|
||||||
|
/build
|
||||||
|
/captures
|
||||||
|
.externalNativeBuild
|
||||||
|
|
@ -0,0 +1 @@
|
|||||||
|
/build
|
@ -0,0 +1,95 @@
|
|||||||
|
import java.security.MessageDigest
|
||||||
|
|
||||||
|
apply plugin: 'com.android.application'
|
||||||
|
|
||||||
|
android {
|
||||||
|
compileSdkVersion 28
|
||||||
|
defaultConfig {
|
||||||
|
applicationId "com.baidu.paddle.lite.demo.ocr"
|
||||||
|
minSdkVersion 15
|
||||||
|
targetSdkVersion 28
|
||||||
|
versionCode 1
|
||||||
|
versionName "1.0"
|
||||||
|
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||||
|
externalNativeBuild {
|
||||||
|
cmake {
|
||||||
|
cppFlags "-std=c++11 -frtti -fexceptions -Wno-format"
|
||||||
|
arguments '-DANDROID_PLATFORM=android-23', '-DANDROID_STL=c++_shared' ,"-DANDROID_ARM_NEON=TRUE"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ndk {
|
||||||
|
// abiFilters "arm64-v8a", "armeabi-v7a"
|
||||||
|
abiFilters "arm64-v8a", "armeabi-v7a"
|
||||||
|
ldLibs "jnigraphics"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buildTypes {
|
||||||
|
release {
|
||||||
|
minifyEnabled false
|
||||||
|
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
externalNativeBuild {
|
||||||
|
cmake {
|
||||||
|
path "src/main/cpp/CMakeLists.txt"
|
||||||
|
version "3.10.2"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation fileTree(include: ['*.jar'], dir: 'libs')
|
||||||
|
implementation 'com.android.support:appcompat-v7:28.0.0'
|
||||||
|
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
|
||||||
|
implementation 'com.android.support:design:28.0.0'
|
||||||
|
testImplementation 'junit:junit:4.12'
|
||||||
|
androidTestImplementation 'com.android.support.test:runner:1.0.2'
|
||||||
|
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
|
||||||
|
}
|
||||||
|
|
||||||
|
def archives = [
|
||||||
|
[
|
||||||
|
'src' : 'https://paddlelite-demo.bj.bcebos.com/libs/android/paddle_lite_libs_v2_6_1.tar.gz',
|
||||||
|
'dest': 'PaddleLite'
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'src' : 'https://paddlelite-demo.bj.bcebos.com/libs/android/opencv-4.2.0-android-sdk.tar.gz',
|
||||||
|
'dest': 'OpenCV'
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'src' : 'https://paddleocr.bj.bcebos.com/deploy/lite/ocr_v1_for_cpu.tar.gz',
|
||||||
|
'dest' : 'src/main/assets/models/ocr_v1_for_cpu'
|
||||||
|
]
|
||||||
|
]
|
||||||
|
|
||||||
|
task downloadAndExtractArchives(type: DefaultTask) {
|
||||||
|
doFirst {
|
||||||
|
println "Downloading and extracting archives including libs and models"
|
||||||
|
}
|
||||||
|
doLast {
|
||||||
|
// Prepare cache folder for archives
|
||||||
|
String cachePath = "cache"
|
||||||
|
if (!file("${cachePath}").exists()) {
|
||||||
|
mkdir "${cachePath}"
|
||||||
|
}
|
||||||
|
archives.eachWithIndex { archive, index ->
|
||||||
|
MessageDigest messageDigest = MessageDigest.getInstance('MD5')
|
||||||
|
messageDigest.update(archive.src.bytes)
|
||||||
|
String cacheName = new BigInteger(1, messageDigest.digest()).toString(32)
|
||||||
|
// Download the target archive if not exists
|
||||||
|
boolean copyFiles = !file("${archive.dest}").exists()
|
||||||
|
if (!file("${cachePath}/${cacheName}.tar.gz").exists()) {
|
||||||
|
ant.get(src: archive.src, dest: file("${cachePath}/${cacheName}.tar.gz"))
|
||||||
|
copyFiles = true; // force to copy files from the latest archive files
|
||||||
|
}
|
||||||
|
// Extract the target archive if its dest path does not exists
|
||||||
|
if (copyFiles) {
|
||||||
|
copy {
|
||||||
|
from tarTree("${cachePath}/${cacheName}.tar.gz")
|
||||||
|
into "${archive.dest}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
preBuild.dependsOn downloadAndExtractArchives
|
@ -0,0 +1,21 @@
|
|||||||
|
# Add project specific ProGuard rules here.
|
||||||
|
# You can control the set of applied configuration files using the
|
||||||
|
# proguardFiles setting in build.gradle.
|
||||||
|
#
|
||||||
|
# For more details, see
|
||||||
|
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||||
|
|
||||||
|
# If your project uses WebView with JS, uncomment the following
|
||||||
|
# and specify the fully qualified class name to the JavaScript interface
|
||||||
|
# class:
|
||||||
|
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||||
|
# public *;
|
||||||
|
#}
|
||||||
|
|
||||||
|
# Uncomment this to preserve the line number information for
|
||||||
|
# debugging stack traces.
|
||||||
|
#-keepattributes SourceFile,LineNumberTable
|
||||||
|
|
||||||
|
# If you keep the line number information, uncomment this to
|
||||||
|
# hide the original source file name.
|
||||||
|
#-renamesourcefileattribute SourceFile
|
@ -0,0 +1,26 @@
|
|||||||
|
package com.baidu.paddle.lite.demo.ocr;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.support.test.InstrumentationRegistry;
|
||||||
|
import android.support.test.runner.AndroidJUnit4;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instrumented test, which will execute on an Android device.
|
||||||
|
*
|
||||||
|
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
||||||
|
*/
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
public class ExampleInstrumentedTest {
|
||||||
|
@Test
|
||||||
|
public void useAppContext() {
|
||||||
|
// Context of the app under test.
|
||||||
|
Context appContext = InstrumentationRegistry.getTargetContext();
|
||||||
|
|
||||||
|
assertEquals("com.baidu.paddle.lite.demo", appContext.getPackageName());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
package="com.baidu.paddle.lite.demo.ocr">
|
||||||
|
|
||||||
|
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
||||||
|
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
|
||||||
|
<uses-permission android:name="android.permission.CAMERA"/>
|
||||||
|
|
||||||
|
|
||||||
|
<application
|
||||||
|
android:allowBackup="true"
|
||||||
|
android:icon="@mipmap/ic_launcher"
|
||||||
|
android:label="@string/app_name"
|
||||||
|
android:roundIcon="@mipmap/ic_launcher_round"
|
||||||
|
android:supportsRtl="true"
|
||||||
|
android:theme="@style/AppTheme">
|
||||||
|
<activity android:name="com.baidu.paddle.lite.demo.ocr.MainActivity">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.MAIN"/>
|
||||||
|
|
||||||
|
<category android:name="android.intent.category.LAUNCHER"/>
|
||||||
|
</intent-filter>
|
||||||
|
</activity>
|
||||||
|
<activity
|
||||||
|
android:name="com.baidu.paddle.lite.demo.ocr.SettingsActivity"
|
||||||
|
android:label="Settings">
|
||||||
|
</activity>
|
||||||
|
</application>
|
||||||
|
|
||||||
|
</manifest>
|
After Width: | Height: | Size: 62 KiB |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,117 @@
|
|||||||
|
# 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)
|
||||||
|
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
set(PaddleLite_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../../PaddleLite")
|
||||||
|
include_directories(${PaddleLite_DIR}/cxx/include)
|
||||||
|
|
||||||
|
set(OpenCV_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../../OpenCV/sdk/native/jni")
|
||||||
|
message(STATUS "opencv dir: ${OpenCV_DIR}")
|
||||||
|
find_package(OpenCV REQUIRED)
|
||||||
|
message(STATUS "OpenCV libraries: ${OpenCV_LIBS}")
|
||||||
|
include_directories(${OpenCV_INCLUDE_DIRS})
|
||||||
|
aux_source_directory(. SOURCES)
|
||||||
|
set(CMAKE_CXX_FLAGS
|
||||||
|
"${CMAKE_CXX_FLAGS} -ffast-math -Ofast -Os"
|
||||||
|
)
|
||||||
|
set(CMAKE_CXX_FLAGS
|
||||||
|
"${CMAKE_CXX_FLAGS} -fvisibility=hidden -fvisibility-inlines-hidden -fdata-sections -ffunction-sections"
|
||||||
|
)
|
||||||
|
set(CMAKE_SHARED_LINKER_FLAGS
|
||||||
|
"${CMAKE_SHARED_LINKER_FLAGS} -Wl,--gc-sections -Wl,-z,nocopyreloc")
|
||||||
|
|
||||||
|
add_library(
|
||||||
|
# Sets the name of the library.
|
||||||
|
Native
|
||||||
|
# Sets the library as a shared library.
|
||||||
|
SHARED
|
||||||
|
# Provides a relative path to your source file(s).
|
||||||
|
${SOURCES})
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
add_library(
|
||||||
|
# Sets the name of the library.
|
||||||
|
paddle_light_api_shared
|
||||||
|
# Sets the library as a shared library.
|
||||||
|
SHARED
|
||||||
|
# Provides a relative path to your source file(s).
|
||||||
|
IMPORTED)
|
||||||
|
|
||||||
|
set_target_properties(
|
||||||
|
# Specifies the target library.
|
||||||
|
paddle_light_api_shared
|
||||||
|
# Specifies the parameter you want to define.
|
||||||
|
PROPERTIES
|
||||||
|
IMPORTED_LOCATION
|
||||||
|
${PaddleLite_DIR}/cxx/libs/${ANDROID_ABI}/libpaddle_light_api_shared.so
|
||||||
|
# Provides the path to the library you want to import.
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# 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
|
||||||
|
paddle_light_api_shared
|
||||||
|
${OpenCV_LIBS}
|
||||||
|
GLESv2
|
||||||
|
EGL
|
||||||
|
jnigraphics
|
||||||
|
${log-lib}
|
||||||
|
)
|
||||||
|
|
||||||
|
add_custom_command(
|
||||||
|
TARGET Native
|
||||||
|
POST_BUILD
|
||||||
|
COMMAND
|
||||||
|
${CMAKE_COMMAND} -E copy
|
||||||
|
${PaddleLite_DIR}/cxx/libs/${ANDROID_ABI}/libc++_shared.so
|
||||||
|
${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/libc++_shared.so)
|
||||||
|
|
||||||
|
add_custom_command(
|
||||||
|
TARGET Native
|
||||||
|
POST_BUILD
|
||||||
|
COMMAND
|
||||||
|
${CMAKE_COMMAND} -E copy
|
||||||
|
${PaddleLite_DIR}/cxx/libs/${ANDROID_ABI}/libpaddle_light_api_shared.so
|
||||||
|
${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/libpaddle_light_api_shared.so)
|
||||||
|
|
||||||
|
add_custom_command(
|
||||||
|
TARGET Native
|
||||||
|
POST_BUILD
|
||||||
|
COMMAND
|
||||||
|
${CMAKE_COMMAND} -E copy
|
||||||
|
${PaddleLite_DIR}/cxx/libs/${ANDROID_ABI}/libhiai.so
|
||||||
|
${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/libhiai.so)
|
||||||
|
|
||||||
|
add_custom_command(
|
||||||
|
TARGET Native
|
||||||
|
POST_BUILD
|
||||||
|
COMMAND
|
||||||
|
${CMAKE_COMMAND} -E copy
|
||||||
|
${PaddleLite_DIR}/cxx/libs/${ANDROID_ABI}/libhiai_ir.so
|
||||||
|
${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/libhiai_ir.so)
|
||||||
|
|
||||||
|
add_custom_command(
|
||||||
|
TARGET Native
|
||||||
|
POST_BUILD
|
||||||
|
COMMAND
|
||||||
|
${CMAKE_COMMAND} -E copy
|
||||||
|
${PaddleLite_DIR}/cxx/libs/${ANDROID_ABI}/libhiai_ir_build.so
|
||||||
|
${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/libhiai_ir_build.so)
|
@ -0,0 +1,48 @@
|
|||||||
|
//
|
||||||
|
// Created by fu on 4/25/18.
|
||||||
|
//
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#import <vector>
|
||||||
|
#import <numeric>
|
||||||
|
|
||||||
|
#ifdef __ANDROID__
|
||||||
|
|
||||||
|
#include <android/log.h>
|
||||||
|
|
||||||
|
#define LOG_TAG "OCR_NDK"
|
||||||
|
|
||||||
|
#define LOGI(...) \
|
||||||
|
__android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
|
||||||
|
#define LOGW(...) \
|
||||||
|
__android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)
|
||||||
|
#define LOGE(...) \
|
||||||
|
__android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#include <stdio.h>
|
||||||
|
#define LOGI(format, ...) \
|
||||||
|
fprintf(stdout, "[" LOG_TAG "]" format "\n", ##__VA_ARGS__)
|
||||||
|
#define LOGW(format, ...) \
|
||||||
|
fprintf(stdout, "[" LOG_TAG "]" format "\n", ##__VA_ARGS__)
|
||||||
|
#define LOGE(format, ...) \
|
||||||
|
fprintf(stderr, "[" LOG_TAG "]Error: " format "\n", ##__VA_ARGS__)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
enum RETURN_CODE {
|
||||||
|
RETURN_OK = 0
|
||||||
|
};
|
||||||
|
|
||||||
|
enum NET_TYPE{
|
||||||
|
NET_OCR = 900100,
|
||||||
|
NET_OCR_INTERNAL = 991008
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
inline T product(const std::vector<T> &vec) {
|
||||||
|
if (vec.empty()){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return std::accumulate(vec.begin(), vec.end(), 1, std::multiplies<T>());
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,138 @@
|
|||||||
|
//
|
||||||
|
// Created by fujiayi on 2020/7/5.
|
||||||
|
//
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
|
||||||
|
#include <jni.h>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <android/bitmap.h>
|
||||||
|
#include <opencv2/opencv.hpp>
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
inline std::string jstring_to_cpp_string(JNIEnv *env, jstring jstr) {
|
||||||
|
// In java, a unicode char will be encoded using 2 bytes (utf16).
|
||||||
|
// so jstring will contain characters utf16. std::string in c++ is
|
||||||
|
// essentially a string of bytes, not characters, so if we want to
|
||||||
|
// pass jstring from JNI to c++, we have convert utf16 to bytes.
|
||||||
|
if (!jstr) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
const jclass stringClass = env->GetObjectClass(jstr);
|
||||||
|
const jmethodID getBytes =
|
||||||
|
env->GetMethodID(stringClass, "getBytes", "(Ljava/lang/String;)[B");
|
||||||
|
const jbyteArray stringJbytes = (jbyteArray) env->CallObjectMethod(
|
||||||
|
jstr, getBytes, env->NewStringUTF("UTF-8"));
|
||||||
|
|
||||||
|
size_t length = (size_t) env->GetArrayLength(stringJbytes);
|
||||||
|
jbyte *pBytes = env->GetByteArrayElements(stringJbytes, NULL);
|
||||||
|
|
||||||
|
std::string ret = std::string(reinterpret_cast<char *>(pBytes), length);
|
||||||
|
env->ReleaseByteArrayElements(stringJbytes, pBytes, JNI_ABORT);
|
||||||
|
|
||||||
|
env->DeleteLocalRef(stringJbytes);
|
||||||
|
env->DeleteLocalRef(stringClass);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline jstring cpp_string_to_jstring(JNIEnv *env, std::string str) {
|
||||||
|
auto *data = str.c_str();
|
||||||
|
jclass strClass = env->FindClass("java/lang/String");
|
||||||
|
jmethodID strClassInitMethodID =
|
||||||
|
env->GetMethodID(strClass, "<init>", "([BLjava/lang/String;)V");
|
||||||
|
|
||||||
|
jbyteArray bytes = env->NewByteArray(strlen(data));
|
||||||
|
env->SetByteArrayRegion(bytes, 0, strlen(data),
|
||||||
|
reinterpret_cast<const jbyte *>(data));
|
||||||
|
|
||||||
|
jstring encoding = env->NewStringUTF("UTF-8");
|
||||||
|
jstring res = (jstring) (
|
||||||
|
env->NewObject(strClass, strClassInitMethodID, bytes, encoding));
|
||||||
|
|
||||||
|
env->DeleteLocalRef(strClass);
|
||||||
|
env->DeleteLocalRef(encoding);
|
||||||
|
env->DeleteLocalRef(bytes);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline jfloatArray cpp_array_to_jfloatarray(JNIEnv *env, const float *buf,
|
||||||
|
int64_t len) {
|
||||||
|
if (len == 0) {
|
||||||
|
return env->NewFloatArray(0);
|
||||||
|
}
|
||||||
|
jfloatArray result = env->NewFloatArray(len);
|
||||||
|
env->SetFloatArrayRegion(result, 0, len, buf);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline jintArray cpp_array_to_jintarray(JNIEnv *env, const int *buf,
|
||||||
|
int64_t len) {
|
||||||
|
jintArray result = env->NewIntArray(len);
|
||||||
|
env->SetIntArrayRegion(result, 0, len, buf);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline jbyteArray cpp_array_to_jbytearray(JNIEnv *env, const int8_t *buf,
|
||||||
|
int64_t len) {
|
||||||
|
jbyteArray result = env->NewByteArray(len);
|
||||||
|
env->SetByteArrayRegion(result, 0, len, buf);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline jlongArray int64_vector_to_jlongarray(JNIEnv *env,
|
||||||
|
const std::vector<int64_t> &vec) {
|
||||||
|
jlongArray result = env->NewLongArray(vec.size());
|
||||||
|
jlong *buf = new jlong[vec.size()];
|
||||||
|
for (size_t i = 0; i < vec.size(); ++i) {
|
||||||
|
buf[i] = (jlong) vec[i];
|
||||||
|
}
|
||||||
|
env->SetLongArrayRegion(result, 0, vec.size(), buf);
|
||||||
|
delete[] buf;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::vector<int64_t> jlongarray_to_int64_vector(JNIEnv *env,
|
||||||
|
jlongArray data) {
|
||||||
|
int data_size = env->GetArrayLength(data);
|
||||||
|
jlong *data_ptr = env->GetLongArrayElements(data, nullptr);
|
||||||
|
std::vector<int64_t> data_vec(data_ptr, data_ptr + data_size);
|
||||||
|
env->ReleaseLongArrayElements(data, data_ptr, 0);
|
||||||
|
return data_vec;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::vector<float> jfloatarray_to_float_vector(JNIEnv *env,
|
||||||
|
jfloatArray data) {
|
||||||
|
int data_size = env->GetArrayLength(data);
|
||||||
|
jfloat *data_ptr = env->GetFloatArrayElements(data, nullptr);
|
||||||
|
std::vector<float> data_vec(data_ptr, data_ptr + data_size);
|
||||||
|
env->ReleaseFloatArrayElements(data, data_ptr, 0);
|
||||||
|
return data_vec;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline cv::Mat bitmap_to_cv_mat(JNIEnv *env, jobject bitmap) {
|
||||||
|
AndroidBitmapInfo info;
|
||||||
|
int result = AndroidBitmap_getInfo(env, bitmap, &info);
|
||||||
|
if (result != ANDROID_BITMAP_RESULT_SUCCESS) {
|
||||||
|
LOGE("AndroidBitmap_getInfo failed, result: %d", result);
|
||||||
|
return cv::Mat{};
|
||||||
|
}
|
||||||
|
if (info.format != ANDROID_BITMAP_FORMAT_RGBA_8888) {
|
||||||
|
LOGE("Bitmap format is not RGBA_8888 !");
|
||||||
|
return cv::Mat{};
|
||||||
|
}
|
||||||
|
unsigned char *srcData = NULL;
|
||||||
|
AndroidBitmap_lockPixels(env, bitmap, (void **) &srcData);
|
||||||
|
cv::Mat mat = cv::Mat::zeros(info.height, info.width, CV_8UC4);
|
||||||
|
memcpy(mat.data, srcData, info.height * info.width * 4);
|
||||||
|
AndroidBitmap_unlockPixels(env, bitmap);
|
||||||
|
cv::cvtColor(mat, mat, cv::COLOR_RGBA2BGR);
|
||||||
|
/**
|
||||||
|
if (!cv::imwrite("/sdcard/1/copy.jpg", mat)){
|
||||||
|
LOGE("Write image failed " );
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
return mat;
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,140 @@
|
|||||||
|
// Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "ocr_crnn_process.h"
|
||||||
|
#include <iostream>
|
||||||
|
#include <vector>
|
||||||
|
#include <iostream>
|
||||||
|
#include <cstring>
|
||||||
|
#include <fstream>
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
const std::string CHARACTER_TYPE = "ch";
|
||||||
|
const int MAX_DICT_LENGTH = 6624;
|
||||||
|
const std::vector<int> REC_IMAGE_SHAPE = {3, 32, 320};
|
||||||
|
|
||||||
|
static cv::Mat crnn_resize_norm_img(cv::Mat img, float wh_ratio) {
|
||||||
|
int imgC = REC_IMAGE_SHAPE[0];
|
||||||
|
int imgW = REC_IMAGE_SHAPE[2];
|
||||||
|
int imgH = REC_IMAGE_SHAPE[1];
|
||||||
|
|
||||||
|
if (CHARACTER_TYPE == "ch")
|
||||||
|
imgW = int(32 * wh_ratio);
|
||||||
|
|
||||||
|
float ratio = float(img.cols) / float(img.rows);
|
||||||
|
int resize_w = 0;
|
||||||
|
if (ceilf(imgH * ratio) > imgW)
|
||||||
|
resize_w = imgW;
|
||||||
|
else
|
||||||
|
resize_w = int(ceilf(imgH * ratio));
|
||||||
|
cv::Mat resize_img;
|
||||||
|
cv::resize(img, resize_img, cv::Size(resize_w, imgH), 0.f, 0.f, cv::INTER_CUBIC);
|
||||||
|
|
||||||
|
resize_img.convertTo(resize_img, CV_32FC3, 1 / 255.f);
|
||||||
|
|
||||||
|
for (int h = 0; h < resize_img.rows; h++) {
|
||||||
|
for (int w = 0; w < resize_img.cols; w++) {
|
||||||
|
resize_img.at<cv::Vec3f>(h, w)[0] = (resize_img.at<cv::Vec3f>(h, w)[0] - 0.5) * 2;
|
||||||
|
resize_img.at<cv::Vec3f>(h, w)[1] = (resize_img.at<cv::Vec3f>(h, w)[1] - 0.5) * 2;
|
||||||
|
resize_img.at<cv::Vec3f>(h, w)[2] = (resize_img.at<cv::Vec3f>(h, w)[2] - 0.5) * 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cv::Mat dist;
|
||||||
|
cv::copyMakeBorder(resize_img, dist, 0, 0, 0, int(imgW - resize_w), cv::BORDER_CONSTANT,
|
||||||
|
{0, 0, 0});
|
||||||
|
|
||||||
|
return dist;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
cv::Mat crnn_resize_img(const cv::Mat &img, float wh_ratio) {
|
||||||
|
int imgC = REC_IMAGE_SHAPE[0];
|
||||||
|
int imgW = REC_IMAGE_SHAPE[2];
|
||||||
|
int imgH = REC_IMAGE_SHAPE[1];
|
||||||
|
|
||||||
|
if (CHARACTER_TYPE == "ch") {
|
||||||
|
imgW = int(32 * wh_ratio);
|
||||||
|
}
|
||||||
|
|
||||||
|
float ratio = float(img.cols) / float(img.rows);
|
||||||
|
int resize_w = 0;
|
||||||
|
if (ceilf(imgH * ratio) > imgW)
|
||||||
|
resize_w = imgW;
|
||||||
|
else
|
||||||
|
resize_w = int(ceilf(imgH * ratio));
|
||||||
|
cv::Mat resize_img;
|
||||||
|
cv::resize(img, resize_img, cv::Size(resize_w, imgH));
|
||||||
|
return resize_img;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
cv::Mat get_rotate_crop_image(const cv::Mat &srcimage, const std::vector<std::vector<int>> &box) {
|
||||||
|
|
||||||
|
std::vector<std::vector<int>> points = box;
|
||||||
|
|
||||||
|
int x_collect[4] = {box[0][0], box[1][0], box[2][0], box[3][0]};
|
||||||
|
int y_collect[4] = {box[0][1], box[1][1], box[2][1], box[3][1]};
|
||||||
|
int left = int(*std::min_element(x_collect, x_collect + 4));
|
||||||
|
int right = int(*std::max_element(x_collect, x_collect + 4));
|
||||||
|
int top = int(*std::min_element(y_collect, y_collect + 4));
|
||||||
|
int bottom = int(*std::max_element(y_collect, y_collect + 4));
|
||||||
|
|
||||||
|
cv::Mat img_crop;
|
||||||
|
srcimage(cv::Rect(left, top, right - left, bottom - top)).copyTo(img_crop);
|
||||||
|
|
||||||
|
for (int i = 0; i < points.size(); i++) {
|
||||||
|
points[i][0] -= left;
|
||||||
|
points[i][1] -= top;
|
||||||
|
}
|
||||||
|
|
||||||
|
int img_crop_width = int(sqrt(pow(points[0][0] - points[1][0], 2) +
|
||||||
|
pow(points[0][1] - points[1][1], 2)));
|
||||||
|
int img_crop_height = int(sqrt(pow(points[0][0] - points[3][0], 2) +
|
||||||
|
pow(points[0][1] - points[3][1], 2)));
|
||||||
|
|
||||||
|
cv::Point2f pts_std[4];
|
||||||
|
pts_std[0] = cv::Point2f(0., 0.);
|
||||||
|
pts_std[1] = cv::Point2f(img_crop_width, 0.);
|
||||||
|
pts_std[2] = cv::Point2f(img_crop_width, img_crop_height);
|
||||||
|
pts_std[3] = cv::Point2f(0.f, img_crop_height);
|
||||||
|
|
||||||
|
cv::Point2f pointsf[4];
|
||||||
|
pointsf[0] = cv::Point2f(points[0][0], points[0][1]);
|
||||||
|
pointsf[1] = cv::Point2f(points[1][0], points[1][1]);
|
||||||
|
pointsf[2] = cv::Point2f(points[2][0], points[2][1]);
|
||||||
|
pointsf[3] = cv::Point2f(points[3][0], points[3][1]);
|
||||||
|
|
||||||
|
cv::Mat M = cv::getPerspectiveTransform(pointsf, pts_std);
|
||||||
|
|
||||||
|
cv::Mat dst_img;
|
||||||
|
cv::warpPerspective(img_crop, dst_img, M, cv::Size(img_crop_width, img_crop_height),
|
||||||
|
cv::BORDER_REPLICATE);
|
||||||
|
|
||||||
|
if (float(dst_img.rows) >= float(dst_img.cols) * 1.5) {
|
||||||
|
/*
|
||||||
|
cv::Mat srcCopy = cv::Mat(dst_img.rows, dst_img.cols, dst_img.depth());
|
||||||
|
cv::transpose(dst_img, srcCopy);
|
||||||
|
cv::flip(srcCopy, srcCopy, 0);
|
||||||
|
return srcCopy;
|
||||||
|
*/
|
||||||
|
cv::transpose(dst_img, dst_img);
|
||||||
|
cv::flip(dst_img, dst_img, 0);
|
||||||
|
return dst_img;
|
||||||
|
} else {
|
||||||
|
return dst_img;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,19 @@
|
|||||||
|
//
|
||||||
|
// Created by fujiayi on 2020/7/3.
|
||||||
|
//
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <opencv2/opencv.hpp>
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
extern const std::vector<int> REC_IMAGE_SHAPE;
|
||||||
|
|
||||||
|
cv::Mat get_rotate_crop_image(const cv::Mat &srcimage, const std::vector<std::vector<int>> &box);
|
||||||
|
|
||||||
|
cv::Mat crnn_resize_img(const cv::Mat &img, float wh_ratio);
|
||||||
|
|
||||||
|
template<class ForwardIterator>
|
||||||
|
inline size_t argmax(ForwardIterator first, ForwardIterator last) {
|
||||||
|
return std::distance(first, std::max_element(first, last));
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,17 @@
|
|||||||
|
//
|
||||||
|
// Created by fujiayi on 2020/7/2.
|
||||||
|
//
|
||||||
|
#pragma once
|
||||||
|
#include <vector>
|
||||||
|
#include <opencv2/opencv.hpp>
|
||||||
|
|
||||||
|
std::vector<std::vector<std::vector<int>>>
|
||||||
|
boxes_from_bitmap(const cv::Mat &pred, const cv::Mat &bitmap);
|
||||||
|
|
||||||
|
std::vector<std::vector<std::vector<int>>>
|
||||||
|
filter_tag_det_res(
|
||||||
|
const std::vector<std::vector<std::vector<int>>> &o_boxes,
|
||||||
|
float ratio_h,
|
||||||
|
float ratio_w,
|
||||||
|
const cv::Mat &srcimg
|
||||||
|
);
|
@ -0,0 +1,70 @@
|
|||||||
|
#include "ppredictor.h"
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
namespace ppredictor {
|
||||||
|
PPredictor::PPredictor(int thread_num, int net_flag, paddle::lite_api::PowerMode mode) :
|
||||||
|
_thread_num(thread_num), _net_flag(net_flag), _mode(mode) {
|
||||||
|
}
|
||||||
|
|
||||||
|
int PPredictor::init_nb(const std::string &model_content) {
|
||||||
|
paddle::lite_api::MobileConfig config;
|
||||||
|
config.set_model_from_buffer(model_content);
|
||||||
|
return _init(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
int PPredictor::init_from_file(const std::string &model_content){
|
||||||
|
paddle::lite_api::MobileConfig config;
|
||||||
|
config.set_model_from_file(model_content);
|
||||||
|
return _init(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename ConfigT>
|
||||||
|
int PPredictor::_init(ConfigT &config) {
|
||||||
|
config.set_threads(_thread_num);
|
||||||
|
config.set_power_mode(_mode);
|
||||||
|
_predictor = paddle::lite_api::CreatePaddlePredictor(config);
|
||||||
|
LOGI("paddle instance created");
|
||||||
|
return RETURN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
PredictorInput PPredictor::get_input(int index) {
|
||||||
|
PredictorInput input{_predictor->GetInput(index), index, _net_flag};
|
||||||
|
_is_input_get = true;
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<PredictorInput> PPredictor::get_inputs(int num) {
|
||||||
|
std::vector<PredictorInput> results;
|
||||||
|
for (int i = 0; i < num; i++) {
|
||||||
|
results.emplace_back(get_input(i));
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
PredictorInput PPredictor::get_first_input() {
|
||||||
|
return get_input(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<PredictorOutput> PPredictor::infer() {
|
||||||
|
LOGI("infer Run start %d", _net_flag);
|
||||||
|
std::vector<PredictorOutput> results;
|
||||||
|
if (!_is_input_get) {
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
_predictor->Run();
|
||||||
|
LOGI("infer Run end");
|
||||||
|
|
||||||
|
for (int i = 0; i < _predictor->GetOutputNames().size(); i++) {
|
||||||
|
std::unique_ptr<const paddle::lite_api::Tensor> output_tensor = _predictor->GetOutput(i);
|
||||||
|
LOGI("output tensor[%d] size %ld", i, product(output_tensor->shape()));
|
||||||
|
PredictorOutput result{std::move(output_tensor), i, _net_flag};
|
||||||
|
results.emplace_back(std::move(result));
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
NET_TYPE PPredictor::get_net_flag() const {
|
||||||
|
return (NET_TYPE) _net_flag;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,29 @@
|
|||||||
|
#include "predictor_input.h"
|
||||||
|
|
||||||
|
namespace ppredictor {
|
||||||
|
|
||||||
|
|
||||||
|
void PredictorInput::set_dims(std::vector<int64_t> dims) {
|
||||||
|
// yolov3
|
||||||
|
if (_net_flag == 101 && _index == 1) {
|
||||||
|
_tensor->Resize({1, 2});
|
||||||
|
_tensor->mutable_data<int>()[0] = (int) dims.at(2);
|
||||||
|
_tensor->mutable_data<int>()[1] = (int) dims.at(3);
|
||||||
|
} else {
|
||||||
|
_tensor->Resize(dims);
|
||||||
|
}
|
||||||
|
_is_dims_set = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
float *PredictorInput::get_mutable_float_data() {
|
||||||
|
if (!_is_dims_set) {
|
||||||
|
LOGE("PredictorInput::set_dims is not called");
|
||||||
|
}
|
||||||
|
return _tensor->mutable_data<float>();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PredictorInput::set_data(const float *input_data, int input_float_len) {
|
||||||
|
float *input_raw_data = get_mutable_float_data();
|
||||||
|
memcpy(input_raw_data, input_data, input_float_len * sizeof(float));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,28 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <paddle_api.h>
|
||||||
|
#include <vector>
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
namespace ppredictor {
|
||||||
|
class PredictorInput {
|
||||||
|
public:
|
||||||
|
PredictorInput(std::unique_ptr<paddle::lite_api::Tensor> &&tensor, int index, int net_flag) :
|
||||||
|
_tensor(std::move(tensor)), _index(index),_net_flag(net_flag) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void set_dims(std::vector<int64_t> dims);
|
||||||
|
|
||||||
|
float *get_mutable_float_data();
|
||||||
|
|
||||||
|
void set_data(const float *input_data, int input_float_len);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::unique_ptr<paddle::lite_api::Tensor> _tensor;
|
||||||
|
bool _is_dims_set = false;
|
||||||
|
int _index;
|
||||||
|
int _net_flag;
|
||||||
|
};
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue