Elementor #7154

Implementing a machine learning model in a Jupyter Notebook is relatively simple. But there is no use of a Machine Learning model trained in your Jupyter Notebook. We must bring them to the real world so everyone can use them.

This documentation will teach us how to turn any machine learning(ML) issue statement into an Android app.

Summary of Contents:

1.      Android ML Project Workflow

2.      Android ML Implementation Requirements

3.      Clarify the Problem Statement

4.      Create an ML model

5.      Create a Flask API

6.      Testing using a simple HTML page

 

7.      Build an android app

1.      Android Deep learning Project Workflow:

First, we have an ML learning model, and we pickle it. For android apps, java is popular and working with android studio, java is mainly preferred. In the backend, we will have a Flask API where we will deploy our ML model whose output will be in JSON format and through the android app, we will hit at Flask API whose response is in JSON, and we will parse this JSON and print it in android frontend.

 

 

2.      Android ML Implementation Requirements:

 

First, you should know Machine learning, the Flask (Python framework) basics, and Android development. So, I’m assuming you are familiar with these things.

3.      Clarify the Problem Statement:

 

This project aims to identify whether the input image is a dog or a cat image. Now there is a requirement for the dataset. You can download it from the internet or get it here.

4.      Create an ML model:

Step 1: Getting the Dataset

Step 2: Installing Required Packages [Python 3.6] 

·         OpenCV — ‘3.4.0’ [ Used to handle image operations like reading the Image, resizing, reshaping]

·         Numpy — ‘1.14.4’ [ Image that is read will be stored in a Numpy array] 

·         TensorFlow —NumPy8.0′ [ Tensorflow is the backend for Keras] 

 

·         Keras —> ‘2.1.6’ [ Keras is used to implement the CNN] 

  Step 3: Copy past the below code and run it in your Jupyter notebook  

 #Step 1:  Import the necessary package

from

keras.models
import Sequential

from
keras.layers
import Conv2D

from
keras.layers
import MaxPooling2D

from
keras.layers
import Flatten

from
keras.layers
import Dense

# Step 2: Initialising the
convolutional neural network

model
=
Sequential()

# Step 3: Convolution

model.add(Conv2D(32,
(
3, 3),
input_shape = (50,
50, 3),
activation = ‘relu’))

# Step 4: Pooling

model.add(MaxPooling2D(pool_size
= (
2, 2)))

# Step 5: Second convolutional layer

model.add(Conv2D(32,
(
3, 3),
activation = ‘relu’))

model.add(MaxPooling2D(pool_size
= (
2, 2)))

# Step 6: Flattening

model.add(Flatten())

# Step 7: Full connection

model.add(Dense(units
=
128, activation
=
‘relu’))

model.add(Dense(units
=
1, activation
=
‘sigmoid’))

# Step 8: Compiling the CNN

model.compile(optimizer
=
‘adam’, loss
=
‘binary_crossentropy’,
metrics = [‘accuracy’])

# Step 9: ImageDataGenerator

from
keras.preprocessing.image
import ImageDataGenerator

train_datagen
=
ImageDataGenerator(rescale
=
1./255,

         
                     
   
shear_range
=
0.2,

         
                     
   
zoom_range
=
0.2,

         
                     
   
horizontal_flip
=
True)

# Step 10: Load the training Set

training_set
=
train_datagen.flow_from_directory(‘./Dataset/training_set’,

         
                     
                 
target_size
= (
50, 50),

         
                     
                 
batch_size
=
32,

         
                     
                 
class_mode
=
‘binary’)

# Step 11: Classifier Training

model.fit_generator(training_set,

         
               
steps_per_epoch
=
4000,

         
               
epochs
=
25,

         
               
validation_steps
=
2000)

# Step 12: Convert the Model to json

model_json
=
model.to_json()

with
open(“./model.json”,“w”)
as json_file:

  json_file.write(model_json)

# Step 13: Save the weights  

model.save_weights(“./model.h5”)

 

