從OpenCV 2.4.4開始,OpenCV支持桌面Java開發(fā),使用與Android開發(fā)幾乎相同的界面。
Clojure是由Java虛擬機(jī)托管的當(dāng)代LISP方言,它提供與底層JVM的完全互操作性。這意味著我們甚至可以使用Clojure REPL(Read Eval Print Loop)作為底層OpenCV引擎的交互式可編程接口。
本教程將幫助您在完全可編程的CLojure REPL中設(shè)置交互式學(xué)習(xí)OpenCV的基本Clojure環(huán)境。
您可以samples/java/clojure/simple-sample
在OpenCV存儲庫的文件夾中找到可運(yùn)行的示例源代碼。按照教程中的說明安裝OpenCV和Clojure后,請執(zhí)行以下命令以從命令行運(yùn)行示例。
cd path/to/samples/java/clojure/simple-sample
lein run
有關(guān)使用桌面Java支持安裝OpenCV的詳細(xì)說明,請參閱相應(yīng)的教程。
如果你是匆忙,這里是一個(gè)最小的快速入門指南在Mac OS X上安裝OpenCV:
cd ~/
mkdir opt
git clone https://github.com/opencv/opencv.git
cd opencv
git checkout 2.4
mkdir build
cd build
cmake -DBUILD_SHARED_LIBS=OFF ..
...
...
make -j8
# optional
# make install
一旦您安裝OpenCV與桌面java支持,唯一的其他要求是安裝Leiningeng,它允許您管理CLJ項(xiàng)目的整個(gè)生命周期。
可用的安裝指南非常容易遵循:
如果您在Windows上工作,請按照此說明進(jìn)行操作
您現(xiàn)在擁有OpenCV庫和完全安裝的基本Clojure環(huán)境?,F(xiàn)在需要配置Clojure環(huán)境與OpenCV庫進(jìn)行交互。
由Leiningen本人支持的一組命令(Leiningen的任務(wù))可以通過各種插件輕松擴(kuò)展。其中一個(gè)是lein-localrepo插件,允許在機(jī)器的本地maven存儲庫中安裝任何jar lib作為工件(通常位于用戶名的/.m2/repository目錄中)。
我們將使用這個(gè)lein插件來添加到本地的maven存儲庫,Java和Clojure需要使用opencv lib的opencv組件。
一般來說,如果您只想在項(xiàng)目基礎(chǔ)上使用插件,則可以直接添加到由lein創(chuàng)建的CLJ項(xiàng)目中。
相反,當(dāng)您希望插件可用于用戶名空間中的任何CLJ項(xiàng)目時(shí),可以將其添加到/ .lein /目錄中的profiles.clj中。
lein-localrepo插件對于我在其他CLJ項(xiàng)目中將是有用的,我需要調(diào)用Java接口包裝的本地庫。所以我決定把它提供給任何CLJ項(xiàng)目:
mkdir?/ .lein
在/ .lein目錄中創(chuàng)建一個(gè)名為profiles.clj的文件,并將其復(fù)制到以下內(nèi)容中:
{:user {:plugins [[lein-localrepo“0.5.2”]]}}
這里我們說,lein-localrepo插件的版本“0.5.2”將可用于由lein創(chuàng)建的任何CLJ項(xiàng)目的用戶配置文件。
您不需要做任何其他安裝插件,因?yàn)樗鼘⒃谀状伟l(fā)布任何lein任務(wù)時(shí)從遠(yuǎn)程存儲庫自動下載。
如果您在計(jì)算機(jī)上遵循用于安裝OpenCV的標(biāo)準(zhǔn)文檔,您應(yīng)該在構(gòu)建OpenCV的目錄下找到以下兩個(gè)lib:
它們是JVM與OpenCV交互所需的唯一opencv庫。
創(chuàng)建一個(gè)新的目錄以存儲在上述兩個(gè)庫中。首先將其復(fù)制到opencv-247.jar lib中。
cd?/ opt
mkdir clj-opencv
cd clj-opencv
cp?/ opt / opencv / build / bin / opencv-247.jar。
首先完成
現(xiàn)在,為了能夠?qū)⒈镜豰aven庫中的libopencv_java247.dylib共享的本地lib添加到我們首先需要將其打包成一個(gè)jar文件。
本機(jī)庫必須被復(fù)制到一個(gè)模擬操作系統(tǒng)和體系結(jié)構(gòu)名稱的目錄布局中。我正在使用具有X86 64位架構(gòu)的Mac OS X。所以我的布局將如下所示:
mkdir -p native / macosx / x86_64
復(fù)制到x86_64目錄中的libopencv_java247.dylib lib。
cp?/ opt / opencv / build / lib / libopencv_java247.dylib native / macosx / x86_64 /
如果您從不同的OS / Architecture對運(yùn)行OpenCV,則可以從中選擇映射的摘要。
OS
Mac OS X -> macosx
Windows -> windows
Linux -> linux
SunOS -> solaris
Architectures
amd64 -> x86_64
x86_64 -> x86_64
x86 -> x86
i386 -> x86
arm -> arm
sparc -> sparc
接下來,您需要使用jar命令從一個(gè)目錄創(chuàng)建一個(gè)新的jar文件,將本機(jī)的lib打包到一個(gè)jar文件中。
jar -cMf opencv-native-247.jar native
請注意,ehe M選項(xiàng)指示jar命令不為該工件創(chuàng)建一個(gè)MANIFEST文件。
您的目錄布局應(yīng)如下所示:
tree
.
|__ native
| |__ macosx
| |__ x86_64
| |__ libopencv_java247.dylib
|
|__ opencv-247.jar
|__ opencv-native-247.jar
3 directories, 3 files
我們現(xiàn)在準(zhǔn)備在lein-localrepo插件的幫助下,將兩個(gè)jar作為工件添加到本地的maven倉庫中。
lein localrepo install opencv-247.jar opencv/opencv 2.4.7
這里的localrepo安裝任務(wù)創(chuàng)建了2.4.7。從opencv-247.jar lib釋放opencv / opencv maven工件,然后將其安裝到本地的maven存儲庫中。然后,opencv / opencv工件將可用于任何符合maven的項(xiàng)目(Leiningen內(nèi)部基于maven)。
與之前包裝在一個(gè)新的jar文件中的native lib做同樣的事情。
lein localrepo install opencv-native-247.jar opencv/opencv-native 2.4.7
請注意,兩個(gè)工件的groupId,opencv是相同的?,F(xiàn)在我們準(zhǔn)備開創(chuàng)一個(gè)新的CLJ項(xiàng)目,開始與OpenCV進(jìn)行互動。
通過使用終端的lein新任務(wù)創(chuàng)建一個(gè)新的CLJ項(xiàng)目。
# cd in the directory where you work with your development projects (e.g. ~/devel)
lein new simple-sample
Generating a project called simple-sample based on the 'default' template.
To see other templates (app, lein plugin, etc), try `lein help new`.
上述任務(wù)創(chuàng)建以下簡單示例目錄布局:
tree simple-sample/
simple-sample/
|__ LICENSE
|__ README.md
|__ doc
| |__ intro.md
|
|__ project.clj
|__ resources
|__ src
| |__ simple_sample
| |__ core.clj
|__ test
|__ simple_sample
|__ core_test.clj
6 directories, 6 files
我們需要將兩個(gè)opencv工件添加為新創(chuàng)建的項(xiàng)目的依賴關(guān)系。打開project.clj并修改其依賴關(guān)系部分,如下所示:
(defproject simple-sample "0.1.0-SNAPSHOT"
description "FIXME: write description"
url "http://example.com/FIXME"
license {:name "Eclipse Public License"
url "http://www.eclipse.org/legal/epl-v10.html"}
dependencies [[org.clojure/clojure "1.5.1"]
[opencv/opencv "2.4.7"] ; added line
[opencv/opencv-native "2.4.7"]]) ;added line
請注意,Clojure編程語言也是一個(gè)jar工件。這就是為什么Clojure被稱為托管語言。
驗(yàn)證一切正確的問題,lein deps任務(wù)。在第一次運(yùn)行l(wèi)ein任務(wù)時(shí),在執(zhí)行任務(wù)本身之前,需要一些時(shí)間才能下載所有必需的依賴項(xiàng)。
cd simple-sample
lein deps
...
deps任務(wù)從project.clj和/ .lein / profiles.clj文件中讀取并合并所有依賴關(guān)系的簡單示例,并驗(yàn)證它們是否已被緩存在本地的maven存儲庫中。如果任務(wù)返回沒有消息,無法檢索兩個(gè)新的工件,您的安裝是正確的,否則返回并仔細(xì)檢查您做的一切正確。
現(xiàn)在cd在簡單樣本目錄中,并發(fā)出以下lein任務(wù):
cd simple-sample
lein repl
...
...
nREPL server started on port 50907 on host 127.0.0.1
REPL-y 0.3.0
Clojure 1.5.1
Docs: (doc function-name-here)
(find-doc "part-of-name-here")
Source: (source function-name-here)
Javadoc: (javadoc java-object-or-class-here)
Exit: Control+D or (exit) or (quit)
Results: Stored in vars *1, *2, *3, an exception in *e
user=>
您可以立即通過發(fā)出要評估的CLJ表達(dá)式與REPL進(jìn)行交互。
user=> (+ 41 1)
42
user=> (println "Hello, OpenCV!")
Hello, OpenCV!
nil
user=> (defn foo [] (str "bar"))
#'user/foo
user=> (foo)
"bar"
當(dāng)從基于lein的項(xiàng)目的主目錄運(yùn)行時(shí),即使lein repl任務(wù)自動加載所有項(xiàng)目依賴項(xiàng),仍然需要加載opencv本機(jī)庫才能與OpenCV進(jìn)行交互。
user=> (clojure.lang.RT/loadLibrary org.opencv.core.Core/NATIVE_LIBRARY_NAME)
nil
然后,您可以通過引用其類的完全限定名稱開始與OpenCV進(jìn)行交互。
user =>(org.opencv.core.Point。0 0)
#<Point {0.0,0.0}>
這里我們創(chuàng)建了一個(gè)二維opencv Point實(shí)例。即使OpenCV的Java接口中包含的所有java包都可以從CLJ REPL中立即獲得,因此在Point前綴非常煩人。具有完全限定包名稱的實(shí)例構(gòu)造函數(shù)。
幸運(yùn)的是,CLJ提供了一種非常簡單的方法來通過直接導(dǎo)入Point類來克服這種煩惱。
user=> (import 'org.opencv.core.Point)
org.opencv.core.Point
user=> (def p1 (Point. 0 0))
#'user/p1
user=> p1
#<Point {0.0, 0.0}>
user=> (def p2 (Point. 100 100))
#'user/p2
我們甚至可以檢查一個(gè)實(shí)例的類,并驗(yàn)證一個(gè)符號的值是否是Point java類的一個(gè)實(shí)例。
user=> (class p1)
org.opencv.core.Point
user=> (instance? org.opencv.core.Point p1)
true
如果我們現(xiàn)在想使用opencv Rect類創(chuàng)建一個(gè)矩形,我們再次必須完全限定它的構(gòu)造函數(shù),即使它留在同一個(gè)Point類的org.opencv.core包中。
user=> (org.opencv.core.Rect. p1 p2)
#<Rect {0, 0, 100x100}>
再次,CLJ進(jìn)口設(shè)施非常方便,讓您可以一次性映射更多的符號。
user=> (import '[org.opencv.core Point Rect Size])
org.opencv.core.Size
user=> (def r1 (Rect. p1 p2))
#'user/r1
user=> r1
#<Rect {0, 0, 100x100}>
user=> (class r1)
org.opencv.core.Rect
user=> (instance? org.opencv.core.Rect r1)
true
user=> (Size. 100 100)
#<Size 100x100>
user=> (def sq-100 (Size. 100 100))
#'user/sq-100
user=> (class sq-100)
org.opencv.core.Size
user=> (instance? org.opencv.core.Size sq-100)
true
顯然你也可以調(diào)用實(shí)例的方法。
user =>(.area r1)
10000.0
user =>(.area sq-100)
10000.0
或修改成員字段的值。
user =>(set?。?x p1)10)
10
user => p1
#<Point {10.0,0.0}>
user =>(set?。?width sq-100)10)
10
user =>(set?。?height sq-100)10)
10
user =>(.area sq-100)
100.0
如果您發(fā)現(xiàn)自己不記得OpenCV類的行為,REPL可以讓您有機(jī)會輕松搜索相應(yīng)的javadoc文檔:
user =>(javadoc Rect)
“http://www.google.com/search?btnI=I%27m%20Feeling%20Lucky&q=allinurl:org/opencv/core/Rect.html”
我們現(xiàn)在嘗試將Clojure的opencv java教程示例移植到其中。而不是將它寫入源文件,我們將在REPL評估它。
以下是引用示例的原始Java源代碼。
import org.opencv.core.Mat;
import org.opencv.core.CvType;
import org.opencv.core.Scalar;
class SimpleSample {
static{ System.loadLibrary("opencv_java244"); }
public static void main(String[] args) {
Mat m = new Mat(5, 10, CvType.CV_8UC1, new Scalar(0));
System.out.println("OpenCV Mat: " + m);
Mat mr1 = m.row(1);
mr1.setTo(new Scalar(1));
Mat mc5 = m.col(5);
mc5.setTo(new Scalar(5));
System.out.println("OpenCV Mat data:\n" + m.dump());
}
}
在開始編碼之前,我們希望在我們開始一個(gè)新的REPL與之交互的時(shí)候,消除對交互式加載本機(jī)opencv lib的無聊需求。
首先,通過在REPL提示符處評估(exit)表達(dá)式來停止REPL。
user=> (exit)
Bye for now!
然后打開你的project.clj文件,并按如下所示進(jìn)行編輯:
(defproject simple-sample "0.1.0-SNAPSHOT"
...
injections [(clojure.lang.RT/loadLibrary org.opencv.core.Core/NATIVE_LIBRARY_NAME)])
這里我們要說,在我們運(yùn)行REPL的時(shí)候加載opencv native lib,這樣我們再也不用記得手動執(zhí)行了。
重新運(yùn)行l(wèi)ein repl任務(wù)
lein repl
nREPL server started on port 51645 on host 127.0.0.1
REPL-y 0.3.0
Clojure 1.5.1
Docs: (doc function-name-here)
(find-doc "part-of-name-here")
Source: (source function-name-here)
Javadoc: (javadoc java-object-or-class-here)
Exit: Control+D or (exit) or (quit)
Results: Stored in vars *1, *2, *3, an exception in *e
user=>
導(dǎo)入感興趣的OpenCV java接口。
user =>(import'[org.opencv.core Mat CvType Scalar])
org.opencv.core.Scalar
我們將逐漸模擬原始的OpenCV java教程:
user=> (def m (Mat. 5 10 CvType/CV_8UC1 (Scalar. 0 0)))
#'user/m
user=> (def mr1 (.row m 1))
#'user/mr1
user=> (.setTo mr1 (Scalar. 1 0))
#<Mat Mat [ 1*10*CV_8UC1, isCont=true, isSubmat=true, nativeObj=0x7fc9dac49880, dataAddr=0x7fc9d9c98d5a ]>
user=> (def mc5 (.col m 5))
#'user/mc5
user=> (.setTo mc5 (Scalar. 5 0))
#<Mat Mat [ 5*1*CV_8UC1, isCont=false, isSubmat=true, nativeObj=0x7fc9d9c995a0, dataAddr=0x7fc9d9c98d55 ]>
user=> (println (.dump m))
[0, 0, 0, 0, 0, 5, 0, 0, 0, 0;
1, 1, 1, 1, 1, 5, 1, 1, 1, 1;
0, 0, 0, 0, 0, 5, 0, 0, 0, 0;
0, 0, 0, 0, 0, 5, 0, 0, 0, 0;
0, 0, 0, 0, 0, 5, 0, 0, 0, 0]
nil
如果你習(xí)慣了功能語言,所有這些被濫用和變異的名詞會激怒你對動詞的偏好。即使CLJ interop語法非常方便和完整,任何OOP語言和任何FP語言之間仍然存在阻抗不匹配(Scala是混合范式編程語言)。
要在REPL提示符處退出REPL類型(退出),ctr-D或(退出)。
user=> (exit)
Bye for now!
在下一個(gè)示例中,您將學(xué)習(xí)如何使用以下OpenCV方法從REPL交互式加載和模糊和映像:
我們還將使用從imread方法返回的Mat類,并將其作為GaussianBlur和imwrite方法的主要參數(shù)。
首先,我們要將圖像文件添加到新創(chuàng)建的目錄中,用于存儲項(xiàng)目的靜態(tài)資源。
mkdir -p resources/images
cp ~/opt/opencv/doc/tutorials/introduction/desktop_java/images/lena.png resource/images/
現(xiàn)在,照常啟動REPL,首先導(dǎo)入我們要使用的所有OpenCV類:
lein repl
nREPL server started on port 50624 on host 127.0.0.1
REPL-y 0.3.0
Clojure 1.5.1
Docs: (doc function-name-here)
(find-doc "part-of-name-here")
Source: (source function-name-here)
Javadoc: (javadoc java-object-or-class-here)
Exit: Control+D or (exit) or (quit)
Results: Stored in vars *1, *2, *3, an exception in *e
user=> (import '[org.opencv.core Mat Size CvType]
'[org.opencv.imgcodecs Imgcodecs]
'[org.opencv.imgproc Imgproc])
org.opencv.imgproc.Imgproc
現(xiàn)在從resources / images / lena.png文件中讀取圖像。
user=> (def lena (Highgui/imread "resources/images/lena.png"))
#'user/lena
user=> lena
#<Mat Mat [ 512*512*CV_8UC3, isCont=true, isSubmat=false, nativeObj=0x7f9ab3054c40, dataAddr=0x19fea9010 ]>
如你所見,通過簡單地評估lena符號,我們知道lena.png是一個(gè)512×512矩陣的CV_8UC3元素類型。我們來創(chuàng)建一個(gè)新的Mat實(shí)例,它的尺寸和元素類型相同。
user=> (def blurred (Mat. 512 512 CvType/CV_8UC3))
#'user/blurred
user=>
現(xiàn)在,使用lena作為源矩陣應(yīng)用GaussianBlur濾波器,并將其模糊為目標(biāo)矩陣。
user=> (Imgproc/GaussianBlur lena blurred (Size. 5 5) 3 3)
nil
作為最后一步,只需將模糊矩陣保存在新的圖像文件中。
user=> (Highgui/imwrite "resources/images/blurred.png" blurred)
true
user=> (exit)
Bye for now!
以下是莉娜的新模糊形象。
本教程僅介紹了在CLJ REPL中與OpenCV進(jìn)行交互的基本環(huán)境。
我推薦任何Clojure新手閱讀Clojure 教程,以獲得所有您需要知道的任何與Clojure中未包裝的任何普通的java lib進(jìn)行互操作,以便在Clojure中以更為慣用和功能的方式使用。
OpenCV Java API不會根據(jù)Qt包裝highgui模塊的功能(例如namedWindow和imshow)。如果要在REPL中與OpenCV進(jìn)行交互時(shí)創(chuàng)建窗口并顯示圖像,那么當(dāng)您自己離開時(shí)。您可以使用Java Swing填補(bǔ)空白。
更多建議: