# Бројање залиха са вашег IoT уређаја - Виртуелни IoT хардвер и Raspberry Pi Комбинација предвиђања и њихових оквира може се користити за бројање залиха на слици. ## Приказивање оквира Као користан корак за отклањање грешака, можете не само исписати оквире, већ их и нацртати на слици која је сачувана на диску када је слика снимљена. ### Задатак - исписивање оквира 1. Уверите се да је пројекат `stock-counter` отворен у VS Code-у и да је виртуелно окружење активирано ако користите виртуелни IoT уређај. 1. Промените `print` изјаву у `for` петљи у следеће како бисте исписали оквире у конзолу: ```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 пиксела, то би се конвертовало у 300 (0.5 x 600 = 300). Сваки оквир се црта на слици користећи црвену линију. На крају, уређена слика се чува, замењујући оригиналну слику. 1. Покрените апликацију са камером усмереном на неке залихе на полици. Видећете фајл `image.jpg` у VS Code прегледачу и моћи ћете да га изаберете како бисте видели оквире. ![4 конзерве парадајз пасте са оквирима око сваке конзерве](../../../../../translated_images/rpi-stock-with-bounding-boxes.b5540e2ecb7cd49f1271828d3be412671d950e87625c5597ea97c90f11e01097.sr.jpg) ## Бројање залиха На приказаној слици, оквири се благо преклапају. Ако би ово преклапање било много веће, оквири би могли указивати на исти објекат. Да бисте правилно избројали објекте, потребно је игнорисати оквире са значајним преклапањем. ### Задатак - бројање залиха игноришући преклапање 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') ``` Преклапање се израчунава користећи Shapely метод `Polygon.intersection` који враћа полигон који представља преклапање. Површина се затим израчунава из овог полигона. Овај праг преклапања није апсолутна вредност, већ мора бити проценат оквира, па се проналази најмањи оквир, а праг преклапања се користи за израчунавање колика површина преклапања може бити да не би премашила дозвољени проценат преклапања најмањег оквира. Ако преклапање премаши ово, предвиђање се означава за брисање. Када је предвиђање означено за брисање, не мора се поново проверавати, па се унутрашња петља прекида како би се проверило следеће предвиђање. Не можете брисати ставке из листе док пролазите кроз њу, па се оквири који се преклапају више од прага додају у листу `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). Иако се трудимо да обезбедимо тачност, молимо вас да имате у виду да аутоматски преводи могу садржати грешке или нетачности. Оригинални документ на његовом изворном језику треба сматрати ауторитативним извором. За критичне информације препоручује се професионални превод од стране људи. Не сносимо одговорност за било каква погрешна тумачења или неспоразуме који могу настати услед коришћења овог превода.