print(“Your
model has beens trained Successfully!”
)

 

1.       Create a Flask API:

Step 1:  It is recommended that Flask should be installed on
Python 2.7.

Step2: The following command installs virtualenv

pip install virtualenv

 

Step 3: Once installed, the new
virtual environment is created in a folder.

 

mkdir newproj
cd newproj
virtualenv venv
 

Step4: To activate the corresponding environment, use the following –

 

venv\scripts\activate
 

Step 5: We are now ready to
install Flask in this environment.

 

 pip install Flask

 

Step:6 Copy and paste the below code into your flask environment and run it 

from flask import Flask, render_template, request

import cv2

from PIL import Image

from flask import request,jsonify

from keras.models import load_model

from keras.preprocessing import image

import tensorflow as tf

import numpy as np

from keras.models import model_from_json

 

app = Flask(__name__)

physical_devices = tf.config.list_physical_devices(‘GPU’)

tf.config.experimental.set_memory_growth(physical_devices[0], enable=True)

 

# Step 2: Load the Model from Json File

json_file = open(‘C:/Users/LENOVO/Desktop/Miety/model.json’, ‘r’)

loaded_model_json = json_file.read()

json_file.close()

loaded_model = model_from_json(loaded_model_json)

 

# Step 3: Load the weights

loaded_model.load_weights(“C:/Users/LENOVO/Desktop/Miety/model.h5”)

print(“Loaded model from disk”)

 

# Step 4: Compile the model

loaded_model.compile(optimizer = ‘adam’, loss = ‘binary_crossentropy’, metrics = [‘accuracy’])

 

@app.route(‘/upload’)

def upload_file():

   return render_template(‘upload.html’)

   

@app.route(‘/uploader’, methods = [‘POST’])

def upload_file2():

      image = request.files[‘file’]

      image= np.array(Image.open(image))

      # Step 5: load the Image you want to test

      image = cv2.resize(image, (50,50))

      image = image.reshape(1, 50, 50, 3)

   

      # Step 6: Predict to which class your input image has been classified

      result = loaded_model.predict(image)

      if(result[0][0] == 1):

        print(“I guess this must be a Dog!”)

        response=“I guess this must be a Dog!”

      else:

        print(“I guess this must be a Cat!”)

        response=“I guess this must be a Cat!”

     

      return jsonify({“Response”:str(response)})

       

if __name__ == ‘__main__’:

 

   app.run(host=‘0.0.0.0’, port=5000, debug=True)

1.       Testing using a simple HTML page:

Indeed, you will get a URL like http://192.168.0.161:5000/upload this after running your flask app

 

If you copy this URL and run it in your browser, you can test it by uploading a dog or cat photo, as we have attached an HTML page in the flask app.

1.       Build an android app:

Step 1: Add the following dependency in your app build.gradle.

implementation ‘com.android.volley:volley:1.2.1’

Step 2: Add the following permissions to your manifest file.

 

       Step 3: Copy and paste the below code:

Activity_main

<?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:orientation=”vertical”
   
android:background=”@color/white”
   
android:layout_height=”match_parent”
   
tools:context=”.MainActivity”>
<ProgressBar
   
android:id=”@+id/progressBar”
   
style=”?android:attr/progressBarStyleHorizontal”
   
android:layout_width=”fill_parent”
   
android:layout_height=”wrap_content”
   
android:indeterminate=”true”
   
android:max=”50″
   
android:visibility=”invisible”
   
android:backgroundTint=”@color/white”
   
android:indeterminateTint=”#1a09d6″
   
android:layout_marginTop=”20dp”></ProgressBar>
    <LinearLayout
       
android:id=”@+id/layout”
       
android:layout_width=”match_parent”
       
android:foreground=”@drawable/custom_border”
       
android:layout_marginTop=”10dp”
       
android:layout_marginStart=”30dp”
       
android:layout_marginEnd=”30dp”
       
android:layout_height=”350dp”>
        <ImageView
           
