# شمارش موجودی با دستگاه IoT - سخت‌افزار مجازی IoT و رزبری پای ترکیبی از پیش‌بینی‌ها و جعبه‌های محدودکننده می‌تواند برای شمارش موجودی در یک تصویر استفاده شود. ## نمایش جعبه‌های محدودکننده به عنوان یک مرحله مفید برای اشکال‌زدایی، می‌توانید نه تنها جعبه‌های محدودکننده را چاپ کنید، بلکه می‌توانید آن‌ها را روی تصویری که هنگام ثبت تصویر در دیسک ذخیره شده است، رسم کنید. ### وظیفه - چاپ جعبه‌های محدودکننده 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.fa.jpg) ## شمارش موجودی در تصویر بالا، جعبه‌های محدودکننده کمی هم‌پوشانی دارند. اگر این هم‌پوشانی بسیار بیشتر بود، ممکن بود جعبه‌های محدودکننده نشان‌دهنده یک شیء یکسان باشند. برای شمارش صحیح اشیاء، باید جعبه‌هایی که هم‌پوشانی قابل‌توجهی دارند را نادیده بگیرید. ### وظیفه - شمارش موجودی با نادیده گرفتن هم‌پوشانی 1. بسته Pip به نام [Shapely](https://pypi.org/project/Shapely/) می‌تواند برای محاسبه تقاطع استفاده شود. اگر از یک رزبری پای استفاده می‌کنید، ابتدا باید یک وابستگی کتابخانه‌ای را نصب کنید: ```sh sudo apt install libgeos-dev ``` 1. بسته Shapely را نصب کنید: ```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) ترجمه شده است. در حالی که ما تلاش می‌کنیم دقت را حفظ کنیم، لطفاً توجه داشته باشید که ترجمه‌های خودکار ممکن است شامل خطاها یا نادرستی‌ها باشند. سند اصلی به زبان اصلی آن باید به عنوان منبع معتبر در نظر گرفته شود. برای اطلاعات حساس، ترجمه حرفه‌ای انسانی توصیه می‌شود. ما مسئولیتی در قبال سوء تفاهم‌ها یا تفسیرهای نادرست ناشی از استفاده از این ترجمه نداریم.