As últimas duas semanas foram difíceis para a nossa equipe. O OpenCV 4 foi lançado e, com ele, eles se prepararam para o kit de ferramentas OpenVINO R4 da Intel , que inclui o OpenCV. Você pensa que estou distraído por um tempo, vou olhar, como sempre, sobre os fóruns do OpenCV e os comentários dos usuários, e aqui ficou moda dizer que o OpenCV não é IoT, que no Raspberry Pi é suficiente montar - não há solda suficiente para colocar make -j2
- de manhã, estará pronto se tiver sorte.
Portanto, proponho juntar as mãos e ver como você pode montar a biblioteca OpenCV para um sistema operacional de 32 bits em execução em um processador ARM usando os recursos de uma máquina com sistema operacional de 64 bits, impulsionada por uma excelente arquitetura de CPU. Feitiçaria Compilação cruzada, não o contrário!
Declaração do problema
Compilar diretamente no quadro, que geralmente é chamado de nativo, é realmente trabalhoso; portanto, consideraremos uma maneira de criar um projeto que permita que dispositivos de computação mais fortes (vamos chamá-los de hosts) preparem binários para seus pequenos parentes. Além disso, ambas as máquinas podem ter arquiteturas de CPU diferentes. Isso é compilação cruzada.
Portanto, para preparar uma torta de framboesa recheada com OpenCV, precisamos:
- Carcaça do docker de imagem do Ubuntu 16.04
- A máquina host é mais poderosa que o Raspberry Pi (caso contrário, qual é o objetivo, não é?)
- Compilador cruzado para ARMhf, bem como bibliotecas da arquitetura correspondente
Todo o processo de criação do OpenCV ocorrerá na máquina host. Eu uso o Ubuntu em casa. Com outra versão do Linux, problemas de reprodução não devem ocorrer. Para usuários do Windows - meus sinceros desejos de não desistir e tentar descobrir por nós mesmos.
Instalar o Docker
Comecei a conhecer o estivador cerca de uma semana atrás, então adicione sal gourmet e açúcar sintático a gosto. Três ingredientes são suficientes para você e para mim - Dockerfile, o conceito de imagem e recipiente.
O Docker em si é uma ferramenta para criar e reproduzir a configuração de qualquer sistema operacional com o conjunto de componentes necessário. Dockerfile é um conjunto de comandos do shell que você geralmente usa na máquina host, mas nesse caso, todos eles se aplicam à chamada imagem do docker
.
Para instalar o docker, considere a maneira mais simples: solicite um pacote através do serviço de entrega apt-get
:
sudo apt-get install -y docker.io
Nós daremos ao daemon do docker tudo o que ele solicitar e faremos logout do sistema (observe o login adequadamente).
sudo usermod -a -G docker $USER
Preparando o Espaço de Trabalho
O Raspberry Pi (no meu caso, o RPI 2 Modelo B) na preparação mais comum é uma CPU ARMv7 com o sistema operacional Raspbian (baseado no Debian). docker
uma imagem do docker
baseada no Ubuntu 16.04, na qual reportaremos o compilador cruzado, as bibliotecas do exército e coletaremos o OpenCV no mesmo local.
Crie um pai onde nosso Dockerfile
estará:
mkdir ubuntu16_armhf_opencv && cd ubuntu16_armhf_opencv touch Dockerfile
Adicione informações sobre o SO base e a arquitetura armhf
para o instalador do pacote apt-get
:
FROM ubuntu:16.04 USER root RUN dpkg --add-architecture armhf RUN apt-get update
Observe que comandos como FROM ...
, RUN ...
são a sintaxe do docker
e são gravados no arquivo de teste do Dockerfile
criado.
Vamos voltar ao diretório pai ubuntu16_armhf_opencv
e tentar criar nossa imagem do docker:
docker image build ubuntu16_armhf_opencv
Durante a execução do comando apt-get update
, você deve ser levado a ver erros do seguinte tipo: Err:[] [url] xenial[-] armhf Packages
Ign:30 http://archive.ubuntu.com/ubuntu xenial-backports/main armhf Packages Ign:32 http://archive.ubuntu.com/ubuntu xenial-backports/universe armhf Packages Err:7 http://archive.ubuntu.com/ubuntu xenial/main armhf Packages 404 Not Found Ign:9 http://archive.ubuntu.com/ubuntu xenial/restricted armhf Packages Ign:18 http://archive.ubuntu.com/ubuntu xenial/universe armhf Packages Ign:20 http://archive.ubuntu.com/ubuntu xenial/multiverse armhf Packages Err:22 http://archive.ubuntu.com/ubuntu xenial-updates/main armhf Packages 404 Not Found Ign:24 http://archive.ubuntu.com/ubuntu xenial-updates/restricted armhf Packages Ign:26 http://archive.ubuntu.com/ubuntu xenial-updates/universe armhf Packages Ign:28 http://archive.ubuntu.com/ubuntu xenial-updates/multiverse armhf Packages Err:30 http://archive.ubuntu.com/ubuntu xenial-backports/main armhf Packages 404 Not Found Ign:32 http://archive.ubuntu.com/ubuntu xenial-backports/universe armhf Packages
Se você observar o arquivo /etc/apt/sources.list
cada erro corresponderá a alguma linha, por exemplo:
Erro
Err:22 http://archive.ubuntu.com/ubuntu xenial-updates/main armhf Packages 404 Not Found
Linha em /etc/apt/sources.list :
deb http://archive.ubuntu.com/ubuntu/ xenial-updates main restricted
Solução :
Divida em dois:
deb [arch=amd64] http://archive.ubuntu.com/ubuntu/ xenial-updates main restricted deb [arch=armhf] http://ports.ubuntu.com/ubuntu-ports/ xenial-updates main restricted
Portanto, você deve substituir várias fontes de pacotes. Em nossa janela de encaixe, substituiremos todos por um comando:
RUN sed -i -E 's|^deb ([^ ]+) (.*)$|deb [arch=amd64] \1 \2\ndeb [arch=armhf] http://ports.ubuntu.com/ubuntu-ports/ \2|' /etc/apt/sources.list
Agora o apt-get update
deve funcionar sem erros.
Colocamos os pacotes necessários
Precisamos fornecer pacotes de host como git
, python-pip
, cmake
e pkg-config
, bem como crossbuild-essential-armhf
, que é um conjunto de cross-compiladores gcc / g ++ ( arm-linux-gnueabihf-gcc
e arm-linux-gnueabihf-g++
) e bibliotecas do sistema da arquitetura correspondente:
RUN apt-get install -y git python-pip cmake pkg-config crossbuild-essential-armhf
Do incomum - também baixamos GTK (usado para desenhar janelas no módulo highgui), GStreamer e Python, mas com uma indicação explícita de uma arquitetura estrangeira:
RUN apt-get install -y --no-install-recommends \ libgtk2.0-dev:armhf \ libpython-dev:armhf \ libgstreamer1.0-dev:armhf \ libgstreamer-plugins-base1.0-dev:armhf \ libgstreamer-plugins-good1.0-dev:armhf \ libgstreamer-plugins-bad1.0-dev:armhf
E então clonamos e coletamos, indicando os sinalizadores necessários:
RUN git clone https://github.com/opencv/opencv --depth 1 RUN mkdir opencv/build && cd opencv/build && \ export PKG_CONFIG_PATH=/usr/lib/arm-linux-gnueabihf/pkgconfig && \ cmake -DCMAKE_BUILD_TYPE=Release \ -DOPENCV_CONFIG_INSTALL_PATH="cmake" \ -DCMAKE_TOOLCHAIN_FILE="../opencv/platforms/linux/arm-gnueabi.toolchain.cmake" \ -DWITH_IPP=OFF \ -DBUILD_TESTS=OFF \ -DBUILD_PERF_TESTS=OFF \ -DOPENCV_ENABLE_PKG_CONFIG=ON \ -DPYTHON2_INCLUDE_PATH="/usr/include/python2.7" \ -DPYTHON2_NUMPY_INCLUDE_DIRS="/usr/local/lib/python2.7/dist-packages/numpy/core/include" \ -DENABLE_NEON=ON \ -DCPU_BASELINE="NEON" ..
onde
CMAKE_TOOLCHAIN_FILE
- o caminho para o arquivo cmake que define o processo de compilação cruzada (define o compilador desejado, restringe o uso de bibliotecas de host.
WITH_IPP=OFF
, - desabilita dependências pesadas.
BUILD_TESTS=OFF
, BUILD_PERF_TESTS=OFF
, desabilite a compilação de teste.
OPENCV_ENABLE_PKG_CONFIG=ON
- para que o pkg-config possa encontrar dependências como GTK. PKG_CONFIG_PATH
é o caminho correto onde o pkg-config
procurará bibliotecas.
PYTHON2_INCLUDE_PATH
, PYTHON2_NUMPY_INCLUDE_DIRS
- caminhos necessários para empacotadores de compilação cruzada para python2.
ENABLE_NEON=ON
, CPU_BASELINE="NEON"
- ativa a otimização NEON.
OPENCV_CONFIG_INSTALL_PATH
- ajusta o local dos arquivos no diretório de install
.
A principal coisa que você deve prestar atenção após a execução do cmake
é que todos os módulos necessários são montados (python2, por exemplo):
-- OpenCV modules: -- To be built: calib3d core dnn features2d flann gapi highgui imgcodecs imgproc java_bindings_generator ml objdetect photo python2 python_bindings_generator stitching ts video videoio -- Disabled: world -- Disabled by dependency: - -- Unavailable: java js python3 -- Applications: tests perf_tests apps -- Documentation: NO -- Non-free algorithms: NO
e as dependências necessárias, como GTK, foram encontradas:
-- GUI: -- GTK+: YES (ver 2.24.30) -- GThread : YES (ver 2.48.2) -- GtkGlExt: NO -- -- Video I/O: -- GStreamer: -- base: YES (ver 1.8.3) -- video: YES (ver 1.8.3) -- app: YES (ver 1.8.3) -- riff: YES (ver 1.8.3) -- pbutils: YES (ver 1.8.3) -- v4l/v4l2: linux/videodev2.h
Tudo o que resta é chamar make
, make install
e aguardar a conclusão da compilação:
Successfully built 4dae6b1a7d32
Use este id
imagem para marcar e criar um contêiner:
docker tag 4dae6b1a7d32 ubuntu16_armhf_opencv:latest docker run ubuntu16_armhf_opencv
E nós apenas temos que bombear o OpenCV montado para fora do contêiner. Primeiro, vejamos o identificador do contêiner criado:
$ docker container ls --all CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES e94667fe60d2 ubuntu16_armhf_opencv "/bin/bash" 6 seconds ago Exited (0) 5 seconds ago clever_yalow
E copie o diretório de instalação com o OpenCV instalado:
docker cp e94667fe60d2:/opencv/build/install/ ./ mv install ocv_install
Ponha a mesa
Copie ocv_install
para o Raspberry Pi, defina os caminhos e tente executar o OpenCV a partir de python.
export LD_LIBRARY_PATH=/path/to/ocv_install/lib/:$LD_LIBRARY_PATH export PYTHONPATH=/path/to/ocv_install/python/:$PYTHONPATH
Execute o exemplo de detecção usando a rede neural MobileNet-SSD em https://github.com/chuanqi305/MobileNet-SSD :
import cv2 as cv print cv.__file__ classes = ['backgroud', 'aeroplane', 'bicycle', 'bird', 'boat', 'bottle', 'bus', 'car', 'cat', 'chair', 'cow', 'diningtable', 'dog', 'horse', 'motorbike', 'person', 'pottedplant', 'sheep', 'sofa', 'train', 'tvmonitor'] cap = cv.VideoCapture(0) net = cv.dnn.readNet('MobileNetSSD_deploy.caffemodel', 'MobileNetSSD_deploy.prototxt') cv.namedWindow('Object detection', cv.WINDOW_NORMAL) while cv.waitKey(1) != 27: hasFrame, frame = cap.read() if not hasFrame: break frame_height, frame_width = frame.shape[0], frame.shape[1] blob = cv.dnn.blobFromImage(frame, scalefactor=0.007843, size=(300, 300), mean=(127.5, 127.5, 127.5)) net.setInput(blob) out = net.forward() for detection in out.reshape(-1, 7): classId = int(detection[1]) confidence = float(detection[2]) xmin = int(detection[3] * frame_width) ymin = int(detection[4] * frame_height) xmax = int(detection[5] * frame_width) ymax = int(detection[6] * frame_height) if confidence > 0.5: cv.rectangle(frame, (xmin, ymin), (xmax, ymax), color=(255, 0, 255), thickness=3) label = '%s: %.2f' % (classes[classId], confidence) labelSize, baseLine = cv.getTextSize(label, cv.FONT_HERSHEY_SIMPLEX, 0.5, 1) ymin = max(ymin, labelSize[1]) cv.rectangle(frame, (xmin, ymin - labelSize[1]), (xmin + labelSize[0], ymin + baseLine), (255, 0, 255), cv.FILLED) cv.putText(frame, label, (xmin, ymin), cv.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 0)) cv.imshow('Object detection', frame)

