modify for tomatos

This commit is contained in:
anetla 2023-12-28 18:40:41 +01:00
parent 27873f727a
commit 9293dc57e2
7 changed files with 240 additions and 44 deletions

File diff suppressed because one or more lines are too long

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 MiB

After

Width:  |  Height:  |  Size: 2.6 MiB

View File

@ -1,20 +1,17 @@
# Traffic Lights Object Detector using YOLOv8 neural network
# Tomato maturity detection web application
<div align="center">
<a href="https://dev.to/andreygermanov/a-practical-introduction-to-object-detection-with-yolov8-neural-network-3n8c">
<img src="https://res.cloudinary.com/practicaldev/image/fetch/s--mZ1E0vOa--/c_imagga_scale,f_auto,fl_progressive,h_420,q_auto,w_1000/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n2auv9i8405cgnxhru40.png"/>
</a>
<img src="example_picture.png"/>
</div>
The source code for [this](https://dev.to/andreygermanov/a-practical-introduction-to-object-detection-with-yolov8-neural-network-3n8c) article.
This is a modified code from [this](https://dev.to/andreygermanov/a-practical-introduction-to-object-detection-with-yolov8-neural-network-3n8c) article.
This is a web interface to [YOLOv8 object detection neural network](https://ultralytics.com/yolov8)
implemented on [Python](https://www.python.org) that uses a model to detect traffic lights and road signs on images.
implemented on [Python](https://www.python.org) that uses a model to detect tomato maturity and road signs on images.
## Install
* Clone this repository: `git clone git@github.com:AndreyGermanov/yolov8_pytorch_python.git`
* Cloning instruction coming soon
* Go to the root of cloned repository
* Install dependencies by running `pip3 install -r requirements.txt`

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 MiB

View File

@ -4,42 +4,44 @@
<meta charset="UTF-8">
<title>YOLOv8 Object Detection</title>
<style>
canvas {
display:block;
border: 1px solid black;
margin-top:10px;
}
canvas {
display:block;
border: 1px solid black;
margin-top:10px;
}
</style>
</head>
<body>
<input id="uploadInput" type="file"/>
<canvas></canvas>
<script>
/**
* "Upload" button onClick handler: uploads selected image file
* to backend, receives array of detected objects
* and draws them on top of image
/**
* "Upload" button onClick handler: uploads selected
* image file to backend, receives an array of
* detected objects and draws them on top of image
*/
const input = document.getElementById("uploadInput");
input.addEventListener("change",async(event) => {
const file = event.target.files[0];
const data = new FormData();
data.append("image_file",event.target.files[0],"image_file");
data.append("image_file",file,"image_file");
const response = await fetch("/detect",{
method:"post",
body:data
});
const boxes = await response.json();
draw_image_and_boxes(event.target.files[0],boxes);
draw_image_and_boxes(file,boxes);
})
/**
/**
* Function draws the image from provided file
* and bounding boxes of detected objects on
* top of the image
* @param file Uploaded file object
* @param boxes Array of bounding boxes in format [[x1,y1,x2,y2,object_type,probability],...]
* @param boxes Array of bounding boxes in format
[[x1,y1,x2,y2,object_type,probability],...]
*/
function draw_image_and_boxes(file,boxes) {
function draw_image_and_boxes(file,boxes) {
const img = new Image()
img.src = URL.createObjectURL(file);
img.onload = () => {
@ -49,18 +51,20 @@
const ctx = canvas.getContext("2d");
ctx.drawImage(img,0,0);
ctx.strokeStyle = "#00FF00";
ctx.lineWidth = 3;
ctx.font = "18px serif";
boxes.forEach(([x1,y1,x2,y2,label]) => {
ctx.lineWidth = 5;
ctx.font = "20px serif";
boxes.forEach(([x1,y1,x2,y2,object_type, prob]) => {
const label = `${object_type} ${prob.toFixed(2)}`;
ctx.strokeRect(x1,y1,x2-x1,y2-y1);
ctx.fillStyle = "#00ff00";
const width = ctx.measureText(label).width;
ctx.fillRect(x1,y1,width+10,25);
ctx.fillStyle = "#000000";
ctx.fillText(label, x1, y1+18);
ctx.fillText(label,x1,y1+18);
});
}
}
</script>
}
</script>
</body>
</html>

View File

@ -2,6 +2,8 @@ from ultralytics import YOLO
from flask import request, Flask, jsonify
from waitress import serve
from PIL import Image
import onnxruntime as ort
import numpy as np
#my changes
import os
@ -10,6 +12,14 @@ script_dir = os.path.dirname(os.path.abspath(__file__))
# Change the working directory to the script's directory
os.chdir(script_dir)
yolo_classes = ["b_fully_ripened",
"b_half_ripened",
"b_green",
"l_fully_ripened",
"l_half_ripened",
"l_green"
]
#app start
app = Flask(__name__)
@ -35,11 +45,86 @@ def detect():
"""
buf = request.files["image_file"]
boxes = detect_objects_on_image(buf.stream)
print(boxes)
return jsonify(boxes)
def detect_objects_on_image(buf):
input, img_width, img_height = prepare_input(buf)
output = run_model(input)
return process_output(output,img_width,img_height)
def prepare_input(buf):
img = Image.open(buf)
img_width, img_height = img.size
img = img.resize((640, 640))
img = img.convert("RGB")
input = np.array(img)
input = input.transpose(2, 0, 1)
input = input.reshape(1, 3, 640, 640) / 255.0
return input.astype(np.float32), img_width, img_height
def run_model(input):
model = ort.InferenceSession("best.onnx", providers=['CPUExecutionProvider'])
outputs = model.run(["output0"], {"images":input})
return outputs[0]
def process_output(output, img_width, img_height):
output = output[0].astype(float)
output = output.transpose()
boxes = []
for row in output:
prob = row[4:].max()
if prob < 0.5:
continue
class_id = row[4:].argmax()
label = yolo_classes[class_id]
xc, yc, w, h = row[:4]
x1 = (xc - w/2) / 640 * img_width
y1 = (yc - h/2) / 640 * img_height
x2 = (xc + w/2) / 640 * img_width
y2 = (yc + h/2) / 640 * img_height
rotated_x1 = img_height - y2
rotated_y1 = x1
rotated_x2 = img_height - y1
rotated_y2 = x2
boxes.append([rotated_x1, rotated_y1, rotated_x2, rotated_y2, label, prob])
#boxes.append([x1, y1, x2, y2, label, prob])
boxes.sort(key=lambda x: x[5], reverse=True)
result = []
while len(boxes) > 0:
result.append(boxes[0])
boxes = [box for box in boxes if iou(box, boxes[0]) < 0.7]
return result
def iou(box1,box2):
return intersection(box1,box2)/union(box1,box2)
def union(box1,box2):
box1_x1,box1_y1,box1_x2,box1_y2 = box1[:4]
box2_x1,box2_y1,box2_x2,box2_y2 = box2[:4]
box1_area = (box1_x2-box1_x1)*(box1_y2-box1_y1)
box2_area = (box2_x2-box2_x1)*(box2_y2-box2_y1)
return box1_area + box2_area - intersection(box1,box2)
def intersection(box1,box2):
box1_x1,box1_y1,box1_x2,box1_y2 = box1[:4]
box2_x1,box2_y1,box2_x2,box2_y2 = box2[:4]
x1 = max(box1_x1,box2_x1)
y1 = max(box1_y1,box2_y1)
x2 = min(box1_x2,box2_x2)
y2 = min(box1_y2,box2_y2)
return (x2-x1)*(y2-y1)
""" def detect_objects_on_image(buf):
"""
""""
Function receives an image,
passes it through YOLOv8 neural network
and returns an array of detected objects
@ -47,6 +132,7 @@ def detect_objects_on_image(buf):
:param buf: Input image file stream
:return: Array of bounding boxes in format [[x1,y1,x2,y2,object_type,probability],..]
"""
"""""
model = YOLO("best.pt")
results = model.predict(Image.open(buf))
result = results[0]
@ -62,5 +148,5 @@ def detect_objects_on_image(buf):
])
return output
"""
serve(app, host='0.0.0.0', port=8080)