STEPS:
- Creating YOLOV5 Flask App
 - Creating Docker Image
 - Running Docker Container and Pushing to DockerHub
 - Deploying Rest API to Azure for Free.
 - Using API in flutter project to perform detections.
 
Creating YOLOV5 Flask App
Create a flask app with your ML model with requests defined.
"""
Run a rest API exposing the yolov5s object detection model
"""
import argparse
import io
from PIL import Image
import torch
from flask import Flask, request
app = Flask(__name__)
DETECTION_URL = "/v1/object-detection/yolov5"
@app.route(DETECTION_URL, methods=["POST"])
def predict():
    if not request.method == "POST":
        return
    if request.files.get("image"):
        image_file = request.files["image"]
        image_bytes = image_file.read()
        img = Image.open(io.BytesIO(image_bytes))
        results = model(img, size=640) # reduce size=320 for faster inference
        return results.pandas().xyxy[0].to_json(orient="records")
if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="Flask api exposing yolov5 model")
    parser.add_argument("--port", default=5000, type=int, help="port number")
    parser.add_argument('--model', default='yolov5s', help='model to run, i.e. --model yolov5s')
    args = parser.parse_args()
    model = torch.hub.load('ultralytics/yolov5', args.model)
    app.run(host="0.0.0.0", port=args.port)  # debug=True causes Restarting with stat
you can use a your own model as well with the help of following place the model on the same path as the app.py or flask app file.
model = torch.hub.load('.','custom', path='best.pt',force_reload=True,source='local', pretrained =Flase)
Creating Docker Image:
- First create a DockerFile with the following:
 
# Use an official Python runtime as a parent image
FROM python:3.8-slim-buster
RUN apt-get update
RUN apt-get install ffmpeg libsm6 libxext6  -y
# Set the working directory to /app
WORKDIR /app
# Copy the current directory contents into the container at /app
COPY . /app
# Install any needed packages specified in requirements.txt
RUN pip install -r requirements.txt
# Make port 5000 available to the world outside this container
EXPOSE 5000
# Run app.py when the container launches
CMD ["python", "app.py", "--port=5000"]
change the app.py if you have different app name
- Run the Following Commands to create an Image and push to the docker hub:
 
Running Docker Container and Pushing to DockerHub
Run to Ensure it is Working:


Login to Docker Hub:

Create  a tag to push to Docker Hub image:

Deploying Rest API to Azure for Free.
- Create a new Web App Service in Azure:
 
- Login to your Azure account.
 - Select "Create a resource" and search for "Web App".
 - Select "Web App" from the search results and click "Create".
 - Choose a unique name, subscription, resource group, and app service plan.
 
- Choose "Docker Container" as the Publish option and "Linux" as the Operating System.
 - Choose "Docker Hub" as the Registry and enter the name and version of the image you created in step 1.
 - Click "Create" to create the Web App Service.
 - Wait for Azure to deploy your container to the Web App Service. This may take a few minutes.
 
