ربط تطبيق اندرويد بتقنيات الذكاء الاصطناعي ML Kit

كودات الجافا هي كودات قمت بنعديلها يدويا و دون ide لدى من الممكن ان تحتوي على بعض الاخطاء .مع اطلاق مشروع tensor Flow lite اصبح ربط تطبيقك مع الذكاء الاصطناعي ابسط لكن ليس بالسهولة التي تظنها لهذا ثم اطلاق مكتبة ML kit من جوجل مدموجة في الفاير بيز حيث يمكنك بسهولة جعل تطبيق يتمتع بخصائص الذكاء الاصطناعي بسهولة . فانا لم افكر يوما في ربطها لانني لم ادخل باب الذكاء الاصطناعي بعد ، و لعل ما جعلني اكتب هذه التدوينة هو ان التدوينات السابقة مملة و فيها الكثير من التكرار و هذه التدوينة يمكننا تسميتها One For All .تدوينة واحدة لكل خواص ML Kit .
هذه المقالة محدثة باستمرار ويمكنك متابعتي على فايسبوك للتوصل بكل جديد

1-انشاء مشروع فايربيز :

للاسف لتستفيد من خواص ML Kit فلابد من انشاء مشروع فايربيز  اذا لم تكن تعرف كيفية الربط فهذه تذوينة سابقة عن كيفية الربط .


2-اعداد المشروع ل Ml Kit:

حسنا الان بعد ربط التطبيق سنتتقل الى كيفية ربط ML Kit مع المشروع :

dependencies {
  // ...

  implementation 'com.google.firebase:firebase-ml-vision:17.0.0'
  implementation 'com.google.firebase:firebase-ml-vision-image-label-model:15.0.0'
}

بعد ذلك يمكنك اضافة خيار اخر الى ملف manifest.xml لكن يفضل اضافته و مهمته الحرص على تحميل الملفات اثناء التنصيب و ليس اثناء تشغيل التطبيق تفاديا لاي اخطاء قد تقع عند تشغيل التطبيق .

اضف الكود التالي الى ملف manifest.xml :
<application ...>
  ...
  <meta-data
      android:name="com.google.firebase.ml.vision.DEPENDENCIES"
      android:value="label,face,text,barcode" />
  <!-- قم باضافة او حذف الموديلات : android:value="label,face,text,barcode" -->
</application>
label :التعرف على الصور => نحلة ، زهور ...
face: التعرف على الوجوه  .
text: التعرف على الصور .
barcode :التعرف على الباركود .

3- الواجهة UI :

الواجهة ستكون بسيطة و الاهم من ذلك انها ستحتوي على 5 ازرار 4 ازرار للخواص الاربع و زر لجلب الصورة من عند المستخدم (ذاكرة الهاتف) و ايضا imageView لاضهار الصورة .
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.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">

    <Button
        android:id="@+id/choose"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginEnd="8dp"
        android:layout_marginLeft="8dp"
        android:layout_marginRight="8dp"
        android:layout_marginStart="8dp"
        android:layout_marginTop="8dp"
        android:text="choose"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/imageView" />

    <Button
        android:id="@+id/text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="8dp"
        android:text="TEXT"
        app:layout_constraintBottom_toBottomOf="parent" />

    <Button
        android:id="@+id/face"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="8dp"
        android:layout_marginLeft="8dp"
        android:layout_marginStart="8dp"
        android:text="FACE"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toEndOf="@+id/text" />

    <Button
        android:id="@+id/label"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="8dp"
        android:layout_marginLeft="8dp"
        android:layout_marginStart="8dp"
        android:text="LABEL"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toEndOf="@+id/face" />

    <Button
        android:id="@+id/barcode"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="8dp"
        android:layout_marginLeft="8dp"
        android:layout_marginStart="8dp"
        android:text="BARCODE"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toEndOf="@+id/label" />

    <ImageView
        android:id="@+id/imageView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:srcCompat="@drawable/bg" />

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="8dp"
        android:text="TextView"
        app:layout_constraintTop_toBottomOf="@+id/choose" />
</android.support.constraint.ConstraintLayout>

3.5 : دوال مساعدة :

