I am new in android developing and I am trying to integrate tess two (Tesseract Android Tools) with my kotlin app to implement text recognition on android app. I've tried several approaches but any of them work. I've encountered errors before this: related to subfolder tessdata and path doesn't exist. I've tried all approaches that i found to integrate tesseract with android but none of them work.I tried also to downgrade my sdk version to 27(one of the solution relating to permission denial) but I coudn't downgrade gradle dependencies versions and all of the dependencies demand sdk34.
My build.gradle file
plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
id 'com.chaquo.python'
}
android {
namespace 'com.example.nogpt'
compileSdk 34
defaultConfig {
applicationId "com.example.nogpt"
minSdk 26
targetSdk 34
versionCode 1
versionName "1.0"
ndk {
// On Apple silicon, you can omit x86_64.
abiFilters "arm64-v8a", "x86_64"
}
python{
version = "3.8"
}
python{
pip {
install "numpy"
install "opencv-python"
install "pytesseract"
}
}
python {
buildPython("C:/Users/User/AppData/Local/Programs/Python/Python38-32/python.exe")
}
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
sourceSets {
main {
java.srcDir("src/main/python")
}
}
buildFeatures {
viewBinding true
}
dataBinding {
enabled true
}
}
dependencies {
implementation 'com.rmtheis:tess-two:9.1.0'
implementation 'androidx.core:core-ktx:1.6.0'
implementation 'androidx.appcompat:appcompat:1.3.1'
implementation 'com.google.android.material:material:1.11.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.3.1'
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1'
implementation 'androidx.navigation:navigation-fragment-ktx:2.3.5'
implementation 'androidx.navigation:navigation-ui-ktx:2.3.5'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
}
HomeFragment.kt file:
class HomeFragment : Fragment() {
private var _binding: FragmentHomeBinding? = null
private val binding get() = _binding!!
lateinit var selectBtn: Button
lateinit var predBtn: Button
lateinit var resView: TextView
lateinit var imageView: ImageView
lateinit var textView2: TextView
lateinit var bitmap: Bitmap
private val REQUEST_CODE_STORAGE_PERMISSION = 100
@SuppressLint("SdCardPath")
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = FragmentHomeBinding.inflate(inflater, container, false)
val root: View = binding.root
val textView2 = binding.textView2
selectBtn = binding.selectbtn
predBtn = binding.predictbtn
resView = binding.textView2
imageView = binding.imageView
selectBtn.setOnClickListener(){
var intent: Intent = Intent()
intent.setAction(Intent.ACTION_GET_CONTENT)
intent.setType("image/*")
startActivityForResult(intent, 100)
}
// Inside your predBtn.setOnClickListener()
predBtn.setOnClickListener() {
val drawable = imageView.drawable
val bitmap = (drawable as BitmapDrawable).bitmap
//-----------------
try {
// val datapath = context?.getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS).toString()
//val tessBaseAPI = TessBaseAPI()
//tessBaseAPI.init(datapath, "kaz")
// Initialize Tesseract API with trained data file
//val tessBaseAPI = TessBaseAPI()
//val dataPath = "${Environment.getExternalStorageDirectory()}/tesseract/"
//val tessDataPath = "$dataPath/tessdata/"
// val language = "kaz"
// val dataPath = context?.filesDir.toString() + "/tesseract/"
// val language = "kaz"
val tessBaseAPI = TessBaseAPI()
tessBaseAPI.init("sdcard/tesseract/", "kaz");
// val dir: File = File(dataPath)
// if (!dir.exists()) dir.mkdirs()
// tessBaseAPI.init(dataPath, language)
if (isStoragePermissionGranted()) {
// Если разрешения на чтение и запись уже предоставлены, выполняем необходимые действия
// Например, инициируем процесс OCR
performOCR(tessBaseAPI, bitmap)
} else {
// Если разрешения не предоставлены, запросите их у пользователя
requestStoragePermission()
}
// Perform OCR on the bitmap
val recognizedText = performOCR(tessBaseAPI, bitmap)
// Display the recognized text
textView2.text = recognizedText
// Release resources
tessBaseAPI.end()
} catch (e: IOException) {
// Handle IOException
Log.e("HomeFragment", "Error loading trained data file: ${e.message}")
}
}
return root
}
private fun isStoragePermissionGranted(): Boolean {
val writePermission = ContextCompat.checkSelfPermission(
requireContext(),
Manifest.permission.WRITE_EXTERNAL_STORAGE
) == PackageManager.PERMISSION_GRANTED
val readPermission = ContextCompat.checkSelfPermission(
requireContext(),
Manifest.permission.READ_EXTERNAL_STORAGE
) == PackageManager.PERMISSION_GRANTED
return writePermission && readPermission
}
private fun requestStoragePermission() {
ActivityCompat.requestPermissions(
requireActivity(),
arrayOf(
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_EXTERNAL_STORAGE
),
REQUEST_CODE_STORAGE_PERMISSION
)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if(requestCode == 100 && resultCode == Activity.RESULT_OK){
val uri = data?.data
uri?.let {
try {
val bitmap = MediaStore.Images.Media.getBitmap(requireActivity().contentResolver, uri)
imageView.setImageBitmap(bitmap)
} catch (e: IOException) {
e.printStackTrace()
}
}
}
}
fun performOCR(tessBaseAPI: TessBaseAPI, bitmap: Bitmap): String {
tessBaseAPI.setImage(bitmap)
return tessBaseAPI.utF8Text
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}
build.gradle(Project)
buildscript {
ext {
agp_version = '4.2.2'
agp_version1 = '7.0.0'
agp_version2 = '8.1.0'
}
}// Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins {
id 'com.android.application' version '8.1.0' apply false
id 'org.jetbrains.kotlin.android' version '1.9.22' apply false
id 'com.chaquo.python' version '15.0.1' apply false
}
fragment_home.xml file:
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ui.home.HomeFragment">
<ImageView
android:id="@+id/imageView"
android:layout_width="match_parent"
android:layout_height="500dp"
android:src="@drawable/ex"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
<LinearLayout
android:id="@+id/linLayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/imageView"
android:layout_centerHorizontal="true"
android:orientation="vertical"
app:layout_constraintTop_toBottomOf="@id/imageView"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent">
<!-- Add your LinearLayout content here -->
</LinearLayout>
<Button
android:id="@+id/selectbtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="select"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/linLayout" />
<Button
android:id="@+id/predictbtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="188dp"
android:text="predict"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/selectbtn"
app:layout_constraintTop_toBottomOf="@id/linLayout" />
<TextView
android:id="@+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="prediction is"
android:textSize="20dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/imageView" />
</androidx.constraintlayout.widget.ConstraintLayout>
I am new in android developing and I am trying to integrate tess two (Tesseract Android Tools) with my kotlin app to implement text recognition on android app. I've tried several approaches but any of them work.