Использование камеры Fish eye на Raspberry Pi 3 с ROS — часть 1

    Добрый день уважаемые читатели Хабра. Несколько лет назад я писал об использовании камеры Raspberry Pi Camera Board на Raspberry Pi в связке с ROS. В этой и следующей статьях я бы хотел рассказать об использовании широкоугольной камеры типа fish eye на Raspberry Pi 3 с установленной Ubuntu 16.04. Кому интересно прошу под кат.

    Для начала почему именно fish eye камера? Я видел много статей об использовании широкоугольных камер для визуальной одометрии и SLAM. Благодаря большему углу обзора fish eye камера повышает точность визуальной одометрии. Поэтому мне захотелось попробовать одну такую камеру с Raspberry Pi с поддержкой ROS. Я купил камеру с углом 160 градусов на dx.com за 28$. В комплект с камерой также входят две IR лампы для ночного видения:

    image

    В первой статье я расскажу об установке необходимых драйверов, OpenCV 3 и пакетов для поддержки камеры Raspberry Pi Camera Board в ROS.

    Установка драйвера камеры fish eye на Raspberry Pi 3


    Итак начнем. Подключимся к RPi 3 по SSH:

    ssh -Y <user>@<ip>
    

    Параметр -Y позволяет решить проблему с получением ошибки “Could not connect to display” при запуске некоторых GUI приложений (Qt, окно с изображением из программы OpenCV). Подробнее можно узнать здесь.

    Для начала нам нужно включить поддержку драйвера камеры в настройках Raspberry Pi raspi-config. В Raspbian эта служба уже включена, в Ubuntu ее нужно установить:

    sudo apt-get install raspi-config
    

    Запустим raspi-config:

    sudo raspi-config
    

    Выберем опцию Interfacing, затем Pi Camera и нажмем Yes. И наконец Finish.
    Проверим, что поддержка камеры включена с помощью утилиты raspistill:

    raspistill -o mypicture.jpg
    

    Если вы получили ошибку “Camera is not detected. Please check carefully the camera module is installed correctly” проверьте, правильно ли вы подключили камеру к Raspberry Pi. Также можно выполнить ребут системы (мне это помогло).

    Попробуем записать видео:

    raspivid -o myvideo.h264
    

    Я получил изображение на мониторе, подключенном к Raspberry Pi. Мне не удалось получить всплывающее окно на моем компьютере при подключении по ssh.

    image

    Использование OpenCV 3 с fish eye камерой на Raspberry Pi


    Установим библиотеку picamera[array]:

    pip install "picamera[array]"
    

    Установим необходимые зависимости для OpenCV. Для начала обновим пакетный менеджер apt и сделаем апгрейд предустановленных пакетов:

    sudo apt-get update
    sudo apt-get upgrade
    

    Установим некоторые библиотеки:

    sudo apt-get install build-essential cmake pkg-config
    
    sudo apt-get install libjpeg8-dev libtiff5-dev libjasper-dev libpng12-dev
    
    sudo apt-get install libavcodec-dev libavformat-dev libswscale-dev libv4l-dev
    sudo apt-get install libxvidcore-dev libx264-dev
    
    sudo apt-get install libgtk-3-dev
    
    sudo apt-get install libatlas-base-dev gfortran
    
    sudo apt-get install python2.7-dev python3.5-dev
    

    Мы установим OpenCV 3 из исходников.

    cd ~
    wget -O opencv.zip https://github.com/Itseez/opencv/archive/3.1.0.zip
    unzip opencv.zip
    

    Нам также необходимо загрузить репозиторий opencv_contrib:

    wget -O opencv_contrib.zip https://github.com/Itseez/opencv_contrib/archive/3.1.0.zip
    unzip opencv_contrib.zip
    

    Дело в том, что в OpenCV 3 пакеты с дескрипторами признаков (такие как SIFT и SURF) были перенесены в отдельный репозиторий contrib. Теперь для использования дескрипторов признаков нам необходимо отдельно скачивать репозиторий contrib.

    Теперь мы наконец-то готовы к установке OpenCV. Мы можем выполнить cmake для компиляции OpenCV с нужными параметрами:

    cd ~/opencv-3.1.0/
    mkdir build
    cd build
    cmake -D CMAKE_BUILD_TYPE=RELEASE \
        -D CMAKE_INSTALL_PREFIX=/usr/local \
        -D INSTALL_PYTHON_EXAMPLES=ON \
        -D INSTALL_C_EXAMPLES=OFF \
        -D OPENCV_EXTRA_MODULES_PATH=~/opencv_contrib-3.1.0/modules \
        -D PYTHON_EXECUTABLE=~/.virtualenvs/cv/bin/python \
        -D BUILD_EXAMPLES=ON ..
    

    Если cmake выполнился без ошибок, выполним make:

    make -j4
    

    При выполнении компиляции я получил ошибку “Segmentation fault”. Если вы получили такую же ошибку, выполните make clean для удаления результатов компиляции и выполните make с одним ядром:

    make clean
    make
    

    У меня процедура компиляции заняла 3 часа. Наконец выполним установку OpenCV 3:

    sudo make install
    sudo ldconfig
    

    Здесь есть интересный нюанс, связанный с ROS Kinetic. Если вы устанавливаете ROS Kinetic, то ROS добавляет путь к библиотекам Python (/opt/ros/kinetic/lib/python2.7/dist-packages) в системный путь при выполнении команды source /opt/ros/kinetic/setup.bash. Это ведет к некоторым проблемам при последующей установке OpenCV из исходников (подробнее об этом написано здесь). Чтобы решить проблему, нужно удалить строку ‘source /opt/ros/kinetic/setup.bash’ из файла .bashrc. Не забудем выполнить:

    source ~/.bashrc
    

    Давайте проверим, что OpenCV теперь корректно линкуется из Python.
    Создадим папку для проекта и простой тестовый скрипт:

    mkdir PiCamera && cd PiCamera
    vim test_cam.py
    

    Добавим следующий код в файл:

    from picamera.array import PiRGBArray                                                                         
    from picamera import PiCamera                                                                                 
    import time                                                                                                   
    import cv2                                                                                                    
                                                                                                                  
    # initialize the camera and reference the raw camera capture                                                  
    camera = PiCamera()                                                                                           
    rawCapture = PiRGBArray(camera)                                                                               
                                                                                                                  
    # allow camera to warmup                                                                                      
    time.sleep(0.1)                                                                                               
                                                                                                                  
    # grab an image                                                                                               
    camera.capture(rawCapture, format="bgr")                                                                      
    image = rawCapture.array                                                                                      
                                                                                                                  
    cv2.imshow("Capture", image)                                                                                  
    cv2.waitKey(0)
    

    Запустим скрипт:

    python test_cam.py
    

    В случае успеха мы получим примерно такую картинку:

    image

    Давайте теперь попробуем записать видео с камеры.

    vim test_videom.py
    

    Добавьте в файл вот такой код:

    # import the necessary packages                                                                               
    from picamera.array import PiRGBArray                                                                         
    from picamera import PiCamera                                                                                 
    import time                                                                                                   
    import cv2                                                                                                    
                                                                                                                  
    # initialize the camera and grab a reference to the raw camera capture                                        
    camera = PiCamera()                                                                                           
    camera.resolution = (640, 480)                                                                                
    camera.framerate = 32                                                                                         
    rawCapture = PiRGBArray(camera, size=(640, 480))                                                              
                                                                                                                  
    # allow the camera to warmup                                                                                  
    time.sleep(0.1)                                                                                               
                                                                                                                  
    # capture frames from the camera                                                                              
    for frame in camera.capture_continuous(rawCapture, format="bgr", use_video_port=True):                        
        # grab the raw NumPy array representing the image, then initialize the timestamp                          
        # and occupied/unoccupied text                                                                            
        image = frame.array                                                                                       
                                                                                                                  
        # show the frame                                                                                          
        cv2.imshow("Frame", image)                                                                                
        key = cv2.waitKey(1) & 0xFF                                                                               
                                                                                                                  
        # clear the stream in preparation for the next frame                                                      
        rawCapture.truncate(0)                                                                                    
                                                                                                                  
        # if the `q` key was pressed, break from the loop                                                         
        if key == ord("q"):                                                                                       
            break
    

    Давайте попробуем что-нибудь поинтереснее, например, добавим детекцию краев. Я здесь использую детектор Кенни (код взят отсюда):

    from picamera.array import PiRGBArray                                                                         
    from picamera import PiCamera                                                                                 
    import time                                                                                                   
    import cv2                                                                                                    
    import numpy as np                                                                                            
                                                                                                                  
    # initialize the camera and grab a reference to the raw camera capture                                        
    camera = PiCamera()                                                                                           
    camera.resolution = (640, 480)                                                                                
    camera.framerate = 32                                                                                         
    rawCapture = PiRGBArray(camera, size=(640, 480))                                                              
                                                                                                                  
                                                                                                                  
    # allow the camera to warmup                                                                                  
    time.sleep(0.1)                                                                                               
                                                                                                                  
    # capture frames from the camera                                                                              
    for frame in camera.capture_continuous(rawCapture, format="bgr", use_video_port=True):                        
        # grab the raw NumPy array representing the image, then initialize the timestamp                          
        # and occupied/unoccupied text                                                                            
        image = frame.array                                                                                       
                                                                                                                  
        hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)                                                              
                                                                                                                  
        lower_red = np.array([30,150,50])                                                                         
        upper_red = np.array([255,255,180])                                                                       
                                                                                                                  
        mask = cv2.inRange(hsv, lower_red, upper_red)                                                             
        res = cv2.bitwise_and(image,image, mask= mask)
        edges = cv2.Canny(res,100,200)                                                                            
        # show the frame                                                                                          
        cv2.imshow("Frame", image)                                                                                
        cv2.imshow("Edges", edges)                                                                                
        key = cv2.waitKey(1) & 0xFF                                                                               
                                                                                                                  
        # clear the stream in preparation for the next frame                                                      
        rawCapture.truncate(0)                                                                                    
                                                                                                                  
        # if the `q` key was pressed, break from the loop                                                         
        if key == ord("q"):                                                                                       
            break
    

    Вот результат запуска программы:

    image

    Добавление поддержки камеры Raspberry Pi Camera в ROS


    Теперь добавим возможность работать с fish eye камерой для Raspberry Pi из ROS. Для начала установим необходимый драйвер V4L2 для Raspberry Pi камеры (можно подробнее прочитать здесь). Выполним команду:

    sudo rpi-update
    

    и сделаем ребут системы. Теперь добавим драйвер:

    sudo modprobe bcm2835-v4l2
    

    Проверим, что устройство /dev/video0 доступно:

    ll /dev/video0
    

    Вывод будет таким:

    crw-rw----+ 1 root video 81, 0 Mar 17 15:47 /dev/video0
    

    Скачаем пакет usb_cam:

    sudo apt-get install ros-kinetic-usb-cam
    source /opt/ros/kinetic/setup.bash
    

    Запустим ROS мастер и rqt_image_view:

    roscore
    roslaunch usb_cam usb_cam-test.launch
    rosrun rqt_image_view rqt_image_view
    

    Выберем топик /usb_cam/image_raw. Мы получим такую картинку:

    image

    Теперь fish eye камеру можно использовать с любыми пакетами компьютерного зрения в ROS. В следующий раз мы попробуем детекцию объектов. Всем удачи в экспериментах и до новых встреч!
    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More
    Ads

    Comments 8

      +3
      На процессоре малины необходимо иметь радиатор, иначе при сборке opencv и при работе перегрев и вылет,
      make -j4
      это явный перебор, можно не пытться, -j2 максимум.
        0
        Странно, по железу прогресс идет полным ходом, а ОС так и осталась в мезазойской эре. Неужели нельзя сделать что бы подключение камеры было как в винде, поставил и все заработало сразу без танцев с бубном?
          0
          Подобные устройства даже в Винде подключаются с танцем с бубном. Это ведь не USB-вебкамера, а совершенно отдельное устройство со своей шиной.

          Конечно можно это все автоматизировать. Но не нужно. Эта автоматизация выльется в лишнее потребление ресурсов, которых на Малинке не так много, а на выхлопе получим упрощение единоразовой задачи одного процента пользователей подобных камер.
            0
            Есть вполне понятная камера, достаточно сделать один файл скрипт в котором все само установится именно под эту камеру. И ничего не нужно руками вводить. Запустил и все подключилось само. Это что, какая то нереальная задача?
            У меня недавно была задача на PI — при запуске что бы открывался браузер с развернутой на весь экран страницей, которая обновлялась бы каждые 15 минут, ночью гас экран а утром включался.
            Я несколько дней потратил что бы этот элементарный алгоритм заработал!!!
            Это ппц просто!
            Не должен человек который в первый раз видит PI столько е… ся что бы решить задачу, которая решается в несколько кликов и без лазания по инету в поисках решения.
            Неправильно это, всего лишь таков мой посыл в сообщении
              +1
              Не не не. Если вы перечитаете статью, то увидите что камера устанавливается всего лишь активацией драйвера утилитой.
              Запустим raspi-config:
              sudo raspi-config
              Выберем опцию Interfacing, затем Pi Camera и нажмем Yes. И наконец Finish


              Все остальное устанавливается для работы проекта, а не для работы камеры.
              Повторюсь, это везде так. Ну можете попробовать подключить, не знаю, SPI-TFT в Windows, и потом на него что-то вывести. Это примерно то же самое.

              У меня недавно была задача на PI — при запуске что бы открывался браузер с развернутой на весь экран страницей, которая обновлялась бы каждые 15 минут, ночью гас экран а утром включался

              Хм, я с таким не сталкивался, но что вам помешало echo 'chromium-browser --kiosk «www.google.com» ' >> ~/.config/lxsession/LXDE/autostart
              А потом crontab -e и
              0 23 * * * echo 0 > /sys/class/backlight/power
              0 7 * * * echo 1 > /sys/class/backlight/power
              Или как там ваш экран включается\выключается?

              Я ничего не гуглил, это первое что на ум пришло. Впрочем Raspberry Pi тут ни при чем. Во-первых, на десктопных Линуксах будет то же самое, а во-вторых, в Винде было бы еще хуже, и хрен бы вы что-то изменили на лету скриптом.
                0
                вот как раз живой пример — так он не выключается :)

                0 23 * * * echo 0 > /sys/class/backlight/power
                0 7 * * * echo 1 > /sys/class/backlight/power
                Или как там ваш экран включается\выключается?

                10 08 * * 0-6 /usr/bin/vcgencmd display_power 1
                10 01 * * 0-6 /usr/bin/vcgencmd display_power 0

                0
                То что ты потратил несколько дней на задачу, которая делается за час это проблема не в RPi или GNU/Linux, а в том, что ты не умеешь читать и делать все по инструкциям
            0
            А тут специально все изображения перевёрнуты?
            Я не спец, извините

            Only users with full accounts can post comments. Log in, please.