8ヶ月ぶりの更新; Raspberry Pi2 で OpenCV をクロス環境で動かしてみる
遅まきながら Raspberry Pi2 を購入して嬉しくなったので、Ubuntu 14.04LTS 上にクロス環境を構築して OpenCV のカメラキャプチャプログラムを動かしてみた。
意外にどはまったので、忘れないようにメモしておきます。
クロスコンパイラは
git clone https://github.com/raspberrypi/tools.git
から gcc 4.8.3(だっけ?)を取得しておきます。
今回は最小限の労力でライブラリを動かしたいため、OpenCV は最新版ではなく、apt-get install libopencv-dev で取得できるバージョンを使用。
(たぶん 2.4.1。古いっ)
これを Ubuntu 側に rsync で吸いだしておきます。
rsync -auv /lib xx.xx.xx.xx:/opt/tools/root/lib rsync -auv /usr/lib xx.xx.xx.xx:/opt/tools/usr/lib
symbolic link を調べると
libpng.so.12 -> /lib/arm-linux-gnueabihf/libpng.12.so.0
となっていて、指定が絶対パスになっています。
これを1つ1つ相対パスに修正していくのが本来のインストールなんだろうけど、日が暮れそうなので
(ホスト側に影響が出てしまうが、)
ln -s /opencv/tools/arm-linux-gnuabhuf/ /usr/arm-linux-gnuabihuf
でお茶濁した。
その他にも技はありますが、大したことでは無いので割愛します。
今度は /usr/lib 直下にあるライブラリがないと宣われるので、-L と -Xlinker -rpath-link でパスを追加しています。エラーが出なくなるまでこの作業を繰り返す。
Videoカメラは EyeToy を使用。motion jpeg で記録されるのでこの手のカメラでは良い方。
秋月に売っている 300 円の VGA はどうなんでしょうか。(YUYVとして使えると予想しますが)
Rasberry Pi2 になって6倍の CPU 速度になっても Core i7 860 の性能には及ばないようなので、今後本格的にクロス環境を作っていくつもりです。
結果的に以下のようになりました。
#gcc, g++ が使用する環境およびディレクトリ $>cat source.sh export ARCH=arm export CROSS_COMPILE=arm-linux-gnueabihf- export ROOTDIR=/opt/tools/arm-bcm2708//gcc-linaro-arm-linux-gnueabihf-raspbian-x64/root #export ROOTDIR=/opt/tools/gcc-4.7-linaro-rpi-gnueabihf/root export PKG_CONFIG_PATH=${ROOTDIR}/usr/lib/pkgconfig pushd ${ROOTDIR}/etc . ld.so.cache popd $>cat ld.so.cache #!/bin/sh dirs=`ls ld.so.conf.d` objpath="" ldpath="${ROOTDIR}/lib" for d in $dirs; do echo "for $d" files=`cat ld.so.conf.d/$d` for f in $files; do echo "for $f" objpath="-L${ROOTDIR}$f $objpath" ldpath="${ROOTDIR}$f:$ldpath" done done export CROSS_LIBDIRS="$objpath" export LD_LIBRARY_PATH="$ldpath" export LIBRARY_PATH="$ldpath"
クロスコンパイラは環境変数を見ないようなので定義しても意味はないんですが。
TARGET=camera SRC=camera.cc OBJ=$(SRC:.cc=.o) CC=$(CROSS_COMPILE)gcc CXX=$(CROSS_COMPILE)g++ PKGCONFIG=$(CROSS_COMPILE)pkg-config # for Pi2 Only binary COMMON_FLAGS=-mcpu=cortex-a7 -mfpu=neon-vfpv4 # for PiB+/2B binary #COMMON_FLAGS=-march=armv6 -mfpu=vfp COMMON_FLAGS+=-mfloat-abi=hard INCLUDES=`$(PKGCONFIG) --cflags opencv` LINKOPT=-Xlinker -rpath-link -Xlinker /opt/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/root/lib LINKOPT+=-Xlinker -rpath-link -Xlinker /opt/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/root/usr/lib LINKOPT+=-Xlinker -rpath-link -Xlinker /lib/arm-linux-gnueabihf LINKOPT+=-Xlinker -rpath-link -Xlinker /usr/lib/arm-linux-gnueabihf LDFLAGS=$(COMMON_FLAGS) ${CROSS_LIBDIRS} `$(PKGCONFIG) --libs opencv` $(LINKOPT) CFLAGS=$(COMMON_FLAGS) $(INCLUDES) $(TARGET): $(OBJ) $(CXX) -o $(TARGET) $(OBJ) $(LDFLAGS) .cc.o: $(CXX) $(CFLAGS) -c $< clean: -rm *.o $(TARGET)
Pi2 用のcpuオプションを通してみたら通ってしまった。本当に正しく動いているかは検証が必要。
最後にいつものビデオキャプチャプログラム
#include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp> #include <iostream> int main() { cv::VideoCapture cap(0); // QVGA cap.set(CV_CAP_PROP_FRAME_WIDTH, 320); cap.set(CV_CAP_PROP_FRAME_HEIGHT, 240); // open camera if (!cap.isOpened()) { std::cout << "failed to open camera" << std::endl; return 1; } cv::namedWindow("Capture", CV_WINDOW_AUTOSIZE | CV_WINDOW_FREERATIO); while(1) { cv::Mat frame; cap >> frame; cv::imshow("Capture", frame); if (cv::waitKey(30) >= 0) { cv::imwrite("/tmp/cap.png", frame); break; } } return 0; }
デバイスを操作するので root ユーザが特別に権限を与えないとオープンできないことに
注意する。