Android app 接入PaddleOCR"/>
Android app 接入PaddleOCR
Android app 接入PaddleOCR
一、 解压文件
资源下载:
解压文件夹,文件目录如下
- assets:模型资源
- cpp:c++源码
- ocr:使用模型需要用到的类
- OpenCV | PaddleLite :编译和使用模型需要的库
二、 库、模型、cpp文件的设置
1. 将你的项目目录切换至Project视图(以下所有操作都要在project视图下完成)
2. 将OCR下的 “OpenCV” 和 “PaddleLite” 复制至Application-app下,这是编译和使用模型需要用到的库
3. 在app-src-main目录下创建一个assets文件夹,具体方式如下
4. 将OCR下assets中的全部内容复制到app-main-scr-assets下,此时目录结构如图
5. 将OCR下的cpp文件夹复制到app-src-main下,其中存放的是C++功能代码
6. 右键cpp文件夹,选择 “Mark Directory as” - “Sources Root”
三、 代码设置
1. 将OCR下的ocr文件夹复制到项目目录app-src-main-java-com.**(你的包名)下,如图
并将ocr文件下代码路径(包名)修改为自己项目的路径(后面的 “.ocr” 不要去掉)
2. 在app-src-main-res中创建文件夹xml,并新建一个xml文件 “file_paths.xml”
并在 “file_paths.xml” 中添加如下代码,照片权限相关
<?xml version="1.0" encoding="utf-8"?>
<paths><external-files-path name="my_images" path="Pictures" />
</paths>
3. 在 “AndroidManifest.xml” 中<manifest></manifest>
之间添加如下带代码
<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></application>
之间添加如下带代码,注意修改包名
<!--注意android:authorities中"com.example.myapplication"要改成自己的包名--><providerandroid:name="androidx.core.content.FileProvider"android:authorities="com.example.myapplication.fileprovider"android:exported="false"android:grantUriPermissions="true"><meta-dataandroid:name="android.support.FILE_PROVIDER_PATHS"android:resource="@xml/file_paths" /></provider>
4. 打开Build.gradle(:app),在android{}中添加如下代码
externalNativeBuild {cmake {path "src/main/cpp/CMakeLists.txtversion "3.10.2"}
}
并在defaultConfig {}中添加如下代码
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"}
5. 打开app-src-main-cpp-native.cpp,找到14、59、105行的java入口,修改包名为自己的包名
至此将PaddleOCR植入自己项目的准备工作完成
四、在自己的Activity中使用PaddleOCR功能
注意activity要与ocr文件在同一包下面
1. Activity{}中添加如下代码
// 1.放在自己的onCreate()前private static final String TAG = "MainActivity";private static final int TAKE_PHOTO_REQUEST_CODE = 1;protected ImageView ivInputImage;protected TextView tvOutputResult;protected String imagePath = "";private String currentPhotoPath;protected Predictor predictor = new Predictor();// 2.重写onResume方法@Overrideprotected void onResume() {super.onResume();boolean settingsChanged = false;//这里要改成自己的初始图片路径String image_path = "images/1.jpg";settingsChanged |= !image_path.equalsIgnoreCase(imagePath);if(settingsChanged){imagePath = image_path;loadModel();}}// 3.重写onActivityResult()方法@Overrideprotected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {super.onActivityResult(requestCode, resultCode, data);if (resultCode == RESULT_OK) {if (currentPhotoPath != null) {ExifInterface exif = null;try {exif = new ExifInterface(currentPhotoPath);} catch (IOException e) {e.printStackTrace();}int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION,ExifInterface.ORIENTATION_UNDEFINED);Log.i(TAG, "rotation " + orientation);Bitmap image = BitmapFactory.decodeFile(currentPhotoPath);image = Utils.rotateBitmap(image, orientation);onImageChanged(image);} else {Log.e(TAG, "currentPhotoPath is null");}}}// 4.重写onRequestPermissionsResult()方法@Overridepublic void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,@NonNull int[] grantResults) {super.onRequestPermissionsResult(requestCode, permissions, grantResults);if (grantResults[0] != PackageManager.PERMISSION_GRANTED || grantResults[1] != PackageManager.PERMISSION_GRANTED) {Toast.makeText(this, "Permission Denied", Toast.LENGTH_SHORT).show();}}// 5.重写onDestroy()方法@Overrideprotected void onDestroy() {if (predictor != null) {predictor.releaseModel();}super.onDestroy();}// 5.拍照方法(在xml文件里用对应拍照按钮的onclick绑定)// !!其中“MainActivity”改成自己的Activity名,“com.example.myapplication”改成自己的包名public void takePhoto(View v) {if(requestAllPermissions()){Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);if (takePictureIntent.resolveActivity(getPackageManager()) != null) {File photoFile = null;try {photoFile = createImageFile();} catch (IOException ex) {Toast.makeText(MainActivity.this,"Create Camera temp file failed: " + ex.getMessage(), Toast.LENGTH_SHORT).show();}if (photoFile != null) {Uri photoURI = FileProvider.getUriForFile(this,"com.example.myapplication.fileprovider",photoFile);currentPhotoPath = photoFile.getAbsolutePath();takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);startActivityForResult(takePictureIntent, TAKE_PHOTO_REQUEST_CODE);}}}}// 6.判断是否调用权限private boolean requestAllPermissions() {if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)!= PackageManager.PERMISSION_GRANTED || ContextCompat.checkSelfPermission(this,Manifest.permission.CAMERA)!= PackageManager.PERMISSION_GRANTED) {ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE,Manifest.permission.CAMERA},0);return false;}return true;}// 7.模型相关public void loadModel() {if (onLoadModel()) {onLoadModelSuccessed();}return;}public boolean onLoadModel() {// 初始化predictor// 这里“MainActivity”改成自己的Activityreturn predictor.init(MainActivity.this);}public void onLoadModelSuccessed() {try {if (imagePath.isEmpty()) {return;}Bitmap image = null;if (!imagePath.substring(0, 1).equals("/")) {InputStream imageStream = getAssets().open(imagePath);image = BitmapFactory.decodeStream(imageStream);} else {if (!new File(imagePath).exists()) {return;}image = BitmapFactory.decodeFile(imagePath);}if (image != null && predictor.isLoaded()) {// 输入识别图片predictor.setInputImage(image);runModel();}} catch (IOException e) {// !!"MainActivity"改成自己的ActivityToast.makeText(MainActivity.this, "Load image failed!", Toast.LENGTH_SHORT).show();e.printStackTrace();}}public void runModel() {if (onRunModel()) {onRunModelSuccessed();}}public boolean onRunModel() {return predictor.isLoaded() && predictor.runModel();}// 这里拿到识别结果!!public void onRunModelSuccessed() {//!!这里拿到识别结果outputImage 类型为Bitmap Bitmap outputImage = predictor.outputImage();if (outputImage != null) {ivInputImage.setImageBitmap(outputImage);}//!!这里拿到predictor.outputResult()是识别结果 类型为String //格式为 1:识别结果1/n// 2:识别结果2/n// 3:识别结果3/ntvOutputResult.setText(predictor.outputResult());tvOutputResult.scrollTo(0, 0);}// 8.图片相关public void onImageChanged (Bitmap image){if (image != null && predictor.isLoaded()) {predictor.setInputImage(image);runModel();}}private File createImageFile() throws IOException {String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());String imageFileName = "JPEG_" + timeStamp + "_";File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);File image = File.createTempFile(imageFileName, ".bmp", storageDir );return image;}
2. 修改页面xml文件
给Activity对应xml文件的拍照按钮添加点击事件,绑定Activity中的takePhoto()方法:
android:onClick="takePhoto"
五、其他配置
1. Settings - Appearance&Behavior - Android SDK - SDK Tools 中 这几项要是已下载的状态
2. Project Structure - SDK Location , 配置自己的sdk、ndk、jdk位置
具体实现可参照项目源代码
下载地址:
更多推荐
Android app 接入PaddleOCR
发布评论