Захват картинки с камеры контроллера TXT в OpenCV

Обсуждаем модели и конструкции, построенные своими руками
Ответить
Вася М.
Сообщения: 26
Зарегистрирован: 20 дек 2010, 19:28

Захват картинки с камеры контроллера TXT в OpenCV

Сообщение Вася М. »

Всем привет!

Изучаю возможности библиотеки компьютерного зрения OpenCV и хочу попробовать эту библиотеку на практике. Для начала требуется захватить изображение с камеры, подключенной к контроллеру fischertechnik TXT, и сохранить в файл формата JPG. Язык программирования C++

В заводской прошивке контроллера 4.7.0.0 уже есть библиотеки OpenCV:

Код: Выделить всё

$ ls -la /usr/lib/libopencv*
-rwxr-xr-x    3 root     root       1957676 Sep  4  2019 /usr/lib/libopencv_core.so.4.0
-rwxr-xr-x    1 root     root       2027680 Sep  4  2019 /usr/lib/libopencv_imgcodecs.so.4.0
-rwxr-xr-x    1 root     root       2246340 Sep  4  2019 /usr/lib/libopencv_imgproc.so.4.0
-rwxr-xr-x    2 root     root        133872 Sep  4  2019 /usr/lib/libopencv_videoio.so.4.0
Можете помочь мне разобраться с этой задачей? Хватит ли для этого библиотек, которые уже есть на борту?
IDKFA!
Аватара пользователя
Mr.Kubikus
Сотрудник ПАКПАК
Сообщения: 1020
Зарегистрирован: 22 окт 2010, 23:57

Re: Захват картинки с камеры контроллера TXT в OpenCV

Сообщение Mr.Kubikus »

Для решения вашей задачи понадобятся следующие классы и функции из библиотеки OpenCV:
Классы:
* VideoCapture - класс для захвата видео из файла или видеокамеры
* Mat - класс для хранения и работы с n-мерными массивами
Функции:
* imwrite() - сохраняет изображение в файл

Для сборки вашего приложения надо будет настроить среду для кросс-компиляции. Для этого нужен кросс-компилятор и комплект заголовочных файлов из релиза OpenCV, версия которого совпадает с версией библиотек на борту TXT. Точную версию релиза и конфигурацию сборки OpenCV можно выяснить с помощью программы opencv_version, исходный код которой находится в папке apps/version. Однако разработчики прошивки TXT почему-то не включили эту программу в состав файловой системы контроллера. Мы можем попробовать собрать opencv_version самостоятельно. Для этого надо включить опцию -DBUILD_opencv_apps=ON в параметрах команды cmake.

Я буду собирать OpenCV и opencv_version для контроллера TXT на компьютере с процессором x86-64 и ОС Linux Ubuntu 18.4. Мне понадобятся следующие компоненты:

Кросс-компилятор: gcc-linaro-7.4.1-2019.02-x86_64_arm-linux-gnueabihf

Код: Выделить всё

mkdir -p /opt/tools
wget -P /tmp https://releases.linaro.org/components/toolchain/binaries/7.4-2019.02/arm-linux-gnueabihf/gcc-linaro-7.4.1-2019.02-x86_64_arm-linux-gnueabihf.tar.xz 
tar xf /tmp/gcc-linaro-7.4.1-2019.02-x86_64_arm-linux-gnueabihf.tar.xz -C /opt/tools
Репозитарий проекта OpenCV: https://github.com/opencv/opencv

Код: Выделить всё

git clone https://github.com/opencv/opencv.git -b 4.x
cd opencv
git checkout 4.0.0
Toolchain file для контроллера TXT (txt_toolchain.cmake):

Код: Выделить всё

set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR arm)

set(tools /opt/tools/gcc-linaro-7.4.1-2019.02-x86_64_arm-linux-gnueabihf)
set(CMAKE_C_COMPILER ${tools}/bin/arm-linux-gnueabihf-gcc)
set(CMAKE_CXX_COMPILER ${tools}/bin/arm-linux-gnueabihf-g++)

set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)

