├── apple.jpg ├── indices.npy ├── weights.npy ├── first.kv ├── main.py ├── .github ├── FUNDING.yml └── workflows │ └── python-publish.yml ├── Fruits.py └── README.md /apple.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmedfgad/KivyAndroidClassification/HEAD/apple.jpg -------------------------------------------------------------------------------- /indices.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmedfgad/KivyAndroidClassification/HEAD/indices.npy -------------------------------------------------------------------------------- /weights.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmedfgad/KivyAndroidClassification/HEAD/weights.npy -------------------------------------------------------------------------------- /first.kv: -------------------------------------------------------------------------------- 1 | BoxLayout: 2 | orientation: "vertical" 3 | Label: 4 | text: "Predicted Class Appears Here." 5 | font_size: 30 6 | id: label 7 | BoxLayout: 8 | orientation: "horizontal" 9 | Image: 10 | source: "apple.jpg" 11 | id: img 12 | Button: 13 | text: "Classify Image." 14 | font_size: 30 15 | on_press: app.classify_image() 16 | 17 | -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | import kivy.app 2 | import Fruits 3 | 4 | class FirstApp(kivy.app.App): 5 | def classify_image(self): 6 | img_path = self.root.ids["img"].source 7 | 8 | img_features = Fruits.extract_features(img_path) 9 | 10 | predicted_class = Fruits.predict_output("weights.npy", img_features, activation="sigmoid") 11 | 12 | self.root.ids["label"].text = "Predicted Class : " + predicted_class 13 | 14 | firstApp = FirstApp(title="Fruits 360 Recognition.") 15 | firstApp.run() 16 | 17 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | # paypal: http://paypal.me/ahmedfgad # Replace with a single Patreon username 5 | open_collective: pygad 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: ['https://donate.stripe.com/eVa5kO866elKgM0144', 'http://paypal.me/ahmedfgad'] # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 13 | 14 | -------------------------------------------------------------------------------- /.github/workflows/python-publish.yml: -------------------------------------------------------------------------------- 1 | # This workflow will upload a Python Package using Twine when a release is created 2 | # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python#publishing-to-package-registries 3 | 4 | # This workflow uses actions that are not certified by GitHub. 5 | # They are provided by a third-party and are governed by 6 | # separate terms of service, privacy policy, and support 7 | # documentation. 8 | 9 | name: Upload Python Package 10 | 11 | on: 12 | release: 13 | types: [published] 14 | 15 | permissions: 16 | contents: read 17 | 18 | jobs: 19 | deploy: 20 | 21 | runs-on: ubuntu-latest 22 | 23 | steps: 24 | - uses: actions/checkout@v4 25 | - name: Set up Python 26 | uses: actions/setup-python@v3 27 | with: 28 | python-version: '3.x' 29 | - name: Install dependencies 30 | run: | 31 | python -m pip install --upgrade pip 32 | pip install build 33 | - name: Build package 34 | run: python -m build 35 | - name: Publish package 36 | uses: pypa/gh-action-pypi-publish@27b31702a0e7fc50959f5ad993c78deac1bdfc29 37 | with: 38 | user: __token__ 39 | password: ${{ secrets.PYPI_API_TOKEN }} 40 | -------------------------------------------------------------------------------- /Fruits.py: -------------------------------------------------------------------------------- 1 | import numpy 2 | import PIL.Image 3 | 4 | def sigmoid(inpt): 5 | return 1.0/(1.0+numpy.exp(-1*inpt)) 6 | 7 | def relu(inpt): 8 | result = inpt 9 | result[inpt<0] = 0 10 | return result 11 | 12 | def predict_output(weights_mat_path, data_inputs, activation="relu"): 13 | weights_mat = numpy.load(weights_mat_path) 14 | r1 = data_inputs 15 | for curr_weights in weights_mat: 16 | r1 = numpy.matmul(a=r1, b=curr_weights) 17 | if activation == "relu": 18 | r1 = relu(r1) 19 | elif activation == "sigmoid": 20 | r1 = sigmoid(r1) 21 | r1 = r1[0, :] 22 | predicted_label = numpy.where(r1 == numpy.max(r1))[0][0] 23 | class_labels = ["Apple", "Raspberry", "Mango", "Lemon"] 24 | predicted_class = class_labels[predicted_label] 25 | return predicted_class 26 | 27 | def extract_features(img_path): 28 | im = PIL.Image.open(img_path).convert("HSV") 29 | fruit_data_hsv = numpy.asarray(im, dtype=numpy.uint8) 30 | 31 | indices = numpy.load(file="indices.npy") 32 | 33 | hist = numpy.histogram(a=fruit_data_hsv[:, :, 0], bins=360) 34 | im_features = hist[0][indices] 35 | img_features = numpy.zeros(shape=(1, im_features.size)) 36 | img_features[0, :] = im_features[:im_features.size] 37 | return img_features 38 | 39 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # KivyAndroidClassification 2 | Image Classification for Android using Artificial Neural Network using NumPy and Kivy. 3 | 4 | This project runs a pre-trained artificial neural network (ANN) in Android for image classification. The ANN is built using NumPy (Numerical Python). In order to be able to run NumPy in Android, the Kivy framework is used for running NumPy on top of it. Kivy is a cross-platform Python framework which supports packaging Python libraries within the APK file. 5 | 6 | The ANN created using NumPy is trained in a desktop computer using 4 classes from the Fruits360 dataset which are apple Braeburn, lemon Meyer, mango, and raspberry. The weights of the ANN are optimized using the genetic algorithm (GA). The optimized weights are saved in a NumPy binary file (.npy). This file is named **weights.npy**. 7 | 8 | After the ANN is trained successfully, a Kivy desktop application is created that invokes this NPY file for predicting the class label of new test images. The application has 2 main files. The first is a KV file that holds the layout of the user interface which is named **first.kv**. The second one is a Python file that reads an image, loads the **weights.npy** file, classify the image, and print its class label on the screen. This file is named **main.py**. 9 | 10 | After making sure the desktop application is working successfully, the Kivy application is exported into an Android application using Buildozer and python-4-android. Within it, a test image could be fed into the pre-trained ANN for classifying it. For building the Android application, the **buildozer.spec** file is requirdd. 11 | 12 | The next figure shows the window of the application after running it in Linux. 13 | ![5](https://user-images.githubusercontent.com/16560492/57416236-a5933d00-71ff-11e9-8d3a-f87ab14f35ba.png) 14 | 15 | For details about building the ANN from scratch in NumPy, extracting the features, optimization using GA, and feature reduction, you can read my previous tutorials that covers these points in details. 16 | 17 | [Artificial Neural Network Implementation using NumPy and Classification of the Fruits360 Image Dataset](https://www.linkedin.com/pulse/artificial-neural-network-implementation-using-numpy-fruits360-gad) 18 | 19 | Its GitHub project: https://github.com/ahmedfgad/NumPyANN 20 | 21 | [Artificial Neural Networks Optimization using Genetic Algorithm with Python](https://www.linkedin.com/pulse/artificial-neural-networks-optimization-using-genetic-ahmed-gad) 22 | 23 | Its GitHub project: https://github.com/ahmedfgad/NeuralGenetic 24 | 25 | [Feature Reduction using Genetic Algorithm with Python](https://www.linkedin.com/pulse/feature-reduction-using-genetic-algorithm-ahmed-gad) 26 | 27 | Its GitHub project: https://github.com/ahmedfgad/FeatureReductionGenetic 28 | 29 | ## For Contacting Me 30 | * E-mail: ahmed.f.gad@gmail.com 31 | * LinkedIn: https://linkedin.com/in/ahmedfgad/ 32 | * Hearbeat: https://heartbeat.fritz.ai/@ahmedfgad 33 | * KDnuggets: https://kdnuggets.com/author/ahmed-gad 34 | * TowardsDataScience: https://towardsdatascience.com/@ahmedfgad 35 | * GitHub: https://github.com/ahmedfgad 36 | --------------------------------------------------------------------------------