Reconnaître un texte à partir d’une simple image, voilà un défi corsé ! Enfin, fut un temps. Car aujourd’hui, je vais vous montrer comment intégrer cette fonctionnalité dans toutes vos applications Android en seulement quelques lignes de code grâce à la magnifique librairie Google Vision développée par Google himself.
La librairie Google Vision regroupe trois sous-modules :
Ici, nous nous intéresserons uniquement à la reconnaissance de texte en direct à partir de la caméra d’un smartphone Android. Les deux autres modules ne sont pas très différents du premier et, une fois que vous saurez vous servir de celui-ci, il sera facile pour vous d’apprendre à les maîtriser.
Commençons par le commencement : intégrer la librairie à votre projet. Pour cela, il suffit d’ajouter la dépendance dans votre build.gradle.
dependencies {
...
implementation ’com.google.android.gms:play-services-vision:11.0.4’
...
}
Deuxièmement étape : dans votre Manifest, demander la permission d’utiliser la caméra du téléphone (pour scanner l’image à lire) et une meta-data.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.tuts.prakash.simpleocr">
...
<uses-permission android:name="android.permission.CAMERA"/>
...
<application>
...
<meta-data android:name="com.google.android.gms.vision.DEPENDENCIES" android:value="ocr"/>
...
</application>
</manifest>
Maintenant que l’APIUne API est un programme permettant à deux applications distinctes de communiquer entre elles et d’échanger des données. est bien installée, on va pouvoir commencer à l’utiliser !
Dans un premier temps, nous allons créer un simple Layout avec deux view :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<SurfaceView
android:id="@+id/surfaceView"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="4" />
<TextView
android:id="@+id/textView"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:gravity="center"
android:textSize="16sp" />
</LinearLayout>
Il va nous falloir 3 objets :
class MainActivity : AppCompatActivity() {
private lateinit var cameraHolder: SurfaceHolder
private lateinit var cameraSource: CameraSource
private lateinit var textRecognizer: TextRecognizer
...
}
Ensuite, dans la méthode .onCreate()
on va initialiser la CameraSource et le TextRecognizer.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
textRecognizer = TextRecognizer.Builder(this).build()
cameraSource = CameraSource.Builder(this, textRecognizer)
.setFacing(CameraSource.CAMERA_FACING_BACK)
.setAutoFocusEnabled(true)
.setRequestedFps(3.0f)
.build()
...
}
Pour la CameraSource, plusieurs options sont ajoutées par confort :
.setFacing(CameraSource.CAMERA_FACING_BACK)
indique que nous utilisons la caméra à l’arrière du téléphone..setAutoFocusEnabled(true)
pour que le Focus soit automatique..setRequestedFps(3.0f)
pour filmer à 3 images par seconde. Pour de la reconnaissance de texte, inutile d’aller au-delà de 3 FPS, cela pourrait même provoquer des erreurs de lecture.Rien de spécial pour le TextRecognizer.
Pour initialiser la SurfaceHolder, c’est un peu plus tricky ! Il faut ajouter le code suivant dans le .onCreate()
.
surfaceView.holder.addCallback(object : SurfaceHolder.Callback {
override fun surfaceCreated(holder: SurfaceHolder) {
cameraHolder = surfaceView.holder
if (ActivityCompat.checkSelfPermission(this@MainActivity, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
finish()
}
cameraSource.start(cameraHolder)
}
override fun surfaceChanged(holder: SurfaceHolder, format: Int, width: Int, height: Int) { }
override fun surfaceDestroyed(holder: SurfaceHolder) { cameraSource.stop() }
})
L’objet SurfaceHolder ne peut être récupéré qu’après la création de la SurfaceView, d’où la nécessité de faire appel à un Callback. De plus, vous remarquez qu’on vérifie que l’application a bien la permission d’utiliser la Camera. Nous ne verrons pas ici comment accorder cette permission, il est d’ailleurs plus judicieux de demander les permissions au lancement de l’application. Dans la cas où la permission ne serait pas accordée, nous fermons l’activité, mais vous pouvez modifier ce comportement.
Enfin, on lance la caméra et l’affichage de son contenu dans la View créée avec cameraSource.start(cameraHolder)
.
Allez, on y est presque !
La dernière chose à faire est donc de dire à notre TextRecognizer que faire lorsqu’il déchiffre quelque chose. Pour cela, ajoutez le code suivant :
textRecognizer.setProcessor(object : Detector.Processor<TextBlock> {
override fun release() {}
override fun receiveDetections(detections: Detector.Detections<TextBlock>) {
val items: SparseArray<TextBlock> = detections.detectedItems
textView.text = (0 until items.size()).joinToString("\n") { items.get(it).value }
}
})
On peut voir que l’on ajoute un Processor à notre TextRecognizer et que sa méthode .receiveDetections()
contient notre logique.
Chose à savoir : un objet TextBlock est une entité que Vision a détectée comme un paragraphe. En plus du texte reconnu, il contient notamment la langue de ce texte, si Vision a réussit à l’identifier.
Ici, on va simplement rassembler tous les paragraphes et les afficher dans le TextView prévu à cet effet.
Oui ! Comme beaucoup d’outils développés par Google, Vision est très simple d’utilisation et extrêmement performant !
En seulement quelques lignes de code, vous pouvez l’intégrer à votre projet afin de rapidement vous concentrer sur la logique après avoir déchiffré un texte.
A vous de jouer !
Dans un contexte où les architectures microservice, le cloud et les systèmes distribués sont devenus la norme, les API (Application Programming Interfaces) jouent un rôle central dans la communication entre les applications et les services. Elles facilitent les échanges de données, l'intégration de fonctionnalités et la scalabilité des infrastructures. Cependant, cette exposition accrue des API ouvre la voie à des vulnérabilités de sécurité majeures, qui peuvent être exploitées pour compromettre des systèmes critiques, voler des données ou perturber des services.
Tuto - JSF 2 – Redirect HTTP 404 de manière programmatique
Découvrez la planche #46 !