set(ARM_LINUX_SYSROOT /usr/include)
set(CMAKE_FIND_ROOT_PATH ${CMAKE_FIND_ROOT_PATH} ${ARM_LINUX_SYSROOT})
Сборка:

Код: Выделить всё

mkdir -p build install
cd build

cmake -D CMAKE_BUILD_TYPE=RELEASE \
            -DCMAKE_TOOLCHAIN_FILE=../txt_toolchain.cmake \
            -DCMAKE_INSTALL_PREFIX=../install \
            -DBUILD_LIST=core,imgcodecs,imgproc,videoio \
            -DBUILD_opencv_java=OFF \
            -DBUILD_opencv_python=OFF \
            -DBUILD_DOCS=OFF \
            -DBUILD_EXAMPLES=OFF \
            -DBUILD_opencv_apps=ON \
            -DBUILD_TESTS=OFF \
            -DBUILD_PERF_TESTS=OFF \
            -DENABLE_VFPV3=ON \
            -DENABLE_NEON=ON \
            -DWITH_V4L=ON \
            ../opencv

make -j$(nproc)
make install
Если сборка завершится успешно, то opencv_version можно найти в папке install/bin
С уважением, Григорий
GitHub FB ВК
Аватара пользователя
Mr.Kubikus
Сотрудник ПАКПАК
Сообщения: 1020
Зарегистрирован: 22 окт 2010, 23:57

Re: Захват картинки с камеры контроллера TXT в OpenCV

Сообщение Mr.Kubikus »

Теперь попробуем запустить opencv_version на контроллере.
Копируем на TXT:

Код: Выделить всё

scp ../install/bin/opencv_version ROBOPro@192.168.7.2:
Подключаемся к консоли TXT через SSH и запускаем opencv_version:

Код: Выделить всё

$ ./opencv_version
./opencv_version: symbol lookup error: ./opencv_version: undefined symbol: _ZN2cv17CommandLineParserC1EiPKPKcRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
Программа завершилась с ошибкой. Похоже, что ОС не может найти определение для символа CommandLineParser, который присутствует в нашем исполняемом файле. Странно. Вроде бы мы собрали программу из ветки 4.0.0, что совпадает с суффиксом в именах разделяемых библиотек OpenCV на борту контроллера. Попробуем разобраться.

Для устранения проблемы проведем небольшое исследование. Для начала выгрузим из контроллера разделяемую библиотеку libopencv_core.4.0 и посмотрим - есть ли в ней символы, в которых присутствует строка "CommandLineParser":

Код: Выделить всё

$ readelf -sW ../../txt4700/libopencv_core.so.4.0  | grep _ZN2cv17CommandLineParserC1Ei
  1420: 00043609   984 FUNC    GLOBAL DEFAULT   11 _ZN2cv17CommandLineParserC1EiPKPKcRKNS_6StringE
 20563: 00043609   984 FUNC    GLOBAL DEFAULT   11 _ZN2cv17CommandLineParserC1EiPKPKcRKNS_6StringE
Теперь посмотрим в библиотеку, которую мы собрали:

Код: Выделить всё

$ readelf -sW ../install/lib/libopencv_core.so.4.0  | grep _ZN2cv17CommandLineParserC1Ei
   262: 00064719  3888 FUNC    GLOBAL DEFAULT   11 _ZN2cv17CommandLineParserC1EiPKPKcRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
 21149: 00064719  3888 FUNC    GLOBAL DEFAULT   11 _ZN2cv17CommandLineParserC1EiPKPKcRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
Видно, что символ CommandLineParser, хранится в декорированном виде - это нормально для С++. Причем декорированные символы отличаются. Если выполнить обратное преобразование, то мы увидим следующие объявления функции CommandLineParser:

Код: Выделить всё

cv::CommandLineParser::CommandLineParser(int, char const* const*, cv::String const&)
cv::CommandLineParser::CommandLineParser(int, char const* const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)
Очевидно, что в TXT находится библиотека, собранная из исходного кода, который отличается от OpenCV 4.0.0. В частности различаются сигнатуры функции CommandLineParser(). Причем в документации к выпуску 4.0.0-alpha указано следующее:

Код: Выделить всё

