Sekarang kursus yang sangat populer tentang cara membuat pilot otomatis untuk mobil.
Gelar nano dari Udacity ini mungkin adalah opsi yang paling terkenal.
Banyak orang belajar darinya dan memposting keputusan mereka. Saya juga tidak bisa lewat dan terbawa.
Perbedaannya adalah bahwa kursus melibatkan pengembangan algoritma berdasarkan data yang diberikan, dan saya melakukan segalanya untuk
robot saya .
Tugas pertama yang siswa hadapi ketika mempelajari visi komputer adalah mengikuti garis di jalan. Banyak artikel telah ditulis tentang topik ini, berikut adalah beberapa yang paling rinci:
Semuanya cukup sederhana dan skema kerjanya dikurangi menjadi beberapa poin:
Saya menempelkan selotip putih ke lantai dan turun ke bisnis.

Dalam karya yang disebutkan di atas, tugas Anda adalah menemukan garis kuning, sehingga mereka bekerja dengan warna HLS dan HSV. Karena garis saya hanya putih, saya memutuskan untuk tidak repot-repot dengan ini dan membatasi diri pada filter hitam dan putih.
Geometri
Masalah dengan geometri segera dimulai. Untuk siswa dalam gambar, garis dengan panah masuk ke cakrawala. Dan masih, banyak garis terdeteksi di sana, yang harus digabungkan oleh penulis. Namun, garis mereka diarahkan dengan baik dan tidak ada puing-puing dalam gambar.
Saya memiliki gambaran yang sangat berbeda. Geometri strip pita listrik jauh dari lurus. Melotot di lantai menimbulkan kebisingan.
Setelah menerapkan Canny, inilah yang terjadi:

Dan garis Hough seperti ini

Memperkuat kriteria, adalah mungkin untuk mengecualikan sampah, tetapi hampir semua garis yang ditemukan di strip menghilang. Mengandalkan segmen sekecil itu akan bodoh.

Secara umum, hasilnya sangat tidak stabil, dan terpikir oleh saya untuk mencoba pendekatan yang berbeda.
Alih-alih garis, saya mulai mencari kontur. Setelah membuat asumsi bahwa rangkaian terbesar adalah pita listrik, kami berhasil membuang sampah. (Kemudian ternyata alas tiang putih besar menempati lebih banyak ruang dalam bingkai daripada pita listrik. Saya harus menutupinya dengan bantal sofa).
Jika kita mengambil persegi panjang minimal yang membatasi kontur, maka garis longitudinal tengah sangat cocok untuk peran vektor gerak.

Cahaya
Masalah kedua adalah pencahayaan. Saya sangat berhasil meletakkan satu sisi trek di bawah bayangan sofa dan sama sekali tidak mungkin untuk memproses foto seluruh trek dengan pengaturan yang sama. Akibatnya, saya harus menerapkan cutoff dinamis pada filter hitam dan putih. Algoritmanya adalah ini: jika setelah menerapkan filter dalam gambar terlalu banyak putih (lebih dari 10%), maka ambang harus dinaikkan. Jika terlalu sedikit (kurang dari 3%) - hilangkan. Praktek telah menunjukkan bahwa rata-rata untuk 3-4 iterasi dimungkinkan untuk menemukan cutoff optimal.
Angka ajaib ditempatkan dalam konfigurasi terpisah (lihat di bawah), Anda dapat bermain dengannya untuk mencari yang optimal.
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
Setelah menyesuaikan visi alat berat, dimungkinkan untuk beralih ke gerakan yang sebenarnya. Algoritma itu adalah sebagai berikut:
- 0,5 detik berkendara lurus
- ambil gambar
- temukan vektor
- jika awal vektor bergeser relatif ke tengah gambar, kami sedikit taksi
- jika sudut kemiringan vektor menyimpang dari vertikal lebih dari yang diperlukan - kita mengarahkan ke arah yang benar
- jika tiba-tiba strip itu menghilang dari bingkai, kita membuat asumsi bahwa kita mengendarai belokan dan mulai berbelok ke arah setir terakhir atau kemiringan vektor pada langkah sebelumnya
Versi
singkat dari kode (Full-on
Github ):
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")
Hasil
Tidak rata, tetapi percaya diri, tangki merangkak di sepanjang lintasan:

Dan berikut ini adalah GIF dari grafik debugging:

Pengaturan Algoritma
Kode
github .