الدالة الاولى هي لتحديد اللون الرسمة لاننا سنرسم على الصور اطارات :
//ماخود من موقع عالم برو بتصرف
private fun getPaint(color: Int, width: Float = 1f): Paint {
 val p = Paint()
 p.style = Paint.Style.STROKE
 p.strokeWidth = width
 p.isAntiAlias = true
 p.isFilterBitmap = true
 p.isDither = true
 p.color = color
 return p
}
الدالة الثانية لتحويل Drawable الى Bitmap :
private fun getBitmapFromImageView(mDrawable:Drawable): Bitmap {
 var drawable=mDrawable
 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
  drawable = DrawableCompat.wrap(drawable).mutate()
 }

 val bitmap = Bitmap.createBitmap(drawable.intrinsicWidth,
   drawable.intrinsicHeight, Bitmap.Config.ARGB_8888)
 val canvas = Canvas(bitmap)
 drawable.setBounds(0, 0, canvas.width, canvas.height)
 drawable.draw(canvas)

 return bitmap
}


4-رفع الصور :

حسنا لاخد صورة من ذاكرة الهاتف الى تطبيقك على شكل bitmap فالامر لا يحتاج الى اي اذونات كل ما في الامر هو اضافة الكود التالي :
اولا نرسل Intent لاخد content من الهاتف ثم نحدد نوع content الذي نريده و نحن بالطبع نريد الصور image/* .
class Mlearing : AppCompatActivity() {

  override fun onCreate(savedInstanceState: Bundle?) {
   super.onCreate(savedInstanceState)
   setContentView(R.layout.image_labeling)

   //اخد الصورة من الهاتف
   choose.setOnClickListener {
    val photoPickerIntent = Intent(Intent.ACTION_GET_CONTENT)
    photoPickerIntent.type = "image/*"
    startActivityForResult(photoPickerIntent, 1)
   }

  }
 }
لالتقاط الصورة يجب ان  ناخدها من خلال onActivityResult  :
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent) {
 super.onActivityResult(requestCode, resultCode, data)
 if (resultCode == Activity.RESULT_OK) {
  val chosenImageUri = data.data

  try {
   val mBitmap = MediaStore.Images.Media.getBitmap(this.contentResolver, chosenImageUri)
            imageView.setImageBitmap(mBitmap)
  } catch (e: IOException) {
   e.printStackTrace()
  }

 }
}

5-التعرف على الصور :

حسنا هذه الخاصية تمكنك من التعرف على الاشياء الموجودة في الصور يستطيع هاتفك المحمول التعرف على ازيد من 400 شيء كالاشخاص حيوان نبات الملامح الاماكن و غيرها و يمكنك ايجاد تفاصيل اكثر من الموقع الرسمي .و كل اقتراح ياتي مع نسبة تعطيك مدى تاكد Model من صحة هذا الاقتراح .
ارني الكود :
حسنا سنضيف دالة الانصات على الضغطة على button label .
label.setOnClickListener {
 val mBitmap=getBitmapFromImageView()
 recognizeLabels(mBitmap)
}
و الان لنحدد معالم دالة recognizeLabel :

private fun recognizeLabels(bitmap: Bitmap) {
  
 val image: FirebaseVisionImage =new FirebaseVisionImage.fromBitmap(bitmap)
 val detector: FirebaseVisionLabelDetector =new FirebaseVision.getInstance().visionLabelDetector
 detector.detectInImage(image)
  .addOnSuccessListener {
   // انتهى بنجاح
   //انشاء نص
   var text=""
    
   for (firebaseVision: FirebaseVisionLabel in it) {
    //اضافة خط للتفويق بين الاسطر
    text+="^--^--^--^--^--^--^--^--^--^--^--^--^--^--^\n"
    //اسم الشيء
    text+="label : "+firebaseVision.label+"\n"
    //نسبة تاكد المودل
    text+="confidence : "+firebaseVision.confidence+"\n"
   }
   //اضافة النص الى العنصر
   textView.text=text
  }
  .addOnFailureListener {
   // خطا ما وقع
   Toast.makeText(baseContext, "Sorry, something went wrong!", Toast.LENGTH_SHORT).show()
  }
}
كما نرى فهو متاكد بنسبة 84٪ من انه حدث رياضي  و بنسبة 73٪ من انه ملعب | و بنسبة 68٪ يوجد فريق | و بنسبة 66% يوجد قميص و 64٪ توجد ان هذه الرياضية هي كرة القدم و اخيرا اقل نسبة 54٪ يوجد حذاء . و هذه نتيجة رائعة على كل حال .

6- التعرف على الوجوه :

هذه التقنية تمكنك من التعرف على الوجه و ايضا ملامحه العينين و الفم و الجبهة و غيرها اما لاضافة تاتيرات او حتى اضافته لقاعدة بياناتك (بصمة الوجه) ،يمكنك تحديد ما اذا كان الشخص سعيدا او خزينا .
الكود التالي يقوم باخد الصورة و يرسم على الوجه لوجو المدونة الجميل فما يقوم به هذا المودل هو تحديد مكان تواجد الوجه من خلال احدثيات boundsBox .
private fun recognizeFace(bitmap: Bitmap) {
  //تحويل بيتماب الى بيتماب قابل للتعديل
  val mBitmap = bitmap.copy(Bitmap.Config.ARGB_8888, true)
  val canvas = Canvas(mBitmap)
  //الحصول على الكود
  val image: FirebaseVisionImage = FirebaseVisionImage.fromBitmap(bitmap)
  val detector = FirebaseVision.getInstance().visionFaceDetector
  detector.detectInImage(image)
    .addOnSuccessListener {
     // انتهى بنجاح
     val drawable = ContextCompat.getDrawable(this, R.drawable.ic_logo)
     for (face in it) {
      val bounds = face.boundingBox
      val btm = getBitmapFromImageView(drawable!!)
      canvas.drawBitmap(btm, bounds.exactCenterX() - btm.height / 2, bounds.exactCenterY() - btm.width / 2, null)
      Log.e("beee", bounds.toShortString())
     }
     imageView.setImageBitmap(mBitmap)
    }
    .addOnFailureListener {
     // خطا ما وقع
     Toast.makeText(baseContext, "Sorry, something went wrong!", Toast.LENGTH_SHORT).show()
    }
 }
لنرى النتيجة اذن :
اضافات :
smilingProbability :نسبة الابتسامة .
leftEyeOpenProbability :نسبة احتمالية فتح العين اليسرى .
rightEyeOpenProbability :نسبة احتمالية فتح العين اليمنى .
landmark :تحديد الملامح من عينين انف الاذنين الفم الخدود .
val leftEar = face.getLandmark(FirebaseVisionFaceLandmark.LEFT_EAR)
val leftEarPos = leftEar?.position
//leftEarPos.x | leftEarPos.y | leftEarPos.z

7-التعرف على النصوص :

حسنا الان مع اكثر الموديلات استعمالا التعرف على النصوص للاسف بالنسبة للمعالجة على الهاتف لا تدعم سوى الحروف الاتنية و بالنسبة للكلاود فهو يدعم عدد اكبر من الحروف و بما اننا نهتم فقط للمعالجة على الهواتف فان الحروف اللاتنية هي المنشودة .
الطريقة التي يقوم عليها المودل ->
يجلب النص كاملا و داخل كل نص يجلب كل سطر من داخل Loop و من داخل كل سطر يجلب كل كلمة .

private fun recognizeText(bitmap: Bitmap) {
  //تحويل بيتماب الى بيتماب قابل للتعديل
  val mBitmap = bitmap.copy(Bitmap.Config.ARGB_8888, true)
  val canvas = Canvas(mBitmap)
  //الحصول على الكود
  val image: FirebaseVisionImage = FirebaseVisionImage.fromBitmap(bitmap)
  val detector = FirebaseVision.getInstance().onDeviceTextRecognizer
  detector.processImage(image)
    .addOnSuccessListener {
     // انتهى بنجاح
     val redPaint = getPaint(Color.RED, 20f)
     val blackPaint = getPaint(Color.BLACK, 5f)
     val bluePaint = getPaint(Color.CYAN, 7f)
     var text = ""
     //تجلب البلوكس
     for (block in it.textBlocks) {
      //احدثيات النص
      val boundingBox = block.boundingBox
                        //Padding
      boundingBox?.top=boundingBox?.top?.minus(20)
      boundingBox?.bottom=boundingBox?.bottom?.plus(20)
                        //رسم مستطيل احمر حول النص
      canvas.drawRect(boundingBox,redPaint)
      //تجلب الاسطر داخل كل بلوك
      for (line in block.lines) {
                            //اخد كل سطر و الانتقال للسطر التالي
       text += line.text+"\n"
                            //Padding
       line.boundingBox?.top=line.boundingBox?.top?.minus(25)
       line.boundingBox?.bottom=line.boundingBox?.bottom?.plus(15)
       line.boundingBox?.right=line.boundingBox?.right?.plus(10)
                            //رسم مستطيل اسود حول كل سطر
       canvas.drawRect(line.boundingBox, blackPaint)
       //تجلب العناصر او الكلمات داخل كل سطر
       for (element in line.elements) {
                                //رسم مستطيل ازرق حول كل كلمة
        canvas.drawRect(element.boundingBox, bluePaint)
       }
      }
     }
                    //اضافة النص للعنصر
     textView.text = text
                    //وضع الصورة على العنصر
     imageView.setImageBitmap(mBitmap)
    }
    .addOnFailureListener {
     // خطا ما وقع
     Toast.makeText(baseContext, "Sorry, something went wrong!", Toast.LENGTH_SHORT).show()
    }
 }
كل نص عليه اطار احمر. هكذا .نص 1
كل سطر داخل النص عليه اطار اسود + بالاضافة انه ياخد كل محتوى السطر + \n (سطر جديد) و يضيفه الى text و من ثم الى TextView .مثال 2
كل كلمة داخل السطر عليها اطار ازرق .مثال 3
كما هو موضح في الصورة



8-التعرف على الباركود :

و الان مع اخر خاصية سيتمكن معها تطبيقك من قراءة مختلف انواع الباركودات و يعتبر الباركود هو الوسيلة الافضل لنقل معلومة من العالم المادي الى العالم الافتراضي لانه سهل القراءة للالة كالعادة اكثرنا من الكلام .
هذا هو الباركود الخاص بي :
لانشاء باركود خاص بك : https://www.qr-code-generator.com
private fun scanBarCode(bitmap: Bitmap) {
  //تحويل بيتماب الى بيتماب قابل للتعديل
  val mBitmap = bitmap.copy(Bitmap.Config.ARGB_8888, true)
  val canvas = Canvas(mBitmap)
  //الحصول على الكود
  val image: FirebaseVisionImage = FirebaseVisionImage.fromBitmap(bitmap)
  val detector = FirebaseVision.getInstance().visionBarcodeDetector
  detector.detectInImage(image)
    .addOnSuccessListener {
     // انتهى بنجاح
     for (barcode in it) {
      //الاحدثيات الباركود في الصورة
      val bounds = barcode.boundingBox
      //مستطيل
      val redPaint = getPaint(Color.RED, 20f)
      //رسم المستطيل
      canvas.drawRect(bounds, redPaint)
      //اخد القيمة
      val rawValue = barcode.rawValue
      //وضع القيمة في TextView
      textView.text=rawValue
     }
     //وضع الصورة الجديدة في ImageView
     imageView.setImageBitmap(mBitmap)
    }.addOnFailureListener {
     // خطا ما وقع
     Toast.makeText(baseContext, "Sorry, something went wrong!", Toast.LENGTH_SHORT).show()
    }
 }
يقوم التطبيق بمعالجة الباركود حسنا الباركود الخاص بي عبارة عن URL تقوم الدالة باخد URL و وضعه في TextView الخاصة بنا ،
اضافات :
نسبيا معالجة الباركود يكون بطيئا في الوضع العادي اذا كنت ترغب في معالجة نوع محدد من البيانات فيمكنك ذلك من خلال .
val options = FirebaseVisionBarcodeDetectorOptions.Builder()
        .setBarcodeFormats(
                FirebaseVisionBarcode.FORMAT_QR_CODE,
                FirebaseVisionBarcode.FORMAT_AZTEC)
        .build()
  val image: FirebaseVisionImage = FirebaseVisionImage.fromBitmap(bitmap)
  val detector = FirebaseVision.getInstance().getVisionBarcodeDetector(options)
//.....

ختاما :

اتمنى ان يكون هذا الدرس اعجبك و لا تنسى هناك العديد من التدوينات المشابهة على موقعنا و ايضا لا تنسى متابعتي على فايسبوك لتتوصل باخر الاخبار و التقنيات لتجعل نفسك مواكبا للتقنيات الحديثة في مجال الاندرويد
هل ترغب في مثل هذه التدوينات

اسماعيل ايت بلا

ببساطة ارغب في تجربة جديدة من التعلم من خلال مشاركة ما تعلمه يجبرني ذلك على البحث لمدة طويلة مما يجعل الموقع جديرا بالثقة

اترك لنا تعليقا

الاشتراك بالقائمة البريدية

توصل باحدث مواضيعنا و كن على اطلاع باخر اخبار وتقنيات الاندرويد