The standard std::string  and  std::shared_ptr  replaced hand-crafted cv::String  and cv::Ptr
Есть предположение, что библиотека была собрана из "грязной" версии ветки 4.0 еще до выхода 4.0.0-alpha. Чтобы разобраться с путаницей попробуем найти в репозитарии коммит, в котором изменяется объявление типа String.

Тип String объявляется в файле modules/core/include/opencv2/core/cvstd.hpp. Посмотрим историю его изменения:

Код: Выделить всё

$ git log --date=short --pretty=format:'%h %<(20)%an %ad %s' modules/core/include/opencv2/core/cvstd.hpp
15aee09c7f Alexander Alekhin    2018-09-06 core: replace cv::Ptr implementation => std::shared_ptr
7f73b105ca Alexander Alekhin    2018-08-23 core: std::string more changes
ae8dcdf40d Vladislav Sovrasov   2017-05-19 core: get rid of built-in String type
e567135ed3 Alexander Alekhin    2018-03-22 next: force C++11 features unconditionally: CV_CXX_MOVE_SEMANTICS/CV_CXX_STD_ARRAY
2b2fa58f97 Alexander Alekhin    2018-03-22 next: drop DISABLE_OPENCV_24_COMPATIBILITY
71e1889825 Alexander Alekhin    2017-08-17 core: fix memcpy with zero size
2a2a1dc5b4 Vladislav Sovrasov   2017-05-19 Get rid of OPENCV_NOSTL definition
e0393f8557 Maksim Shabunin      2017-06-29 Fixed some issues found by static analysis (4th round)
ff31d069d0 Fangjun KUANG        2017-04-07 avoid allocating memory for string with a length of zero.
9ac9e9e29a Alexander Alekhin    2017-02-09 core: fix String::end() implementation
a34fbf7bb1 sourin               2016-09-30  Fixed identifiers warns
ff0601cda5 Alexander Alekhin    2016-05-30 core: prevent changes in 'std' namespace
dd9da53860 Alexander Alekhin    2015-09-22 disable String(int) ctor
ff8aa6662e Vadim Pisarevsky     2015-08-24 Merge pull request #5201 from alalek:move_semantics
5a0af53683 Alexander Alekhin    2015-08-15 c++ move semantics for cv::Ptr<>
cda9ed449f Alexander Alekhin    2015-08-10 fix some functions for valid processing of empty string content (cstr_==0, len_==0)
decbdd1abb Ying Xiong           2015-03-19 Fix compiler error on std::swap (CUDA7.0/clang/OSX)
c485aee464 Maksim Shabunin      2014-12-18 Included c-headers for better 2.4 compatibility
6aa7a86ae9 Maksim Shabunin      2014-10-31 Doxygen documentation for core module
fc49d33c8d Roman Donchenko      2013-11-21 Gave cv::String appropriate += operators.
461c98fa86 Roman Donchenko      2013-08-13 Replaced Ptr with my new implementation.
4ac2db271d Roman Donchenko      2013-07-25 Removed CV_EXPORTS from all template classes (that I could find).
4692d4b36e Roman Donchenko      2013-07-04 Fix bug: cv::String would break if assigned to itself.
b8ed00bd64 Andrey Kamaev        2013-04-18 Compile OpenCV with GCC visibility set to hidden
940eedfb27 Andrey Kamaev        2013-04-02 Finalize core headers reorganization
3d1d219561 Andrey Kamaev        2013-03-28 Move cv::fastMalloc, cv::fastFree and cv::Ptr out of core.hpp
15f09f8068 Vladislav Vinogradov 2013-03-27 fixed gpu module compilation
78a843e8ac Andrey Kamaev        2013-03-25 Move implementation of cv::String methods out of class definition
14bb4cbe1e Andrey Kamaev        2013-03-20 Add cv::String class
Похоже, что интересующее изменение находится в коммите e8dcdf40d от 2017-05-19 с сообщением "core: get rid of built-in String typ". Попробуем собрать библиотеку из коммита e567135ed3, выполненного перед e8dcdf40d:

Код: Выделить всё

