|
|
<!--
|
|
|
CO_OP_TRANSLATOR_METADATA:
|
|
|
{
|
|
|
"original_hash": "9c4320311c0f2c1884a6a21265d98a51",
|
|
|
"translation_date": "2025-08-27T21:38:32+00:00",
|
|
|
"source_file": "5-retail/lessons/2-check-stock-device/single-board-computer-count-stock.md",
|
|
|
"language_code": "el"
|
|
|
}
|
|
|
-->
|
|
|
# Καταμέτρηση αποθεμάτων από τη συσκευή IoT σας - Εικονικό IoT Hardware και Raspberry Pi
|
|
|
|
|
|
Ένας συνδυασμός των προβλέψεων και των ορίων τους μπορεί να χρησιμοποιηθεί για την καταμέτρηση αποθεμάτων σε μια εικόνα.
|
|
|
|
|
|
## Εμφάνιση ορίων
|
|
|
|
|
|
Ως ένα χρήσιμο βήμα αποσφαλμάτωσης, μπορείτε όχι μόνο να εκτυπώσετε τα όρια, αλλά και να τα σχεδιάσετε πάνω στην εικόνα που αποθηκεύτηκε στον δίσκο όταν καταγράφηκε μια εικόνα.
|
|
|
|
|
|
### Εργασία - εκτύπωση των ορίων
|
|
|
|
|
|
1. Βεβαιωθείτε ότι το έργο `stock-counter` είναι ανοιχτό στο VS Code και ότι το εικονικό περιβάλλον είναι ενεργοποιημένο αν χρησιμοποιείτε εικονική συσκευή IoT.
|
|
|
|
|
|
1. Αλλάξτε τη δήλωση `print` μέσα στη `for` loop με την εξής για να εκτυπώσετε τα όρια στην κονσόλα:
|
|
|
|
|
|
```python
|
|
|
print(f'{prediction.tag_name}:\t{prediction.probability * 100:.2f}%\t{prediction.bounding_box}')
|
|
|
```
|
|
|
|
|
|
1. Εκτελέστε την εφαρμογή με την κάμερα να δείχνει σε κάποια αποθέματα σε ένα ράφι. Τα όρια θα εκτυπωθούν στην κονσόλα, με τιμές για αριστερά, πάνω, πλάτος και ύψος από 0-1.
|
|
|
|
|
|
```output
|
|
|
pi@raspberrypi:~/stock-counter $ python3 app.py
|
|
|
tomato paste: 33.42% {'additional_properties': {}, 'left': 0.3455171, 'top': 0.09916268, 'width': 0.14175442, 'height': 0.29405564}
|
|
|
tomato paste: 34.41% {'additional_properties': {}, 'left': 0.48283678, 'top': 0.10242918, 'width': 0.11782813, 'height': 0.27467814}
|
|
|
tomato paste: 31.25% {'additional_properties': {}, 'left': 0.4923783, 'top': 0.35007596, 'width': 0.13668466, 'height': 0.28304994}
|
|
|
tomato paste: 31.05% {'additional_properties': {}, 'left': 0.36416405, 'top': 0.37494493, 'width': 0.14024884, 'height': 0.26880276}
|
|
|
```
|
|
|
|
|
|
### Εργασία - σχεδίαση των ορίων στην εικόνα
|
|
|
|
|
|
1. Το πακέτο Pip [Pillow](https://pypi.org/project/Pillow/) μπορεί να χρησιμοποιηθεί για τη σχεδίαση πάνω σε εικόνες. Εγκαταστήστε το με την εξής εντολή:
|
|
|
|
|
|
```sh
|
|
|
pip3 install pillow
|
|
|
```
|
|
|
|
|
|
Αν χρησιμοποιείτε εικονική συσκευή IoT, βεβαιωθείτε ότι εκτελείτε αυτή την εντολή μέσα από το ενεργοποιημένο εικονικό περιβάλλον.
|
|
|
|
|
|
1. Προσθέστε την εξής δήλωση εισαγωγής στην κορυφή του αρχείου `app.py`:
|
|
|
|
|
|
```python
|
|
|
from PIL import Image, ImageDraw, ImageColor
|
|
|
```
|
|
|
|
|
|
Αυτό εισάγει τον κώδικα που χρειάζεται για την επεξεργασία της εικόνας.
|
|
|
|
|
|
1. Προσθέστε τον εξής κώδικα στο τέλος του αρχείου `app.py`:
|
|
|
|
|
|
```python
|
|
|
with Image.open('image.jpg') as im:
|
|
|
draw = ImageDraw.Draw(im)
|
|
|
|
|
|
for prediction in predictions:
|
|
|
scale_left = prediction.bounding_box.left
|
|
|
scale_top = prediction.bounding_box.top
|
|
|
scale_right = prediction.bounding_box.left + prediction.bounding_box.width
|
|
|
scale_bottom = prediction.bounding_box.top + prediction.bounding_box.height
|
|
|
|
|
|
left = scale_left * im.width
|
|
|
top = scale_top * im.height
|
|
|
right = scale_right * im.width
|
|
|
bottom = scale_bottom * im.height
|
|
|
|
|
|
draw.rectangle([left, top, right, bottom], outline=ImageColor.getrgb('red'), width=2)
|
|
|
|
|
|
im.save('image.jpg')
|
|
|
```
|
|
|
|
|
|
Αυτός ο κώδικας ανοίγει την εικόνα που αποθηκεύτηκε νωρίτερα για επεξεργασία. Στη συνέχεια, επαναλαμβάνει τις προβλέψεις, λαμβάνοντας τα όρια και υπολογίζει τις συντεταγμένες κάτω δεξιά χρησιμοποιώντας τις τιμές των ορίων από 0-1. Αυτές μετατρέπονται σε συντεταγμένες εικόνας πολλαπλασιάζοντας με τη σχετική διάσταση της εικόνας. Για παράδειγμα, αν η τιμή αριστερά ήταν 0.5 σε μια εικόνα πλάτους 600 pixel, αυτό θα μετατρεπόταν σε 300 (0.5 x 600 = 300).
|
|
|
|
|
|
Κάθε όριο σχεδιάζεται στην εικόνα χρησιμοποιώντας μια κόκκινη γραμμή. Τέλος, η επεξεργασμένη εικόνα αποθηκεύεται, αντικαθιστώντας την αρχική εικόνα.
|
|
|
|
|
|
1. Εκτελέστε την εφαρμογή με την κάμερα να δείχνει σε κάποια αποθέματα σε ένα ράφι. Θα δείτε το αρχείο `image.jpg` στον εξερευνητή του VS Code και θα μπορείτε να το επιλέξετε για να δείτε τα όρια.
|
|
|
|
|
|

|
|
|
|
|
|
## Καταμέτρηση αποθεμάτων
|
|
|
|
|
|
Στην εικόνα που φαίνεται παραπάνω, τα όρια έχουν μια μικρή επικάλυψη. Αν αυτή η επικάλυψη ήταν πολύ μεγαλύτερη, τότε τα όρια μπορεί να υποδείκνυαν το ίδιο αντικείμενο. Για να μετρήσετε σωστά τα αντικείμενα, πρέπει να αγνοήσετε τα όρια με σημαντική επικάλυψη.
|
|
|
|
|
|
### Εργασία - καταμέτρηση αποθεμάτων αγνοώντας την επικάλυψη
|
|
|
|
|
|
1. Το πακέτο Pip [Shapely](https://pypi.org/project/Shapely/) μπορεί να χρησιμοποιηθεί για τον υπολογισμό της επικάλυψης. Αν χρησιμοποιείτε Raspberry Pi, θα χρειαστεί να εγκαταστήσετε πρώτα μια βιβλιοθήκη εξάρτησης:
|
|
|
|
|
|
```sh
|
|
|
sudo apt install libgeos-dev
|
|
|
```
|
|
|
|
|
|
1. Εγκαταστήστε το πακέτο Shapely Pip:
|
|
|
|
|
|
```sh
|
|
|
pip3 install shapely
|
|
|
```
|
|
|
|
|
|
Αν χρησιμοποιείτε εικονική συσκευή IoT, βεβαιωθείτε ότι εκτελείτε αυτή την εντολή μέσα από το ενεργοποιημένο εικονικό περιβάλλον.
|
|
|
|
|
|
1. Προσθέστε την εξής δήλωση εισαγωγής στην κορυφή του αρχείου `app.py`:
|
|
|
|
|
|
```python
|
|
|
from shapely.geometry import Polygon
|
|
|
```
|
|
|
|
|
|
Αυτό εισάγει τον κώδικα που χρειάζεται για τη δημιουργία πολυγώνων για τον υπολογισμό της επικάλυψης.
|
|
|
|
|
|
1. Πάνω από τον κώδικα που σχεδιάζει τα όρια, προσθέστε τον εξής κώδικα:
|
|
|
|
|
|
```python
|
|
|
overlap_threshold = 0.20
|
|
|
```
|
|
|
|
|
|
Αυτό ορίζει το ποσοστό επικάλυψης που επιτρέπεται πριν τα όρια θεωρηθούν ότι ανήκουν στο ίδιο αντικείμενο. Το 0.20 ορίζει μια επικάλυψη 20%.
|
|
|
|
|
|
1. Για να υπολογίσετε την επικάλυψη χρησιμοποιώντας το Shapely, τα όρια πρέπει να μετατραπούν σε πολυγώνια Shapely. Προσθέστε την εξής συνάρτηση για να το κάνετε αυτό:
|
|
|
|
|
|
```python
|
|
|
def create_polygon(prediction):
|
|
|
scale_left = prediction.bounding_box.left
|
|
|
scale_top = prediction.bounding_box.top
|
|
|
scale_right = prediction.bounding_box.left + prediction.bounding_box.width
|
|
|
scale_bottom = prediction.bounding_box.top + prediction.bounding_box.height
|
|
|
|
|
|
return Polygon([(scale_left, scale_top), (scale_right, scale_top), (scale_right, scale_bottom), (scale_left, scale_bottom)])
|
|
|
```
|
|
|
|
|
|
Αυτή δημιουργεί ένα πολύγωνο χρησιμοποιώντας το όριο μιας πρόβλεψης.
|
|
|
|
|
|
1. Η λογική για την αφαίρεση επικαλυπτόμενων αντικειμένων περιλαμβάνει τη σύγκριση όλων των ορίων και αν οποιαδήποτε ζεύγη προβλέψεων έχουν όρια που επικαλύπτονται περισσότερο από το όριο, διαγράφεται μία από τις προβλέψεις. Για να συγκρίνετε όλες τις προβλέψεις, συγκρίνετε την πρόβλεψη 1 με τις 2, 3, 4, κ.λπ., μετά την 2 με τις 3, 4, κ.λπ. Ο εξής κώδικας το κάνει αυτό:
|
|
|
|
|
|
```python
|
|
|
to_delete = []
|
|
|
|
|
|
for i in range(0, len(predictions)):
|
|
|
polygon_1 = create_polygon(predictions[i])
|
|
|
|
|
|
for j in range(i+1, len(predictions)):
|
|
|
polygon_2 = create_polygon(predictions[j])
|
|
|
overlap = polygon_1.intersection(polygon_2).area
|
|
|
|
|
|
smallest_area = min(polygon_1.area, polygon_2.area)
|
|
|
|
|
|
if overlap > (overlap_threshold * smallest_area):
|
|
|
to_delete.append(predictions[i])
|
|
|
break
|
|
|
|
|
|
for d in to_delete:
|
|
|
predictions.remove(d)
|
|
|
|
|
|
print(f'Counted {len(predictions)} stock items')
|
|
|
```
|
|
|
|
|
|
Η επικάλυψη υπολογίζεται χρησιμοποιώντας τη μέθοδο `Polygon.intersection` του Shapely που επιστρέφει ένα πολύγωνο που έχει την επικάλυψη. Η περιοχή υπολογίζεται από αυτό το πολύγωνο. Το όριο επικάλυψης δεν είναι απόλυτη τιμή, αλλά πρέπει να είναι ποσοστό του ορίου, οπότε βρίσκουμε το μικρότερο όριο και χρησιμοποιούμε το όριο επικάλυψης για να υπολογίσουμε ποια περιοχή μπορεί να έχει η επικάλυψη ώστε να μην υπερβαίνει το ποσοστό επικάλυψης του μικρότερου ορίου. Αν η επικάλυψη το υπερβαίνει, η πρόβλεψη σημειώνεται για διαγραφή.
|
|
|
|
|
|
Μόλις μια πρόβλεψη σημειωθεί για διαγραφή, δεν χρειάζεται να ελεγχθεί ξανά, οπότε η εσωτερική επανάληψη διακόπτεται για να ελεγχθεί η επόμενη πρόβλεψη. Δεν μπορείτε να διαγράψετε στοιχεία από μια λίστα ενώ επαναλαμβάνεστε μέσα σε αυτήν, οπότε τα όρια που επικαλύπτονται περισσότερο από το όριο προστίθενται στη λίστα `to_delete` και στη συνέχεια διαγράφονται στο τέλος.
|
|
|
|
|
|
Τέλος, ο αριθμός των αποθεμάτων εκτυπώνεται στην κονσόλα. Αυτό θα μπορούσε στη συνέχεια να σταλεί σε μια υπηρεσία IoT για ειδοποίηση αν τα επίπεδα αποθεμάτων είναι χαμηλά. Όλος αυτός ο κώδικας είναι πριν σχεδιαστούν τα όρια, οπότε θα δείτε τις προβλέψεις αποθεμάτων χωρίς επικαλύψεις στις παραγόμενες εικόνες.
|
|
|
|
|
|
> 💁 Αυτός είναι ένας πολύ απλοϊκός τρόπος για την αφαίρεση επικαλύψεων, απλώς αφαιρώντας την πρώτη σε ένα ζεύγος που επικαλύπτεται. Για κώδικα παραγωγής, θα θέλατε να προσθέσετε περισσότερη λογική εδώ, όπως να εξετάσετε τις επικαλύψεις μεταξύ πολλαπλών αντικειμένων ή αν ένα όριο περιέχεται από ένα άλλο.
|
|
|
|
|
|
1. Εκτελέστε την εφαρμογή με την κάμερα να δείχνει σε κάποια αποθέματα σε ένα ράφι. Η έξοδος θα δείξει τον αριθμό των ορίων χωρίς επικαλύψεις που υπερβαίνουν το όριο. Δοκιμάστε να προσαρμόσετε την τιμή `overlap_threshold` για να δείτε προβλέψεις που αγνοούνται.
|
|
|
|
|
|
> 💁 Μπορείτε να βρείτε αυτόν τον κώδικα στον φάκελο [code-count/pi](../../../../../5-retail/lessons/2-check-stock-device/code-count/pi) ή [code-count/virtual-iot-device](../../../../../5-retail/lessons/2-check-stock-device/code-count/virtual-iot-device).
|
|
|
|
|
|
😀 Το πρόγραμμα καταμέτρησης αποθεμάτων σας ήταν επιτυχές!
|
|
|
|
|
|
---
|
|
|
|
|
|
**Αποποίηση ευθύνης**:
|
|
|
Αυτό το έγγραφο έχει μεταφραστεί χρησιμοποιώντας την υπηρεσία αυτόματης μετάφρασης [Co-op Translator](https://github.com/Azure/co-op-translator). Παρόλο που καταβάλλουμε προσπάθειες για ακρίβεια, παρακαλούμε να έχετε υπόψη ότι οι αυτοματοποιημένες μεταφράσεις ενδέχεται να περιέχουν σφάλματα ή ανακρίβειες. Το πρωτότυπο έγγραφο στη μητρική του γλώσσα θα πρέπει να θεωρείται η αυθεντική πηγή. Για κρίσιμες πληροφορίες, συνιστάται επαγγελματική ανθρώπινη μετάφραση. Δεν φέρουμε ευθύνη για τυχόν παρεξηγήσεις ή εσφαλμένες ερμηνείες που προκύπτουν από τη χρήση αυτής της μετάφρασης. |