Using API in flutter project to perform detections.
main.dart
import 'package:flutter/material.dart';
import 'package:flutter_restapi/ObjectDetectionScreen.dart';
void main() {
  runApp(const MyApp());
}
class MyApp extends StatelessWidget {
  const MyApp({super.key});
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        // This is the theme of your application.
        //
        // Try running your application with "flutter run". You'll see the
        // application has a blue toolbar. Then, without quitting the app, try
        // changing the primarySwatch below to Colors.green and then invoke
        // "hot reload" (press "r" in the console where you ran "flutter run",
        // or simply save your changes to "hot reload" in a Flutter IDE).
        // Notice that the counter didn't reset back to zero; the application
        // is not restarted.
        primarySwatch: Colors.blue,
      ),
      home: ObjectDetectionScreen(),
    );
  }
}
ObjectScreen.dart
import 'dart:io';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'package:http/http.dart' as http;
class BoundingBox {
  final double xMin;
  final double yMin;
  final double xMax;
  final double yMax;
  final double confidence;
  final String name;
  BoundingBox({
    required this.xMin,
    required this.yMin,
    required this.xMax,
    required this.yMax,
    required this.confidence,
    required this.name,
  });
}
class ObjectDetectionScreen extends StatefulWidget {
  const ObjectDetectionScreen({super.key});
  @override
  State<ObjectDetectionScreen> createState() => _ObjectDetectionScreenState();
}
class _ObjectDetectionScreenState extends State<ObjectDetectionScreen> {
  late List<BoundingBox> _boundingBoxes = [];
  File? _image;
  bool _loading = false;
  final picker = ImagePicker();
  Future<List<BoundingBox>> detectObjects(File image) async {
    final url =
        "https://flask-restapi-yolov5s.azurewebsites.net/v1/object-detection/yolov5";
    final request = await http.MultipartRequest("POST", Uri.parse(url));
    request.files.add(await http.MultipartFile.fromPath("image", image.path));
    final response = await request.send();
    if (response.statusCode == 200) {
      final jsonStr = await response.stream.bytesToString();
      final jsonResponse = json.decode(jsonStr);
      print(jsonResponse);
      return List<BoundingBox>.from(jsonResponse.map((bbox) => BoundingBox(
            xMin: bbox["xmin"],
            yMin: bbox["ymin"],
            xMax: bbox["xmax"],
            yMax: bbox["ymax"],
            confidence: bbox["confidence"],
            name: bbox["name"],
          )));
    } else {
      throw Exception('Failed to detect objects');
    }
  }
  Future<void> getImage(ImageSource source) async {
    setState(() {
      _loading = true;
    });
    final pickedFile =
        await picker.pickImage(source: source, maxWidth: 340, maxHeight: 340);
    if (pickedFile != null) {
      setState(() {
        _image = File(pickedFile.path);
      });
      final bboxes = await detectObjects(_image!);
      setState(() {
        _boundingBoxes = bboxes;
        _loading = false;
      });
    } else {
      setState(() {
        _loading = false;
      });
    }
  }
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: const Text('Object Detection Using Flask Rest Api'),
        ),
        body: Center(
          child: SingleChildScrollView(
            child: Column(
              children: [
                _image == null
                    ? const Text('No image selected.')
                    : Stack(
                        children: [
                          Image.file(_image!),
                          ..._boundingBoxes.asMap().entries.map((entry) {
                            final index = entry.key;
                            final bbox = entry.value;
                            final xMin = bbox.xMin;
                            final yMin = bbox.yMin;
                            final xMax = bbox.xMax;
                            final yMax = bbox.yMax;
                            final confidence = bbox.confidence;
                            final name = bbox.name;
                            final left = xMin;
                            final top = yMin;
                            final width = xMax - xMin;
                            final height = yMax - yMin;
                            Color color;
                            if (index % 3 == 0) {
                              color = Colors.green;
                            } else if (index % 3 == 1) {
                              color = Colors.yellow;
                            } else {
                              color = Colors.red;
                            }
                            return Positioned(
                              left: left,
                              top: top,
                              width: width,
                              height: height,
                              child: Container(
                                decoration: BoxDecoration(
                                  border: Border.all(
                                    color: color,
                                    width: 2.0,
                                  ),
                                  borderRadius: BorderRadius.circular(20),
                                ),
                                child: Text(
                                  "$name ${(confidence * 100).toStringAsFixed(0)}%",
                                  textAlign: TextAlign.center,
                                  style: TextStyle(
                                    color: color,
                                    fontSize: 12.0,
                                    fontWeight: FontWeight.bold,
                                    shadows: const [
                                      Shadow(
                                        color: Colors.black,
                                        offset: Offset(1, 1),
                                        blurRadius: 2,
                                      )
                                    ],
                                  ),
                                ),
                              ),
                            );
                          }).toList(),
                        ],
                      ),
                ElevatedButton(
                  onPressed: () => getImage(ImageSource.camera),
                  child: const Text("Take a Picture"),
                ),
                ElevatedButton(
                  onPressed: () => getImage(ImageSource.gallery),
                  child: const Text("Choose from Gallery"),
                ),
                const SizedBox(height: 10),
                _loading
                    ? const CircularProgressIndicator(
                        color: Colors.blue,
                      )
                    : const SizedBox(),
              ],
            ),
          ),
        ));
  }
}
BoundingBox.dart
import 'dart:ui';
import 'package:flutter/material.dart';
class BoxPainter extends CustomPainter {
  final dynamic predictions;
  BoxPainter(this.predictions);
  @override
  void paint(Canvas canvas, Size size) {
    final width = size.width;
    final height = size.height;
    final colors = [
      Colors.red,
      Colors.green,
      Colors.blue,
      Colors.yellow,
      Colors.orange,
      Colors.purple,
      Colors.pink,
    ];
    if (predictions != null) {
      for (var i = 0; i < predictions.length; i++) {
        final prediction = predictions[i];
        final bbox = prediction['bbox'];
        final left = bbox['xmin'].toDouble();
        final top = bbox['ymin'].toDouble();
        final right = bbox['xmax'].toDouble();
        final bottom = bbox['ymax'].toDouble();
        final rect = Rect.fromLTWH(
          left / 640 * width,
          top / 640 * height,
          (right - left) / 640 * width,
          (bottom - top) / 640 * height,
        );
        final paint = Paint()
          ..color = colors[i % colors.length]
          ..style = PaintingStyle.stroke
          ..strokeWidth = 2.0;
        final labelPaint = Paint()
          ..color = colors[i % colors.length]
          ..style = PaintingStyle.fill
          ..strokeWidth = 2.0;
        canvas.drawRect(rect, paint);
        final label = '${prediction['name']} (${prediction['confidence']})';
        final labelOffset = Offset(
          left / 640 * width,
          top / 480 * height - 20,
        );
        canvas.drawRect(
          Rect.fromPoints(
            labelOffset,
            Offset(
              labelOffset.dx + label.length * 8,
              labelOffset.dy + 20,
            ),
          ),
          labelPaint,
        );
        final textStyle = TextStyle(
          color: Colors.white,
          fontSize: 14.0,
        );
        final textSpan = TextSpan(
          text: label,
          style: textStyle,
        );
        final textPainter = TextPainter(
          text: textSpan,
          textDirection: TextDirection.ltr,
        );
        textPainter.layout(
          minWidth: 0,
          maxWidth: size.width,
        );
        textPainter.paint(
          canvas,
          Offset(
            labelOffset.dx + 4,
            labelOffset.dy + 2,
          ),
        );
      }
    }
  }
  @override
  bool shouldRepaint(BoxPainter oldDelegate) => false;
}
Compile and debug the project.
App is Running ๐๐๐
              

        drive.google.com
      
    
Top comments (0)