feat: 切换后端至PaddleOCR-NCNN,切换工程为CMake

1.项目后端整体迁移至PaddleOCR-NCNN算法,已通过基本的兼容性测试
2.工程改为使用CMake组织,后续为了更好地兼容第三方库,不再提供QMake工程
3.重整权利声明文件,重整代码工程,确保最小化侵权风险

Log: 切换后端至PaddleOCR-NCNN,切换工程为CMake
Change-Id: I4d5d2c5d37505a4a24b389b1a4c5d12f17bfa38c
This commit is contained in:
wangzhengyang
2022-05-10 09:54:44 +08:00
parent ecdd171c6f
commit 718c41634f
10018 changed files with 3593797 additions and 186748 deletions

View File

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.opencv.engine"
android:versionCode="345@ANDROID_PLATFORM_ID@"
android:versionName="3.45">
<uses-sdk android:minSdkVersion="@ANDROID_NATIVE_API_LEVEL@" android:targetSdkVersion="22"/>
<uses-feature android:name="android.hardware.touchscreen" android:required="false"/>
<application
android:icon="@drawable/icon"
android:label="@string/app_name" android:allowBackup="true">
<service android:exported="true" android:name="OpenCVEngineService" android:process=":OpenCVEngineProcess">
<intent-filter>
<action android:name="org.opencv.engine.BIND"></action>
</intent-filter>
</service>
<activity
android:name="org.opencv.engine.manager.ManagerActivity"
android:label="@string/app_name"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>

View File

@ -0,0 +1,3 @@
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/${ANDROID_MANIFEST_FILE}" "${OpenCV_BINARY_DIR}/platforms/android/service/engine/.build/${ANDROID_MANIFEST_FILE}" @ONLY)
unset(__android_project_chain CACHE)
add_android_project(opencv_engine "${CMAKE_CURRENT_SOURCE_DIR}" SDK_TARGET 9 ${ANDROID_SDK_TARGET} IGNORE_JAVA ON IGNORE_MANIFEST ON COPY_LIBS ON)

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@ -0,0 +1,49 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/ScrollBox"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical|center_horizontal"
android:orientation="vertical"
android:scrollbarStyle="insideInset" >
<TextView
android:id="@+id/textView4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/about"
android:textAppearance="?android:attr/textAppearanceLarge" />
<TextView
android:id="@+id/textViewIntro"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:autoLink="web"
android:text="@string/intro"
android:textAppearance="?android:attr/textAppearanceSmall" />
<TextView
android:id="@+id/textView5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall" />
<TextView
android:id="@+id/textView6"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall" />
<Button
android:id="@+id/CheckEngineUpdate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical|center_horizontal"
android:text="@string/checkUpdate" />
</LinearLayout>
</ScrollView>

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">OpenCV Manager</string>
<string name="about">About</string>
<string name="checkUpdate">Check for update</string>
<string name="intro">OpenCV library is used by other applications for image enhancement, panorama stitching, object detection, recognition and tracking and so on. OpenCV Manager provides the best version of the OpenCV for your hardware. See opencv.org for details.</string>
</resources>

View File

@ -0,0 +1,118 @@
package org.opencv.engine;
import java.io.File;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Scanner;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
import android.os.Build;
import android.text.TextUtils;
import android.util.Log;
public class HardwareDetector {
private static String TAG = "OpenCVEngine/HardwareDetector";
public static final int ARCH_UNKNOWN = -1;
public static final int ARCH_X86 = 0x01000000;
public static final int ARCH_X86_64 = 0x02000000;
public static final int ARCH_ARM = 0x04000000;
public static final int ARCH_ARMv7 = 0x10000000;
public static final int ARCH_ARMv8 = 0x20000000;
public static final int ARCH_MIPS = 0x40000000;
public static final int ARCH_MIPS_64 = 0x80000000;
// Return CPU flags list
public static List<String> getFlags() {
Map<String, String> raw = getRawCpuInfo();
String f = raw.get("flags");
if (f == null)
f = raw.get("Features");
if (f == null)
return Arrays.asList();
return Arrays.asList(TextUtils.split(f, " "));
}
// Return CPU arch
public static int getAbi() {
List<String> abis = Arrays.asList(Build.CPU_ABI, Build.CPU_ABI2);
Log.i(TAG, "ABIs: " + abis.toString());
if (abis.contains("x86_64")) {
return ARCH_X86_64;
} else if (abis.contains("x86")) {
return ARCH_X86;
} else if (abis.contains("arm64-v8a")) {
return ARCH_ARMv8;
} else if (abis.contains("armeabi-v7a")
|| abis.contains("armeabi-v7a-hard")) {
return ARCH_ARMv7;
} else if (abis.contains("armeabi")) {
return ARCH_ARM;
} else if (abis.contains("mips64")) {
return ARCH_MIPS_64;
} else if (abis.contains("mips")) {
return ARCH_MIPS;
}
return ARCH_UNKNOWN;
}
// Return hardware platform name
public static String getHardware() {
Map<String, String> raw = getRawCpuInfo();
return raw.get("Hardware");
}
// Return processor count
public static int getProcessorCount() {
int result = 0;
try {
Pattern pattern = Pattern.compile("(\\d)+(-(\\d+))?");
Scanner s = new Scanner(
new File("/sys/devices/system/cpu/possible"));
if (s.hasNextLine()) {
String line = s.nextLine();
Log.d(TAG, "Got CPUs: " + line);
Matcher m = pattern.matcher(line);
while (m.find()) {
int start = Integer.parseInt(m.group(1));
int finish = start;
if (m.group(3) != null) {
finish = Integer.parseInt(m.group(3));
}
result += finish - start + 1;
Log.d(TAG, "Got CPU range " + start + " ~ " + finish);
}
}
} catch (Exception e) {
Log.e(TAG, "Failed to read cpu count");
e.printStackTrace();
}
return result;
}
// Return parsed cpuinfo contents
public static Map<String, String> getRawCpuInfo() {
Map<String, String> map = new HashMap<String, String>();
try {
Scanner s = new Scanner(new File("/proc/cpuinfo"));
while (s.hasNextLine()) {
String line = s.nextLine();
String[] vals = line.split(": ");
if (vals.length > 1) {
map.put(vals[0].trim(), vals[1].trim());
} else {
Log.d(TAG, "Failed to parse cpuinfo: " + line);
}
}
} catch (Exception e) {
Log.e(TAG, "Failed to read cpuinfo");
e.printStackTrace();
}
return map;
}
}