android:id=”@+id/imageView”
           
android:scaleType=”fitXY”
           
android:padding=”3dp”
           
android:layout_width=”match_parent”
           
android:layout_height=”match_parent”></ImageView>
    </LinearLayout>
    <Button
       
android:id=”@+id/uploadImage”
       
style=”@style/Widget.AppCompat.Button”
       
android:layout_width=”match_parent”
       
android:layout_marginStart=”30dp”
       
android:layout_marginEnd=”30dp”
       
android:layout_height=”50dp”
       
android:layout_marginTop=”20dp”
       
android:layout_gravity=”center”
       
android:background=”@drawable/buttonshape”
       
android:drawableRight=”@android:drawable/ic_menu_gallery”
       
android:text=”Upload Image”
       
android:textColor=”@color/white”
       
android:textSize=”15sp”></Button>
    <Button
       
android:id=”@+id/captureImage”
       
style=”@style/Widget.AppCompat.Button”
       
android:layout_width=”match_parent”
       
android:layout_marginStart=”30dp”
       
android:layout_marginEnd=”30dp”
       
android:layout_marginTop=”20dp”
       
android:layout_height=”50dp”
       
android:textSize=”15sp”
       
android:layout_gravity=”center”
       
android:text=”Capture Image”
       
android:textColor=”@color/black”
       
android:drawableRight=”@android:drawable/ic_menu_camera”
       
android:background=”@drawable/button_shape1″></Button>


</LinearLayout>

 


                                                                MainActivity.java

