
بمجرد أن أحتاج إلى تحليل المعلومات من الصورة وعند الإخراج للحصول على نوع الكائن ونوعه ، وكذلك تحليل مجمل الإطارات ، كنت بحاجة لإعطاء معرف الكائن والوقت الذي يقضيه في الإطار ، كان من الضروري تحديد كيفية تحرك الكائن والكاميرات التي ظهرت. لنبدأ ، ربما ، مع الأولين ، سيتم مناقشة تحليل الموظفين في المجموع في الجزء التالي.
حسنًا ، سنصف بمزيد من التفصيل مهامنا:
- إصلاح الأشخاص والسيارات - حددهم في الصورة وإنشاء مثيلات الفصل المقابلة مع الحقول الضرورية.
- حدد عدد السيارة ، إذا سقط في إطار كاميرا معينة
- قارن الإطار الحالي بالإطار السابق من أجل تحقيق المساواة في الكائنات ، حتى نتمكن من معرفة ذلك
حسناً ، لقد فكرت وأخذت ثعبان سميك ، ثعبان ، وهذا يعني. تقرر استخدام شبكة Mask R-Cnn العصبية فيما يتعلق ببساطتها وميزاتها الحديثة . أيضًا ، بالطبع ، سوف نستخدم OpenCV لمعالجة الصور.
إعداد البيئة
سنستخدم نظام التشغيل Windows 10 ، لأنك على الأرجح ستستخدمه.
من المعلوم أن لديك بالفعل 64 بت بيثون. إذا لم يكن كذلك ، فيمكنك تنزيل الحزمة ، على سبيل المثال ، من هنا
حزمة التثبيت
git clone https://github.com/matterport/Mask_RCNN cd Mask_RCNN pip3 install -r requirements.txt python3 setup.py install
إذا تعذر الترجمة من مصدر لسبب ما ، فهناك إصدار من النقطة:
pip3 install mrcnn --user
الحزمة ، بالطبع ، تأتي مع كل التبعيات .
المرحلة 1. إنشاء أداة التعرف بسيطة.
سنجعل الواردات اللازمة
import os import cv2 import mrcnn.config import mrcnn from mrcnn.model import MaskRCNN
تتطلب الشبكة العصبية إنشاء تكوين مع الحقول التي تم تجاوزها
class MaskRCNNConfig(mrcnn.config.Config): NAME = "coco_pretrained_model_config" GPU_COUNT = 1 IMAGES_PER_GPU = 1 DETECTION_MIN_CONFIDENCE = 0.8
أشر إلى موقع الملف مع المقاييس. واسمحوا في هذا المثال سيكون في المجلد مع هذا الملف. إذا لم يكن كذلك ، فسيتم تنزيله.
import mrcnn.utils DATASET_FILE = "mask_rcnn_coco.h5" if not os.path.exists(DATASET_FILE): mrcnn.utils.download_trained_weights(DATASET_FILE)
لنقم بإنشاء نموذجنا بالإعدادات المذكورة أعلاه
model = MaskRCNN(mode="inference", model_dir="logs", config=MaskRCNNConfig()) model.load_weights(DATASET_FILE, by_name=True)
وربما سنبدأ في معالجة جميع الصور في دليل images
في الدليل الحالي.
IMAGE_DIR = os.path.join(os.getcwd(), "images") for filename in os.listdir(IMAGE_DIR): image = cv2.imread(os.path.join(IMAGE_DIR, filename)) rgb_image = image[:, :, ::-1] detections = model.detect([rgb_image], verbose=1)[0]
ماذا سوف نرى في الاكتشافات؟
print(detections)
على سبيل المثال ، شيء مشابه:
{'rois': array([[ 303, 649, 542, 1176],[ 405, 2, 701, 319]]), 'class_ids': array([3, 3]), 'scores': array([0.99896, 0.99770015], dtype=float32), 'masks': array()}
في هذه الحالة ، تم العثور على 2 الكائنات.
rois
- صفائف إحداثيات الزاوية اليمنى السفلى والسفلية اليمنى
class_ids
هي المعرفات العددية للكائنات التي تم العثور عليها ، بينما نحتاج إلى معرفة أن 1 شخص ، و 3 عبارة عن سيارة ، و 8 عبارة عن شاحنة.
scores
- بقدر ما يكون النموذج واثقًا في الحل ، يمكن DETECTION_MIN_CONFIDENCE
هذه المعلمة من خلال DETECTION_MIN_CONFIDENCE
في التكوين ، مع إيقاف جميع الخيارات غير المناسبة.
masks
- محيط الكائن. يتم استخدام البيانات لرسم قناع كائن. لأن إنهم كثيرون للغاية ، وليسوا مخصصين لفهم الإنسان ؛ ولن أذكرهم في المقال.
حسنًا ، يمكن أن نتوقف عند هذا الحد ، لكننا نريد أن ننظر إلى الصورة التي ترشدك إلى استخدام الشبكات العصبية ذات الأجسام المختارة بشكل جميل عادة ما نعطيه؟
سيكون من الأسهل استدعاء الدالة mrcnn.visualize.display_instances
، لكننا لن نفعل ذلك ، وسوف نكتب الخاصة بنا.
سوف تأخذ وظيفة صورة ، والمعلمات الرئيسية التي تم الحصول عليها من القاموس من الخطوات الأولى.
def visualize_detections(image, masks, boxes, class_ids, scores): import numpy as np bgr_image = image[:, :, ::-1] CLASS_NAMES = ['BG',"person", "bicycle", "car", "motorcycle", "bus", "truck"] COLORS = mrcnn.visualize.random_colors(len(CLASS_NAMES)) for i in range(boxes.shape[0]): y1, x1, y2, x2 = boxes[i] classID = class_ids[i] label = CLASS_NAMES[classID] font = cv2.FONT_HERSHEY_DUPLEX color = [int(c) for c in np.array(COLORS[classID]) * 255] text = "{}: {:.3f}".format(label, scores[i]) size = 0.8 width = 2 cv2.rectangle(bgr_image, (x1, y1), (x2, y2), color, width) cv2.putText(bgr_image, text, (x1, y1-20), font, size, color, width)

