خط OpenCV التالي

الآن دورات شعبية للغاية في إنشاء الطيار الآلي للسيارات. هذه الدرجة النانوية من Udacity هي الخيار الأكثر شهرة.

كثير من الناس يتعلمون منه وينشرون قراراتهم. أنا أيضاً لم أستطع المرور وحمل.

الفرق هو أن الدورة تتضمن تطوير خوارزمية تستند إلى البيانات المقدمة ، وفعلت كل شيء للروبوت الخاص بي .

المهمة الأولى التي يواجهها طلاب الدورة عند دراسة رؤية الكمبيوتر هي اتباع الخط على الطريق. تمت كتابة العديد من المقالات حول هذا الموضوع ، فيما يلي بعض من أكثرها تفصيلاً:


كلها بسيطة للغاية ويتم تخفيض مخطط العمل إلى عدة نقاط:


قمت بلصق الشريط الأبيض على الأرض وذهبت إلى العمل.



في الأعمال التي ذكرتها ، كانت المهمة أيضًا هي العثور على الخط الأصفر ، لذلك عملوا مع ألوان HLS و HSV. نظرًا لأن خطي كان أبيض فقط ، فقد قررت ألا أزعجك بهذا وأقصر نفسي على مرشح أبيض وأسود.

الهندسة


بدأت مشاكل الهندسة على الفور. بالنسبة للطلاب في الصور ، ينتقل الشريط مع السهم إلى الأفق. ومع ذلك ، تم اكتشاف الكثير من الخطوط عليه ، والتي كان على المؤلفين دمجها. ومع ذلك ، كانت خطوطهم موجهة بشكل جيد ولم يكن هناك حطام في الصور.

لدي صورة مختلفة تماما. كانت هندسة شريط الشريط الكهربائي بعيدة عن المستقيمة. تولد الوهج على الأرض ضوضاء.

بعد تطبيق Canny ، هذا ما حدث:



وكانت خطوط هوغ على هذا النحو:

الصورة

من خلال تعزيز المعايير ، كان من الممكن استبعاد القمامة ، ولكن اختفت جميع الخطوط الموجودة على الشريط تقريبًا. الاعتماد على مثل هذه الأجزاء الصغيرة سيكون من الغباء.



بشكل عام ، كانت النتائج غير مستقرة للغاية ، وحدث لي تجربة طريقة مختلفة.

بدلاً من الخطوط ، بدأت في البحث عن الخطوط. بعد أن افترضنا أن الدائرة الأكبر هي الشريط الكهربائي ، تمكنا من التخلص من القمامة. (ثم ​​اتضح أن اللوح الأبيض الكبير يشغل مساحة أكبر في الإطار من الشريط الكهربائي. كان علي أن أغطيه بوسادة أريكة).
إذا أخذنا الحد الأدنى من المستطيل المحيط بالكفاف ، فإن الخط الطولي الأوسط مناسب تمامًا لدور ناقل الحركة.



النور


المشكلة الثانية كانت الإضاءة. لقد نجحت في وضع جانب واحد من المسار في ظل الأريكة وكان من المستحيل تمامًا معالجة صور المسار بأكمله بنفس الإعدادات. ونتيجة لذلك ، اضطررت إلى تنفيذ قطع ديناميكي على مرشح أبيض وأسود. الخوارزمية هي: إذا كان هناك الكثير من اللون الأبيض (أكثر من 10 ٪) بعد تطبيق المرشح في الصورة ، فيجب رفع الحد الأدنى. إذا كان قليلًا جدًا (أقل من 3٪) - احذف. وقد أظهرت الممارسة أنه في المتوسط ​​لمدة 3-4 التكرارات ، من الممكن العثور على الحد الأمثل.

يتم وضع الأرقام السحرية في تكوين منفصل (انظر أدناه) ، يمكنك اللعب معهم بحثًا عن الأمثل.

def balance_pic(image): global T ret = None direction = 0 for i in range(0, tconf.th_iterations): rc, gray = cv.threshold(image, T, 255, 0) crop = Roi.crop_roi(gray) nwh = cv.countNonZero(crop) perc = int(100 * nwh / Roi.get_area()) logging.debug(("balance attempt", i, T, perc)) if perc > tconf.white_max: if T > tconf.threshold_max: break if direction == -1: ret = crop break T += 10 direction = 1 elif perc < tconf.white_min: if T < tconf.threshold_min: break if direction == 1: ret = crop break T -= 10 direction = -1 else: ret = crop break return ret 

بعد تعديل رؤية الماكينة ، كان من الممكن الانتقال إلى الحركة الفعلية. كانت الخوارزمية كما يلي:

  • 0.5 ثانية تدفع مباشرة
  • التقاط صورة
  • ابحث عن المتجه
  • إذا تحولت بداية المتجه بالنسبة لمركز الصورة ، فإننا نركب سيارات الأجرة قليلاً في الاتجاه الصحيح
  • إذا انحرفت زاوية ميل المتجه عن العمودي أكثر من اللازم - فنحن نسير في الاتجاه الصحيح
  • إذا حدث فجأة اختفاء الشريط من الإطار ، فنحن نفترض أننا قدنا منعطفًا وبدأنا في الدوران في اتجاه آخر توجيه أو إمالة للمتجه في الخطوة السابقة

نسخة مختصرة من الكود (كامل - على جيثب ):

 def check_shift_turn(angle, shift): turn_state = 0 if angle < tconf.turn_angle or angle > 180 - tconf.turn_angle: turn_state = np.sign(90 - angle) shift_state = 0 if abs(shift) > tconf.shift_max: shift_state = np.sign(shift) return turn_state, shift_state def get_turn(turn_state, shift_state): turn_dir = 0 turn_val = 0 if shift_state != 0: turn_dir = shift_state turn_val = tconf.shift_step if shift_state != turn_state else tconf.turn_step elif turn_state != 0: turn_dir = turn_state turn_val = tconf.turn_step return turn_dir, turn_val def follow(iterations): tanq.set_motors("ff") try: last_turn = 0 last_angle = 0 for i in range(0, iterations): a, shift = get_vector() if a is None: if last_turn != 0: a, shift = find_line(last_turn) if a is None: break elif last_angle != 0: logging.debug(("Looking for line by angle", last_angle)) turn(np.sign(90 - last_angle), tconf.turn_step) continue else: break turn_state, shift_state = check_shift_turn(a, shift) turn_dir, turn_val = get_turn(turn_state, shift_state) if turn_dir != 0: turn(turn_dir, turn_val) last_turn = turn_dir else: time.sleep(tconf.straight_run) last_turn = 0 last_angle = a finally: tanq.set_motors("ss") 

النتائج


بشكل غير متساو ، ولكن من المؤكد أن الخزان يزحف على طول المسار:



وهنا صورة GIF من رسومات التصحيح:



إعدادات الخوارزمية


 ## Picture settings # initial grayscale threshold threshold = 120 # max grayscale threshold threshold_max = 180 #min grayscale threshold threshold_min = 40 # iterations to find balanced threshold th_iterations = 10 # min % of white in roi white_min=3 # max % of white in roi white_max=12 ## Driving settings # line angle to make a turn turn_angle = 45 # line shift to make an adjustment shift_max = 20 # turning time of shift adjustment shift_step = 0.125 # turning time of turn turn_step = 0.25 # time of straight run straight_run = 0.5 # attempts to find the line if lost find_turn_attempts = 5 # turn step to find the line if lost find_turn_step = 0.2 # max # of iterations of the whole tracking max_steps = 100 

كود جيثب .

Source: https://habr.com/ru/post/ar426675/


All Articles