View File

@ -0,0 +1,31 @@
package org.opencv.engine;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.util.Log;
public class MarketConnector {
protected static final String OpenCVPackageNamePreffix = "org.opencv.lib";
private static final String TAG = "OpenCVEngine/MarketConnector";
protected Context mContext;
public MarketConnector(Context context) {
mContext = context;
}
public boolean InstallAppFromMarket(String AppID) {
Log.d(TAG, "Installing app: " + AppID);
boolean result = true;
try {
Uri uri = Uri.parse("market://details?id=" + AppID);
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mContext.startActivity(intent);
} catch (Exception e) {
Log.e(TAG, "Installation failed");
result = false;
}
return result;
}
}

View File

@ -0,0 +1,33 @@
package org.opencv.engine;
/**
* Class provides Java interface to OpenCV Engine Service. Is synchronous with native OpenCVEngine class.
*/
interface OpenCVEngineInterface
{
/**
* @return Return service version
*/
int getEngineVersion();
/**
* Find installed OpenCV library
* @param OpenCV version
* @return Returns path to OpenCV native libs or empty string if OpenCV was not found
*/
String getLibPathByVersion(String version);
/**
* Try to install defined version of OpenCV from Google Play (Android Market).
* @param OpenCV version
* @return Returns true if installation was successful or OpenCV package has been already installed
*/
boolean installVersion(String version);
/**
* Return list of libraries in loading order separated by ";" symbol
* @param OpenCV version
* @return Returns OpenCV libraries names separated by symbol ";" in loading order
*/
String getLibraryList(String version);
}

View File