git checkout e567135ed3
Инструкцию по сборке можно найти в предыдущем посте.

После завершения сборки проверим как выглядит декорированное имя функции CommandLineParser():

Код: Выделить всё

$ readelf -sW ../install/lib/libopencv_core.so.4.0  | grep _ZN2cv17CommandLineParserC1Ei
  1341: 0005ea61  2552 FUNC    GLOBAL DEFAULT   11 _ZN2cv17CommandLineParserC1EiPKPKcRKNS_6StringE
 20802: 0005ea61  2552 FUNC    GLOBAL DEFAULT   11 _ZN2cv17CommandLineParserC1EiPKPKcRKNS_6StringE
Теперь декорированное имя совпадает с тем, что мы видим в библиотеке на борту TXT. Можно скопировать приложение opencv_version на TXT и проверить, но я не могу этого сделать, так как в папке install нет opencv_version. Причина в том, что в коммите e567135ed3 в файле CMakeLists.txt указана зависимость от модуля opencv_highgui, который мы убрали из сборки в опции -DBUILD_LIST=core,imgcodecs,imgproc,videoio:

Код: Выделить всё

SET(OPENCV_APPLICATION_DEPS opencv_core opencv_highgui opencv_imgproc opencv_imgcodecs opencv_videoio)
Правалю файл CMakeLists.txt и запускаю сборку еще раз. Теперь программа opencv_version собирается нормально. Копируем на TXT и запускаем:

Код: Выделить всё

$ ./opencv_version -v
OpenCV version : 3.2.0
Major version : 3
Minor version : 2
Subminor version : 0

