OpenCV Open Source Computer Vision Library 是一個跨平台的電腦視覺庫,由 Intel 發起並參與開發,由於 Intel 為了推動需要更高速運算的應用,增加硬體的銷售,因此發展了這個機器視覺的運算函式庫,以BSD授權條款授權發行,可以在商業和研究領域中免費使用。OpenCV可用於開發 real time 的圖像處理、電腦視覺以及特徵識別程式。
OpenCV 雖然是以 C++ 寫成,但同時提供了 python 及 java 的 bindings,也因為 python,我們可以用更短的程式碼就完成一些基本的視覺應用,以下紀錄如何在 RPi 3 以及 MacOS 中安裝 OpenCV。
Raspberry Pi 3
RPi 的 camera 是使用 CSI 介面,參考 Raspberry Pi相機模組開箱文 將 RPi 的 camera 裝好。
以 raspi-config 指令 enable camera,然後 reboot。
vcgencmd 是用來查詢一些系統參數的指令,可以用 vcgencmd 測試 camera 狀態。
$ vcgencmd get_camera
supported=1 detected=1
vcgencmd version
vcgencmd get_mem arm
vcgencmd get_mem gpu
安裝 OpenCV 3,必須先更新 RPi,安裝一些基本的工具及 library
sudo apt-get update
sudo apt-get upgrade
sudo apt-get -y install build-essential cmake pkg-config
sudo apt-get -y install cmake-curses-gui htop swig
# load various image file formats from disk
sudo apt-get -y install libjpeg-dev libtiff5-dev libjasper-dev libpng12-dev
#sudo apt-get -y install build-essential cmake cmake-curses-gui pkg-config libpng12-0 libpng12-dev libpng++-dev libpng3 libpnglite-dev zlib1g-dbg zlib1g zlib1g-dev pngtools libtiff5-dev libtiff5 libtiffxx0c2 libtiff-tools libeigen3-dev
#sudo apt-get -y install libjpeg8 libjpeg8-dev libjpeg8-dbg libjpeg-progs swig libv4l-0 libv4l-dev python-numpy
# read various video file formats from disk
sudo apt-get -y install libavcodec-dev libavformat-dev libswscale-dev libv4l-dev
sudo apt-get -y install libxvidcore-dev libx264-dev
# for module: highgui
sudo apt-get -y install libgtk2.0-dev
# matrix operations
sudo apt-get -y install libatlas-base-dev gfortran
# python
sudo apt-get -y install python2.7-dev python3-dev python-numpy python3-numpy
sudo apt-get -y install doxygen
如果需要 tesseract,不安裝也沒關係,可以直接用 pytesseract:
sudo apt-get install -y tesseract-ocr libtesseract-dev libleptonica-dev
安裝 python library
wget https://bootstrap.pypa.io/get-pip.py
sudo python get-pip.py
# for numerical processing
sudo pip install numpy
下載並安裝 OpenCV 3.1
wget -O opencv-3.1.0.zip https://github.com/Itseez/opencv/archive/3.1.0.zip
wget -O opencv_contrib-3.1.0.zip https://github.com/opencv/opencv_contrib/archive/3.1.0.zip
unzip opencv-3.1.0.zip
unzip opencv_contrib-3.1.0.zip
因為 Opencv + Tesseract 編譯會發生問題,所以要把 OpenCV 偵測 Tesseract library 的部分關閉,未來直接用 pytesseract 就可以做 OCR,不用透過 OpenCV 呼叫 tesseract。
#修改 /opt/opencv_contrib-3.1.0/modules/text/FindTesseract.cmake
#增加最後一行
set(Tesseract_FOUND 0)
編譯 opencv
cd opencv-3.1.0/
mkdir build
cd build
# setup build with cmake 或是以 ccmake ../ 用介面設定 build
cmake -D CMAKE_BUILD_TYPE=RELEASE \
-D CMAKE_INSTALL_PREFIX=/usr/local \
-D INSTALL_C_EXAMPLES=OFF \
-D INSTALL_PYTHON_EXAMPLES=ON \
-D OPENCV_EXTRA_MODULES_PATH=~/opencv/opencv_contrib-3.1.0/modules \
-D BUILD_EXAMPLES=ON ..
如果不直接用 cmake,也可以用 ccmake gui 設定 cmake 的選項
ccmake ../
# 按 c 產生全新設定,決定細項設定後,修改完後,按 c 設定新的選項,然後再按下 g 即可產生編譯用的設定檔案。
如果 cmake 時會出現這個錯誤
CMake Error at samples/gpu/CMakeLists.txt:100 (list):
list sub-command REMOVE_ITEM requires list to be present.
參考這裡的解法,要將 INSTALLCEXAMPLES=OFF 設定為 OFF。
# 這個步驟會要做很久,大概是 80 分鐘,如果一直發生問題,就改用 make 去掉 -j4,但會需要 3~4 hrs
# 如果 make -j4 出現 error,可以再用 make -j4 或是改用 make -j2 多試幾次看看,如果錯誤沒有出現在同一個地方,,可以這樣繼續編譯
make -j2
也可以用這樣的方式重複 10 次 make
for i in {1..10}; do make -j2; done
或是用 shell script
#!/bin/bash
for i in {1..10}
do
make -j2
if [ $? -ne 0 ]; then
echo "Try again";
else
break;
fi
done
sudo make install
sudo ldconfig
在 python 的 dist-packages 目錄中,看到 cv2.so 就成功了。
ls -l /usr/local/lib/python2.7/dist-packages/
以 python 測試 cv2
$ python
>>> import cv2
>>> cv2.__version__
'3.1.0'
測試拍照及錄影
raspistill -o t.jpg
raspivid -o t.h264
要讓 OpenCV 使用 camera 必須安裝V4L2套件,在 RPi 必須要先載入 video driver for cv video capture method,camera 的程式才會有作用。
可以直接編譯
cd ~/opencv/
wget http://linuxtv.org/downloads/v4l-utils/v4l-utils-1.6.2.tar.bz2
tar xfvj v4l-utils-1.6.2.tar.bz2
sudo apt-get -y install autoconf gettext libtool libjpeg-dev
cd v4l-utils-1.6.2
autoreconf -vfi
./configure
make
sudo make install
或是用這樣的方式安裝
# 增加sources.list
$ sudo vim /etc/apt/sources.list
於sources.list中寫入以下資訊
deb http://www.linux-projects.org/listing/uv4l_repo/raspbian/ wheezy main
# 加入GPG key
$ sudo wget http://www.linux-projects.org/listing/uv4l_repo/lrkey.asc ~/
$ sudo apt-key add ./lrkey.asc
# 再更新一次系統
$ sudo apt-get update && sudo apt-get upgrade
# 安裝V4L2套件
$ sudo apt-get install uv4l uv4l-raspicam
sudo modprobe bcm2835-v4l2
在modules文件中寫入以下資訊,下次開機就會自動載入這個 module
$ sudo vim /etc/modules
bcm2835-v4l2
測試 /dev/video0
v4l2-ctl --list-ctrls --device /dev/video0
Mac OS El Caption
用類似 RPi 的方式編譯,因為 OpenCV 3.2 會遇到 freetype 編譯錯誤,還不知道怎麼解決,目前只能使用 OpenCV 3.1。另外 python 整合的部分也沒有裝好。所以就不用這樣的方式,改用 macport 直接安裝 opencv +python27。
#安裝 macport, xcode
sudo xcodebuild -license
sudo port install cmake +gui
sudo port install libgphoto2
sudo port install jpeg libpng tiff openexr
sudo port install eigen tbb eigen3
sudo port install py27-numpy
unzip opencv-3.1.0.zip
unzip opencv_contrib-3.1.0.zip
cd opencv-3.1.0
mkdir build
cd build
cmake -D CMAKE_BUILD_TYPE=Release \
-D CMAKE_INSTALL_PREFIX=/usr/local \
-D OPENCV_EXTRA_MODULES_PATH=~/project/opencv/opencv_contrib-3.1.0/modules \
-D BUILD_opencv_python2=ON \
-D BUILD_opencv_python3=OFF \
-D INSTALL_PYTHON_EXAMPLES=ON \
-D INSTALL_C_EXAMPLES=OFF \
-D BUILD_EXAMPLES=ON \
-D WITH_EIGEN=OFF \
-D PYTHON2_PACKAGES_PATH=/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages \
-D PYTHON2_LIBRARY=/opt/local/Library/Frameworks/Python.framework/Versions/2.7/bin \
-D PYTHON2_INCLUDE_DIR=/opt/local/Library/Frameworks/Python.framework/Versions/2.7/include/python2.7/ \
..
make -j4
sudo make install
改用 macport 直接安裝的方式
# 安裝 xcode
xcode-select -install
sudo port selfupdate
sudo port install py27-tkinter
sudo port install cmake +gui
sudo port install py27-scipy
# 設定 python
sudo port install python_select
sudo port slect python python27
# 編譯 opencv
sudo port install opencv +python27 +openni
可以在編譯 opencv 的 Porfile 中查看一些資料,目前是用 3.1.0 版,也已經包含了 opencv_contrib modules,如果真的需要調整編譯的過程,可以設定 macport 的 local repository,複製這個 Portfile,修改編譯的過程。
/opt/local/var/macports/sources/rsync.macports.org/release/tarballs/ports/graphics/opencv/Portfile
測試 1: 打開 1.jpg 顯示在視窗畫面中
test.cpp: 打開 1.jpg 顯示在視窗畫面中
#include <opencv2/opencv.hpp>
using namespace cv;
int main()
{
Mat img=imread("1.jpg");
imshow("result",img);
// 6s後視窗自動關閉
waitKey(6000);
}
編譯與執行
# 在 mac 編譯
g++ -ggdb `pkg-config --cflags --libs opencv` -stdlib=libc++ test.cpp -o test
# 在 RPi 編譯
g++ -ggdb `pkg-config --cflags --libs opencv` test.cpp -o test
./test
一樣的程式碼,改用 python 寫:test.py
#!/usr/bin/python
# coding=utf-8
import cv2
import time
img = cv2.imread('1.jpg');
cv2.imshow("result",img);
cv2.waitKey()
直接用 python 就可以執行,在 Mac 及 RPi 都一樣。
測試 2: 載入圖片, 並用 MORPH_RECT 腐蝕操作
用圖片中暗色的部分,腐蝕高亮的部分。
test2.cpp
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
using namespace cv;
int main( )
{
//載入原圖
Mat srcImage = imread("1.jpg");
//顯示原圖
imshow("source", srcImage);
//進行腐蝕操作
Mat element = getStructuringElement(MORPH_RECT, Size(15, 15));
Mat dstImage;
erode(srcImage, dstImage, element);
//顯示效果圖
imshow("result", dstImage);
waitKey(0);
return 0;
}
編譯+執行
# 在 mac 編譯
g++ -ggdb `pkg-config --cflags --libs opencv` -stdlib=libc++ test2.cpp -o test2
# 在 RPi 編譯
g++ -ggdb `pkg-config --cflags --libs opencv` test2.cpp -o test2
./test2
test2.py
#!/usr/bin/python
# coding=utf-8
import cv2
import time
# 中文字型
from matplotlib.font_manager import FontProperties
font = FontProperties(fname=r"SimSun.ttc", size=14)
img = cv2.imread('1.jpg');
# grayscale image
#img = cv2.imread('1.jpg', 0);
#img = cv2.imread('1.jpg', cv2.IMREAD_GRAYSCALE)
kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(5,5))
#腐蝕圖像
eroded = cv2.erode(img,kernel)
#顯示腐蝕後的圖片
cv2.imshow("result", eroded);
cv2.waitKey(0)
cv2.destroyAllWindows()
編譯+執行
測試 3: blur 影像模糊
test3.cpp
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
using namespace cv;
int main( )
{
Mat srcImage=imread("1.jpg");
imshow( "source", srcImage );
Mat dstImage;
blur( srcImage, dstImage, Size(7, 7));
imshow( "result" ,dstImage );
waitKey( 0 );
}
編譯+執行
# 在 mac 編譯
g++ -ggdb `pkg-config --cflags --libs opencv` -stdlib=libc++ test3.cpp -o test3
./test3
# 在 RPi 編譯
g++ -ggdb `pkg-config --cflags --libs opencv` test3.cpp -o test3
./test3
tes3.py
#!/usr/bin/python
# coding=utf-8
import cv2
import time
img = cv2.imread('1.jpg');
blur = cv2.blur(img,(7,7))
cv2.imshow("result", blur);
cv2.waitKey(0)
cv2.destroyAllWindows()
測試 4: canny 邊緣檢測
test4.cpp
#include <opencv2/opencv.hpp>
#include<opencv2/imgproc/imgproc.hpp>
using namespace cv;
int main( )
{
Mat srcImage = imread("1.jpg");
imshow("source", srcImage); //顯示原始圖
Mat dstImage,edge,grayImage; //參數定義
//建立與src同類別型和大小的矩陣(dst)
dstImage.create( srcImage.size(), srcImage.type() );
//將原圖像轉換為灰度圖像
//此句程式碼的OpenCV2版為:
//cvtColor( srcImage, grayImage, CV_BGR2GRAY );
//此句程式碼的OpenCV3版為:
cvtColor( srcImage, grayImage, COLOR_BGR2GRAY );
// 使用 3x3核心來降噪
blur( grayImage, edge, Size(3,3) );
// 執行Canny算子
Canny( edge, edge, 3, 9,3 );
imshow("result", edge);
waitKey(0);
return 0;
}
編譯+執行
# 在 mac 編譯
g++ -ggdb `pkg-config --cflags --libs opencv` -stdlib=libc++ test4.cpp -o test4
./test4
# 在 RPi 編譯
g++ -ggdb `pkg-config --cflags --libs opencv` test4.cpp -o test4
./test4
test4.py
#!/usr/bin/python
# coding=utf-8
import cv2
import time
# grayscale image
img = cv2.imread('1.jpg', 0);
# 用高斯平滑處理原圖像降噪
img = cv2.GaussianBlur(img,(3,3),0)
# Canny只能處理 grayscale image, 指定最大和最小閾值,其中apertureSize默認為3
canny = cv2.Canny(img, 3, 9)
cv2.imshow("result", canny);
cv2.waitKey(0)
cv2.destroyAllWindows()
test5: 播放 avi 影片
test5.cpp
#include <opencv2/opencv.hpp>
using namespace cv;
//-----------------------------------【main( )函數】--------------------------------------------
// 描述:控制臺應用程式的入口函數,我們的程式從這里開始
//-------------------------------------------------------------------------------------------------
int main( )
{
VideoCapture capture("1.avi");
while(1)
{
Mat frame;//定義一個Mat變數, 儲存現在的 frame
capture>>frame; //讀取現在的 frame
if (!frame.empty()) {
imshow("result",frame);
} else {
break;
}
waitKey(30); // delay 30ms
}
return 0;
}
編譯+執行
# 在 mac 編譯
g++ -ggdb `pkg-config --cflags --libs opencv` -stdlib=libc++ test5.cpp -o test5
./test5
# 在 RPi 編譯
g++ -ggdb `pkg-config --cflags --libs opencv` test5.cpp -o test5
./test5
test5.py
#!/usr/bin/python
# coding=utf-8
import cv2
import time
cap = cv2.VideoCapture('1.avi');
while True:
ret, frame = cap.read()
if ret == True:
## grayscale avi
#gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
#cv2.imshow('frame', gray)
## normal avi
cv2.imshow('frame', frame)
if cv2.waitKey(30) & 0xFF == ord('q'):
break
else:
break
cap.release()
cv2.destroyAllWindows()
test6: 使用 camera
test6.cpp,只有將 VideoCapture capture(0); 換成 camera index 就可以了。
#include <opencv2/opencv.hpp>
using namespace cv;
int main( )
{
VideoCapture capture(0);
while(1)
{
Mat frame, dst;
capture>>frame;
if (!frame.empty()) {
imshow("result", frame);
} else {
break;
}
waitKey(30); //delay 30ms
}
return 0;
}
編譯+執行
# 在 mac 編譯
g++ -ggdb `pkg-config --cflags --libs opencv` -stdlib=libc++ test6.cpp -o test6
./test6
# 在 RPi 編譯
g++ -ggdb `pkg-config --cflags --libs opencv` test6.cpp -o test6
./test6
test6.py
#!/usr/bin/python
# coding=utf-8
import cv2
import time
cap = cv2.VideoCapture(0);
while True:
ret, frame = cap.read()
if ret == True:
## grayscale avi
#gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
#cv2.imshow('frame', gray)
## normal avi
cv2.imshow('frame', frame)
if cv2.waitKey(30) & 0xFF == ord('q'):
break
else:
break
cap.release()
cv2.destroyAllWindows()
test7: 使用 camera 加上畫面旋轉
上面的 test6 在 mac 的 camera 角度不對,畫面必須逆時針旋轉一下,才回變成正面。
#include <opencv2/opencv.hpp>
using namespace cv;
void rotate_90n(cv::Mat const &src, cv::Mat &dst, int angle)
{
CV_Assert(angle % 90 == 0 && angle <= 360 && angle >= -360);
if(angle == 270 || angle == -90){
// Rotate clockwise 270 degrees
cv::transpose(src, dst);
cv::flip(dst, dst, 0);
}else if(angle == 180 || angle == -180){
// Rotate clockwise 180 degrees
cv::flip(src, dst, -1);
}else if(angle == 90 || angle == -270){
// Rotate clockwise 90 degrees
cv::transpose(src, dst);
cv::flip(dst, dst, 1);
}else if(angle == 360 || angle == 0 || angle == -360){
if(src.data != dst.data){
src.copyTo(dst);
}
}
}
int main( )
{
VideoCapture capture(0);
while(1)
{
Mat frame, dst;
capture>>frame;
if (!frame.empty()) {
rotate_90n(frame, dst, -90);
imshow("result", dst);
} else {
break;
}
waitKey(30); //delay 30ms
}
return 0;
}
編譯+執行
# 在 mac 編譯
g++ -ggdb `pkg-config --cflags --libs opencv` -stdlib=libc++ test7.cpp -o test7
./test7
# 在 RPi 編譯
g++ -ggdb `pkg-config --cflags --libs opencv` test7.cpp -o test7
./test7
test7.py
#!/usr/bin/python
# coding=utf-8
import cv2
import time
def rot90(img, angle):
if(angle == 270 or angle == -90):
img = cv2.transpose(img)
img = cv2.flip(img, 0) # transpose+flip(0)=CCW
elif (angle == 180 or angle == -180):
img = cv2.flip(img, -1) # transpose+flip(-1)=180
elif (angle == 90 or angle == -270):
img = cv2.transpose(img)
img = cv2.flip(img, 1) # transpose+flip(1)=CW
elif (angle == 360 or angle == 0 or angle == -360):
pass
else :
raise Exception("Unknown rotation angle({})".format(angle))
return img
cap = cv2.VideoCapture(0);
while True:
ret, frame = cap.read()
if ret == True:
## grayscale avi
#gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
#cv2.imshow('frame', gray)
## normal avi
dst = rot90(frame, -90)
cv2.imshow('frame', dst)
if cv2.waitKey(30) & 0xFF == ord('q'):
break
else:
break
cap.release()
cv2.destroyAllWindows()
References
Install OpenCV-Python in Windows
Computer Vision with Raspberry Pi and the Camera Pi module
使用 vcgencmd 指令查看 Raspberry Pi 的 CPU 溫度、運行速度與電壓等資訊
在 Raspberry Pi 上面安裝 OpenCV 函式庫
安裝 OPENCV 紀錄
Install guide: Raspberry Pi 3 + Raspbian Jessie + OpenCV 3
[翻译]Python 2.7 和 Python 3+ 的OpenCV 3.0 安装教程
[Raspberry Pi] 解決 Raspberry Pi 找不到 /dev/video0
OpenCV on Raspberry Pi - Using Java(6)- 使用 OpenCV 拍攝照片(Camera Module)
Installing OpenCV in Mac OSx tutorial
macOS: Install OpenCV 3 and Python 2.7
Mac下安装OpenCV3.0—包含opencv_contrib模块
Undefined freetype symbols when building openCV 3.2.0
How to compile OpenCV sample code ?
【OpenCV】安裝在Mac及XCode筆記
VideoCapture.open(0) won't recognize pi cam
Rotate image by 90, 180 or 270 degrees