Isso é tudo, uma montagem completa não leva mais que 20 minutos. Dockerfile
a versão final do Dockerfile
abaixo e, aproveitando esta oportunidade, proponho fazer uma pequena pesquisa da equipe do OpenCV para aqueles que já tiveram experiência com a biblioteca: https://opencv.org/survey-2018.html .
E sim, parabéns pelo OpenCV 4! Este não é apenas o trabalho de uma equipe separada, é o trabalho de toda a comunidade - OpenCV 4 você.
FROM ubuntu:16.04 USER root RUN dpkg --add-architecture armhf RUN sed -i -E 's|^deb ([^ ]+) (.*)$|deb [arch=amd64] \1 \2\ndeb [arch=armhf] http://ports.ubuntu.com/ubuntu-ports/ \2|' /etc/apt/sources.list RUN apt-get update && \ apt-get install -y --no-install-recommends \ cmake \ pkg-config \ crossbuild-essential-armhf \ git \ python-pip \ libgtk2.0-dev:armhf \ libpython-dev:armhf \ libgstreamer1.0-dev:armhf \ libgstreamer-plugins-base1.0-dev:armhf \ libgstreamer-plugins-good1.0-dev:armhf \ libgstreamer-plugins-bad1.0-dev:armhf RUN pip install numpy==1.12.1 RUN git clone https://github.com/opencv/opencv --depth 1 RUN mkdir opencv/build && cd opencv/build && \ export PKG_CONFIG_PATH=/usr/lib/arm-linux-gnueabihf/pkgconfig && \ cmake -DCMAKE_BUILD_TYPE=Release \ -DOPENCV_CONFIG_INSTALL_PATH="cmake" \ -DCMAKE_TOOLCHAIN_FILE="../opencv/platforms/linux/arm-gnueabi.toolchain.cmake" \ -DWITH_IPP=OFF \ -DBUILD_TESTS=OFF \ -DBUILD_PERF_TESTS=OFF \ -DOPENCV_ENABLE_PKG_CONFIG=ON \ -DPYTHON2_INCLUDE_PATH="/usr/include/python2.7" \ -DPYTHON2_NUMPY_INCLUDE_DIRS="/usr/local/lib/python2.7/dist-packages/numpy/core/include" \ -DENABLE_NEON=ON \ -DCPU_BASELINE="NEON" .. && make -j4 && make install