General configuration for OpenCV 4.0.0-pre =====================================

  Version control:               unknown

  Platform:
    Timestamp:                   2018-04-08T16:26:23Z
    Host:                        Windows 6.1.7601 AMD64
    Target:                      Linux 1
    CMake:                       3.10.0
    CMake generator:             MinGW Makefiles
    CMake build tool:            C:/MinGW/bin/mingw32-make.exe
    Configuration:               Minsizerel

  CPU/HW features:
    Baseline:
      requested:                 DETECT

  C/C++:
    Built as dynamic libs?:      YES
    C++ Compiler:                D:/TXT/toolchain/Linaro2017.11/gcc-linaro-7.2.1-2017.11-i686-mingw32_arm-linux-gnueabihf/bin/arm-linux-gnueabihf-g++.exe  (ver 7.2.1)
    C++ flags (Release):         -fsigned-char -W -Wall -Werror=return-type -Werror=non-virtual-dtor -Werror=address -Werror=sequence-point -Wformat -Werror=format-security -Wmissing-declarations -Wundef -Winit-self -Wpointer-arith -Wshadow -Wsign-promo -Wuninitialized -Winit-self -Wsuggest-override -Wno-narrowing -Wno-delete-non-virtual-dtor -Wno-comment -Wimplicit-fallthrough=3 -fdiagnostics-show-option -pthread -fomit-frame-pointer -ffunction-sections -fdata-sections  -fvisibility=hidden -fvisibility-inlines-hidden -O3 -DNDEBUG  -DNDEBUG
    C++ flags (Debug):           -fsigned-char -W -Wall -Werror=return-type -Werror=non-virtual-dtor -Werror=address -Werror=sequence-point -Wformat -Werror=format-security -Wmissing-declarations -Wundef -Winit-self -Wpointer-arith -Wshadow -Wsign-promo -Wuninitialized -Winit-self -Wsuggest-override -Wno-narrowing -Wno-delete-non-virtual-dtor -Wno-comment -Wimplicit-fallthrough=3 -fdiagnostics-show-option -pthread -fomit-frame-pointer -ffunction-sections -fdata-sections  -fvisibility=hidden -fvisibility-inlines-hidden -g  -O0 -DDEBUG -D_DEBUG
    C Compiler:                  D:/TXT/toolchain/Linaro2017.11/gcc-linaro-7.2.1-2017.11-i686-mingw32_arm-linux-gnueabihf/bin/arm-linux-gnueabihf-gcc.exe
    C flags (Release):           -fsigned-char -W -Wall -Werror=return-type -Werror=non-virtual-dtor -Werror=address -Werror=sequence-point -Wformat -Werror=format-security -Wmissing-declarations -Wmissing-prototypes -Wstrict-prototypes -Wundef -Winit-self -Wpointer-arith -Wshadow -Wuninitialized -Winit-self -Wno-narrowing -Wno-comment -Wimplicit-fallthrough=3 -fdiagnostics-show-option -pthread -fomit-frame-pointer -ffunction-sections -fdata-sections  -fvisibility=hidden -O3 -DNDEBUG  -DNDEBUG
    C flags (Debug):             -fsigned-char -W -Wall -Werror=return-type -Werror=non-virtual-dtor -Werror=address -Werror=sequence-point -Wformat -Werror=format-security -Wmissing-declarations -Wmissing-prototypes -Wstrict-prototypes -Wundef -Winit-self -Wpointer-arith -Wshadow -Wuninitialized -Winit-self -Wno-narrowing -Wno-comment -Wimplicit-fallthrough=3 -fdiagnostics-show-option -pthread -fomit-frame-pointer -ffunction-sections -fdata-sections  -fvisibility=hidden -g  -O0 -DDEBUG -D_DEBUG
    Linker flags (Release):      
    Linker flags (Debug):        
    ccache:                      NO
    Precompiled headers:         NO
    Extra dependencies:          dl m pthread rt
    3rdparty dependencies:

  OpenCV modules:
    To be built:                 calib3d core dnn features2d flann highgui imgcodecs imgproc java_bindings_generator ml objdetect photo python_bindings_generator shape stitching superres ts video videoio videostab
    Disabled:                    js world
    Disabled by dependency:      -
    Unavailable:                 cudaarithm cudabgsegm cudacodec cudafeatures2d cudafilters cudaimgproc cudalegacy cudaobjdetect cudaoptflow cudastereo cudawarping cudev java python2 python3 viz
    Applications:                tests perf_tests apps
    Documentation:               NO
    Non-free algorithms:         NO

  GUI: 
    GTK+:                        NO

  Media I/O: 
    ZLib:                        build (ver 1.2.11)
    JPEG:                        libjpeg-turbo (ver 1.5.3-62)
    WEBP:                        build (ver encoder: 0x020e)
    PNG:                         build (ver 1.6.34)
    TIFF:                        build (ver 42 - 4.0.9)
    JPEG 2000:                   build (ver 1.900.1)
    OpenEXR:                     build (ver 1.7.1)
    HDR:                         YES
    SUNRASTER:                   YES
    PXM:                         YES

  Video I/O:
    DC1394:                      NO
    FFMPEG:                      NO
      avcodec:                   NO
      avformat:                  NO
      avutil:                    NO
      swscale:                   NO
      avresample:                NO
    GStreamer:                   NO
    libv4l/libv4l2:              NO
    v4l/v4l2:                    linux/videodev2.h
    gPhoto2:                     NO

  Parallel framework:            pthreads

  Trace:                         YES (built-in)

  Other third-party libraries:
    Lapack:                      NO
    Custom HAL:                  NO
    Protobuf:                    build (3.5.1)

  NVIDIA CUDA:                   NO

  OpenCL:                        YES (no extra features)
    Include path:                D:/libs_cv/opencv.git/3rdparty/include/opencl/1.2
    Link libraries:              Dynamic load

  Python (for build):            C:/Python27/python.exe

  Matlab:                        NO

  Install to:                    D:/libs_cv/opencv.git_install_linaro2017.11
-----------------------------------------------------------------
С уважением, Григорий
GitHub FB ВК
Аватара пользователя
Mr.Kubikus
Сотрудник ПАКПАК
Сообщения: 1020
Зарегистрирован: 22 окт 2010, 23:57

Re: Захват картинки с камеры контроллера TXT в OpenCV

Сообщение Mr.Kubikus »

Теперь, когда мы знаем какая версия OpenCV установлена в контроллере TXT, можно собрать программу для решения поставленной задачи. Вот исходный код, который захватывает один кадр из потока от видеокамеры и сохраняет его в файл frame.jpg в текущей папке:

