Продвинутое обнаружение криволинейных полос с OpenCV
История
Введение
Разметка полос — основа любой системы автономного вождения, безопасно направляющая транспорт через трафик. Опираясь на мой предыдущий проект детекции прямых полос, я разработал надёжный конвейер для криволинейных полос, который надежно работает в сложных условиях: тени, окклюзии, неровности покрытия.
Полный образоперерабатывающий workflow реализован на Python с OpenCV:
- Коррекция дисторсии
- Перспективное преобразование (warp)
- Собел-фильтрация
- Детекция пиков гистограммы
- Скользящий оконный поиск
- Аппроксимация полиномиальной кривой
- Наложение обнаруженной полосы
- Обработка видео в реальном времени
Ограничения предыдущей системы
Ранняя модель ограничивалась прямыми полосами и не справлялась с кривыми, тенями и частичными окклюзиями. Новый конвейер устраняет эти недостатки, включая градиентную фильтрацию и динамический скользящий оконный подход.
Коррекция дисторсии
Объективы камер вводят радиальную дисторсию, искажающую измерения. Калибруя камеру на известном паттерне — обычно асимметричной шахматной доске — мы строим модель дисторсии, корректирующую весь датасет.
Процедура калибровки: захват множества изображений шахматной доски, детекция углов через cv2.findChessboardCorners(), вычисление матрицы камеры и коэффициентов дисторсии через cv2.calibrateCamera(). Исправленные изображения получаются с cv2.undistort().
Ниже показано сравнение до/после на изображении шахматной доски, демонстрирующее тонкое, но критически важное улучшение.
Код калибровки:
def undistort_img():
# Prepare object points 0,0,0 … 8,5,0
obj_pts = np.zeros((6*9,3), np.float32)
obj_pts[:,:2] = np.mgrid[0:9, 0:6].T.reshape(-1,2)
objpoints = []
imgpoints = []
images = glob.glob('camera_cal/*.jpg')
for fname in images:
img = cv2.imread(fname)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, corners = cv2.findChessboardCorners(gray, (9,6), None)
if ret:
objpoints.append(obj_pts)
imgpoints.append(corners)
img_size = (img.shape[1], img.shape[0])
ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(objpoints, imgpoints, img_size, None, None)
dst = cv2.undistort(img, mtx, dist, None, mtx)
dist_pickle = {'mtx': mtx, 'dist': dist}
pickle.dump(dist_pickle, open('camera_cal/cal_pickle.p', 'wb'))
return dst
def undistort(img, cal_dir='camera_cal/cal_pickle.p'):
with open(cal_dir, 'rb') as f:
file = pickle.load(f)
mtx, dist = file['mtx'], file['dist']
return cv2.undistort(img, mtx, dist, None, mtx)
undistort_img()
img = cv2.imread('camera_cal/calibration1.jpg')
dst = undistort(img)
Функции также доступны в сопровождающем Jupyter notebook в разделе Code.
Пример коррекции дисторсии на дорожной сцене. Хотя визуальная разница невелика, точная геометрия критична для последующей обработки.
Перспективное преобразование (Perspective Warp)
Детекция кривых полос прямо в камерном пространстве сложна. Преобразуя изображение в «видов с птичьего полёта», можно предположить, что полоса лежит в плоскости и подогнать полином с высокой точностью.
Трансформация выполняется через cv2.getPerspectiveTransform() и cv2.warpPerspective(). Исходные и целевые точки выбраны для сохранения геометрии полосы при максимальной видимости.
def perspective_warp(img, dst_size=(1280,720), src=np.float32([(0.43,0.65),(0.58,0.65),(0.1,1),(1,1)]), dst=np.float32([(0,0),(1,0),(0,1),(1,1)])):
img_size = np.float32([img.shape[1], img.shape[0]])
src = src * img_size
dst = dst * np.float32(dst_size)
M = cv2.getPerspectiveTransform(src, dst)
return cv2.warpPerspective(img, M, dst_size)
Собел-фильтрация (Sobel Filtering)
Цветовая фильтрация وحدها может ошибочно классифицировать светлый бетон как разметку. Вместо этого используем градиентное обнаружение краёв. Оператор Собеля вычисляет горизонтальные градиенты в цветовом пространстве HLS, выделяя высококонтрастные края полос и подавляя дорожное покрытие.
Полученная бинарная маска устойчива к вариациям освещения и служит входом для скользящего оконного поиска.
Детекция пиков гистограммы
Перед применением скользящего окна определяем приблизительные горизонтальные позиции полос, вычисляя гистограмму бинарного изображения по оси X. Наибольшие пики с каждой стороны соответствуют базовым точкам левой и правой полос.
Скользящий оконный поиск
Используя базовые точки, алгоритм скользящего окна итеративно собирает индексы пикселей, принадлежащих каждой полосе. Затем подгоняет полином второй степени к каждой полосе, позволяя точно оценить кривизну и положение автомобиля относительно центра полосы.
Финальный оверлей отображает область обнаруженной полосы, кривизну и смещение автомобиля в реальном времени.
Читать подробнее: Curved Lane Detection
Производственный процесс
- Ультразвуковой датчик расстояния на базе 8051: проектирование, схема и применения
- Системы обнаружения вторжений (IDS): защита сети с умными алертами
- Фотоэлектрические датчики Omron E3AS-F достигают детекции Time-of-Flight на 1,5 метра
- Hydra3D ToF сенсор доставляет быстрый, точный 3D детект для промышленных и наружных применений
- AEye представляет дальнодействующий лидар, детектирующий автомобили до 1000 м для автономных транспортных средс…
- Система сигнализации с детектором движения на Java и Reactive Blocks — Развертывание на Raspberry Pi и отправка SMS
- Farmaid: Автономный робот для точного обнаружения и маркировки болезней растений
- Интеграция Microsoft Kinect с Raspberry Pi для детекции людей в реальном времени на роботе Sonbi
- Использование микрочипной технологии для детекции геновой экспрессии в клинических исследованиях
- Точное фрезерование криволинейных поверхностей на ЧПУ: технология и лучшие практики