@ -0,0 +1,165 @@
package org.opencv.engine;
import android.app.Service;
import android.content.Intent;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.XmlResourceParser;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import android.text.TextUtils;
import java.io.File;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.xmlpull.v1.XmlPullParser;
public class OpenCVEngineService extends Service {
private static final String TAG = "OpenCVEngine/Service";
private IBinder mEngineInterface = null;
private List<LibVariant> variants = new ArrayList<LibVariant>();
private class LibVariant {
public String version;
public List<String> files;
public void parseFile(XmlResourceParser p) {
try {
int eventType = p.getEventType();
while (eventType != XmlPullParser.END_DOCUMENT) {
if (eventType == XmlPullParser.START_TAG) {
if (p.getName().equals("library")) {
parseLibraryTag(p);
} else if (p.getName().equals("file")) {
parseFileTag(p);
}
}
eventType = p.next();
}
} catch (Exception e) {
Log.e(TAG, "Failed to parse xml library descriptor");
}
}
private void parseLibraryTag(XmlResourceParser p) {
version = p.getAttributeValue(null, "version");
files = new ArrayList<String>();
}
private void parseFileTag(XmlResourceParser p) {
files.add(p.getAttributeValue(null, "name"));
}
public boolean hasAllFiles(String path) {
boolean result = true;
List<String> actualFiles = Arrays.asList((new File(path)).list());
for (String f : files)
result &= actualFiles.contains(f);
return result;
}
public boolean isCompatible(String v) {
String[] expected = v.split("\\.");
String[] actual = version.split("\\.");
int i = 0;
for (; i < Math.min(expected.length, actual.length); ++i) {
int diff = Integer.valueOf(expected[i])
- Integer.valueOf(actual[i]);
if (diff > 0 || (diff != 0 && i == 0)) {
// requested version is greater than actual OR major version differs
return false;
} else if (diff < 0) {
// version is compatible
return true;
}
}
if (expected.length > i) {
// requested version is longer than actual - 2.4.11.2 and 2.4.11
return false;
}
return true;
}
public String getFileList() {
return TextUtils.join(";", files);
}
}
public void onCreate() {
Log.d(TAG, "Service starting");
for (Field field : R.xml.class.getDeclaredFields()) { // Build error here means that all config.xml files are missing (configuration problem)
Log.d(TAG, "Found config: " + field.getName());
final LibVariant lib = new LibVariant();
try {
final int id = field.getInt(R.xml.class);
final XmlResourceParser p = getResources().getXml(id);
lib.parseFile(p);
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
if (lib.version != null
&& lib.files.size() != 0
&& lib.hasAllFiles(getApplication().getApplicationInfo().nativeLibraryDir)) {
variants.add(lib);
Log.d(TAG, "Added config: " + lib.version);
}
}
super.onCreate();
mEngineInterface = new OpenCVEngineInterface.Stub() {
@Override
public boolean installVersion(String version)
throws RemoteException {
// DO NOTHING
return false;
}
@Override
public String getLibraryList(String version) throws RemoteException {
Log.i(TAG, "getLibraryList(" + version + ")");
for (LibVariant lib : variants) {
Log.i(TAG, "checking " + lib.version + " ...");
if (lib.isCompatible(version))
return lib.getFileList();
}
return null;
}
@Override
public String getLibPathByVersion(String version)
throws RemoteException {
// TODO: support API 8
return getApplication().getApplicationInfo().nativeLibraryDir;
}
@Override
public int getEngineVersion() throws RemoteException {
int version = 3450;
try {
version = getPackageManager().getPackageInfo(getPackageName(), 0).versionCode;
} catch (NameNotFoundException e) {
e.printStackTrace();
}
return version / 1000;
}
};
}
public IBinder onBind(Intent intent) {
Log.i(TAG, "Service onBind called for intent " + intent.toString());
return mEngineInterface;
}
public boolean onUnbind(Intent intent) {
Log.i(TAG, "Service onUnbind called for intent " + intent.toString());
return true;
}
public void OnDestroy() {
Log.i(TAG, "OpenCV Engine service destruction");
}
}

View File

@ -0,0 +1,113 @@
package org.opencv.engine.manager;
import org.opencv.engine.MarketConnector;
import org.opencv.engine.HardwareDetector;
import org.opencv.engine.OpenCVEngineInterface;
import org.opencv.engine.OpenCVEngineService;
import org.opencv.engine.R;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
public class ManagerActivity extends Activity {
protected static final String TAG = "OpenCVEngine/Activity";
protected MarketConnector mMarket;
protected TextView mVersionText;
protected boolean mExtraInfo = false;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
final Class<OpenCVEngineService> c = OpenCVEngineService.class;
final String packageName = c.getPackage().getName();
mMarket = new MarketConnector(this);
Button updateButton = (Button) findViewById(R.id.CheckEngineUpdate);
updateButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
if (!mMarket.InstallAppFromMarket(packageName)) {
Toast toast = Toast.makeText(getApplicationContext(),
"Google Play is not available", Toast.LENGTH_SHORT);
toast.show();
}
}
});
TextView aboutText = (TextView) findViewById(R.id.textView4);
aboutText.setText("About (" + packageName + ")");
if (mExtraInfo) {
TextView extraText = (TextView) findViewById(R.id.textView6);
extraText.setText(
"CPU count: "
+ HardwareDetector.getProcessorCount()
+ "\nABI: 0x"
+ Integer.toHexString(HardwareDetector.getAbi())
+ "\nFlags: "
+ TextUtils.join(";", HardwareDetector.getFlags())
+ "\nHardware: "
+ HardwareDetector.getHardware());
}
mVersionText = (TextView) findViewById(R.id.textView5);
if (!bindService(new Intent(this, c),
new OpenCVEngineServiceConnection(), Context.BIND_AUTO_CREATE)) {
Log.e(TAG, "Failed to bind to service:" + c.getName());
mVersionText.setText("not available");
} else {
Log.d(TAG, "Successfully bound to service:" + c.getName());
mVersionText.setText("available");
}
}
protected class OpenCVEngineServiceConnection implements ServiceConnection {
public void onServiceDisconnected(ComponentName name) {
Log.d(TAG, "Handle: service disconnected");
}
public void onServiceConnected(ComponentName name, IBinder service) {
Log.d(TAG, "Handle: service connected");
OpenCVEngineInterface engine = OpenCVEngineInterface.Stub
.asInterface(service);
if (engine == null) {
Log.e(TAG, "Cannot connect to OpenCV Manager Service!");
unbindService(this);
return;
}
Log.d(TAG, "Successful connection");
try {
String[] vars = { "2.4", "3.0" };
String res = new String();
for (String piece : vars) {
res += "\n\t" + piece + " -> "
+ engine.getLibraryList(piece);
}
mVersionText.setText("Path: "
+ engine.getLibPathByVersion(null) + res);
} catch (RemoteException e) {
e.printStackTrace();
Log.e(TAG, "Call failed");
}
unbindService(this);
}
};
}