package satyaprakash.catdogimagepredictor;
import
androidx.activity.result.ActivityResult;
import
androidx.activity.result.ActivityResultCallback;
import
androidx.activity.result.ActivityResultLauncher;
import
androidx.activity.result.contract.ActivityResultContracts;
import
androidx.appcompat.app.AppCompatActivity;
import
android.app.AlertDialog;
import
android.content.DialogInterface;
import
android.content.Intent;
import
android.graphics.Bitmap;
import
android.graphics.BitmapFactory;
import
android.net.Uri;
import
android.os.Bundle;
import
android.provider.MediaStore;
import
android.util.Log;
import
android.view.View;
import
android.widget.Button;
import
android.widget.ImageView;
import
android.widget.ProgressBar;
import
android.widget.Toast;
import
com.android.volley.NetworkResponse;
import
com.android.volley.Request;
import
com.android.volley.Response;
import
com.android.volley.VolleyError;
import
com.android.volley.toolbox.Volley;
import
org.json.JSONException;
import
org.json.JSONObject;
import
java.io.ByteArrayOutputStream;
import
java.io.FileNotFoundException;
import
java.io.InputStream;
import
java.util.HashMap;
import
java.util.Map;
import
satyaprakash.VolleyMultipartRequest;
public class
MainActivity extends AppCompatActivity {
    Button
buttonUpload,buttonCapture;
    private
Bitmap bitmap;
   
ProgressBar progressBar;
   
ImageView imageView;
   
String url =“http://192.168.0.161:5000/uploader”;
   
@Override
   
protected void onCreate(Bundle savedInstanceState) {
       
super.onCreate(savedInstanceState);
       
setContentView(R.layout.activity_main);
       
imageView=findViewById(R.id.imageView);
       
progressBar=findViewById(R.id.progressBar);
       
buttonUpload =findViewById(R.id.uploadImage);
       
buttonUpload.setOnClickListener(new View.OnClickListener() {
           
@Override
           
public void onClick(View v) { Intent photoPickerIntent =
new Intent(Intent.ACTION_PICK);
               
photoPickerIntent.setType(“image/*”);
               
activityResultLauncherGallery.launch(photoPickerIntent);
           
}
        })
;
       
buttonCapture=findViewById(R.id.captureImage);
       
buttonCapture.setOnClickListener(new View.OnClickListener() {
           
@Override
           
public void onClick(View v) {
                Intent i =
new Intent(MediaStore.ACTION_IMAGE_CAPTURE_SECURE);
               
activityResultLauncherCamera.launch(i);
           
}
        })
;
   
}
    ActivityResultLauncher<Intent>
activityResultLauncherCamera=registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), new ActivityResultCallback<ActivityResult>()
{
       
@Override
       
public void onActivityResult(ActivityResult result) {
           
if (result.getResultCode() == RESULT_OK &&        

                result.getData()!=null) {
                Bundle bundle =
result.getData().getExtras()
;
               
Bitmap bitmap = (Bitmap) bundle.get(“data”);
               
imageView.setImageBitmap(bitmap);
               
uploadBitmap(bitmap);
               
progressBar.setVisibility(View.VISIBLE);
           
}
        }
    })
;
   
ActivityResultLauncher<Intent> activityResultLauncherGallery=registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), new ActivityResultCallback<ActivityResult>()
{
       
@Override
       
public void onActivityResult(ActivityResult result) {
           
if (result.getResultCode() == RESULT_OK &&

              result.getData()!=null) {
                Intent data =
result.getData()
;
               
Uri filePath = data.getData();
                try
{
                    InputStream
image_stream
;
                    try
{
                        image_stream =
getContentResolver().openInputStream(filePath)
;
                       
bitmap = BitmapFactory.decodeStream(image_stream);
                   
} catch (FileNotFoundException e) {
                       
e.printStackTrace()
;
                   
}
                }
catch (Exception e) {
                    e.printStackTrace()
;
               
}
                
imageView.setImageBitmap(bitmap);
               
uploadBitmap(bitmap);
               
progressBar.setVisibility(View.VISIBLE);
           
}
        }
    })
;
    private void
uploadBitmap(final Bitmap bitmap) {
        VolleyMultipartRequest volleyMultipartRequest
=
new VolleyMultipartRequest(Request.Method.POST, url,
                new
Response.Listener<NetworkResponse>()
{
                   
@Override
                   
public void onResponse(NetworkResponse response) {
                        
try {
                            JSONObject
obj =
new JSONObject(new

                            String(response.data));
                           
String result = obj.getString(“Response”);
                          
// String result1= obj.getString(“Matched
 

                            Features”);

 


                      
if(result.equals(“I guess this must be a Dog!”))

                           {
                               
AlertDialog.Builder builder =
new

                                AlertDialog.Builder(MainActivity.this);
                               
progressBar.setVisibility(View.INVISIBLE);
                               
// Set the message show for the Alert
time
                               
builder.setMessage(“I guess this must be a

                                Dog!”);
                               
// Set Alert Title
                               
builder.setTitle(“Response !”);
                               
// Set Cancelable false
                                // for
when the user clicks on the outside
                                // the
Dialog Box then it will remain show
                               
builder.setCancelable(false);
                               
builder.setNegativeButton(“Cancel”, new

                                DialogInterface.OnClickListener() {
                                   
@Override
                                   
public void onClick(DialogInterface

                                    
dialog
, int which)
                                    {
                                       
// If the user click no
                                       
// then the dialog box is cancelled.
                                       
dialog.cancel();
                                   
}
                                })
;
                               
// Create the Alert dialogue
                               
AlertDialog alertDialog =
builder.create()
;
                               
// Show the Alert Dialog box
                               
alertDialog.show();
                           
}
                           
else if(result.equals(“I guess this must be a

                                      
Cat!”
)){
                               
progressBar.setVisibility(View.INVISIBLE);
                               
AlertDialog.Builder builder = new

                                 AlertDialog.Builder(MainActivity.this);
                               
// Set the message show for the Alert
time
                               
builder.setMessage(“I guess this must be a

                                      
Cat!”
);
                               
// Set Alert Title
                               
builder.setTitle(“Response !”);


                               
// Set Cancelable false
                                // for
when the user clicks on the outside
                                // the
Dialog Box then it will remain show
                               
builder.setCancelable(false);
                               
builder.setNegativeButton(“Cancel”, new

                                DialogInterface.OnClickListener() {
                                   
@Override
                                   
public void onClick(DialogInterface

                                   
dialog
, int which)
                                    {
                                       
// If the user click no
                                       
// then the dialog box is cancelled.
                                        
dialog.cancel();
                                   
}
                                })
;


                               
// Create the Alert dialog
                               
AlertDialog alertDialog =
builder.create()
;
                               
// Show the Alert Dialog box
                               
alertDialog.show();
                           

 

 

}
                        }
catch (JSONException e) {
                           
e.printStackTrace()
;
                       
}
                    }
                }
,
                new
Response.ErrorListener() {
                   
@Override
                   
public void onErrorResponse(VolleyError error) {
                        Toast.makeText(getApplicationContext()
,

                        error.getMessage(), Toast.LENGTH_LONG).show();
                       
Log.e(“GotError”,“”+error.getMessage());
                   
}
                })
        {

           
@Override
           
protected Map<String, DataPart> getByteData() {
                Map<String
, DataPart> params = new HashMap<>();
                long
ImageName = System.currentTimeMillis();
               
params.put(“file”, new DataPart(ImageName + “.JPEG”,

                getFileDataFromDrawable(bitmap)));
                return
params;
           
}
        }
;
       
//adding the request to volley
       
Volley.newRequestQueue(this).add(volleyMultipartRequest);
   
}
   
private byte[] getFileDataFromDrawable(Bitmap bitmap) {
        ByteArrayOutputStream
byteArrayOutputStream =
new

        ByteArrayOutputStream();
       
bitmap.compress(Bitmap.CompressFormat.JPEG, 100,

        byteArrayOutputStream);
        return
byteArrayOutputStream.toByteArray();
   
}}

 


 

VolleyMultipartRequest.java

package satyaprakash;
import
com.android.volley.AuthFailureError;
import
com.android.volley.NetworkResponse;
import
com.android.volley.ParseError;
import
com.android.volley.Request;
import
com.android.volley.Response;
import
com.android.volley.VolleyError;
import
com.android.volley.toolbox.HttpHeaderParser;
import
java.io.ByteArrayInputStream;
import
java.io.ByteArrayOutputStream;
import
java.io.DataOutputStream;
import
java.io.IOException;
import
java.io.UnsupportedEncodingException;
import
java.util.Map;
public class
VolleyMultipartRequest extends Request {
   
private final String VTwoHyphens = "--";
    private final
String VLineEnd = "\r\n";
    private final
String VBoundary = "client-" + System.currentTimeMillis();
    private
Response.Listener SListener;
    private
Response.ErrorListener SErrorListener;
    private
Map<String, String> SHeaders;
    public
VolleyMultipartRequest(int method, String url,
                                 
Response.Listener listener,
                                 
Response.ErrorListener errorListener) {
       
super(method, url, errorListener);
        this
.SListener = listener;
        this
.SErrorListener = errorListener;
   
}
   
@Override
   
public Map<String, String> getHeaders() throws AuthFailureError {
       
return (SHeaders != null) ? SHeaders : super.getHeaders();
   
}
   
@Override
   
public String getBodyContentType() {
       
return "multipart/form-data;boundary=" + VBoundary;
   
}
   
@Override
   
public byte[] getBody() throws AuthFailureError {
        ByteArrayOutputStream bos =
new ByteArrayOutputStream();
       
DataOutputStream dos = new DataOutputStream(bos);
        try
{
           
// populate text payload
           
Map<String, String> params = getParams();
            if
(params != null && params.size() > 0) {
                textParse(dos
, params, getParamsEncoding());
           
}
           
// populate data byte payload
           
Map<String, DataPart> data = getByteData();
            if
(data != null && data.size() > 0) {
                dataParse(dos
, data);
           
}
           
// close multipart form data after text and file data
           
dos.writeBytes(VTwoHyphens + VBoundary + VTwoHyphens + VLineEnd);
            return
bos.toByteArray();
       
} catch (IOException e) {
            e.printStackTrace()
;
       
}
       
return null;
   
}
   
protected Map<String, DataPart> getByteData() throws AuthFailureError {
       
return null;
   
}
   
@Override
   
protected Response parseNetworkResponse(NetworkResponse response) {
       
try {
           
return Response.success(
                    response
,
                   
HttpHeaderParser.parseCacheHeaders(response));
       
} catch (Exception e) {
           
return Response.error(new ParseError(e));
       
}
    }
   
@Override
   
protected void deliverResponse(NetworkResponse response) {
       
SListener.onResponse(response);
   
}
   
@Override
   
public void deliverError(VolleyError error) {
       
SErrorListener.onErrorResponse(error);
   
}
   
private void textParse(DataOutputStream dataOutputStream, Map<String, String> params, String encoding) throws IOException {
       
try {
           
for (Map.Entry<String, String> entry : params.entrySet()) {
                buildTextPart(dataOutputStream
, entry.getKey(), entry.getValue());
           
}
        }
catch (UnsupportedEncodingException uee) {
           
throw new RuntimeException("Encoding not supported: " + encoding, uee);
       
}
    }

   
private void dataParse(DataOutputStream dataOutputStream, Map<String, DataPart> data) throws IOException {
       
for (Map.Entry<String, DataPart> entry : data.entrySet()) {
            buildDataPart(dataOutputStream
, entry.getValue(), entry.getKey());
       
}
    }
   
private void buildTextPart(DataOutputStream dataOutputStream, String parameterName, String parameterValue) throws IOException {
        dataOutputStream.writeBytes(
VTwoHyphens + VBoundary + VLineEnd);
       
dataOutputStream.writeBytes("Content-Disposition: form-data; name=\"" + parameterName + "\"" + VLineEnd);
       
dataOutputStream.writeBytes(VLineEnd);
       
dataOutputStream.writeBytes(parameterValue + VLineEnd);
   
}
   
private void buildDataPart(DataOutputStream dataOutputStream, DataPart dataFile, String inputName) throws IOException {
        dataOutputStream.writeBytes(
VTwoHyphens + VBoundary + VLineEnd);
       
dataOutputStream.writeBytes("Content-Disposition: form-data; name=\"" +
                inputName +
"\"; filename=\"" + dataFile.getFileName() + "\"" + VLineEnd);
        if
(dataFile.getType() != null && !dataFile.getType().trim().isEmpty()) {
            dataOutputStream.writeBytes(
"Content-Type: " + dataFile.getType() + VLineEnd);
       
}
        dataOutputStream.writeBytes(
VLineEnd);
       
ByteArrayInputStream fileInputStream = new ByteArrayInputStream(dataFile.getContent());
        int
bytesAvailable = fileInputStream.available();
        int
maxBufferSize = 1024 * 1024;
        int
bufferSize = Math.min(bytesAvailable, maxBufferSize);
        byte
[] buffer = new byte[bufferSize];
        int
bytesRead = fileInputStream.read(buffer, 0, bufferSize);
        while
(bytesRead > 0) {
            dataOutputStream.write(buffer
, 0, bufferSize);
           
bytesAvailable = fileInputStream.available();
           
bufferSize = Math.min(bytesAvailable, maxBufferSize);
           
bytesRead = fileInputStream.read(buffer, 0, bufferSize);
       
}
        dataOutputStream.writeBytes(
VLineEnd);
   
}
   
public class DataPart {
       
private String fName;
        private byte
[] content;
        private
String type;
        public
DataPart() {
        }
       
public DataPart(String name, byte[] data) {
           
fName = name;
           
content = data;
       
}
        String
getFileName() {
           
return fName;
       
}
       
byte[] getContent() {
           
return content;
       
}
        String
getType() {
           
return type;
       
}
    }
}

Congratulations! We have deployed a Machine learning model to Android.MainActivity.java

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>