التعرف على كل خواص مكتبة ML kit من فايربيز

اصبح ربط تطبيقك مع الذكاء الاصطناعي ابسط مع Ml Kit من فايربيز

Ismail Ait Bellaمنذ 6 سنوات

قبل كل شيء اذا كنت جافاوي فكودات الجافا متوفرة على التدوينة  الاصلية  جنبا الى جنب مع كوتلن.
 

مع اطلاق مشروع 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()
    }
 }

كل نص عليه اطار احمر. 
كل سطر داخل النص عليه اطار اسود + بالاضافة انه ياخد كل محتوى السطر + \n (سطر جديد) و يضيفه الى text و من ثم الى TextView .
كل كلمة داخل السطر عليها اطار ازرق .
كما هو موضح في الصورة

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)
//.....

ختاما :

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

يمكنك ان تجدني على :

Facebook

androidbella.com

 

6
إعجاب
3445
مشاهدات
0
مشاركة
3
متابع
متميز
محتوى رهيب

التعليقات (0)

لايوجد لديك حساب في عالم البرمجة؟

تحب تنضم لعالم البرمجة؟ وتنشئ عالمك الخاص، تنشر المقالات، الدورات، تشارك المبرمجين وتساعد الآخرين، اشترك الآن بخطوات يسيرة !