Код: Выделить всё

#include <opencv2/opencv.hpp>
#include <iostream>

using namespace cv;
using namespace std;

int main(int, char**)
{
    Mat frame;

    VideoCapture cap;

    cap.open(0, cv::CAP_V4L2);

    if (!cap.isOpened()) {
        cerr << "ERROR! Unable to open camera\n";
        return -1;
    }

    cout << "Set PROP_FOURCC" << endl; 
    bool r = cap.set(cv::CAP_PROP_FOURCC, cv::VideoWriter::fourcc('Y','U','Y','V'));
    if (!r) {
        std::cout << "error cap.set()" << std::endl;
    	return -1;
    }
 
    cap.set(CAP_PROP_FRAME_WIDTH,320);
    cap.set(CAP_PROP_FRAME_HEIGHT,240);
    
    cout << "Camera frame W " << dec << cap.get(CAP_PROP_FRAME_WIDTH);
    cout << "; Camera frame H " << dec << cap.get(CAP_PROP_FRAME_HEIGHT);
    cout << "; Format " << dec << cap.get(CAP_PROP_FORMAT) << endl;

    cout << "Start grabbing" << endl;
    cap.read(frame);
    if (frame.empty()) {
        cerr << "ERROR! blank frame grabbed" << endl;
        return -1;
    } else {
        cout << "I Have a frame!\n";
    }

    cout << "Frame size: W " << frame.cols << ", H " << frame.rows << endl;     
    cout << "Frame channels:" << frame.channels() << endl; 

    if (imwrite("frame.jpg", frame)) {
        cout << "Frame written to file" << endl;
    } else {
        cerr << "ERROR! write to file failed" << endl;
    }

    return 0;
}
Для сборки надо выполнить:

Код: Выделить всё

mkdir build
cd build
cmake -DCMAKE_TOOLCHAIN_FILE=../txt-toolchain.cmake ..
cmake --build .
Копируем opencv-grab на TXT и запускаем:

Код: Выделить всё

$ ./opencv-grab
Set PROP_FOURCC
Camera frame W 320; Camera frame H 240; Format 16
Start grabbing
I Have a frame!
Frame size: W 320, H 240
Frame channels:3
Frame written to file
После запуска в папке должен появиться файл frame.jpg. Кстати, если вы запускали программу из папки /opt/knobloch, то файл frame.jpg можно открыть в браузере через web-интерфейс контроллера http://192.168.7.2/txt/frame.jpg:
-
txt-opencv-cpp-01.jpg
txt-opencv-cpp-01.jpg (58.15 КБ) 11342 просмотра
-
На всякий случай оформил исходники в репозитарий на гитхабе.
С уважением, Григорий
GitHub FB ВК
Вася М.
Сообщения: 26
Зарегистрирован: 20 дек 2010, 19:28

Re: Захват картинки с камеры контроллера TXT в OpenCV

Сообщение Вася М. »

Спасибо за ваш пример на гитхабе! У меня получилось захватить картинку и сохранить в файл на контроллере. Теперь я хотел бы перейти к решению практической задачи в области робототехники. Например, собрать мобильного робота с системой компьютерного зрения (Computer Vision), который ориентируется в пространстве с помощью навигационной линии на поверхности (line follower). Для отладки программы мне надо будет получить доступ к промежуточным этапам обработки изображений. Может быть вы можете порекомендовать какой-либо инструмент или технологию для этого?
IDKFA!
Аватара пользователя
Mr.Kubikus
Сотрудник ПАКПАК
Сообщения: 1020
Зарегистрирован: 22 окт 2010, 23:57

Re: Захват картинки с камеры контроллера TXT в OpenCV

Сообщение Mr.Kubikus »

Отлично! Мне очень приятно, что вам помогла моя рекомендация.
Для отладки программы мне надо будет получить доступ к промежуточным этапам обработки изображений. Может быть вы можете порекомендовать какой-либо инструмент или технологию для этого?
Создайте для нового вопроса отдельную ветку. Продолжим общение в ней.
С уважением, Григорий
GitHub FB ВК
Ответить