على الرغم من أن إحدى المزايا الرئيسية لهذه الشبكة العصبية هي حل مشكلات تجزئة مثيل - الحصول على حدود الكائنات ، لم نستخدمها بعد ، لكننا سنحللها.
لتطبيق الأقنعة ، أضف سطرين قبل رسم مستطيل لكل كائن تم العثور عليه.
mask = masks[:, :, i]
النتيجة:

المرحلة الثانية. النجاحات الأولى. الاعتراف بأعداد السيارات.
من أجل الاعتراف ، نحتاج إلى إطار واضح للسيارة القريبة ، لذلك تقرر أخذ إطارات فقط من نقطة التفتيش ، ثم مقارنتها بالتشابه (المزيد حول ذلك في الفصل التالي). هذه الطريقة ، ومع ذلك ، يعطي الكثير من عدم الدقة ، لأنه يمكن أن تكون الأجهزة متشابهة للغاية بصريًا ولا يمكن لخوارزمي تجنب مثل هذه الحالات.
تقرر استخدام lib الجاهزة من الشركة المصنعة الأوكرانية nomeroff-net (وليس الإعلان). لأن يمكن العثور على كل الشفرة تقريبًا في أمثلة النموذج ، ثم لن أقدم وصفًا كاملاً.
لا أستطيع إلا أن أقول إن هذه الوظيفة يمكن أن تبدأ بالصورة الأصلية أو أن الجهاز المعترف به يمكن قطعه عن الإطار وتمريره إلى هذه الوظيفة.
import sys import matplotlib.image as mpimg import os sys.path.append(cfg.NOMEROFF_NET_DIR) from NomeroffNet import filters, RectDetector, TextDetector, OptionsDetector, Detector, textPostprocessing nnet = Detector(cfg.MASK_RCNN_DIR, cfg.MASK_RCNN_LOG_DIR) nnet.loadModel("latest") rectDetector = RectDetector() optionsDetector = OptionsDetector() optionsDetector.load("latest") textDetector = TextDetector.get_static_module("ru")() textDetector.load("latest") def detectCarNumber(imgPath: str) -> str: img = mpimg.imread(imgPath) NP = nnet.detect([img]) cvImgMasks = filters.cv_img_mask(NP) arrPoints = rectDetector.detect(cvImgMasks) zones = rectDetector.get_cv_zonesBGR(img, arrPoints) regionIds, stateIds, _c = optionsDetector.predict(zones) regionNames = optionsDetector.getRegionLabels(regionIds)
سيمثل textArr الناتج مجموعة من السلاسل مع أرقام الأجهزة الموجودة على الإطار ، على سبيل المثال:
["293163"]
أو [""]
، []
- إذا لم يتم العثور على أرقام مطابقة.
المرحلة الثالثة. تحديد الأشياء عن طريق التشابه.
نحن الآن بحاجة إلى فهم كيفية إصلاح كائن مرة واحدة ، لفهم أنه في الإطار التالي. في هذه المرحلة ، سوف نفترض أن لدينا كاميرا واحدة فقط وسوف نميز فقط بين إطارات مختلفة عنها.
للقيام بذلك ، تحتاج إلى معرفة كيف سنقارن بين الكائنين.
سوف أقترح خوارزمية فرزت لهذه الأغراض. نحن نحتفظ بأنه ليس جزءًا من الجزء الرئيسي من OpenCV ، لذلك نحن بحاجة إلى تقديم وحدات المساهمة بشكل إضافي. لسوء الحظ ، الخوارزمية حاصلة على براءة اختراع واستخدامها في البرامج التجارية محدود. لكننا نركز على الأنشطة البحثية ، أليس كذلك؟
pip3 install opencv-contrib-python --user
~~ الزائد المشغل == ~~ نكتب وظيفة تأخذ 2 الكائنات مقارنة في شكل المصفوفات. على سبيل المثال ، نحصل عليها بعد استدعاء الدالة cv2.open(path)
سنكتب تنفيذ خوارزمية لدينا.
def compareImages(img1, img2) -> bool: sift = cv2.xfeatures2d.SIFT_create()
ابحث عن النقاط الرئيسية والأوصاف باستخدام SIFT. ربما لن أقدم مساعدة لهذه الوظائف ، لأنه يمكنك دائمًا help(somefunc)
في الغلاف التفاعلي help(somefunc)
kp1, des1 = sift.detectAndCompute(img1, None) kp2, des2 = sift.detectAndCompute(img2, None)
إعداد الخوارزمية لدينا.
FLANN_INDEX_KDTREE = 0 indexParams = dict(algorithm=FLANN_INDEX_KDTREE, trees=5) searchParams = dict(checks=50) flann = cv2.FlannBasedMatcher(indexParams, searchParams)
الآن تشغيله.
matches = flann.knnMatch(des1, des2, k=2)
عد أوجه التشابه بين الصور.
matchesCount = 0 for m, n in matches: if m.distance < cfg.cencitivity*n.distance: matchesCount += 1 return matchesCount > cfg.MIN_MATCH_COUNT
الآن ، حاول استخدامه
للقيام بذلك ، بعد اكتشاف الكائنات ، نحتاج إلى قطعها عن الصورة الأصلية
لم أتمكن من كتابة أي شيء أفضل من حفظه للذاكرة البطيئة ، ثم قرأ من هناك.
def extractObjects(objects, binaryImage, outputImageDirectory, filename=None): for item in objects: y1, x1, y2, x2 = item.coordinates
الآن لدينا الكائنات في <outputImageDirectory>/objectsOn<imageFilename>
الآن ، إذا كان لدينا دليلان على الأقل ، فيمكننا مقارنة الكائنات الموجودة بها. قم بتشغيل الوظيفة المكتوبة مسبقًا
if compareImages(previousObjects, currentObjects): print(“ !”)
أو يمكننا القيام بعمل آخر ، مثل تعليم هذه الكائنات بنفس المعرف.
بالطبع ، مثل كل الشبكات العصبية ، تميل هذه الشبكة إلى إعطاء نتائج خاطئة في بعض الأحيان.
بشكل عام ، أكملنا المهام الثلاث التي تم تعيينها في البداية ، لذلك سننتهي. أشك في أن هذه المقالة فتحت عيون الأشخاص الذين كتبوا برنامجًا واحدًا على الأقل يحل مشاكل التعرف على الصور / تجزئة الصورة ، لكنني آمل أن ساعدت مطورًا مبتدئًا واحدًا على الأقل).
يمكن العثور على الكود المصدري الكامل للمشروع هنا .