├── .github
├── FUNDING.yml
└── workflows
│ └── build.yml
├── .gitignore
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── pom.xml
├── src
├── main
│ ├── java
│ │ └── nu
│ │ │ └── pattern
│ │ │ ├── OpenCV.java
│ │ │ └── PrintVersion.java
│ └── resources
│ │ └── nu
│ │ └── pattern
│ │ └── opencv
│ │ ├── linux
│ │ ├── ARMv7
│ │ │ └── README.md
│ │ ├── ARMv8
│ │ │ └── README.md
│ │ ├── x86_32
│ │ │ └── README.md
│ │ └── x86_64
│ │ │ └── README.md
│ │ ├── osx
│ │ ├── ARMv8
│ │ │ └── README.md
│ │ └── x86_64
│ │ │ └── README.md
│ │ └── windows
│ │ ├── x86_32
│ │ └── README.md
│ │ └── x86_64
│ │ └── README.md
└── test
│ ├── java
│ └── nu
│ │ └── pattern
│ │ ├── LibraryLoadingTest.java
│ │ ├── LoadLibraryRunListener.java
│ │ └── MserTest.java
│ └── resources
│ └── logging.properties
└── upstream
└── README.md
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | github: vonnieda
4 | ko_fi: vonnieda
5 | custom: "https://www.buymeacoffee.com/vonnieda"
6 |
--------------------------------------------------------------------------------
/.github/workflows/build.yml:
--------------------------------------------------------------------------------
1 | # https://github.com/marketplace/actions/run-on-architecture
2 | # https://github.com/openpnp/opencv/pull/56
3 | # https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idstrategymatrix
4 | # https://github.com/openpnp/opencv/actions
5 | # https://github.com/openpnp/opencv/pull/59/files
6 | # https://stackoverflow.com/questions/57498605/github-actions-share-workspace-artifacts-between-jobs?rq=1
7 | # https://github.com/actions/upload-artifact
8 | # https://github.com/actions/download-artifact
9 |
10 | # TODO
11 | # - maybe consider doing an arm64 test with run on?
12 | # - see if I can remove more hardcoded paths and such using the matrix variables.
13 |
14 | name: Build OpenPnP OpenCV Distribution
15 |
16 | on:
17 | push:
18 | pull_request:
19 |
20 | jobs:
21 | build_linux_arm:
22 | strategy:
23 | matrix:
24 | os: [ubuntu-22.04]
25 | java: [8]
26 |
27 | runs-on: ${{ matrix.os }}
28 |
29 | steps:
30 | - name: Checkout Repo
31 | uses: actions/checkout@v2
32 |
33 | - name: Setup JDK ${{ matrix.java }}
34 | uses: actions/setup-java@v1
35 | with:
36 | java-version: ${{ matrix.java }}
37 |
38 | - name: Get Version Info
39 | run: |
40 | echo "POM_VERSION=$(mvn build-helper:parse-version org.apache.maven.plugins:maven-help-plugin:3.2.0:evaluate -Dexpression=project.version -q -DforceStdout)" >> $GITHUB_ENV
41 | echo "OPENCV_VERSION=$(mvn build-helper:parse-version org.apache.maven.plugins:maven-help-plugin:3.2.0:evaluate -Dexpression=opencv.version.long -q -DforceStdout)" >> $GITHUB_ENV
42 | echo "OPENCV_VERSION_SHORT=$(mvn build-helper:parse-version org.apache.maven.plugins:maven-help-plugin:3.2.0:evaluate -Dexpression=opencv.version.short -q -DforceStdout)" >> $GITHUB_ENV
43 |
44 | - name: Build OpenCV on Arm
45 | uses: uraimo/run-on-arch-action@v2.0.9
46 | with:
47 | arch: armv7
48 | distro: ubuntu18.04
49 |
50 | # Not required, but speeds up builds
51 | githubToken: ${{ github.token }}
52 |
53 | # Create an artifacts directory
54 | setup: |
55 | mkdir -p "${PWD}/artifacts"
56 |
57 | # Mount the artifacts directory as /artifacts in the container
58 | # Also mount the checked out repo as /host_repo so we can do a test build.
59 | dockerRunArgs: |
60 | --volume "${PWD}/artifacts:/artifacts"
61 | --volume "${PWD}:/host_repo"
62 |
63 | run: |
64 | apt-get update -q -y
65 | apt-get install -q -y git wget cmake unzip build-essential default-jre default-jdk ant maven python3
66 |
67 | # TODO: I'd like to get this path automatically somehow. I think it might be
68 | # in /etc/environment but sourcing it didn't seem to work. Need to figure out
69 | # where it would be after starting a new shell.
70 | export JAVA_HOME=/usr/lib/jvm/java-11-openjdk-armhf
71 |
72 | wget https://github.com/opencv/opencv/archive/${{ env.OPENCV_VERSION }}.zip > /dev/null
73 | unzip ${{ env.OPENCV_VERSION }} > /dev/null
74 |
75 | cd opencv-${{ env.OPENCV_VERSION }}
76 | mkdir build
77 | cd build
78 | cmake \
79 | -D OPENCV_FORCE_3RDPARTY_BUILD=ON \
80 | -D BUILD_JAVA=ON \
81 | -D BUILD_FAT_JAVA_LIB=ON \
82 | -D OPENCV_ENABLE_NONFREE=ON \
83 | -D BUILD_SHARED_LIBS=OFF \
84 | -D BUILD_PERF_TESTS=OFF \
85 | -D BUILD_TESTS=OFF \
86 | -D BUILD_EXAMPLES=OFF \
87 | -D BUILD_DOCS=OFF \
88 | -D BUILD_PACKAGE=OFF \
89 | -D BUILD_opencv_python2=OFF \
90 | -D BUILD_opencv_python3=OFF \
91 | -D BUILD_opencv_apps=OFF \
92 | -D BUILD_opencv_gapi=OFF \
93 | -D CMAKE_BUILD_TYPE=RELEASE \
94 | ..
95 | make -j4
96 |
97 | # Copy the build artifacts to the /artifacts directory, which will be
98 | # used by the host to upload them.
99 | mkdir -p /artifacts/bin
100 | mkdir -p /artifacts/lib
101 | cp bin/opencv-${{ env.OPENCV_VERSION_SHORT }}.jar /artifacts/bin
102 | cp lib/libopencv_java${{ env.OPENCV_VERSION_SHORT }}.so /artifacts/lib
103 |
104 | # And also copy the build artifacts to the repo, so we can do a test build.
105 | # Note that we use the repo checked out on the host so that we can use
106 | # actions/checkout for the Git stuff, rather than having to mess with
107 | # the authentication in this container.
108 | cp bin/opencv-${{ env.OPENCV_VERSION_SHORT }}.jar /host_repo/upstream
109 | cp lib/libopencv_java${{ env.OPENCV_VERSION_SHORT }}.so /host_repo/src/main/resources/nu/pattern/opencv/linux/ARMv7
110 |
111 | # Peform a test build in the host repo, which now contains all of the
112 | # build artifacts.
113 | cd /host_repo
114 | mvn -B test
115 |
116 | - name: Upload Artifacts
117 | uses: actions/upload-artifact@v2
118 | with:
119 | name: ubuntu-18.04-arm
120 | path: |
121 | artifacts/bin/opencv-${{ env.OPENCV_VERSION_SHORT }}.jar
122 | artifacts/lib/libopencv_java${{ env.OPENCV_VERSION_SHORT }}.so
123 |
124 |
125 |
126 |
127 | build_linux_arm64:
128 | strategy:
129 | matrix:
130 | os: [ubuntu-22.04]
131 | java: [15]
132 |
133 | runs-on: ${{ matrix.os }}
134 |
135 | steps:
136 | - name: Checkout Repo
137 | uses: actions/checkout@v2
138 |
139 | - name: Setup JDK ${{ matrix.java }}
140 | uses: actions/setup-java@v1
141 | with:
142 | java-version: ${{ matrix.java }}
143 |
144 | - name: Get Version Info
145 | run: |
146 | echo "POM_VERSION=$(mvn build-helper:parse-version org.apache.maven.plugins:maven-help-plugin:3.2.0:evaluate -Dexpression=project.version -q -DforceStdout)" >> $GITHUB_ENV
147 | echo "OPENCV_VERSION=$(mvn build-helper:parse-version org.apache.maven.plugins:maven-help-plugin:3.2.0:evaluate -Dexpression=opencv.version.long -q -DforceStdout)" >> $GITHUB_ENV
148 | echo "OPENCV_VERSION_SHORT=$(mvn build-helper:parse-version org.apache.maven.plugins:maven-help-plugin:3.2.0:evaluate -Dexpression=opencv.version.short -q -DforceStdout)" >> $GITHUB_ENV
149 |
150 | - name: Build OpenCV on Arm64
151 | uses: uraimo/run-on-arch-action@v2.0.9
152 | with:
153 | arch: aarch64
154 | distro: ubuntu18.04
155 |
156 | # Not required, but speeds up builds
157 | githubToken: ${{ github.token }}
158 |
159 | # Create an artifacts directory
160 | setup: |
161 | mkdir -p "${PWD}/artifacts"
162 |
163 | # Mount the artifacts directory as /artifacts in the container
164 | # Also mount the checked out repo as /host_repo so we can do a test build.
165 | dockerRunArgs: |
166 | --volume "${PWD}/artifacts:/artifacts"
167 | --volume "${PWD}:/host_repo"
168 |
169 | run: |
170 | apt-get update -q -y
171 | apt-get install -q -y git wget cmake unzip build-essential default-jre default-jdk ant maven python3
172 |
173 | # TODO: I'd like to get this path automatically somehow. I think it might be
174 | # in /etc/environment but sourcing it didn't seem to work. Need to figure out
175 | # where it would be after starting a new shell.
176 | export JAVA_HOME=/usr/lib/jvm/java-11-openjdk-arm64
177 |
178 | wget https://github.com/opencv/opencv/archive/${{ env.OPENCV_VERSION }}.zip > /dev/null
179 | unzip ${{ env.OPENCV_VERSION }} > /dev/null
180 |
181 | cd opencv-${{ env.OPENCV_VERSION }}
182 | mkdir build
183 | cd build
184 | cmake \
185 | -D OPENCV_FORCE_3RDPARTY_BUILD=ON \
186 | -D BUILD_JAVA=ON \
187 | -D BUILD_FAT_JAVA_LIB=ON \
188 | -D OPENCV_ENABLE_NONFREE=ON \
189 | -D BUILD_SHARED_LIBS=OFF \
190 | -D BUILD_PERF_TESTS=OFF \
191 | -D BUILD_TESTS=OFF \
192 | -D BUILD_EXAMPLES=OFF \
193 | -D BUILD_DOCS=OFF \
194 | -D BUILD_PACKAGE=OFF \
195 | -D BUILD_opencv_python2=OFF \
196 | -D BUILD_opencv_python3=OFF \
197 | -D BUILD_opencv_apps=OFF \
198 | -D BUILD_opencv_gapi=OFF \
199 | -D CMAKE_BUILD_TYPE=RELEASE \
200 | ..
201 | make -j4
202 |
203 | # Copy the build artifacts to the /artifacts directory, which will be
204 | # used by the host to upload them.
205 | mkdir -p /artifacts/bin
206 | mkdir -p /artifacts/lib
207 | cp bin/opencv-${{ env.OPENCV_VERSION_SHORT }}.jar /artifacts/bin
208 | cp lib/libopencv_java${{ env.OPENCV_VERSION_SHORT }}.so /artifacts/lib
209 |
210 | # And also copy the build artifacts to the repo, so we can do a test build.
211 | # Note that we use the repo checked out on the host so that we can use
212 | # actions/checkout for the Git stuff, rather than having to mess with
213 | # the authentication in this container.
214 | cp bin/opencv-${{ env.OPENCV_VERSION_SHORT }}.jar /host_repo/upstream
215 | cp lib/libopencv_java${{ env.OPENCV_VERSION_SHORT }}.so /host_repo/src/main/resources/nu/pattern/opencv/linux/ARMv8
216 |
217 | # Peform a test build in the host repo, which now contains all of the
218 | # build artifacts.
219 | cd /host_repo
220 | mvn -B test
221 |
222 | - name: Upload Artifacts
223 | uses: actions/upload-artifact@v2
224 | with:
225 | name: ubuntu-18.04-arm64
226 | path: |
227 | artifacts/bin/opencv-${{ env.OPENCV_VERSION_SHORT }}.jar
228 | artifacts/lib/libopencv_java${{ env.OPENCV_VERSION_SHORT }}.so
229 |
230 |
231 |
232 |
233 | # Build native libraries for Linux and Mac. Uploads the libraries
234 | # as artifacts which are used in subsequent jobs.
235 | build_mac_linux_x64:
236 | strategy:
237 | matrix:
238 | os: [ubuntu-20.04, macos-11]
239 | java: [8]
240 |
241 | runs-on: ${{ matrix.os }}
242 |
243 | steps:
244 | - name: Checkout Repo
245 | uses: actions/checkout@v2
246 |
247 | - name: Setup JDK ${{ matrix.java }}
248 | uses: actions/setup-java@v1
249 | with:
250 | java-version: ${{ matrix.java }}
251 |
252 | - name: Get Version Info
253 | run: |
254 | echo "POM_VERSION=$(mvn build-helper:parse-version org.apache.maven.plugins:maven-help-plugin:3.2.0:evaluate -Dexpression=project.version -q -DforceStdout)" >> $GITHUB_ENV
255 | echo "OPENCV_VERSION=$(mvn build-helper:parse-version org.apache.maven.plugins:maven-help-plugin:3.2.0:evaluate -Dexpression=opencv.version.long -q -DforceStdout)" >> $GITHUB_ENV
256 | echo "OPENCV_VERSION_SHORT=$(mvn build-helper:parse-version org.apache.maven.plugins:maven-help-plugin:3.2.0:evaluate -Dexpression=opencv.version.short -q -DforceStdout)" >> $GITHUB_ENV
257 |
258 | - name: Build OpenCV
259 | run: |
260 | wget https://github.com/opencv/opencv/archive/${{ env.OPENCV_VERSION }}.zip > /dev/null
261 | unzip ${{ env.OPENCV_VERSION }} > /dev/null
262 | cd opencv-${{ env.OPENCV_VERSION }}
263 | mkdir build
264 | cd build
265 | cmake \
266 | -D OPENCV_FORCE_3RDPARTY_BUILD=ON \
267 | -D BUILD_JAVA=ON \
268 | -D BUILD_FAT_JAVA_LIB=ON \
269 | -D OPENCV_ENABLE_NONFREE=ON \
270 | -D BUILD_SHARED_LIBS=OFF \
271 | -D BUILD_PERF_TESTS=OFF \
272 | -D BUILD_TESTS=OFF \
273 | -D BUILD_EXAMPLES=OFF \
274 | -D BUILD_DOCS=OFF \
275 | -D BUILD_PACKAGE=OFF \
276 | -D BUILD_opencv_python2=OFF \
277 | -D BUILD_opencv_python3=OFF \
278 | -D BUILD_opencv_apps=OFF \
279 | -D BUILD_opencv_gapi=OFF \
280 | -D CMAKE_BUILD_TYPE=RELEASE \
281 | ..
282 | make -j8
283 |
284 | - name: Copy Libraries
285 | run: |
286 | cp opencv-${{ env.OPENCV_VERSION }}/build/bin/opencv-${{ env.OPENCV_VERSION_SHORT }}.jar upstream || :
287 | cp opencv-${{ env.OPENCV_VERSION }}/build/lib/libopencv_java${{ env.OPENCV_VERSION_SHORT }}.so src/main/resources/nu/pattern/opencv/linux/x86_64 || :
288 | cp opencv-${{ env.OPENCV_VERSION }}/build/lib/libopencv_java${{ env.OPENCV_VERSION_SHORT }}.dylib src/main/resources/nu/pattern/opencv/osx/x86_64 || :
289 |
290 | - name: Build with Maven
291 | run: mvn -B test
292 |
293 | - name: Upload Libraries
294 | uses: actions/upload-artifact@v2
295 | with:
296 | name: ${{ matrix.os }}
297 | path: |
298 | opencv-${{ env.OPENCV_VERSION }}/build/bin/opencv-${{ env.OPENCV_VERSION_SHORT }}.jar
299 | opencv-${{ env.OPENCV_VERSION }}/build/lib/libopencv_java${{ env.OPENCV_VERSION_SHORT }}.so
300 | opencv-${{ env.OPENCV_VERSION }}/build/lib/libopencv_java${{ env.OPENCV_VERSION_SHORT }}.dylib
301 |
302 |
303 |
304 |
305 | # Build Apple Silicon Mac native binary.
306 | # See https://cmake.org/cmake/help/v3.23/variable/CMAKE_APPLE_SILICON_PROCESSOR.html
307 | build_mac_aarch64:
308 | strategy:
309 | matrix:
310 | java: [18]
311 | runs-on: [macos-13-xlarge]
312 |
313 | steps:
314 | - name: Checkout Repo
315 | uses: actions/checkout@v2
316 |
317 | - name: Setup JDK ${{ matrix.java }}
318 | uses: actions/setup-java@v3
319 | with:
320 | distribution: 'temurin'
321 | architecture: aarch64
322 | java-version: ${{ matrix.java }}
323 |
324 | - name: Get Version Info
325 | run: |
326 | echo "POM_VERSION=$(mvn build-helper:parse-version org.apache.maven.plugins:maven-help-plugin:3.2.0:evaluate -Dexpression=project.version -q -DforceStdout)" >> $GITHUB_ENV
327 | echo "OPENCV_VERSION=$(mvn build-helper:parse-version org.apache.maven.plugins:maven-help-plugin:3.2.0:evaluate -Dexpression=opencv.version.long -q -DforceStdout)" >> $GITHUB_ENV
328 | echo "OPENCV_VERSION_SHORT=$(mvn build-helper:parse-version org.apache.maven.plugins:maven-help-plugin:3.2.0:evaluate -Dexpression=opencv.version.short -q -DforceStdout)" >> $GITHUB_ENV
329 |
330 | - name: Build OpenCV
331 | run: |
332 | wget https://github.com/opencv/opencv/archive/${{ env.OPENCV_VERSION }}.zip > /dev/null
333 | unzip ${{ env.OPENCV_VERSION }} > /dev/null
334 | cd opencv-${{ env.OPENCV_VERSION }}
335 | mkdir build
336 | cd build
337 | cmake \
338 | -D OPENCV_FORCE_3RDPARTY_BUILD=ON \
339 | -D BUILD_JAVA=ON \
340 | -D BUILD_FAT_JAVA_LIB=ON \
341 | -D OPENCV_ENABLE_NONFREE=ON \
342 | -D BUILD_SHARED_LIBS=OFF \
343 | -D BUILD_PERF_TESTS=OFF \
344 | -D BUILD_TESTS=OFF \
345 | -D BUILD_EXAMPLES=OFF \
346 | -D BUILD_DOCS=OFF \
347 | -D BUILD_PACKAGE=OFF \
348 | -D BUILD_opencv_python2=OFF \
349 | -D BUILD_opencv_python3=OFF \
350 | -D BUILD_opencv_apps=OFF \
351 | -D BUILD_opencv_gapi=OFF \
352 | -D CMAKE_BUILD_TYPE=RELEASE \
353 | -D CMAKE_APPLE_SILICON_PROCESSOR=arm64 \
354 | -D CMAKE_CXX_STANDARD=17 \
355 | ..
356 | make -j8
357 |
358 | - name: Copy Libraries
359 | run: |
360 | cp opencv-${{ env.OPENCV_VERSION }}/build/bin/opencv-${{ env.OPENCV_VERSION_SHORT }}.jar upstream || :
361 | cp opencv-${{ env.OPENCV_VERSION }}/build/lib/libopencv_java${{ env.OPENCV_VERSION_SHORT }}.dylib src/main/resources/nu/pattern/opencv/osx/ARMv8 || :
362 |
363 | - name: Build with Maven
364 | run: mvn -B test
365 |
366 | - name: Upload Libraries
367 | uses: actions/upload-artifact@v2
368 | with:
369 | name: macos-aarch64
370 | path: |
371 | opencv-${{ env.OPENCV_VERSION }}/build/bin/opencv-${{ env.OPENCV_VERSION_SHORT }}.jar
372 | opencv-${{ env.OPENCV_VERSION }}/build/lib/libopencv_java${{ env.OPENCV_VERSION_SHORT }}.dylib
373 |
374 |
375 |
376 |
377 | # Downloads the Windows distribution from OpenCV, extracts it and uploads
378 | # the native libraries as artifacts for use by subsequent jobs. This is
379 | # in leiu of building the native libraries on Windows.
380 | build_windows:
381 | strategy:
382 | matrix:
383 | os: [ubuntu-20.04]
384 | java: [15]
385 |
386 | runs-on: ${{ matrix.os }}
387 |
388 | steps:
389 | - name: Checkout Repo
390 | uses: actions/checkout@v2
391 |
392 | - name: Setup JDK ${{ matrix.java }}
393 | uses: actions/setup-java@v1
394 | with:
395 | java-version: ${{ matrix.java }}
396 |
397 | - name: Get Version Info
398 | run: |
399 | echo "POM_VERSION=$(mvn build-helper:parse-version org.apache.maven.plugins:maven-help-plugin:3.2.0:evaluate -Dexpression=project.version -q -DforceStdout)" >> $GITHUB_ENV
400 | echo "OPENCV_VERSION=$(mvn build-helper:parse-version org.apache.maven.plugins:maven-help-plugin:3.2.0:evaluate -Dexpression=opencv.version.long -q -DforceStdout)" >> $GITHUB_ENV
401 | echo "OPENCV_VERSION_SHORT=$(mvn build-helper:parse-version org.apache.maven.plugins:maven-help-plugin:3.2.0:evaluate -Dexpression=opencv.version.short -q -DforceStdout)" >> $GITHUB_ENV
402 |
403 | - name: Download Windows Distribution
404 | run: wget -O opencv-${{ env.OPENCV_VERSION }}.exe https://github.com/opencv/opencv/releases/download/${{ env.OPENCV_VERSION }}/opencv-${{ env.OPENCV_VERSION }}-windows.exe
405 |
406 | - name: Extract Windows Distribution
407 | run: 7z x opencv-${{ env.OPENCV_VERSION }}.exe
408 |
409 | - name: Upload Libraries
410 | uses: actions/upload-artifact@v2
411 | with:
412 | name: windows-2016
413 | path: opencv/build/java
414 |
415 |
416 |
417 |
418 | # Download and combine the artifacts from the above jobs and build the
419 | # distribution jar. Uploads it as an artifact for subsequent steps.
420 | build_dist:
421 | needs: [build_mac_aarch64, build_linux_arm, build_linux_arm64, build_mac_linux_x64, build_windows]
422 |
423 | strategy:
424 | matrix:
425 | os: [ubuntu-20.04]
426 | java: [8]
427 |
428 | runs-on: ${{ matrix.os }}
429 |
430 | steps:
431 | - name: Checkout Repo
432 | uses: actions/checkout@v2
433 |
434 | - name: Setup JDK ${{ matrix.java }}
435 | uses: actions/setup-java@v1
436 | with:
437 | java-version: ${{ matrix.java }}
438 |
439 | - name: Get Version Info
440 | run: |
441 | echo "POM_VERSION=$(mvn build-helper:parse-version org.apache.maven.plugins:maven-help-plugin:3.2.0:evaluate -Dexpression=project.version -q -DforceStdout)" >> $GITHUB_ENV
442 | echo "OPENCV_VERSION=$(mvn build-helper:parse-version org.apache.maven.plugins:maven-help-plugin:3.2.0:evaluate -Dexpression=opencv.version.long -q -DforceStdout)" >> $GITHUB_ENV
443 | echo "OPENCV_VERSION_SHORT=$(mvn build-helper:parse-version org.apache.maven.plugins:maven-help-plugin:3.2.0:evaluate -Dexpression=opencv.version.short -q -DforceStdout)" >> $GITHUB_ENV
444 |
445 | - name: Download Libraries
446 | uses: actions/download-artifact@v2
447 |
448 | - name: Copy Binaries
449 | run: |
450 | cp macos-11/bin/opencv-${{ env.OPENCV_VERSION_SHORT }}.jar upstream
451 | cp macos-11/lib/libopencv_java${{ env.OPENCV_VERSION_SHORT }}.dylib src/main/resources/nu/pattern/opencv/osx/x86_64
452 | cp macos-aarch64/lib/libopencv_java${{ env.OPENCV_VERSION_SHORT }}.dylib src/main/resources/nu/pattern/opencv/osx/ARMv8
453 | cp ubuntu-20.04/lib/libopencv_java${{ env.OPENCV_VERSION_SHORT }}.so src/main/resources/nu/pattern/opencv/linux/x86_64
454 | cp ubuntu-18.04-arm/lib/libopencv_java${{ env.OPENCV_VERSION_SHORT }}.so src/main/resources/nu/pattern/opencv/linux/ARMv7
455 | cp ubuntu-18.04-arm64/lib/libopencv_java${{ env.OPENCV_VERSION_SHORT }}.so src/main/resources/nu/pattern/opencv/linux/ARMv8
456 | cp windows-2016/x86/opencv_java${{ env.OPENCV_VERSION_SHORT }}.dll src/main/resources/nu/pattern/opencv/windows/x86_32
457 | cp windows-2016/x64/opencv_java${{ env.OPENCV_VERSION_SHORT }}.dll src/main/resources/nu/pattern/opencv/windows/x86_64
458 |
459 | - name: Build with Maven
460 | run: mvn -B install
461 |
462 | - name: Upload Distribution
463 | uses: actions/upload-artifact@v2
464 | with:
465 | name: dist
466 | path: target/opencv*
467 |
468 |
469 |
470 |
471 | # Downloads the distribution jar that was built above and runs
472 | # a short smoke test on it on many platforms and versions of
473 | # Java. This is intended to ensure that the built jar
474 | # runs on all of the supported targets.
475 | test:
476 | needs: build_dist
477 | strategy:
478 | matrix:
479 | os: [macos-11, windows-2019, ubuntu-20.04, ubuntu-22.04]
480 | java: [8, 9, 10, 11, 12, 13, 14, 15]
481 |
482 | runs-on: ${{ matrix.os }}
483 |
484 | steps:
485 | - name: Checkout Repo
486 | uses: actions/checkout@v2
487 |
488 | - name: Setup JDK ${{ matrix.java }}
489 | uses: actions/setup-java@v1
490 | with:
491 | java-version: ${{ matrix.java }}
492 |
493 | - name: Get Version Info
494 | shell: bash
495 | run: |
496 | echo "POM_VERSION=$(mvn build-helper:parse-version org.apache.maven.plugins:maven-help-plugin:3.2.0:evaluate -Dexpression=project.version -q -DforceStdout)" >> $GITHUB_ENV
497 | echo "OPENCV_VERSION=$(mvn build-helper:parse-version org.apache.maven.plugins:maven-help-plugin:3.2.0:evaluate -Dexpression=opencv.version.long -q -DforceStdout)" >> $GITHUB_ENV
498 | echo "OPENCV_VERSION_SHORT=$(mvn build-helper:parse-version org.apache.maven.plugins:maven-help-plugin:3.2.0:evaluate -Dexpression=opencv.version.short -q -DforceStdout)" >> $GITHUB_ENV
499 |
500 | - name: Download Distribution
501 | uses: actions/download-artifact@v2
502 | with:
503 | name: dist
504 |
505 | - name: Run Test
506 | shell: bash
507 | run: java -cp opencv-${{ env.POM_VERSION }}.jar nu.pattern.PrintVersion
508 |
509 |
510 |
511 |
512 | publish:
513 | if: github.event_name == 'push' && contains(github.ref, 'refs/tags/')
514 |
515 | needs: test
516 |
517 | strategy:
518 | matrix:
519 | os: [ubuntu-20.04]
520 | java: [8]
521 |
522 | runs-on: ${{ matrix.os }}
523 |
524 | steps:
525 | - name: Checkout Repo
526 | uses: actions/checkout@v2
527 |
528 | - name: Setup JDK ${{ matrix.java }}
529 | uses: actions/setup-java@v1
530 | with:
531 | java-version: ${{ matrix.java }}
532 | server-id: ossrh
533 | server-username: OSSRH_USERNAME
534 | server-password: OSSRH_PASSWORD
535 | gpg-private-key: ${{ secrets.MAVEN_GPG_PRIVATE_KEY }}
536 | gpg-passphrase: MAVEN_GPG_PASSPHRASE
537 |
538 | - name: Get Version Info
539 | run: |
540 | echo "POM_VERSION=$(mvn build-helper:parse-version org.apache.maven.plugins:maven-help-plugin:3.2.0:evaluate -Dexpression=project.version -q -DforceStdout)" >> $GITHUB_ENV
541 | echo "OPENCV_VERSION=$(mvn build-helper:parse-version org.apache.maven.plugins:maven-help-plugin:3.2.0:evaluate -Dexpression=opencv.version.long -q -DforceStdout)" >> $GITHUB_ENV
542 | echo "OPENCV_VERSION_SHORT=$(mvn build-helper:parse-version org.apache.maven.plugins:maven-help-plugin:3.2.0:evaluate -Dexpression=opencv.version.short -q -DforceStdout)" >> $GITHUB_ENV
543 |
544 | - name: Download Libraries
545 | uses: actions/download-artifact@v2
546 |
547 | - name: Copy Binaries
548 | run: |
549 | cp macos-11/bin/opencv-${{ env.OPENCV_VERSION_SHORT }}.jar upstream
550 | cp macos-11/lib/libopencv_java${{ env.OPENCV_VERSION_SHORT }}.dylib src/main/resources/nu/pattern/opencv/osx/x86_64
551 | cp macos-aarch64/lib/libopencv_java${{ env.OPENCV_VERSION_SHORT }}.dylib src/main/resources/nu/pattern/opencv/osx/ARMv8
552 | cp ubuntu-20.04/lib/libopencv_java${{ env.OPENCV_VERSION_SHORT }}.so src/main/resources/nu/pattern/opencv/linux/x86_64
553 | cp ubuntu-18.04-arm/lib/libopencv_java${{ env.OPENCV_VERSION_SHORT }}.so src/main/resources/nu/pattern/opencv/linux/ARMv7
554 | cp ubuntu-18.04-arm64/lib/libopencv_java${{ env.OPENCV_VERSION_SHORT }}.so src/main/resources/nu/pattern/opencv/linux/ARMv8
555 | cp windows-2016/x86/opencv_java${{ env.OPENCV_VERSION_SHORT }}.dll src/main/resources/nu/pattern/opencv/windows/x86_32
556 | cp windows-2016/x64/opencv_java${{ env.OPENCV_VERSION_SHORT }}.dll src/main/resources/nu/pattern/opencv/windows/x86_64
557 |
558 | - name: Publish to Apache Maven Central
559 | run: mvn -B -e clean deploy -P release-sign-artifacts
560 | env:
561 | OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }}
562 | OSSRH_PASSWORD: ${{ secrets.OSSRH_PASSWORD }}
563 | MAVEN_GPG_PASSPHRASE: ${{ secrets.MAVEN_GPG_PASSPHRASE }}
564 |
565 |
566 |
567 |
568 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | *.sc
3 | .DS_Store
4 | .idea
5 | settings.xml
6 | target
7 | .classpath
8 | .project
9 | .settings/org.eclipse.core.resources.prefs
10 | .settings/org.eclipse.jdt.core.prefs
11 | .settings/org.eclipse.m2e.core.prefs
12 | opencv/**
13 | .metadata/
14 | .vscode
15 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Issues, Bug Reports, and Feature Requests
2 |
3 | * When creating a new Issue, first search to see if it has already been filed.
4 | * Bug reports must include the following or will be deleted:
5 | * Steps to reproduce.
6 | * Expected result.
7 | * Actual result.
8 | * A Short, Self Contained, Correct, Example: http://sscce.org/
9 | * Notes, log files, screen captures, videos, etc. to show the problem.
10 |
11 | # Code Contributions and Pull Requests
12 |
13 | Before starting work on a pull request, please read: https://github.com/openpnp/openpnp/wiki/Developers-Guide#contributing
14 |
15 | Summary of guidelines:
16 |
17 | * One pull request per issue, bug or feature.
18 | * Describe the change in detail and why it is needed.
19 | * Follow the coding style.
20 | * Include tests and documentation.
21 | * Run and pass the tests.
22 | * Think of how this affects other users.
23 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | By downloading, copying, installing or using the software you agree to this license.
2 | If you do not agree to this license, do not download, install,
3 | copy or use the software.
4 |
5 |
6 | License Agreement
7 | For Open Source Computer Vision Library
8 | (3-clause BSD License)
9 |
10 | Redistribution and use in source and binary forms, with or without modification,
11 | are permitted provided that the following conditions are met:
12 |
13 | * Redistributions of source code must retain the above copyright notice,
14 | this list of conditions and the following disclaimer.
15 |
16 | * Redistributions in binary form must reproduce the above copyright notice,
17 | this list of conditions and the following disclaimer in the documentation
18 | and/or other materials provided with the distribution.
19 |
20 | * Neither the names of the copyright holders nor the names of the contributors
21 | may be used to endorse or promote products derived from this software
22 | without specific prior written permission.
23 |
24 | This software is provided by the copyright holders and contributors "as is" and
25 | any express or implied warranties, including, but not limited to, the implied
26 | warranties of merchantability and fitness for a particular purpose are disclaimed.
27 | In no event shall copyright holders or contributors be liable for any direct,
28 | indirect, incidental, special, exemplary, or consequential damages
29 | (including, but not limited to, procurement of substitute goods or services;
30 | loss of use, data, or profits; or business interruption) however caused
31 | and on any theory of liability, whether in contract, strict liability,
32 | or tort (including negligence or otherwise) arising in any way out of
33 | the use of this software, even if advised of the possibility of such damage.
34 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # OpenCV (packaged by [OpenPnP](http://openpnp.org))
2 |
3 | [OpenCV](http://opencv.org) Java bindings packaged with native libraries, seamlessly delivered as a turn-key Maven dependency.
4 |
5 | ## Fork Notes
6 |
7 | ### Soft Fork
8 |
9 | This is a soft fork of Pattern's OpenCV package at https://github.com/PatternConsulting/opencv.
10 | That package has not been maintained in quite some time and I needed updated OpenCV
11 | binaries for OpenPnP. I intend to maintain this fork for the foreseeable future
12 | or until Pattern resumes maintenance of their package.
13 |
14 | ### Backwards Compatibility
15 |
16 | I have left the source code packages and directories the same (nu.pattern)
17 | and only changed the Maven coordinates in the pom.xml. This way the package
18 | remains backwards compatible and it is very easy to switch between the
19 | OpenPnP version and the Pattern version.
20 |
21 | ### Maven
22 |
23 | To use this fork in your project, instead of the Pattern one, simply add
24 | the same dependency but with the groupId org.openpnp instead of nu.pattern.
25 |
26 | ### Scala
27 |
28 | I'm not uploading Scala artifacts as I don't know or use Scala. If someone
29 | wants to maintain that portion of the package, let me know.
30 |
31 | ## Usage
32 |
33 | ### Project
34 |
35 | OpenPnP's OpenCV package is added to your project as any other dependency.
36 |
37 | #### [Maven](http://maven.apache.org/)
38 |
39 | ```xml
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 | org.openpnp
50 | opencv
51 | [4.3.0,)
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 | ```
62 |
63 | A list of all published versions can be found at https://mvnrepository.com/artifact/org.openpnp/opencv.
64 |
65 | ### API
66 |
67 | Typically, using the upstream [OpenCV Java bindings involves loading the native library](http://docs.opencv.org/doc/tutorials/introduction/desktop_java/java_dev_intro.html#java-sample-with-ant) as follows:
68 |
69 | ```java
70 | static {
71 | System.loadLibrary(org.opencv.core.Core.NATIVE_LIBRARY_NAME);
72 | }
73 | ```
74 |
75 | Fortunately, this is unchanged except for one caveat. To use the native libraries included with this package, first call [`nu.pattern.OpenCV.loadShared()`](https://github.com/PatternConsulting/opencv/blob/master/src/main/java/nu/pattern/OpenCV.java).
76 |
77 | **Note: In Java 12+ loadShared() is not available. Use loadLocally() instead, and see notes below.**
78 |
79 | This call will—exactly once per class loader—first attempt to load from the system-wide installation (exactly as if `System.loadLibrary(org.opencv.core.Core.NATIVE_LIBRARY_NAME);` were called without any preceding steps). If that fails, the loader will select a binary from the package appropriate for the runtime environment's operating system and architecture. It will write that native library to a temporary directory (also defined by the environment), add that directory to `java.library.path`. _This involves writing to disk_, so consider the implications. Temporary files will be garbage-collected on clean shutdown.
80 |
81 | This approach keeps most clients decoupled from Pattern's package and loader. As long as this is done sufficiently early in execution, any library using the OpenCV Java bindings can use the usual load call as documented by the OpenCV project.
82 |
83 | There are, however, cases where Java class loaders are frequently changing (_e.g._, application servers, SBT projects, Scala worksheets), and [spurious attempts to load the native library will result in JNI errors](https://github.com/PatternConsulting/opencv/issues/7). As a partial work-around, this package offers an alternative API, [`nu.pattern.OpenCV.loadLocally()`](https://github.com/PatternConsulting/opencv/blob/master/src/main/java/nu/pattern/OpenCV.java), which—also exactly once per class loader—extracts the binary appropriate for the runtime platform, and passes it to `System#load(String)`. Ultimately, this may eventually load the library redundantly in the same JVM, which could be unsafe in production. Use with caution and understand the implications.
84 |
85 | It's recommended developers using any JNI library read further:
86 |
87 | - [JNI 1.2 Specifications: Library and Version Management](http://docs.oracle.com/javase/7/docs/technotes/guides/jni/jni-12.html#libmanage)
88 | - [Holger Hoffstätte's Comments on Native Libraries, Class Loaders, and Garbage Collection](https://groups.google.com/forum/#!msg/ospl-developer/J4i6cF6yPk0/-3Jm3Qs_HDwJ)
89 |
90 | ## Debugging
91 |
92 | [Java logging](http://docs.oracle.com/javase/8/docs/api/java/util/logging/package-summary.html) is used to produce log messages from `nu.pattern.OpenCV`.
93 |
94 | ## Rationale
95 |
96 | Developers wishing to use the Java API for OpenCV would typically go through the process of building the project, and building it for each platform they wished to support (_e.g._, 32-bit Linux, OS X). This project provides those binaries for inclusion as a typical dependency in Maven, Ivy, and SBT projects.
97 |
98 | Apart from testing, this package deliberately specifies no external dependencies. It does, however, make use of modern Java APIs (such as [Java NIO](http://docs.oracle.com/javase/tutorial/essential/io/fileio.html)).
99 |
100 | ## Contributing
101 |
102 | Producing native binaries is the most cumbersome process in maintaining this package. If you can contribute binaries _for the current version_, please make a pull request including the build artifacts and any platform definitions in `nu.pattern.OpenCV`.
103 |
104 | ## Support
105 |
106 | The following platforms are supported by this package:
107 |
108 | OS | Architecture
109 | --- | ---
110 | macOS | Intel
111 | macOS | Apple Silicon (arm64)
112 | Linux | x86_64
113 | Linux | ARMv7 (arm)
114 | Linux | ARMv8 (arm64 / aarch64)
115 | Windows | x86_32
116 | Windows | x86_64
117 |
118 | If you can help create binaries for additional platforms, please see notes under [_Contributing_](#contributing).
119 |
120 | ## Credits
121 |
122 | This package is maintained by [Jason von Nieda](http://github.com/vonnieda). If you find it useful, please
123 | consider [sponsoring me](https://github.com/sponsors/vonnieda).
124 |
125 | ## Acknowledgements
126 |
127 | - [Michael Ahlers](http://github.com/michaelahlers), for originally creating and maintaining this project.
128 | - [Greg Borenstein](https://github.com/atduskgreg), whose advice and [OpenCV for Processing](https://github.com/atduskgreg/opencv-processing) project informed this package's development.
129 | - [Alex Osborne](https://github.com/ato), for helpful [utility class producing temporary directories with Java NIO that are properly garbage-collected on shutdown](https://gist.github.com/ato/6774390).
130 |
131 | ## Builds
132 |
133 | Builds are automatically created and published to Maven Central by Github Actions triggered by new tags. Builds are also created for branches and pull requests, and the artifacts can be downloaded from the Actions tab. These are not automatically released to Maven Central.
134 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | bundle
8 | org.openpnp
9 | opencv
10 | 4.9.0-0
11 | OpenPnP OpenCV
12 | OpenCV packaged with native libraries and loader for multiple platforms.
13 | http://github.com/openpnp/opencv
14 |
15 |
16 | UTF-8
17 | ${parsedVersion.majorVersion}.${parsedVersion.minorVersion}.${parsedVersion.incrementalVersion}
18 | ${parsedVersion.majorVersion}${parsedVersion.minorVersion}${parsedVersion.incrementalVersion}
19 |
20 |
21 |
22 |
23 | jdk-8
24 |
25 | 1.8
26 |
27 |
28 |
29 | -Xdoclint:none
30 |
31 |
32 |
33 |
34 | release-sign-artifacts
35 |
36 |
37 | gpg.sign
38 | true
39 |
40 |
41 |
42 |
43 |
44 | org.apache.maven.plugins
45 | maven-gpg-plugin
46 | 1.6
47 |
48 |
49 | sign-artifacts
50 | verify
51 |
52 | sign
53 |
54 |
55 |
56 |
57 | --pinentry-mode
58 | loopback
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 | BSD License
72 | http://github.com/Itseez/opencv/raw/master/LICENSE
73 |
74 |
75 |
76 |
77 | http://github.com/openpnp/opencv
78 | scm:git:http://github.com/openpnp/opencv.git
79 | scm:git:http://github.com/openpnp/opencv.git
80 |
81 |
82 |
83 | GitHub
84 | http://github.com/openpnp/opencv/issues
85 |
86 |
87 |
88 |
89 | vonnieda
90 | Jason von Nieda
91 | jason@vonnieda.org
92 | OpenPnP
93 | http://openpnp.org
94 |
95 | maintainer
96 |
97 |
98 |
99 | michaelahlers
100 | Michael Ahlers
101 | michael.ahlers@pattern.nu
102 | Pattern
103 | http://pattern.nu
104 |
105 | maintainer
106 |
107 |
110 |
111 |
112 |
113 |
114 |
115 | ossrh
116 | https://oss.sonatype.org/content/repositories/snapshots
117 |
118 |
119 |
120 |
121 |
122 |
123 | org.codehaus.mojo
124 | build-helper-maven-plugin
125 | 3.2.0
126 |
127 |
128 | parse-version
129 |
130 | parse-version
131 |
132 |
133 |
134 |
135 |
136 |
137 | org.sonatype.plugins
138 | nexus-staging-maven-plugin
139 | 1.6.7
140 | true
141 |
142 | ossrh
143 | https://oss.sonatype.org/
144 | true
145 |
146 |
147 |
148 |
149 | org.apache.felix
150 | maven-bundle-plugin
151 | true
152 |
153 |
154 | nu.pattern.*, org.opencv.*
155 | !sun.reflect.*
156 |
157 |
158 |
159 |
160 |
161 |
162 | maven-compiler-plugin
163 |
164 | 1.7
165 | 1.7
166 |
167 |
168 |
169 |
170 |
171 | maven-antrun-plugin
172 | 1.3
173 |
174 |
175 | generate-sources
176 |
177 |
178 | Extracting Java classes.
179 |
180 |
181 |
182 |
183 |
184 |
185 | Extracting Java sources.
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 | run
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 | org.codehaus.mojo
203 | build-helper-maven-plugin
204 | 1.8
205 |
206 |
207 | prepare-package
208 |
209 | add-source
210 |
211 |
212 |
213 | ${project.build.directory}/upstream-sources
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 | org.apache.maven.plugins
223 | maven-source-plugin
224 | 2.2.1
225 |
226 |
227 |
228 | jar
229 |
230 |
231 |
232 |
233 |
234 |
235 | maven-surefire-plugin
236 | 2.12.4
237 |
238 |
239 |
240 | java.util.logging.config.file
241 | ${project.build.directory}/test-classes/logging.properties
242 |
243 |
244 |
245 |
246 |
247 | listener
248 | nu.pattern.LoadLibraryRunListener
249 |
250 |
251 |
252 | ${project.basedir}/upstream
253 |
254 |
255 | **/OpenCVTestCase.*
256 |
257 |
258 |
259 |
260 |
261 | org.apache.maven.plugins
262 | maven-javadoc-plugin
263 | 2.9.1
264 |
265 |
266 | attach-javadocs
267 |
268 | jar
269 |
270 |
271 |
272 |
273 |
274 | http://docs.opencv.org/java/
275 | http://docs.oracle.com/javase/8/docs/api/
276 |
277 | ${javadoc.parameters}
278 |
279 |
280 |
281 |
282 |
283 |
284 |
285 | org.eclipse.m2e
286 | lifecycle-mapping
287 | 1.0.0
288 |
289 |
290 |
291 |
292 |
293 |
294 | org.apache.maven.plugins
295 |
296 |
297 | maven-antrun-plugin
298 |
299 | [1.3,)
300 |
301 | run
302 |
303 |
304 |
305 |
306 |
307 |
308 |
309 |
310 |
311 |
312 |
313 |
314 |
315 |
316 |
317 |
318 | junit
319 | junit
320 | 4.11
321 | test
322 |
323 |
324 |
325 |
326 |
--------------------------------------------------------------------------------
/src/main/java/nu/pattern/OpenCV.java:
--------------------------------------------------------------------------------
1 | package nu.pattern;
2 |
3 | import java.io.File;
4 | import java.io.IOException;
5 | import java.io.InputStream;
6 | import java.lang.reflect.Field;
7 | import java.nio.file.AccessDeniedException;
8 | import java.nio.file.FileVisitResult;
9 | import java.nio.file.Files;
10 | import java.nio.file.Path;
11 | import java.nio.file.SimpleFileVisitor;
12 | import java.nio.file.attribute.BasicFileAttributes;
13 | import java.util.Arrays;
14 | import java.util.HashSet;
15 | import java.util.List;
16 | import java.util.Set;
17 | import java.util.logging.Level;
18 | import java.util.logging.Logger;
19 | import java.util.regex.Pattern;
20 |
21 | import org.opencv.core.Core;
22 |
23 | public class OpenCV {
24 |
25 | private final static Logger logger = Logger.getLogger(OpenCV.class.getName());
26 |
27 |
28 |
29 | static enum OS {
30 | OSX("^[Mm]ac OS X$"),
31 | LINUX("^[Ll]inux$"),
32 | WINDOWS("^[Ww]indows.*");
33 |
34 | private final Set patterns;
35 |
36 | private OS(final String... patterns) {
37 | this.patterns = new HashSet();
38 |
39 | for (final String pattern : patterns) {
40 | this.patterns.add(Pattern.compile(pattern));
41 | }
42 | }
43 |
44 | private boolean is(final String id) {
45 | for (final Pattern pattern : patterns) {
46 | if (pattern.matcher(id).matches()) {
47 | return true;
48 | }
49 | }
50 | return false;
51 | }
52 |
53 | public static OS getCurrent() {
54 | final String osName = System.getProperty("os.name");
55 |
56 | for (final OS os : OS.values()) {
57 | if (os.is(osName)) {
58 | logger.log(Level.FINEST, "Current environment matches operating system descriptor \"{0}\".", os);
59 | return os;
60 | }
61 | }
62 |
63 | throw new UnsupportedOperationException(String.format("Operating system \"%s\" is not supported.", osName));
64 | }
65 | }
66 |
67 | static enum Arch {
68 | X86_32("i386", "i686", "x86"),
69 | X86_64("amd64", "x86_64"),
70 | ARMv7("arm"),
71 | ARMv8("aarch64", "arm64");
72 |
73 | private final Set patterns;
74 |
75 | private Arch(final String... patterns) {
76 | this.patterns = new HashSet(Arrays.asList(patterns));
77 | }
78 |
79 | private boolean is(final String id) {
80 | return patterns.contains(id);
81 | }
82 |
83 | public static Arch getCurrent() {
84 | final String osArch = System.getProperty("os.arch");
85 |
86 | for (final Arch arch : Arch.values()) {
87 | if (arch.is(osArch)) {
88 | logger.log(Level.FINEST, "Current environment matches architecture descriptor \"{0}\".", arch);
89 | return arch;
90 | }
91 | }
92 |
93 | throw new UnsupportedOperationException(String.format("Architecture \"%s\" is not supported.", osArch));
94 | }
95 | }
96 |
97 | private static class UnsupportedPlatformException extends RuntimeException {
98 | private UnsupportedPlatformException(final OS os, final Arch arch) {
99 | super(String.format("Operating system \"%s\" and architecture \"%s\" are not supported.", os, arch));
100 | }
101 | }
102 |
103 | private static class TemporaryDirectory {
104 | static final String OPENCV_PREFIX = "opencv_openpnp";
105 | final Path path;
106 |
107 | public TemporaryDirectory() {
108 | try {
109 | path = Files.createTempDirectory(OPENCV_PREFIX);
110 | } catch (IOException e) {
111 | throw new RuntimeException(e);
112 | }
113 | }
114 |
115 | public Path getPath() {
116 | return path;
117 | }
118 |
119 | public TemporaryDirectory deleteOldInstancesOnStart() {
120 | Path tempDirectory = path.getParent();
121 |
122 | for (File file : tempDirectory.toFile().listFiles()) {
123 | if (file.isDirectory() && file.getName().startsWith(OPENCV_PREFIX)) {
124 | try {
125 | delete(file.toPath());
126 | } catch (RuntimeException e) {
127 | if (e.getCause() instanceof AccessDeniedException) {
128 | logger.fine("Failed delete a previous instance of the OpenCV binaries, "
129 | + "likely in use by another program: ");
130 | }
131 | }
132 | }
133 | }
134 |
135 | return this;
136 | }
137 |
138 | public TemporaryDirectory markDeleteOnExit() {
139 | Runtime.getRuntime().addShutdownHook(new Thread() {
140 | @Override
141 | public void run() {
142 | delete();
143 | }
144 | });
145 |
146 | return this;
147 | }
148 |
149 | private void delete(Path path) {
150 | if (!Files.exists(path)) {
151 | return;
152 | }
153 |
154 | try {
155 | Files.walkFileTree(path, new SimpleFileVisitor() {
156 | @Override
157 | public FileVisitResult postVisitDirectory(final Path dir, final IOException e) throws IOException {
158 | Files.deleteIfExists(dir);
159 | return super.postVisitDirectory(dir, e);
160 | }
161 |
162 | @Override
163 | public FileVisitResult visitFile(final Path file, final BasicFileAttributes attrs)
164 | throws IOException {
165 | Files.deleteIfExists(file);
166 | return super.visitFile(file, attrs);
167 | }
168 | });
169 | } catch (IOException e) {
170 | throw new RuntimeException(e);
171 | }
172 | }
173 |
174 | public void delete() {
175 | delete(path);
176 | }
177 | }
178 |
179 | /**
180 | * Exactly once per {@link ClassLoader}, attempt to load the native library (via {@link System#loadLibrary(String)} with {@link Core#NATIVE_LIBRARY_NAME}). If the first attempt fails, the native binary will be extracted from the classpath to a temporary location (which gets cleaned up on shutdown), that location is added to the {@code java.library.path} system property and {@link ClassLoader#usr_paths}, and then another call to load the library is made. Note this method uses reflection to gain access to private memory in {@link ClassLoader} as there's no documented method to augment the library path at runtime. Spurious calls are safe.
181 | */
182 | public static void loadShared() {
183 | SharedLoader.getInstance();
184 | }
185 |
186 | /**
187 | * @see Initialization-on-demand holder idiom
188 | */
189 | private static class SharedLoader {
190 | // Class loader error messages indicating OpenCV is not found on java.library.path
191 | private static final List errorMessages = Arrays.asList(
192 | String.format("no %s in java.library.path", Core.NATIVE_LIBRARY_NAME),
193 | String.format("%s (Not found in java.library.path)", Core.NATIVE_LIBRARY_NAME)
194 | );
195 |
196 | private Path libraryPath;
197 |
198 | private SharedLoader() {
199 | try {
200 | System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
201 | logger.log(Level.FINEST, "Loaded existing OpenCV library \"{0}\" from library path.", Core.NATIVE_LIBRARY_NAME);
202 | } catch (final UnsatisfiedLinkError ule) {
203 |
204 | /* Only update the library path and load if the original error indicates it's missing from the library path. */
205 | if (ule == null || !openCVNotFoundInJavaLibraryPath(ule.getMessage())) {
206 | logger.log(Level.FINEST, String.format("Encountered unexpected loading error."), ule);
207 | throw ule;
208 | }
209 |
210 | /**
211 | * In Java >= 12 it is no longer possible to use addLibraryPath, which modifies the
212 | * ClassLoader's static usr_paths field. There does not seem to be any way around this
213 | * so we fall back to loadLocally() and return.
214 | */
215 | if (Double.parseDouble(System.getProperty("java.specification.version")) >= 12) {
216 | logger.log(Level.SEVERE, "OpenCV.loadShared() is not supported in Java >= 12. Falling back to OpenCV.loadLocally().");
217 | OpenCV.loadLocally();
218 | return;
219 | }
220 |
221 | /* Retain this path for cleaning up the library path later. */
222 | this.libraryPath = extractNativeBinary();
223 |
224 | addLibraryPath(libraryPath.getParent());
225 | System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
226 |
227 | logger.log(Level.FINEST, "OpenCV library \"{0}\" loaded from extracted copy at \"{1}\".", new Object[]{Core.NATIVE_LIBRARY_NAME, System.mapLibraryName(Core.NATIVE_LIBRARY_NAME)});
228 | }
229 | }
230 |
231 | /**
232 | * Check if any error fragment is contained in the errorMessage
233 | * @param errorMessage the message to check
234 | * @return true if any error fragment matches, false otherwise
235 | */
236 | private boolean openCVNotFoundInJavaLibraryPath(String errorMessage) {
237 | for (String errorFragment : errorMessages) {
238 | if (errorMessage.contains(errorFragment)) {
239 | return true;
240 | }
241 | }
242 |
243 | return false;
244 | }
245 |
246 | /**
247 | * Cleans up patches done to the environment.
248 | */
249 | @Override
250 | protected void finalize() throws Throwable {
251 | super.finalize();
252 |
253 | if (null == libraryPath) {
254 | return;
255 | }
256 |
257 | removeLibraryPath(libraryPath.getParent());
258 | }
259 |
260 | private static class Holder {
261 | private static final SharedLoader INSTANCE = new SharedLoader();
262 | }
263 |
264 | public static SharedLoader getInstance() {
265 | return Holder.INSTANCE;
266 | }
267 |
268 | /**
269 | * Adds the provided {@link Path}, normalized, to the {@link ClassLoader#usr_paths} array, as well as to the {@code java.library.path} system property. Uses the reflection API to make the field accessible, and may be unsafe in environments with a security policy.
270 | *
271 | * @see Adding new paths for native libraries at runtime in Java
272 | */
273 | private static void addLibraryPath(final Path path) {
274 | final String normalizedPath = path.normalize().toString();
275 |
276 | try {
277 | final Field field = ClassLoader.class.getDeclaredField("usr_paths");
278 | field.setAccessible(true);
279 |
280 | final Set userPaths = new HashSet<>(Arrays.asList((String[]) field.get(null)));
281 | userPaths.add(normalizedPath);
282 |
283 | field.set(null, userPaths.toArray(new String[userPaths.size()]));
284 |
285 | System.setProperty("java.library.path", System.getProperty("java.library.path") + File.pathSeparator + normalizedPath);
286 |
287 | logger.log(Level.FINEST, "System library path now \"{0}\".", System.getProperty("java.library.path"));
288 | } catch (IllegalAccessException e) {
289 | throw new RuntimeException("Failed to get permissions to set library path");
290 | } catch (NoSuchFieldException e) {
291 | throw new RuntimeException("Failed to get field handle to set library path");
292 | }
293 | }
294 |
295 | /**
296 | * Removes the provided {@link Path}, normalized, from the {@link ClassLoader#usr_paths} array, as well as to the {@code java.library.path} system property. Uses the reflection API to make the field accessible, and may be unsafe in environments with a security policy.
297 | */
298 | private static void removeLibraryPath(final Path path) {
299 | final String normalizedPath = path.normalize().toString();
300 |
301 | try {
302 | final Field field = ClassLoader.class.getDeclaredField("usr_paths");
303 | field.setAccessible(true);
304 |
305 | final Set userPaths = new HashSet<>(Arrays.asList((String[]) field.get(null)));
306 | userPaths.remove(normalizedPath);
307 |
308 | field.set(null, userPaths.toArray(new String[userPaths.size()]));
309 |
310 | System.setProperty("java.library.path", System.getProperty("java.library.path").replace(File.pathSeparator + path.normalize().toString(), ""));
311 | } catch (IllegalAccessException e) {
312 | throw new RuntimeException("Failed to get permissions to set library path");
313 | } catch (NoSuchFieldException e) {
314 | throw new RuntimeException("Failed to get field handle to set library path");
315 | }
316 | }
317 | }
318 |
319 | /**
320 | * Exactly once per {@link ClassLoader}, extract the native binary from the classpath to a temporary location (which gets cleaned up on shutdown), and load that binary (via {@link System#load(String)}). Spurious calls are safe.
321 | */
322 | public static void loadLocally() {
323 | LocalLoader.getInstance();
324 | }
325 |
326 | private static class LocalLoader {
327 | private LocalLoader() {
328 | /* Retain this path for cleaning up later. */
329 | final Path libraryPath = extractNativeBinary();
330 | System.load(libraryPath.normalize().toString());
331 |
332 | logger.log(Level.FINEST, "OpenCV library \"{0}\" loaded from extracted copy at \"{1}\".", new Object[]{Core.NATIVE_LIBRARY_NAME, System.mapLibraryName(Core.NATIVE_LIBRARY_NAME)});
333 | }
334 |
335 | private static class Holder {
336 | private static final LocalLoader INSTANCE = new LocalLoader();
337 | }
338 |
339 | public static LocalLoader getInstance() {
340 | return Holder.INSTANCE;
341 | }
342 | }
343 |
344 | /**
345 | * Selects the appropriate packaged binary, extracts it to a temporary location (which gets deleted when the JVM shuts down), and returns a {@link Path} to that file.
346 | */
347 | private static Path extractNativeBinary() {
348 | final OS os = OS.getCurrent();
349 | final Arch arch = Arch.getCurrent();
350 | return extractNativeBinary(os, arch);
351 | }
352 |
353 | /**
354 | * Extracts the packaged binary for the specified platform to a temporary location (which gets deleted when the JVM shuts down), and returns a {@link Path} to that file.
355 | */
356 | private static Path extractNativeBinary(final OS os, final Arch arch) {
357 | final String location;
358 |
359 | switch (os) {
360 | case LINUX:
361 | switch (arch) {
362 | case X86_64:
363 | location = "/nu/pattern/opencv/linux/x86_64/libopencv_java490.so";
364 | break;
365 | case ARMv7:
366 | location = "/nu/pattern/opencv/linux/ARMv7/libopencv_java490.so";
367 | break;
368 | case ARMv8:
369 | location = "/nu/pattern/opencv/linux/ARMv8/libopencv_java490.so";
370 | break;
371 | default:
372 | throw new UnsupportedPlatformException(os, arch);
373 | }
374 | break;
375 | case OSX:
376 | switch (arch) {
377 | case X86_64:
378 | location = "/nu/pattern/opencv/osx/x86_64/libopencv_java490.dylib";
379 | break;
380 | case ARMv8:
381 | location = "/nu/pattern/opencv/osx/ARMv8/libopencv_java490.dylib";
382 | break;
383 | default:
384 | throw new UnsupportedPlatformException(os, arch);
385 | }
386 | break;
387 | case WINDOWS:
388 | switch (arch) {
389 | case X86_32:
390 | location = "/nu/pattern/opencv/windows/x86_32/opencv_java490.dll";
391 | break;
392 | case X86_64:
393 | location = "/nu/pattern/opencv/windows/x86_64/opencv_java490.dll";
394 | break;
395 | default:
396 | throw new UnsupportedPlatformException(os, arch);
397 | }
398 | break;
399 | default:
400 | throw new UnsupportedPlatformException(os, arch);
401 | }
402 |
403 | logger.log(Level.FINEST, "Selected native binary \"{0}\".", location);
404 |
405 | final InputStream binary = OpenCV.class.getResourceAsStream(location);
406 | final Path destination;
407 |
408 | // Do not try to delete the temporary directory on the close if Windows
409 | // because there will be a write lock on the file which will cause an
410 | // AccessDeniedException. Instead, try to delete existing instances of
411 | // the temporary directory before extracting.
412 | if (OS.WINDOWS.equals(os)) {
413 | destination = new TemporaryDirectory().deleteOldInstancesOnStart().getPath().resolve("./" + location).normalize();
414 | } else {
415 | destination = new TemporaryDirectory().markDeleteOnExit().getPath().resolve("./" + location).normalize();
416 | }
417 |
418 | try {
419 | logger.log(Level.FINEST, "Copying native binary to \"{0}\".", destination);
420 | Files.createDirectories(destination.getParent());
421 | Files.copy(binary, destination);
422 | binary.close();
423 | } catch (final IOException ioe) {
424 | throw new IllegalStateException(String.format("Error writing native library to \"%s\".", destination), ioe);
425 | }
426 |
427 | logger.log(Level.FINEST, "Extracted native binary to \"{0}\".", destination);
428 |
429 | return destination;
430 | }
431 | }
432 |
--------------------------------------------------------------------------------
/src/main/java/nu/pattern/PrintVersion.java:
--------------------------------------------------------------------------------
1 | package nu.pattern;
2 |
3 | import org.opencv.core.Core;
4 |
5 | public class PrintVersion {
6 | static {
7 | OpenCV.loadLocally();
8 | }
9 |
10 | public static void main(String[] args) {
11 | System.out.println(Core.getVersionString());
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/main/resources/nu/pattern/opencv/linux/ARMv7/README.md:
--------------------------------------------------------------------------------
1 | Placeholder
--------------------------------------------------------------------------------
/src/main/resources/nu/pattern/opencv/linux/ARMv8/README.md:
--------------------------------------------------------------------------------
1 | # Placeholder
2 |
--------------------------------------------------------------------------------
/src/main/resources/nu/pattern/opencv/linux/x86_32/README.md:
--------------------------------------------------------------------------------
1 | # Linux x86_32
2 |
3 | ## Preparation
4 |
5 | ```shell
6 | cmake -DBUILD_SHARED_LIBS=OFF ..
7 | ```
8 |
9 | ## Build
10 |
11 | ```shell
12 | make -j8
13 | ```
14 |
--------------------------------------------------------------------------------
/src/main/resources/nu/pattern/opencv/linux/x86_64/README.md:
--------------------------------------------------------------------------------
1 | # Linux x86_64
2 |
3 | ## Preparation
4 |
5 | ```shell
6 | cmake -DBUILD_SHARED_LIBS=OFF ..
7 | ```
8 |
9 | ## Build
10 |
11 | ```shell
12 | make -j8
13 | ```
14 |
--------------------------------------------------------------------------------
/src/main/resources/nu/pattern/opencv/osx/ARMv8/README.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openpnp/opencv/098e4996bc304eb3e5e81f0e3def2ff6af28ccc1/src/main/resources/nu/pattern/opencv/osx/ARMv8/README.md
--------------------------------------------------------------------------------
/src/main/resources/nu/pattern/opencv/osx/x86_64/README.md:
--------------------------------------------------------------------------------
1 | # OS X x86_64
2 |
3 | ```shell
4 | cmake -DBUILD_SHARED_LIBS=OFF -DEIGEN_INCLUDE_PATH=/usr/local/include/eigen3 ..
5 | ```
6 |
7 | ```shell
8 | git clone git://github.com/Itseez/opencv.git itseez-opencv
9 | cd itseez-opencv
10 | git checkout 2.4
11 | mkdir build
12 | cd build
13 | cmake -DBUILD_SHARED_LIBS=OFF -DCMAKE_OSX_ARCHITECTURES=x86_64 -DCMAKE_C_FLAGS=-m64 -DCMAKE_CXX_FLAGS=-m64 .. > cmake.log
14 | make -j8
15 | ```
16 |
--------------------------------------------------------------------------------
/src/main/resources/nu/pattern/opencv/windows/x86_32/README.md:
--------------------------------------------------------------------------------
1 | # Placeholder
2 |
--------------------------------------------------------------------------------
/src/main/resources/nu/pattern/opencv/windows/x86_64/README.md:
--------------------------------------------------------------------------------
1 | # Placeholder
2 |
--------------------------------------------------------------------------------
/src/test/java/nu/pattern/LibraryLoadingTest.java:
--------------------------------------------------------------------------------
1 | package nu.pattern;
2 |
3 | import java.util.logging.Level;
4 | import java.util.logging.Logger;
5 |
6 | import org.junit.Test;
7 | import org.junit.runner.RunWith;
8 | import org.junit.runners.JUnit4;
9 | import org.opencv.core.CvType;
10 | import org.opencv.core.Mat;
11 | import org.opencv.core.Scalar;
12 |
13 | /**
14 | * @see Issue 7
15 | */
16 | @RunWith(JUnit4.class)
17 | public class LibraryLoadingTest {
18 | private final static Logger logger = Logger.getLogger(LibraryLoadingTest.class.getName());
19 |
20 | public static class Client {
21 | static {
22 | OpenCV.loadLocally();
23 | }
24 |
25 | /**
26 | * Run interesting tests on instantiation to make reflection chores simpler.
27 | */
28 | public Client() {
29 | final Mat m = new Mat(5, 10, CvType.CV_8UC1, new Scalar(0));
30 | logger.log(Level.FINEST, "Initial matrix: {0}.", m.dump());
31 |
32 | final Mat mr1 = m.row(1);
33 | mr1.setTo(new Scalar(1));
34 |
35 | final Mat mc5 = m.col(5);
36 | mc5.setTo(new Scalar(5));
37 |
38 | logger.log(Level.FINEST, "Final matrix: {0}.", m.dump());
39 | }
40 | }
41 |
42 | /**
43 | * {@link OpenCV#loadLocally()} is safe to call repeatedly within a single {@link ClassLoader} context.
44 | */
45 | @Test
46 | public void spuriousLoads() {
47 | OpenCV.loadLocally();
48 | OpenCV.loadLocally();
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/test/java/nu/pattern/LoadLibraryRunListener.java:
--------------------------------------------------------------------------------
1 | package nu.pattern;
2 |
3 | import org.junit.runner.Description;
4 | import org.junit.runner.notification.RunListener;
5 |
6 | public class LoadLibraryRunListener extends RunListener {
7 | @Override
8 | public void testRunStarted(final Description description) throws Exception {
9 | super.testRunStarted(description);
10 | OpenCV.loadShared();
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/test/java/nu/pattern/MserTest.java:
--------------------------------------------------------------------------------
1 | package nu.pattern;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 |
6 | import org.junit.Assert;
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 | import org.junit.runners.JUnit4;
10 | import org.opencv.core.CvType;
11 | import org.opencv.core.Mat;
12 | import org.opencv.core.MatOfPoint;
13 | import org.opencv.core.MatOfRect;
14 | import org.opencv.core.Point;
15 | import org.opencv.core.Scalar;
16 | import org.opencv.features2d.MSER;
17 | import org.opencv.imgproc.Imgproc;
18 |
19 | @RunWith(JUnit4.class)
20 | public class MserTest {
21 | static {
22 | OpenCV.loadLocally();
23 | }
24 |
25 | /**
26 | * Draws a filled circle in an image and then uses MSER to attempt to
27 | * find it. Expects to find one result.
28 | */
29 | @Test
30 | public void testMser() {
31 | Mat mat = new Mat(400, 400, CvType.CV_8U);
32 | mat.setTo(new Scalar(0));
33 | Imgproc.circle(
34 | mat,
35 | new Point(200, 200),
36 | 20,
37 | new Scalar(100),
38 | -1);
39 | MSER mser = MSER.create();
40 | List msers = new ArrayList<>();
41 | MatOfRect bboxes = new MatOfRect();
42 | mser.detectRegions(mat, msers, bboxes);
43 | Assert.assertEquals(1, msers.size());
44 | }
45 | }
46 |
47 |
48 |
--------------------------------------------------------------------------------
/src/test/resources/logging.properties:
--------------------------------------------------------------------------------
1 | handlers=java.util.logging.ConsoleHandler
2 |
3 | java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter
4 | java.util.logging.ConsoleHandler.level=ALL
5 |
6 | nu.pattern.level=ALL
7 |
--------------------------------------------------------------------------------
/upstream/README.md:
--------------------------------------------------------------------------------
1 | # Upstream
2 |
3 | Java resources produced by the OpenCV build process. This project extracts them to standard locations.
4 |
5 | Aritfact | Origin | Comments
6 | --- | --- | ---
7 | `res/` | `build/modules/java/test/.build/res/` | Test fixtures.
8 | `opencv-249.jar` | `build/modules/java/test/.build/bin/opencv-249.jar` | Java API with sources.
9 | `opencv-test.jar` | `build/modules/java/test/.build/jar/opencv-test.jar` | Compiled test classes.
10 |
11 | A primary goal of this package is to avoid making any modifications to the artifacts produced by the upstream OpenCV project. The listed resources will be incorporated into standard Maven conventions.
12 |
--------------------------------------------------------------------------------