Repository: bytedeco/javacv Branch: master Commit: 47b4003c00b0 Files: 131 Total size: 1.9 MB Directory structure: gitextract_7jum8khe/ ├── .github/ │ ├── FUNDING.yml │ └── workflows/ │ └── javacv.yml ├── .gitignore ├── .travis.yml ├── CHANGELOG.md ├── LICENSE.txt ├── README.md ├── platform/ │ ├── pom.xml │ └── src/ │ ├── main/ │ │ ├── assembly/ │ │ │ ├── bin.xml │ │ │ └── src.xml │ │ └── java9/ │ │ └── module-info.java │ └── test/ │ └── java/ │ └── org/ │ └── bytedeco/ │ └── javacv/ │ ├── FrameConverterTest.java │ ├── FrameFilterTest.java │ ├── FrameGrabberChangingResolutionTest.java │ ├── FrameGrabberTest.java │ └── SeekableByteArrayOutputStreamTest.java ├── pom.xml ├── samples/ │ ├── AudioSplitMergeHelper.java │ ├── BioInspiredRetina.java │ ├── BlobDemo.java │ ├── CaffeGooglenet.java │ ├── ColoredObjectTrack.java │ ├── DeepLearningFaceDetection.java │ ├── DeinterlacedVideoPlayer.java │ ├── Demo.java │ ├── FFmpegStreamingTimeout.java │ ├── FaceApplet.html │ ├── FaceApplet.java │ ├── FaceApplet.jnlp │ ├── FacePreview.java │ ├── FaceRecognizerInVideo.java │ ├── HoughLines.java │ ├── ImageSegmentation.java │ ├── JavaFxPlayVideoAndAudio.java │ ├── KazemiFacemarkExample.java │ ├── LBFFacemarkExampleWithVideo.java │ ├── MotionDetector.java │ ├── OpenCVFaceRecognizer.java │ ├── OpenCVFeatures2dSerialization.java │ ├── OpticalFlowDense.java │ ├── OpticalFlowTracker.java │ ├── PacketRecorderTest.java │ ├── PerspectiveWarpDemo.java │ ├── PrincipalComponentAnalysis.java │ ├── RLSA.java │ ├── RealSense2DepthMeasuring.java │ ├── RecordActivity.java │ ├── Similarity.java │ ├── Smoother.java │ ├── Square.java │ ├── TemplateMatching.java │ ├── WebcamAndMicrophoneCapture.java │ ├── YOLONet.java │ ├── haarcascade_frontalface_alt2.xml │ └── pom.xml └── src/ └── main/ ├── java/ │ ├── cl/ │ │ └── eye/ │ │ └── CLCamera.java │ └── org/ │ └── bytedeco/ │ └── javacv/ │ ├── AndroidFrameConverter.java │ ├── BaseChildSettings.java │ ├── BaseSettings.java │ ├── Blobs.java │ ├── BufferRing.java │ ├── CameraDevice.java │ ├── CameraSettings.java │ ├── CanvasFrame.java │ ├── ColorCalibrator.java │ ├── DC1394FrameGrabber.java │ ├── FFmpegFrameFilter.java │ ├── FFmpegFrameGrabber.java │ ├── FFmpegFrameRecorder.java │ ├── FFmpegLockCallback.java │ ├── FFmpegLogCallback.java │ ├── FlyCapture2FrameGrabber.java │ ├── FlyCaptureFrameGrabber.java │ ├── Frame.java │ ├── FrameConverter.java │ ├── FrameFilter.java │ ├── FrameGrabber.java │ ├── FrameRecorder.java │ ├── GLCanvasFrame.java │ ├── GNImageAligner.java │ ├── GNImageAlignerCL.java │ ├── GeometricCalibrator.java │ ├── HandMouse.java │ ├── IPCameraFrameGrabber.java │ ├── ImageAligner.java │ ├── ImageAlignerCL.java │ ├── ImageTransformer.java │ ├── ImageTransformerCL.java │ ├── Java2DFrameConverter.java │ ├── Java2DFrameUtils.java │ ├── JavaCV.java │ ├── JavaCVCL.java │ ├── JavaCvErrorCallback.java │ ├── JavaFXFrameConverter.java │ ├── LeptonicaFrameConverter.java │ ├── LibgdxFrameConverter.java │ ├── MarkedPlane.java │ ├── Marker.java │ ├── MarkerDetector.java │ ├── ObjectFinder.java │ ├── OpenCVFrameConverter.java │ ├── OpenCVFrameGrabber.java │ ├── OpenCVFrameRecorder.java │ ├── OpenKinect2FrameGrabber.java │ ├── OpenKinectFrameGrabber.java │ ├── PS3EyeFrameGrabber.java │ ├── Parallel.java │ ├── ProCamColorCalibrator.java │ ├── ProCamGeometricCalibrator.java │ ├── ProCamTransformer.java │ ├── ProCamTransformerCL.java │ ├── ProjectiveColorTransformer.java │ ├── ProjectiveColorTransformerCL.java │ ├── ProjectiveDevice.java │ ├── ProjectiveTransformer.java │ ├── ProjectiveTransformerCL.java │ ├── ProjectorDevice.java │ ├── ProjectorSettings.java │ ├── RealSense2FrameGrabber.java │ ├── RealSenseFrameGrabber.java │ ├── ReflectanceInitializer.java │ ├── Seekable.java │ ├── SeekableByteArrayOutputStream.java │ ├── VideoInputFrameGrabber.java │ └── cvkernels.java ├── java9/ │ └── module-info.java └── resources/ └── org/ └── bytedeco/ └── javacv/ ├── ImageTransformer.cl ├── JavaCV.cl ├── ProCamTransformer.cl ├── ProjectiveColorTransformer.cl └── ProjectiveTransformer.cl ================================================ FILE CONTENTS ================================================ ================================================ FILE: .github/FUNDING.yml ================================================ github: bytedeco ================================================ FILE: .github/workflows/javacv.yml ================================================ name: javacv on: [push, pull_request, workflow_dispatch] env: CI_DEPLOY_MODULE: . CI_DEPLOY_PLATFORM: ${{ github.job }} CI_DEPLOY_SETTINGS: ${{ secrets.CI_DEPLOY_SETTINGS }} CI_DEPLOY_USERNAME: ${{ secrets.CI_DEPLOY_USERNAME }} CI_DEPLOY_PASSWORD: ${{ secrets.CI_DEPLOY_PASSWORD }} STAGING_REPOSITORY: ${{ secrets.STAGING_REPOSITORY }} jobs: linux-arm64: runs-on: ubuntu-22.04-arm steps: - uses: bytedeco/javacpp-presets/.github/actions/deploy-ubuntu@actions - uses: mxschmitt/action-tmate@v3 if: ${{ github.event_name == 'workflow_dispatch' }} linux-x86_64: runs-on: ubuntu-22.04 steps: - uses: bytedeco/javacpp-presets/.github/actions/deploy-ubuntu@actions - uses: mxschmitt/action-tmate@v3 if: ${{ github.event_name == 'workflow_dispatch' }} macosx-arm64: runs-on: macos-15 steps: - uses: bytedeco/javacpp-presets/.github/actions/deploy-macosx@actions - uses: mxschmitt/action-tmate@v3 if: ${{ github.event_name == 'workflow_dispatch' }} macosx-x86_64: runs-on: macos-15-intel steps: - uses: bytedeco/javacpp-presets/.github/actions/deploy-macosx@actions - uses: mxschmitt/action-tmate@v3 if: ${{ github.event_name == 'workflow_dispatch' }} windows-x86_64: runs-on: windows-2022 steps: - uses: bytedeco/javacpp-presets/.github/actions/deploy-windows@actions - uses: mxschmitt/action-tmate@v3 if: ${{ github.event_name == 'workflow_dispatch' }} platform: needs: [linux-x86_64, macosx-arm64, macosx-x86_64, windows-x86_64] runs-on: ubuntu-22.04 steps: - uses: bytedeco/javacpp-presets/.github/actions/redeploy@actions ================================================ FILE: .gitignore ================================================ **/target/** # Mac .DS_Store # Eclipse .classpath .project .settings # IntelliJ *.iml .idea ================================================ FILE: .travis.yml ================================================ dist: xenial cache: directories: - $HOME/.m2/repository before_install: - "echo '${env.HOME}/.m2/repositorysonatype-nexus-snapshots${env.CI_DEPLOY_USERNAME}${env.CI_DEPLOY_PASSWORD}' > $HOME/settings.xml" - "[[ $TRAVIS_PULL_REQUEST == 'false' ]] && export MAVEN_PHASE=deploy || export MAVEN_PHASE=install" jobs: include: - os: linux arch: arm64 language: java addons: apt: packages: openjdk-8-jdk openjfx maven env: PLATFORMS="linux-arm64" install: - export JAVA_HOME="/usr/lib/jvm/java-8-openjdk-arm64" script: - mvn clean $MAVEN_PHASE -B -V -U -s $HOME/settings.xml - mvn clean $MAVEN_PHASE -B -V -U -s $HOME/settings.xml -f platform/pom.xml -Djavacpp.platform=linux-arm64 '-Dtest=!FrameGrabberTest#testFFmpegFrameGrabber' - os: linux arch: ppc64le language: java addons: apt: packages: openjdk-8-jdk openjfx maven env: PLATFORMS="linux-ppc64le" install: - export JAVA_HOME="/usr/lib/jvm/java-8-openjdk-ppc64el" script: - mvn clean $MAVEN_PHASE -B -V -U -s $HOME/settings.xml - mvn clean $MAVEN_PHASE -B -V -U -s $HOME/settings.xml -f platform/pom.xml -Djavacpp.platform=linux-ppc64le - os: linux arch: amd64 language: java addons: apt: packages: openjdk-8-jdk openjfx maven env: PLATFORMS="linux-x86_64" install: - export JAVA_HOME="/usr/lib/jvm/java-8-openjdk-amd64" script: - mvn clean $MAVEN_PHASE -B -V -U -s $HOME/settings.xml - mvn clean $MAVEN_PHASE -B -V -U -s $HOME/settings.xml -f platform/pom.xml -Djavacpp.platform=linux-x86_64 - os: osx osx_image: xcode12.2 language: java env: PLATFORMS="macosx-x86_64" install: - brew update - brew install gpg1 - brew tap AdoptOpenJDK/openjdk - brew install --cask adoptopenjdk8 - export JAVA_HOME=$(/usr/libexec/java_home -v1.8) script: - mvn clean $MAVEN_PHASE -B -V -U -s $HOME/settings.xml - mvn clean $MAVEN_PHASE -B -V -U -s $HOME/settings.xml -f platform/pom.xml -Djavacpp.platform=macosx-x86_64 '-Dtest=!FrameGrabberTest#testFFmpegFrameGrabber' - os: windows language: bash env: PLATFORMS="windows-x86_64" install: - powershell Install-WindowsFeature Server-Media-Foundation - choco install jdk8 --params 'installdir=c:\\jdk8' - choco install maven --version=3.6.3 - export JAVA_HOME="/c/jdk8/" - export PATH="$PATH:/c/ProgramData/chocolatey/lib/maven/apache-maven-3.6.3/bin/:/c/Program Files (x86)/Microsoft Visual Studio/2017/BuildTools/VC/Auxiliary/Build/" script: - cmd.exe //C 'vcvarsall.bat amd64 && mvn clean %MAVEN_PHASE% -B -V -U -s %HOME%/settings.xml' - cmd.exe //C 'vcvarsall.bat amd64 && mvn clean %MAVEN_PHASE% -B -V -U -s %HOME%/settings.xml -f platform/pom.xml -Djavacpp.platform=windows-x86_64 -Dtest=!FrameConverterTest#testOpenCV*' ================================================ FILE: CHANGELOG.md ================================================ * Compile classes with `parameters` bumping minimum requirements to Java SE 8 and Android 7.0 ([issue bytedeco/javacpp-presets#1739](https://github.com/bytedeco/javacpp-presets/issues/1739)) ### February 22, 2026 version 1.5.13 * Call `Pointer.trimMemory()` on `FFmpegFrameGrabber/Filter/Recorder` close to reclaim system memory on Linux ([issue #2334](https://github.com/bytedeco/javacv/issues/2334)) * Add `FrameRecorder.videoProfile` property ([pull #2361](https://github.com/bytedeco/javacv/pull/2361)) * Upgrade dependencies for OpenBLAS 0.3.31, OpenCV 4.13.0, FFmpeg 8.0.1, Leptonica 1.87.0, Tesseract 5.5.2 ### June 30, 2025 version 1.5.12 * Add `LibgdxFrameConverter` to convert `Frame` to Libgdx `Pixmap` ([pull #2315](https://github.com/bytedeco/javacv/pull/2315)) * Fix `FFmpegFrameRecorder` dropped frame issues with audio samples ([pull #2307](https://github.com/bytedeco/javacv/pull/2307)) * Add `FrameFilter.videoFilterArgs/audioFilterArgs` properties to support multiple different inputs ([pull #2304](https://github.com/bytedeco/javacv/pull/2304)) * Ensure `FFmpegFrameGrabber.start()` skips over streams with no codecs ([issue #2299](https://github.com/bytedeco/javacv/issues/2299)) * Add `FFmpegLogCallback.logRejectedOptions()` for debugging purposes ([pull #2301](https://github.com/bytedeco/javacv/pull/2301)) * Upgrade dependencies for OpenBLAS 0.3.30, OpenCV 4.11.0, FFmpeg 7.1.1, Tesseract 5.5.1 ### November 16, 2024 version 1.5.11 * Fix memory leak in `FFmpegFrameGrabber` when decoding from `InputStream` ([pull #2214](https://github.com/bytedeco/javacv/pull/2214)) * Upgrade dependencies for OpenBLAS 0.3.28, OpenCV 4.10.0, FFmpeg 7.1, Leptonica 1.85.0, Tesseract 5.5.0 ### January 29, 2024 version 1.5.10 * Work around `swscale` bug in `FFmpegFrameGrabber` for images with unaligned width ([issue #1960](https://github.com/bytedeco/javacv/issues/1960)) * Improve `FFmpegFrameGrabber.setTimestamp()` further for MPEG-TS streams ([pull #2144](https://github.com/bytedeco/javacv/pull/2144)) * Fix `module-info.java` broken since last release ([issue bytedeco/javacpp-presets#1414](https://github.com/bytedeco/javacpp-presets/issues/1414)) * Add new `AudioSplitMergeHelper` sample for processing raw audio frames ([pull #2052](https://github.com/bytedeco/javacv/pull/2052)) * Upgrade dependencies for OpenBLAS 0.3.26, OpenCV 4.9.0, FFmpeg 6.1.1, Leptonica 1.84.1, Tesseract 5.3.4 ### June 6, 2023 version 1.5.9 * Add `FrameRecorder.videoSideData/audioSideData` properties and `FFmpegFrameRecorder.setDisplayRotation()` for convenience ([issue #1976](https://github.com/bytedeco/javacv/issues/1976)) * Fix `FFmpegFrameGrabber.grab()` not returning audio frames buffered by the codec ([issue #1971](https://github.com/bytedeco/javacv/issues/1971)) * Upgrade dependencies for OpenBLAS 0.3.23, OpenCV 4.7.0, FFmpeg 6.0 ([issue #1693](https://github.com/bytedeco/javacv/issues/1693)), librealsense2 2.53.1, Leptonica 1.83.0, Tesseract 5.3.1 ### November 2, 2022 version 1.5.8 * Override `FFmpegFrameGrabber.getVideoCodecName()/getAudioCodecName()` to return names of opened codecs ([pull #1901](https://github.com/bytedeco/javacv/pull/1901)) * Add `FrameGrabber.videoDisposition/audioDisposition` properties to select streams by disposition ([pull #1879](https://github.com/bytedeco/javacv/pull/1879)) * Work around `OpenKinect2FrameGrabber` failing when provided with a pipeline on some system ([pull #1886](https://github.com/bytedeco/javacv/pull/1886)) * Fix `FFmpegFrameRecorder.record()` incorrectly flushing the video codec on data frames ([issue #1858](https://github.com/bytedeco/javacv/issues/1858)) * Improve accuracy of `FFmpegFrameGrabber.setFrameNumber()` ([pull #1851](https://github.com/bytedeco/javacv/pull/1851)) * Add `FrameGrabber.resetStartTime()` to allow `grabAtFrameRate()` after operations such as seeking ([pull #1846](https://github.com/bytedeco/javacv/pull/1846)) * Add `FrameGrabber.videoSideData/audioSideData` properties and `FFmpegFrameGrabber.getDisplayRotation()` for convenience ([issue #1361](https://github.com/bytedeco/javacv/issues/1361)) * Add to `FFmpegFrameGrabber` and `FFmpegFrameRecorder` constructors taking a `URL` for convenience and clarity * Fix incorrect call to `opencv_calib3d.stereoRectify()` in `ProjectiveDevice` ([issue #1802](https://github.com/bytedeco/javacv/issues/1802)) * Retry after 10 ms when `av_read_frame()` returns `EAGAIN` in `FFmpegFrameGrabber.grabFrame()` ([issue #1784](https://github.com/bytedeco/javacv/issues/1784)) * Append `frame_rate=%d/%d` input parameter in `FFmpegFrameFilter` as required by `xfade` ([issue #1776](https://github.com/bytedeco/javacv/issues/1776)) * Update `FFmpegStreamingTimeout` sample to use `timeout` instead of `stimeout` for RTSP ([pull #1758](https://github.com/bytedeco/javacv/pull/1758)) * Restore static calls to `FFmpegFrameGrabber.tryLoad()` and `FFmpegFrameRecorder.tryLoad()` ([issue #1756](https://github.com/bytedeco/javacv/issues/1756)) * Enable by default on `RealSense2FrameGrabber.start()` all color, depth, and IR streams as `videoStream` ([pull #1750](https://github.com/bytedeco/javacv/pull/1750)) * Upgrade dependencies for OpenBLAS 0.3.21, OpenCV 4.6.0, FFmpeg 5.1.2, Leptonica 1.82.0 ([pull #1791](https://github.com/bytedeco/javacv/pull/1791)), Tesseract 5.2.0 ### February 11, 2022 version 1.5.7 * Fix accuracy and latency issues with `FFmpegFrameGrabber.setVideoFrameNumber()` ([pull #1734](https://github.com/bytedeco/javacv/pull/1734)) * Add new `Frame.pictType` field set to `I`, `P`, `B`, etc by `FFmpegFrameGrabber` ([pull #1730](https://github.com/bytedeco/javacv/pull/1730)) * Set metadata for `AVFrame.opaque` in `FFmpegFrameGrabber` with call to `av_frame_copy_props()` ([issue #1729](https://github.com/bytedeco/javacv/issues/1729)) * Add `charset` property to `FrameGrabber` and `FrameRecorder` to use for metadata from FFmpeg ([pull #1720](https://github.com/bytedeco/javacv/pull/1720)) * Call `Frame.close()` on temporary clones in `Java2DFrameUtils` to prevent premature deallocations ([issue #1716](https://github.com/bytedeco/javacv/issues/1716)) * Ignore errors from `avcodec_send_packet()` and `avcodec_receive_frame()` to emulate old API in `FFmpegFrameGrabber` ([issue #1679](https://github.com/bytedeco/javacv/issues/1679)) * Upgrade dependencies for OpenBLAS 0.3.19, OpenCV 4.5.5, FFmpeg 5.0, librealsense2 2.50.0, Leptonica 1.82.0, Tesseract 5.0.1 ### August 2, 2021 version 1.5.6 * Enhance audio and video synchronization of `JavaFxPlayVideoAndAudio` sample ([pull #1662](https://github.com/bytedeco/javacv/pull/1662)) * Add `FrameGrabber.grabAtFrameRate()` to simulate a device or stream when reading from files ([pull #1659](https://github.com/bytedeco/javacv/pull/1659)) * Update `FFmpegFrameGrabber` and `FFmpegFrameRecorder` with new `avcodec` API ([issue #1498](https://github.com/bytedeco/javacv/issues/1498)) * Add new `Similarity` sample with PSNR and MSSIM ([pull #1622](https://github.com/bytedeco/javacv/pull/1622)) * Avoid crash in `FFmpegFrameRecorder.stop()` by moving `av_write_trailer()` out of `flush()` ([issue #1616](https://github.com/bytedeco/javacv/issues/1616)) * Upgrade dependencies for OpenBLAS 0.3.17, OpenCV 4.5.3, FFmpeg 4.4, librealsense2 2.44.0, Leptonica 1.81.1 ### March 8, 2021 version 1.5.5 * Have `Frame` and `FrameConverter` implement `AutoCloseable` to release memory explicitly ([issue #1574](https://github.com/bytedeco/javacv/issues/1574)) * Add new `YOLONet` sample for object detection ([pull #1595](https://github.com/bytedeco/javacv/pull/1595)) * Fix crash on `FFmpegFrameGrabber.stop()` when in `ImageMode.RAW` ([issue #1568](https://github.com/bytedeco/javacv/issues/1568)) * Let `FFmpegFrameRecorder.flush()` ignore errors from the encoder ([issue #1563](https://github.com/bytedeco/javacv/issues/1563)) * Improve `FFmpegFrameGrabber.setTimestamp()` and fix `getAudioFrameRate()` ([pull #1559](https://github.com/bytedeco/javacv/pull/1559)) * Fix frame rate and aspect ratio on `FFmpegFrameRecorder.start(AVFormatContext)` ([pull #1535](https://github.com/bytedeco/javacv/pull/1535)) * Upgrade dependencies for OpenBLAS 0.3.13, OpenCV 4.5.1, FFmpeg 4.3.2, librealsense2 2.40.0 * Update unit tests to use codecs available in FFmpeg under LGPL v3 ([pull bytedeco/javacpp-presets#950](https://github.com/bytedeco/javacpp-presets/pull/950)) * Add `RealSense2FrameGrabber.tryLoad()` method and missing entries for librealsense2 ([issue bytedeco/procamcalib#25](https://github.com/bytedeco/procamcalib/issues/25)) ### September 9, 2020 version 1.5.4 * Fix error message thrown from `FFmpegFrameRecorder.start()` not containing filename ([pull #1492](https://github.com/bytedeco/javacv/pull/1492)) * Fix `FFmpegFrameFilter.pull()` not returning audio/video frames without audio/video filtergraph ([issue #1466](https://github.com/bytedeco/javacv/issues/1466)) * Update `OpenCVFrameConverter.convertToOrgOpenCvCoreMat()` with new API to set the stride ([issue #1460](https://github.com/bytedeco/javacv/issues/1460)) * Fix memory leaks and reduce memory fragmentation in `FFmpegFrameGrabber` and `FFmpegFrameRecorder` ([issue #1366](https://github.com/bytedeco/javacv/issues/1366)) * Use `PointerScope` in `FFmpegFrameFilter`, `FFmpegFrameGrabber`, and `FFmpegFrameRecorder` to deallocate quickly temporary buffers ([issue #1383](https://github.com/bytedeco/javacv/issues/1383)) * Fix `FFmpegFrameFilter` by calling `String.format()` with `Locale.ROOT` ([pull #1441](https://github.com/bytedeco/javacv/pull/1441)) * Increase thread safety of `FFmpegFrameFilter`, `FFmpegFrameGrabber`, and `FFmpegFrameRecorder` with `synchronized` methods ([issue #1434](https://github.com/bytedeco/javacv/issues/1434)) * Upgrade dependencies for OpenBLAS 0.3.10, OpenCV 4.4.0, FFmpeg 4.3.1, and Leptonica 1.80.0 ### April 14, 2020 version 1.5.3 * Add `FFmpegFrameGrabber.start(boolean findStreamInfo)` parameter to minimize startup time ([issue #1376](https://github.com/bytedeco/javacv/issues/1376)) * Let `FFmpegFrameGrabber.grab()` return non-audio/video streams as new `Frame.DATA` type ([pull #1378](https://github.com/bytedeco/javacv/pull/1378)) * Fix crash in `FFmpegFrameRecorder.flush()` for HLS format and possibly others ([pull #1374](https://github.com/bytedeco/javacv/pull/1374)) * Fix "Resetting to invalid mark" `IOException` thrown on `FFmpegFrameGrabber.release()` ([issue #911](https://github.com/bytedeco/javacv/issues/911)) * Upgrade dependencies for OpenBLAS 0.3.9, OpenCV 4.3.0, FFmpeg 4.2.2, Leptonica 1.79.0, and Tesseract 4.1.1 * Add `Seekable` and `SeekableByteArrayOutputStream` to be used with `FFmpegFrameRecorder` ([pull #1350](https://github.com/bytedeco/javacv/pull/1350)) * Update `RealSense2FrameGrabber` with support for sensor options and fix for multiple devices ([pull #1348](https://github.com/bytedeco/javacv/pull/1348)) ### November 5, 2019 version 1.5.2 * Increase thread safety of `FFmpegFrameFilter`, `FFmpegFrameGrabber`, and `FFmpegFrameRecorder` with `volatile boolean started` flag ([pull #1325](https://github.com/bytedeco/javacv/pull/1325)) * Let `FFmpegFrameFilter.push(null)` indicate EOF to audio filters as well ([issue #1315](https://github.com/bytedeco/javacv/issues/1315)) * Add `RealSense2FrameGrabber` to capture images with librealsense2 ([pull #1316](https://github.com/bytedeco/javacv/pull/1316)) * Disable seek function in `FFmpegFrameGrabber` when `maximumSize <= 0` ([issue #1304](https://github.com/bytedeco/javacv/issues/1304)) * Use `Pointer.retainReference()` to prevent `PointerScope` from deallocating globally shared callback objects for FFmpeg * Fix `FFmpegFrameRecorder` failing to encode `float` samples in MP3 ([issue #1294](https://github.com/bytedeco/javacv/issues/1294)) * Fix `OpenCVFrameConverter` error in `IPCameraFrameGrabber` ([pull #1278](https://github.com/bytedeco/javacv/pull/1278)) * Allow setting properties for `OpenCVFrameGrabber` and `OpenCVFrameRecorder` with `setOption()` ([issue #1269](https://github.com/bytedeco/javacv/issues/1269)) * Add missing `requires java.desktop` to `module-info.java` ([issue #1265](https://github.com/bytedeco/javacv/issues/1265)) * Upgrade dependencies for OpenBLAS 0.3.7, OpenCV 4.1.2, FFmpeg 4.2.1, librealsense 1.12.4, and librealsense2 2.29.0 ### July 9, 2019 version 1.5.1 * Work around `swscale` bug in `FFmpegFrameGrabber` for images with unaligned width ([issue #845](https://github.com/bytedeco/javacv/issues/845)) * Add support for `AVSEEK_SIZE` to `FFmpegFrameGrabber` as required by MPEG-TS ([issue #1234](https://github.com/bytedeco/javacv/issues/1234)) * Throw exception on `start()` for already started `FFmpegFrameFilter`, `FFmpegFrameGrabber`, or `FFmpegFrameRecorder` ([issue #1233](https://github.com/bytedeco/javacv/issues/1233)) * Add dependency on OpenBLAS/MKL, now used by OpenCV to accelerate some matrix operations * Upgrade dependencies for OpenCV 4.1.0, libdc1394 2.2.6, and Tesseract 4.1.0 * Add support for `Frame.timestamp` to `FFmpegFrameFilter` ([issue #1177](https://github.com/bytedeco/javacv/issues/1177)) ### April 11, 2019 version 1.5 * Override methods in `FFmpegFrameGrabber` to get all metadata from streams ([issue #1180](https://github.com/bytedeco/javacv/issues/1180)) * Fix sample rate in output of `FFmpegFrameRecorder` by setting deprecated `AVStream.codec.time_base` ([issue #1179](https://github.com/bytedeco/javacv/issues/1179)) * Add `asetpts=N` to input of `FFmpegFrameFilter` to make filters like `afade` behave as expected ([issue #1171](https://github.com/bytedeco/javacv/issues/1171)) * Use `AVFormat.format()` from `Frame.opaque` when available in `FFmpegFrameFilter` and `FFmpegFrameRecorder` ([issue #1173](https://github.com/bytedeco/javacv/issues/1173)) * Enable multithreading for all codecs by default in `FFmpegFrameGrabber` and `FFmpegFrameRecorder` ([issue #1163](https://github.com/bytedeco/javacv/issues/1163)) * Improve thread safety of `FFmpegFrameRecorder` and `Java2DFrameConverter` by relying less on `Buffer.position` ([pull #1166](https://github.com/bytedeco/javacv/pull/1166)) * Use ModiTect to compile `module-info.java` with JDK 8 and preserve backward compatibility * Add `FFmpegFrameRecorder.closeOutputStream` and `FFmpegFrameGrabber.closeInputStream` properties to leave streams opened ([issue #1149](https://github.com/bytedeco/javacv/issues/1149)) * Add `FFmpegFrameRecorder.flush()` method that does not release the stream ([issue #1149](https://github.com/bytedeco/javacv/issues/1149)) * Readd `synchronized` blocks for `FFmpegFrameGrabber` and `FFmpegFrameRecorder`, but make unsafe methods public ([issue #1139](https://github.com/bytedeco/javacv/issues/1139)) * Allocate native memory for `Frame` using `Pointer` to allow deallocation with `PointerScope` ([issue #1152](https://github.com/bytedeco/javacv/issues/1152)) * Add `module-info.java` and depend on modularized JavaCPP Presets to comply with JPMS * Upgrade dependencies for FFmpeg 4.1.3, libfreenect 0.5.7, and Leptonica 1.78.0 * Allow allocation of `Frame` images with custom strides * Take into account `Bitmap.getRowBytes()` in `AndroidFrameConverter.convert(Bitmap)` ([issue #1143](https://github.com/bytedeco/javacv/issues/1143)) * Add `static { Loader.load(); }` in `LeptonicaFrameConverter` and `OpenCVFrameConverter` to prevent link errors ([issue #1128](https://github.com/bytedeco/javacv/issues/1128)) ### January 11, 2019 version 1.4.4 * Add `FFmpegFrameGrabber(InputStream, int)` constructor to set the maximum cache size used for seeking * Set `pts` and `dts` for `AVPacket` in `FFmpegFrameRecorder.recordPacket()` ([pull #1097](https://github.com/bytedeco/javacv/pull/1097)) * Prevent premature deallocations with `LeptonicaFrameConverter` ([issue bytedeco/javacpp#272](https://github.com/bytedeco/javacpp/issues/272)) and `OpenCVFrameConverter.IplImage` ([issue #1101](https://github.com/bytedeco/javacv/issues/1101)) * Fix `OpenCVFrameGrabber` from crashing when in `ImageMode.GRAY` * Add support for multiple inputs to `FFmpegFrameFilter` ([issue #955](https://github.com/bytedeco/javacv/issues/955)) * Fix fps in output of `FFmpegFrameRecorder` by setting deprecated `AVStream.codec.time_base` ([issue #1069](https://github.com/bytedeco/javacv/issues/1069)) * Fix memory leak in `FFmpegFrameRecorder` on `writePacket()` ([issue #1068](https://github.com/bytedeco/javacv/issues/1068)) * Upgrade dependencies for OpenCV 4.0.1, FFmpeg 4.1, FlyCapture 2.13.3.31, Leptonica 1.77.0, and Tesseract 4.0.0 ### October 15, 2018 version 1.4.3 * Add `imageScalingFlags` property to `FrameGrabber` and `FrameRecorder`, with `SWS_BILINEAR` as default for FFmpeg ([issue #845](https://github.com/bytedeco/javacv/issues/845)) * Add `OpenCVFrameConverter.ToOrgOpenCvCoreMat` to easily but efficiently get image data from official Java API of OpenCV ([issue bytedeco/javacpp#38](https://github.com/bytedeco/javacpp/issues/38)) * Keep globally shared callback objects for FFmpeg out of `PointerScope` ([issue #911](https://github.com/bytedeco/javacv/issues/911)) * Upgrade dependencies for OpenCV 3.4.3, FFmpeg 4.0.2, and Tesseract 4.0.0-rc2 * Update the `Demo` class to use the C++ API of OpenCV ([issue #1042](https://github.com/bytedeco/javacv/issues/1042)) * Add new `DeepLearningFaceDetection` ([pull #1041](https://github.com/bytedeco/javacv/pull/1041)) and `PerspectiveWarpDemo` ([pull #1066](https://github.com/bytedeco/javacv/pull/1066)) samples ### July 17, 2018 version 1.4.2 * Allow `FFmpegFrameGrabber` to use accelerated decoders with `videoCodecName` and `audioCodecName` properties ([pull #948](https://github.com/bytedeco/javacv/pull/948)) * Add new `KazemiFacemarkExample` and `LBFFacemarkExampleWithVideo` samples ([pull #1030](https://github.com/bytedeco/javacv/pull/1030)) * Expose `apiPreference` constructor argument of `VideoCapture` to `OpenCVFrameGrabber` ([pull #1025](https://github.com/bytedeco/javacv/pull/1025)) * Add `LeptonicaFrameConverter` to easily but efficiently pass image data to Tesseract ([issue bytedeco/javacpp-presets#224](https://github.com/bytedeco/javacpp-presets/issues/224)) * Update `RecordActivity` to fix issue with pixel formats ([issue #979](https://github.com/bytedeco/javacv/issues/979)) * Fix `FFmpegFrameFilter` to support negative strides returned by "vflip" ([pull #977](https://github.com/bytedeco/javacv/pull/977)) * Fix `FFmpegFrameFilter` on Mac throwing "Resource temporarily unavailable" ([issue #974](https://github.com/bytedeco/javacv/issues/974)) * Upgrade dependencies for OpenCV 3.4.2, FFmpeg 4.0.1 and Tesseract 4.0.0-beta.3 * Add initial limited version of `JavaFXFrameConverter` ([pull #969](https://github.com/bytedeco/javacv/pull/969)) * Revert default behavior of `FFmpegFrameGrabber.setTimestamp()` to previous version ([pull #949](https://github.com/bytedeco/javacv/pull/949)) * Add support for audio frames to `FFmpegFrameFilter` ([issue #492](https://github.com/bytedeco/javacv/issues/492)) * Add `setpts=N` to input of `FFmpegFrameFilter` to make `fade` and `overlay` filters behave as expected ([issue #667](https://github.com/bytedeco/javacv/issues/667)) * Fix crash on `FFmpegFrameRecorder.stop()` when no audio samples are left to write ### March 29, 2018 version 1.4.1 * Improve seeking and frame number estimates in `FFmpegFrameGrabber` ([pull #908](https://github.com/bytedeco/javacv/pull/908)) * Add `maxBFrames`, `trellis`, and `maxDelay` properties to `FFmpegFrameRecorder` ([pull #939](https://github.com/bytedeco/javacv/pull/939)) * Introduce `FFmpegFrameGrabber.maxDelay` property ([pull #938](https://github.com/bytedeco/javacv/pull/938)) * Upgrade dependencies for OpenCV 3.4.1, FFmpeg 3.4.2 * Allow enabling streams with `RealSenseFrameGrabber.setFormat()` for compatibility ([pull #922](https://github.com/bytedeco/javacv/pull/922)) * Process audio frames after `FFmpegFrameGrabber.setTimestamp()` to avoid corrupted images ([issue #896](https://github.com/bytedeco/javacv/issues/896)) * Fix `FFmpegFrameRecorder` not flushing all audio samples properly ([pull #886](https://github.com/bytedeco/javacv/pull/886)) * Give access to pixel format, etc for images returned by `FFmpegFrameFilter.pull()` ([issue #887](https://github.com/bytedeco/javacv/issues/887)) ### January 16, 2018 version 1.4 * Decode audio frames on `FFmpegFrameGrabber.setTimestamp()` to avoid sync issues ([pull #871](https://github.com/bytedeco/javacv/pull/871)) * Give access to options and metadata `Map` from `FrameGrabber` and `FrameRecorder` ([issue #858](https://github.com/bytedeco/javacv/issues/858)) * Make `FFmpegFrameGrabber(InputStream)` and `FFmpegFrameRecorder(OutputStream)` thread-safe * Add new `OpenCVFeatures2dSerialization` sample ([pull #842](https://github.com/bytedeco/javacv/pull/842)) * Upgrade dependencies for OpenCV 3.4.0, FFmpeg 3.4.1, librealsense 1.12.1 * Fix potential audio read issue in `WebcamAndMicrophoneCapture` sample ([issue #826](https://github.com/bytedeco/javacv/issues/826)) * Update `JavaFxPlayVideoAndAudio` sample to support `FrameGrabber.sampleMode` property ([issue #820](https://github.com/bytedeco/javacv/issues/820)) * Set the `Frame.timestamp` field on `FFmpegFrameGrabber.grab()` ([pull #810](https://github.com/bytedeco/javacv/pull/810)) * Fix image loading issue with the `CaffeGooglenet.java` sample ([pull #805](https://github.com/bytedeco/javacv/pull/805)) * Prevent `FFmpegFrameGrabber.setTimestamp()` from going into an infinite loop ([issue #731](https://github.com/bytedeco/javacv/issues/731)) * Fix `FFmpegFrameRecorder.record()` when called with `AV_PIX_FMT_NV21` ([pull #787](https://github.com/bytedeco/javacv/pull/787)) * Add `FFmpegLockCallback` to use more efficient thread-safe mechanisms ([pull #770](https://github.com/bytedeco/javacv/pull/770)) * Make `FFmpegFrameGrabber` support streams with changing resolution ([pull #769](https://github.com/bytedeco/javacv/pull/769)) * Add new `DeinterlacedVideoPlayer` sample ([pull #757](https://github.com/bytedeco/javacv/pull/757)) ### July 25, 2017 version 1.3.3 * Fix `Java2DFrameConverter.cloneBufferedImage()` not copying the data ([pull #739](https://github.com/bytedeco/javacv/pull/739)) * Make sure `OpenCVFrameConverter` always resets `Frame.opaque` even when `Pointer` is equal ([issue deeplearning4j/DataVec#316](https://github.com/deeplearning4j/DataVec/issues/316)) * Fix `OutputStream` leak in `FFmpegFrameRecorder` ([pull #727](https://github.com/bytedeco/javacv/pull/727)) * Synchronize on `FFmpegFrameRecorder.stop()` to avoid potential race conditions ([issue #700](https://github.com/bytedeco/javacv/issues/700)) * Add `src/main/java/cl/eye/CLCamera.java` to remove build dependency on external module * Fix seeking issues with `FFmpegFrameGrabber(InputStream)` ([pull #703](https://github.com/bytedeco/javacv/pull/703)) * Upgrade dependencies for FFmpeg 3.3.2, FlyCapture 2.11.3.121 ([pull bytedeco/javacpp-presets#424](https://github.com/bytedeco/javacpp-presets/pull/424)) * Initialize the `avdevice` module for `FFmpegFrameRecorder` in the same way as with `FFmpegFrameGrabber` * Add `FrameGrabber.sampleMode` property and have `FFmpegFrameGrabber` convert audio samples to user-specified format ([issue #18](https://github.com/bytedeco/javacv/issues/18)) * Add new `ImageSegmentation` ([pull #460](https://github.com/bytedeco/javacv/pull/460)) and `FFmpegStreamingTimeout` ([pull #712](https://github.com/bytedeco/javacv/pull/712)) samples * Fix up and add missing functionality to `FlyCapture2FrameGrabber` ([pull #655](https://github.com/bytedeco/javacv/pull/655)) * Take `OpenCVFrameGrabber.setFormat()` value to set FOURCC of `VideoCapture` ([pull #651](https://github.com/bytedeco/javacv/pull/651)) * Fix call to `FaceRecognizer.predict()` in samples ([issue #642](https://github.com/bytedeco/javacv/issues/642)) ### March 13, 2017 version 1.3.2 * Add `Java2DFrameUtils` to facilitate conversion between `Frame`, `BufferedImage`, `IplImage`, and `Mat` * Add new `JavaFxPlayVideoAndAudio` sample ([pull #618](https://github.com/bytedeco/javacv/pull/618)) * Get rid of deprecated calls in `FFmpegFrameFilter`, `FFmpegFrameGrabber` and `FFmpegFrameRecorder` ([issue #607](https://github.com/bytedeco/javacv/issues/607)) * Fix crash in `FFmpegFrameGrabber.restart()` ([issue #605](https://github.com/bytedeco/javacv/issues/605)) * Upgrade dependencies for OpenCV 3.2.0, FFmpeg 3.2.1, libdc1394 2.2.5 ### January 14, 2017 version 1.3.1 * Let `FFmpegFrameRecorder` pass options to the protocol as well ([issue #598](https://github.com/bytedeco/javacv/issues/598)) * Add `RealSenseFrameGrabber` and `OpenKinect2FrameGrabber` to `FrameGrabber.list` to have them loaded by default * Remove confusing and no longer useful profiles from the `pom.xml` file * Provide new `FFmpegFrameGrabber(InputStream)` and `FFmpegFrameRecorder(OutputStream)` constructors ([issue #95](https://github.com/bytedeco/javacv/issues/95)) * Make `FrameFilter`, `FrameGrabber`, and `FrameRecorder` implement `Closeable` to let us try-with-resources * Fix potential crash when recording audio with `FFmpegFrameRecorder` * Add `OpenKinect2FrameGrabber` to capture images with libfreenect2 ([pull #584](https://github.com/bytedeco/javacv/pull/584)) * Add `OpenKinectFrameGrabber.grabIR()` and stabilize `RealSenseFrameGrabber` ([pull #585](https://github.com/bytedeco/javacv/pull/585)) ### December 7, 2016 version 1.3 * Fix unnecessary memory allocation in `OpenCVFrameGrabber` ([pull #575](https://github.com/bytedeco/javacv/pull/575)) * Add `FFmpegFrameFilter` to `RecordActivity` sample for Android ([pull #550](https://github.com/bytedeco/javacv/pull/550)) * Introduce platform artifact for easier cross-platform builds and to avoid issues with some build systems ([issue #395](https://github.com/bytedeco/javacv/issues/395)) * Add `RealSenseFrameGrabber` to capture images with librealsense ([pull #486](https://github.com/bytedeco/javacv/pull/486)) * Add `BioInspiredRetina.java` sample for the `opencv_bioinspired` module ([pull #505](https://github.com/bytedeco/javacv/pull/505)) * Update the `JavaCV` class with appropriate documentation comments ([issue #444](https://github.com/bytedeco/javacv/issues/444)) * Fix Javadoc links for externally referenced classes * Fix seeking when calling `FFmpegFrameGrabber.setTimestamp()` on audio-only files * Add more appropriate default pixel formats for JPEG formats in `FFmpegFrameRecorder` ([issue #410](https://github.com/bytedeco/javacv/issues/410)) ### May 15, 2016 version 1.2 * Optimize `AndroidFrameConverter` a bit and add a test ([pull #379](https://github.com/bytedeco/javacv/pull/379)) * Fix `DC1394FrameGrabber` on the Windows platform ([issue bytedeco/procamcalib#4](https://github.com/bytedeco/procamcalib/issues/4)) * Support `AVPacket` in `FFmpegFrameGrabber` and `FFmpegFrameRecorder` to copy without re-encoding ([issue #93](https://github.com/bytedeco/javacv/issues/93)) * Lower Maven prerequisite in the `pom.xml` file to 3.0 ([issue bytedeco/javacpp#93](https://github.com/bytedeco/javacpp/issues/93)) * Add new `PrincipalComponentAnalysis` sample ([pull #373](https://github.com/bytedeco/javacv/pull/373)) * Upgrade `OpenCVFrameRecorder` to use the new C++ `VideoWriter` API ([pull #370](https://github.com/bytedeco/javacv/pull/370)) * Upgrade `OpenCVFrameGrabber` to use the new C++ `VideoCapture` API ([pull #361](https://github.com/bytedeco/javacv/pull/361)) * Add `CaffeGooglenet.java` sample for the `opencv_dnn` module ([pull #341](https://github.com/bytedeco/javacv/pull/341)) * Clean up `IPCameraFrameGrabber` and fix incorrectly reading some headers ([pull #323](https://github.com/bytedeco/javacv/pull/323), [pull #345](https://github.com/bytedeco/javacv/pull/345)) * Fix swallowed `InterruptedException` and throw appropriate exception in `FrameGrabber.start()` ([issue #315](https://github.com/bytedeco/javacv/issues/315)) * Fix `IPCameraFrameGrabber.stop()` not checking for null ([pull #300](https://github.com/bytedeco/javacv/pull/300)) * Upgrade dependencies for OpenCV 3.1.0, FFmpeg 3.0.2, FlyCapture 2.9.3.43, libdc1394 2.2.4 * Let users call `FFmpegFrameFilter.push(null)` to indicate EOF, as required by some filters like "palettegen" ([issue #287](https://github.com/bytedeco/javacv/issues/287)) * Call `cvHaarDetectObjects()` with `CV_HAAR_FIND_BIGGEST_OBJECT | CV_HAAR_DO_ROUGH_SEARCH` instead of `CV_HAAR_DO_CANNY_PRUNING` in the face detection samples to get acceptable performance with OpenCV 3.0 ([issue #272](https://github.com/bytedeco/javacv/issues/272)) * Change `WakeLock` for `keepScreenOn` in `AndroidManifest.xml` file and add `setPreviewDisplay()` call on `surfaceChanged()` event for the `RecordActivity` sample ([pull #269](https://github.com/bytedeco/javacv/pull/269), [pull #271](https://github.com/bytedeco/javacv/pull/271)) ### October 25, 2015 version 1.1 * Make `FrameConverter` for images return `null` when `Frame.image == null` ([issue #249](https://github.com/bytedeco/javacv/issues/249)) * Add `FFmpegLogCallback` to redirect easily to Java log messages from FFmpeg * Upgrade all Maven dependencies and plugins to latest versions, thus bumping minimum requirements to Java SE 7, Android 4.0, and Maven 3.0 * Fix broken `FFmpegFrameGrabber.grabImage()` after `setTimestamp()` ([issue #236](https://github.com/bytedeco/javacv/issues/236)) * Add `FFmpegFrameGrabber.grabSamples()` to grab only audio samples, and ignore video frames ([issue #235](https://github.com/bytedeco/javacv/issues/235)) * Fix broken `setVideoCodecName()` and `setAudioCodecName()` for `FFmpegFrameRecorder` ([issue #229](https://github.com/bytedeco/javacv/issues/229)) * Remove `FaceRecognition.java` sample, which requires the deprecated `opencv_legacy` module ([issue #200](https://github.com/bytedeco/javacv/issues/200)) * Fix potential crash in `ObjectFinder` with FLANN ([issue #210](https://github.com/bytedeco/javacv/issues/210)) * Add `FFmpegFrameFilter` to let users process `Frame` images with `libavfilter` easily ([issue #164](https://github.com/bytedeco/javacv/issues/164)) * Add `FaceRecognizerInVideo.java` sample that does a combo of face detection and recognition ([issue #203](https://github.com/bytedeco/javacv/issues/203)) * Return `AVStream.r_frame_rate` when `AVStream.avg_frame_rate` is invalid in `FFmpegFrameGrabber.getFrameRate()` ([issue #292](https://code.google.com/p/javacv/issues/detail?id=292)) * Update some samples to make them work with OpenCV 3.0 * Add new convenience `FFmpegFrameRecorder.record(Frame frame, int pixelFormat)` method ([issue #181](https://github.com/bytedeco/javacv/issues/181)) * Let `Java2DFrameConverter.copy()` from `ByteBuffer` with 4 channels to `BufferedImage.TYPE_INT_RGB`, among others, also taking into account the `flipChannels` argument ([issue #181](https://github.com/bytedeco/javacv/issues/181)) ### July 11, 2015 version 1.0 * Offer the Apache License, Version 2.0, as a new choice of license, in addition to the GPLv2 with Classpath exception * Upgrade support to OpenCV 3.0.0 * Upgrade supported FFmpeg API to the 2.7 release branch * Switch descriptor used by `ObjectFinder` from SURF to AKAZE * Let users get resized images from `FFmpegFrameGrabber` by calling `setImageWidth()` and `setImageHeight()` before `start()` * Add check for supported display size in the `RecordActivity` sample ([pull #153](https://github.com/bytedeco/javacv/pull/153)) * Clarify the semantics of `FrameConverter` ([issue #150](https://github.com/bytedeco/javacv/issues/150)) * Fix `FFmpegFrameRecorder` not saving the last few frames, especially when encoding with x264 ([issue #50](https://github.com/bytedeco/javacv/issues/50)) * Add `FrameConverterTest` and fix a couple of bugs uncovered by it * Make `Frame implements Indexable` for easy and efficient access to image pixels * Fix `AbstractMethodError` thrown from `OpenCVFrameConverter` on some versions of the JDK ([issue #143](https://github.com/bytedeco/javacv/issues/143)) * Add `FFmpegFrameGrabber.grabImage()` method to restore the functionality previously provided by `IplImage grab()` ([issue #116](https://github.com/bytedeco/javacv/issues/116)) * Give users of `FFmpegFrameGrabber` and `FFmpegFrameRecorder` access to more options and metadata ([issue #132](https://github.com/bytedeco/javacv/issues/132)) * Add the ability to specify from which video and audio streams `FFmpegFrameGrabber` should grab from ([issue #135](https://github.com/bytedeco/javacv/issues/135)) * Fix `Java2DFrameConverter` when used with `BufferedImage.TYPE_INT_RGB` or other types based on `int` ([issue #140](https://github.com/bytedeco/javacv/issues/140)) * Add new `WebcamAndMicrophoneCapture` sample ([pull #131](https://github.com/bytedeco/javacv/pull/131)) * Add `aspectRatio` property to `FrameGrabber` and `FrameRecorder`, to be able to use pixel aspect ratios other than 1.0 ([issue #90](https://github.com/bytedeco/javacv/issues/90)) ### April 4, 2015 version 0.11 * Upgrade support to OpenCV 2.4.11 * Upgrade supported FFmpeg API to the 2.6 release branch * Add new `Square` sample, thanks to Geir Ruud * Add `AndroidFrameConverter`, `Java2DFrameConverter` and `OpenCVFrameConverter`, and use them to refactor `Frame`, `CanvasFrame`, `FrameGrabber`, and `FrameRecorder` in a way to help users avoid coupling with Android, Java 2D, or OpenCV ([issue #84](https://github.com/bytedeco/javacv/issues/84)) * Fix `Demo` class in the `README.md` file ([issue #102](https://github.com/bytedeco/javacv/issues/102)) * Add new `ColoredObjectTrack` sample ([pull #99](https://github.com/bytedeco/javacv/pull/99)) * Add `option` property to `FFmpegFrameGrabber` to let users set such things as "analyzeduration", "probesize", or "list_devices" * Fix "AVFrame.format is not set" and "AVFrame.width or height is not set" warning messages ([issue #76](https://github.com/bytedeco/javacv/issues/76)) ### December 23, 2014 version 0.10 * Upgrade support to OpenCV 2.4.10 * Upgrade supported FFmpeg API to the 2.5 release branch * Fix `time_base` warnings displayed by `FFmpegFrameRecorder` ([issue #75](https://github.com/bytedeco/javacv/issues/75)) * Add new `TemplateMatching` sample, thanks to Waldemar Neto * Update instructions in the `README.md` file for manual installation in Android Studio * Replace deprecated `CvMat` and `IplImage` functionality used in the `Demo` class with new `Indexer` API, and provide sample `pom.xml` file for Maven * Make `FFmpegFrameGrabber.getFrameRate()` return `AVStream.avg_frame_rate` instead of `r_frame_rate` ([issue #63](https://github.com/bytedeco/javacv/issues/63)) * Disable DocLint, which prevents the build from succeeding on Java 8 ([issue bytedeco/javacpp#5](https://github.com/bytedeco/javacpp/issues/5)) * Add `FlyCapture2FrameGrabber` with cross-platform support of FlyCapture2 ([pull #45](https://github.com/bytedeco/javacv/pull/45)) * Fix issue that would prevent `CanvasFrame` from working on Mac OS X with recent versions of the JDK ([issue #39](https://github.com/bytedeco/javacv/issues/39) and [issue #314](http://code.google.com/p/javacv/issues/detail?id=314)) * Upgrade `RecordActivity` sample with a continuous record loop, thanks to Federico Sendra and Juan Manuel Sobral * Make `FrameGrabber.createDefault()` throw an exception on unsupported input, instead of returning a cryptic `null` ([issue #30](https://github.com/bytedeco/javacv/issues/30)) * Add `videoCodec`, `videoBitrate`, `audioCodec`, and `audioBitrate` properties to `FrameGrabber` * Work around `avcodec` and `avdevice` not loading properly for `FFmpegFrameGrabber` and `FFmpegFrameRecorder` ([issue #24](https://github.com/bytedeco/javacv/issues/24)) * Do key frame detection in `FFmpegFrameRecorder` based on `AVPacket`, not `AVPicture` ([pull #20](https://github.com/bytedeco/javacv/pull/20)) ### July 27, 2014 version 0.9 * Remove `platform` property from `pom.xml`, replaced with the `platform.dependency` one in JavaCPP Presets ([issue #10](https://github.com/bytedeco/javacv/issues/10)) * Add new `RLSA` sample, thanks to Nicholas Woodward ([issue #469](http://code.google.com/p/javacv/issues/detail?id=469)) * Fix a timestamp rounding issue in `FFmpegFrameGrabber` that causes `setFrameNumber()` to sometimes pick the wrong frame if FPS is not a proper divisor of 1000000 ([issue #5](https://github.com/bytedeco/javacv/issues/5)) * Increase the flexibility of the `pom.xml` file by making it possible to specify a custom version of JavaCPP * Add missing dependencies for JogAmp in the `pom.xml` file ([issue #2](https://github.com/bytedeco/javacv/issues/2)) * Add new `OpenCVFaceRecognizer` sample, thanks to Petter Christian Bjelland * Add new `OpticalFlowDense` sample, thanks to Dawit Gebreyohannes ([issue #468](http://code.google.com/p/javacv/issues/detail?id=468)) * Make it easier to try out the `FaceRecognition.java` sample ([issue #1](https://github.com/bytedeco/javacv/issues/1)) ### April 28, 2014 version 0.8 * Move from Google Code to GitHub as main source code repository * Upgrade support to OpenCV 2.4.9 * Upgrade supported FFmpeg API to the 2.2 release branch * Fix `FFmpegFrameRecorder` not refreshing the resampler when the format of samples changes (issue #465) * Rename the `com.googlecode.javacv.cpp` package to `org.bytedeco.javacpp`, and `com.googlecode.javacv` to `org.bytedeco.javacv` * Removed old NetBeans project files that cause a conflict when trying to open as a Maven project (issue #210) * Adjusted the samples a bit because of small changes in the API with the move to the JavaCPP Presets * Fixed `ObjectFinder` not working with recent versions of OpenCV, especially on Android (issue #214) * Added new `FrameRecorder.gopSize` property to let users set a desired GOP size instead of the default one of 12 * `FFmpegFrameGrabber` now takes into account calls to `setPixelFormat()` (issue #429), but does not enforce it * Added a `Frame.audioChannels` field for resampling purposes in `FFmpegFrameRecorder` (issue #388) * In `FFmpegFrameRecorder`, fixed audio encoding with the Vorbis codec (issue #428) and the WebM container (issue #435), and other audio related things * Added missing `allocateArray()` constructors to `CameraParams` and `MatchesInfo` (issue #421) * Fixed errors such as "jniopencv_nonfree.dll: Can't find dependent libraries" by adding the `opencv_ocl` module as dependency * Added support to seek in audio-only streams with `FFmpegFrameGrabber.setTimestamp()` (issue #417) * Fixed potential thread concurrency issues and crash in the `stopRecording()` and `onDestroy()` methods of the `RecordActivity` sample, thanks to Jacob Duron * To capture the last frame of a video file, reverted `FFmpegFrameGrabber.setTimestamp()` to its previous behavior (issue #413) * Updated `samples/FaceApplet.jnlp` to make it work with JDK/JRE 7u45 ### January 6, 2014 version 0.7 * Upgraded support to OpenCV 2.4.8 * Upgraded supported FFmpeg API to the 2.1 release branch * Updated `freenect` to reflect the latest changes of OpenKinect's master branch * Updated `videoInput` to reflect the latest changes in the "update2013" branch * Added `Frame.opaque` field to give access to the raw `AVFrame` in the case of `FFmpegFrameGrabber` (issue #399) * Added new `FFmpegFrameGrabber.grabKeyFrame()` method to grab key frames (I-frames) directly (issue #312) * `VideoInputFrameGrabber` now uses 640x480 as default image size to prevent "videoInput.getPixels() Error: Could not get pixels." * Fixed `FFmpegFrameGrabber.setTimestamp()` not working for streams with audio (issue #398) * Fixed wrong `haarcascade_frontalface_alt.xml` file getting downloaded by the `Demo` class (issue #402) * Added a `Frame.sampleRate` field to allow audio samples to be resampled by `FFmpegFrameRecorder` (issue #388) * Incorporated `IPCameraFrameGrabber` from Greg Perry (issue #384) * Fixed thread safety issues with FFmpeg in `FFmpegFrameGrabber` and `FFmpegFrameRecorder` (issue #377) * Fixed memory leak in the `MotionDetector.java` sample file (issue #372) * New `videoCodecName` and `audioCodecName` properties to allow users of `FFmpegFrameRecorder` to use codecs such as "libx264rgb" (issue #369) ### September 15, 2013 version 0.6 * Upgraded supported FFmpeg API to the 2.0 release branch (with Java interface files now based on code automatically produced by [JavaCPP Presets](https://github.com/bytedeco/javacpp-presets)) * Fixed `FFmpegFrameGrabber.getFrameNumber()` * Upgraded support to OpenCV 2.4.6 * Fixed callbacks when used with custom class loaders such as with Web containers * Upgraded to ARToolKitPlus 2.3.0 (issue #234) * Fixed drawing issues with `MarkerDetector.draw()` * Fixed `FFmpegFrameGrabber.getTimestamp()` not returning values for audio frames (issue #328) * Added new `Frame.keyFrame` field returned by `FFmpegFrameGrabber.grabFrame()` to know when a grabbed frame is a key frame or not (issue #312) * Worked around problem in `samples/RecordActivity.java` that would happen when trying to record a frame with an invalid timestamp (issue #313) * Fixed potential resource leak that could occur after `FFmpegFrameRecorder` throwing an `Exception` * Fixed `FFmpegFrameGrabber` not returning the last few frames of video streams (issue #315) * Fixed wrong dependencies of OpenCV preventing correct loading (issue #304) * Renamed `FrameRecorder.record(Buffer[] samples)` to a cleaner `record(Buffer ... samples)` (issue #303) * Fixed `FFmpegFrameRecorder` not flushing buffers on `stop()` (issue #302) ### April 7, 2013 version 0.5 * Upgraded support to OpenCV 2.4.5 * Upgraded supported FFmpeg API to the 1.2 release branch * New methods `FFmpegFrameRecorder.setVideoOption()` and `setAudioOption()` generalize the way to set arbitrary codec options, such as "profile", "preset", "tune", etc. used by the x264 codec * Included better format guessing inside `FFmpegFrameRecorder` for protocols like RTP * Added support for planar audio formats to `FFmpegFrameGrabber` and `FFmpegFrameRecorder`, as required by newer versions of FFmpeg for at least MP3 and AAC * Enhanced `FFmpegFrameRecorder` by making it use the closest supported frame rate for the given codec instead of failing * To support variable bitrate (VBR) encoding, appended new `videoQuality` and `audioQuality` properties to `FFmpegFrameRecorder`, which usually have an effective range of [0, 51] and overrides the `videoBitrate` and `audioBitrate` properties ### March 3, 2013 version 0.4 * Upgraded support to OpenCV 2.4.4 * `CanvasFrame.waitKey(-1)` does not wait anymore and returns the last `KeyEvent` dispatched since the last call to it * Upgraded supported FFmpeg API to the 1.1 release branch * Fixed bug in `FaceRecognition.java` sample (issue #276) * Included `Sobel()`, `Scharr()`, `Laplacian()`, and `Canny()` from `opencv_imgproc` whose equivalent functions in the C API have missing parameters * Extended `OpenKinectFrameGrabber` with `setDepthFormat()` and `setVideoFormat()` methods to be able to set both formats independently (issue #273) * Fixed `Blender.blend()` having its `@OutputMat` incorrectly annotated as `@InputMat` (issue #272) * Added new `RecordActivity.java` Android sample from Shawn Van Every and Qianliang Zhang * Added missing `allocate()` methods for `FunctionPointer` in `AVIOContext` and others, which prevented these FFmpeg callbacks from functioning * Fixed infinite loop in `FrameGrabber.Array.grab()` (as used by ProCamCalib in the case of stereo cameras, issue #262) when `FrameGrabber.getTimestamp()` returns an invalid negative value (as with `opencv_highgui`) or when using different types of (unsynchronized) `FrameGrabber` together * Fixed `cvQueryHistValue_1D()` and other functions that use a raw `CvArr` object * Fixed problem when subclassing `CanvasFrame` ### November 4, 2012 version 0.3 * Upgraded support to OpenCV 2.4.3 (issue #233) * Fixed functions like `Algorithm.getMat()` and `HOGDescriptor.getDefaultPeopleDetector()` returning `null` instead of the expected data * Implemented better, more transparent, handling of `cv::Ptr` * When allocating an empty `IplImage`, `CvMat`, `CvBGCodeBookModel`, etc. its memory content now gets zeroed out, giving OpenCV a better chance of displaying an error message instead of crashing * Upgraded supported FFmpeg API to the 1.0 release branch * Appended to `StringVector` and `MatVector` new convenient bulk constructors and `put()` methods taking arrays of `String`, `IplImage`, `CvMat`, etc. * Included new `Blobs` module from David Grossman and the corresponding `BlobDemo` sample * Added missing `opencv_core.partition()` function (issue #144) * Fixed up the samples a bit (issue #229 and issue #230) * Switched the majority of `@Adapter` annotations to more concise ones like `@StdVector` as allowed by new capabilities of JavaCPP * Fixed `FFmpegFrameGrabber.getLengthInFrames()` and `OpenCVFrameGrabber.getLengthInTime()` (issue #231 and issue #236) * Enhanced `FFmpegFrameRecorder` to support conversion between audio sample formats (for the experimental AAC encoder among other things) and to let two different threads call `record(samples)` and `record(image)` simultaneously, plus a couple of other features like `setFrameNumber()`, which lets users skip image frames (achieving variable frame rate) * Added a `javacpp.skip` property to `pom.xml`, such that a command like `mvn package -Pall -Djavacpp.skip=true` only recompiles the Java source files, but also added `platform.root` and `compiler.path` properties, which map directly to JavaCPP's for convenience ### July 21, 2012 version 0.2 * Provided new `javacv-linux-arm.jar` build thanks to Jeremy Nicola (issue #184) * Additional default properties inside `pom.xml` make it easier to build JavaCV from source (issue #202), calling `mvn package` now succeeds with only OpenCV and a C++ compiler for JavaCPP * Made a few minor updates for OpenCV 2.4.2 * New `Pointer.limit` property of JavaCPP can now be used to get the `size` of an output parameter, and to specify the maximum `size` on input as well * Upgraded supported FFmpeg API to the 0.11 release branch * Added audio support to `FFmpegFrameGrabber` (call `grabFrame()` instead of `grab()`) and `FFmpegFrameRecorder` (call `setAudioChannels()` before `start()`, and `record(Frame)` instead of `record(IplImage)`) (issue #160) * Gave better default `FFmpegFrameRecorder` settings to H.263, MPEG-4, etc. codecs and fixed H.264 encoding with libx264 (issue #160) * Refined the `FaceApplet` sample * Fixed `FlannBasedMatcher` constructor, `FaceRecognizer.train()`, and `Stitcher.stitch()/composePanorama()` (issue #211) * Fixed `CanvasFrame` sometimes blanking out under Windows and maybe Linux (issue #212) ### May 27, 2012 version 0.1 * Started using version numbers, friendly to tools like Maven, and placing packages in a sort of [Maven repository](http://maven2.javacv.googlecode.com/git/) * JavaCV can now extract and load native dependent libraries such as `libopencv_core.so.2.4`, `libopencv_core.2.4.dylib`, `opencv_core240.dll`, etc. from Java resources placed inside the `com.googlecode.javacv.cpp.` package (i.e.: under the `/com/googlecode/javacv/cpp//` directory of a JAR file in the classpath) (issue #146) * Included new `FaceApplet` sample to demonstrate [How to use JavaCV in an applet](http://code.google.com/p/javacv/wiki/HowToMakeAnApplet) * Added handy `IplImage.asCvMat()` and `CvMat.asIplImage()` conversion methods * Fixed a few small things with `OpenCVFrameGrabber`, `opencv_contrib`, `opencv_legacy`, and `opencv_stitching` ### May 12, 2012 * Upgraded support to OpenCV 2.4.0 (issue #187) * Moved the source code repository to Git * Added `pom.xml` file for Maven support and changed the directory structure of the source code to match Maven's standard directory layout * Made it easier to create one massive statically linked native library by passing something like "-Xcompiler -Wl,-static -o javacv" as command line options to JavaCPP, usually from inside `build.xml` or `pom.xml` (issue #146) * Fixed missing parameter from `CvANN_MLP.create()` * Added methods `cvCalcCovarMatrixEx()`, `cvEigenDecomposite()`, and `cvEigenProjection()` taking an `IplImage[]` as argument for convenience * `VideoInputFrameGrabber.start()` now accepts a `connection` argument such as `VI_COMPOSITE` to support analog cameras and what not * Fixed `FaceRecognition` sample (issue #188) * Added a few convenience methods to avoid the need to create empty `CvAttrList` ### March 29, 2012 * Added missing array allocators and `position()` methods to `KDTree.Node`, `DefaultRngAuto`, `CvAffinePose`, `KeyPoint`, `BaseKeypoint`, `ReferenceTrees`, `DMatch`, `*.Params`, `CvFuzzy*`, `Octree.Node`, `CvDefParam`, `Cv*Blob*`, `Cv*Track*`, `CvDrawShape`, `CvVectors`, `CvParamGrid`, `Cv*Params`, `CvSVM*`, `CvPair16u32s`, `CvDTree*` `CvTrainTestSplit`, `CvMLData`, `FeatureEvaluator`, and `*DataMatrixCode` * Increased versatility of `IplImage.createFrom()`, `copyFrom()`, `copyTo()`, `getBufferedImage()` by providing a `flipChannels` parameter, whose effect was previously mistakenly forced onto four-channel images of byte values only (issue #163) * Fixed a couple of things with `CvMat.get()/put()` (issue #167) * In addition to an `IplImage`, we may now specify the pixel format of the data when calling `FFmpegFrameRecorder.record()`, but otherwise when `IplImage.nChannels == 2`, it assumes `PIX_FMT_NV21`, allowing for easy and efficient encoding of data captured from the camera on Android (issue #160), image objects we can also convert to RGB using `cvCvtColor()` with `CV_YUV420sp2BGR` * Fixed seeking capabilities of `FFmpegFrameGrabber` (issue #162) and added `getLengthInFrames()` and `getLengthInTime()` methods to query the duration of streams, when known * Enhanced `IplImage.clone()` and `create*Compatible()` with cloning of their `BufferedImage` to make it easier to keep color components in the right order (issue #163) * Refactored `FrameGrabber` and `FrameRecorder` a bit to accommodate new `createDefault(...)` and `create(String className, ...)` factory methods, offering to users an easier selection method to work around limitations of some APIs (issue #70) * Adjusted `GNImageAligner`, `ProCamTransformer`, etc. to support alignment of only the projector display on textureless surface planes * Renamed a few more `Settings` properties to reflect better their meanings ### February 18, 2012 * Added `GLCanvasFrame` to show OpenGL renderbuffers on screen, plus a new factory method `JavaCVCL.createCLGLImageFrom()` to create compatible ones from `IplImage` objects, as well as more user-friendly `getGLContext()`, `getGL()` and `getGL2()` methods * Fixed various things of the original `CanvasFrame`, and `JavaCV.createCLImage()` and `createIplImage()`, also appending `From` to their names * New `createPinnedBuffer()` and `createPinnedIplImage()` factory methods in `JavaCVCL` to allocate page-locked memory for faster CPU<->GPU transfers, but it does not seem to work for OpenCL image objects, only linear buffer objects :( * Fixed and enhanced `GNImageAlignerCL` and `ProjectorDevice` (its `useOpenGL` property) to support fully OpenCL and OpenGL acceleration * Refactored `Parallel` a bit so that we may set the number of threads it uses via its static `numThreads` property or the "com.googlecode.javacv.numthreads" system property, which defaults to `Parallel.getNumCores() = Runtime.getRuntime().availableProcessors()` * Cleaned up and renamed some methods in `JavaCV`, while adding `boundingRect()`, functionally similar to `cvBoundingRect`, but better adapted to compute a properly aligned and padded ROI * Inserted a couple of missing `allocate()` inside `opencv_flann` * Updated `ObjectFinder` with a `Settings.useFLANN` property to let it use FLANN via OpenCV * Cleaned up and optimized `HandMouse` * `CanvasFrame`, `FrameGrabber`, `FrameRecorder`, and `ProjectiveDevice` objects now throw `Exception` objects of a nested class instead of the too generic `java.lang.Exception` one * Moved parallel execution of `cvkernels.multiWarpColorTransform()`, modifying `ImageTransformer` classes, from `GNImageAligner` into `cvkernels`, which now also supports other image types than `float` * Renamed some `Settings` properties here and there to correct typos and reflect better their meanings * Updated `freenect` to reflect the latest changes of OpenKinect's master branch * FFmpeg and other libraries did not work under Android when compiled with the latest NDK, r7 (issue #147): Fixed in JavaCPP * Moved `IplImage.timestamp` to `FrameGrabber`, also adding a `frameNumber` property, both allowing to seek within streams too * Removed `triggerFlushSize` property from `CameraDevice` and `FrameGrabber`, instead relying on the `numBuffers` property to decide the required size of a buffer flush * Corrected the logic behind `FFmpegFrameGrabber.getFrameRate()` and `getTimestamp()` (issue #151) * Created a `BufferRing` class for convenient circular rings of large buffers that require manual release of resources, such as OpenCL memory * Added a few more useful methods to `FrameGrabber`, including `restart()`, `flush()`, and `delayedGrab()` (to be used in conjunction with `getDelayedTime()` and `getDelayedImage()`) * Inserted `cvLoadImageBGRA()` and `cvLoadImageRGBA()` methods into `opencv_highgui` to load color images compatible with OpenCL more easily * `JavaCvErrorCallback` now outputs messages to `Logger` instead of `System.err` * Defined `VI_COM_MULTI_THREADED` for `videoInput`, allowing it to run on multiple threads if needed ### January 8, 2012 * JavaCV should now have an easier time automatically finding libraries inside standard directories such as `/usr/local/lib/`, `/opt/local/lib/`, and `C:\opencv\`, even when they are not part of the system configuration or PATH (issue #127) * Renamed `set()` and `fill()` methods to `put()` inside `CvPoint*` classes, for better naming consistency * Renamed `FrameGrabber.ColorMode` to `ImageMode` and its `BGR` value to `COLOR` to reflect the fact that a `FrameGrabber` instance can return color images in some arbitrary format, but added a new `pixelFormat` property to let users know or specify the exact pixel format desired, such as `PIX_FMT_BGR24`, etc. in the case of `FFmpegFrameGrabber` * After `FFmpegFrameGrabber.start()`, the `format`, `imageWidth`, `imageHeight`, and `frameRate` properties switch to their effective values * Added new `FrameGrabber.sensorPattern` property to obtain the Bayer filter layout of raw data from `DC1394FrameGrabber` and `FlyCaptureFrameGrabber` * Readded to `KDTree`, `Index`, and `HOGDescriptor` some functions with `FloatPointer` and `IntPointer` arguments that were mistakenly removed when OpenCV switched to using `cv::InputArray` and `cv::OutputArray` parameter types (issue #134) * Renamed `ProjectiveGainBiasTransformer` to `ProjectiveColorTransformer` * Added a few classes to do some processing using OpenCL and OpenGL: `JavaCVCL`, `GNImageAlignerCL`, `ProjectiveTransformerCL`, `ProjectiveColorTransformerCL`, and `ProCamTransformerCL` with some other related files * Renamed `Parallel.numCores` to the more conventional `Parallel.NUM_CORES` * Added new `FaceRecognition.java` sample from Stephen L. Reed * Inserted a couple of missing calls to `Loader.load()` (issue #142) * Improved hacks for `Loader.load()` in JavaCPP make JavaCV work on Android 4.0 * New `PS3EyeFrameGrabber` from Jiri Masa can now grab images using the SDK from Code Laboratories ### October 1, 2011 * Fixed `DC1394FrameGrabber` and `FlyCaptureFrameGrabber` to behave as expected with all Bayer/Raw/Mono/RGB/YUV cameras modes (within the limits of libdc1394 and PGR FlyCapture) (issue #91) * Fixed regression of `IplImage.copyFrom()` and `createFrom()` with `BufferedImage` objects of `SinglePixelPackedSampleModel` (issue #102) * C++ functions using `std::vector` objects as output parameters now work on Windows Vista and Windows 7 as well ### August 20, 2011 * Upgraded support to OpenCV 2.3.1 * An output argument of type `cv::Mat` or `cv::OutputArray` returned with a size 0 now correctly sets `CvArr.address = 0` * Fixed `IplImage.createFrom()` and `copyFrom()` when called on objects returned by `BufferedImage.getSubimage()` * Added missing allocator to `CvRNG` * `OpenCVFrameGrabber` now detects when CV_CAP_PROP_POS_MSEC is broken and gives up calling `cvGetCaptureProperty()` * New `OpenKinectFrameGrabber.grabDepth()` and `grabVideo()` methods to capture "depth" and "video" simultaneously, regardless of the mode ### July 5, 2011 * Upgraded support to OpenCV 2.3.0 * Fixed `OpenKinectFrameGrabber`, which can now also capture depth images when `setFormat("depth")` is called before `start()` * Fixed `CvMatArray` and `IplImageArray` as well as histogram related functions * Fixed `FFmpegFrameGrabber`, and `FFmpegFrameRecorder` now works on Android also * Fixed calls, such as `opencv_flann.Index.knnSearch()`, that require a `MatAdapter` or an `ArrayAdapter` for output ### June 10, 2011 * New `freenect` wrapper and corresponding `OpenKinectFrameGrabber` to capture from Microsoft's Kinect stereo camera using OpenKinect * JavaCV now exposes all C++ functions and classes of OpenCV not covered by the C API * Fixed various erroneous declarations and calls, including those due to changes in JavaCPP ### May 11, 2011 * Removed `CvMat` object pooling in favor of more efficient `ThreadLocal` objects created by `CvMat.createThreadLocal()` * Changed `Marker.getCenter()` back to the centroid, because it has better noise averaging properties and gives in practice more accurate results than the actual center * Added hack to `OpenCVFrameGrabber.start()` to wait for `cvRetrieveFrame()` to return something else than `null` under Mac OS X * FFmpeg now works properly on Windows and Android (issue #63) with newer binaries * New `videoInputLib` wrapper and corresponding `VideoInputFrameGrabber` to capture using DirectShow, useful under Windows 7 where OpenCV and FFmpeg can fail to capture using Video for Windows (issue #58) * `GeometricCalibrator` now reports the maximum errors in addition to the average (RMS) errors ### April 7, 2011 * Added a `format` property to `CameraDevice`, `FrameGrabber`, and `FrameRecorder`, mostly useful for `FFmpegFrameGrabber`, where interesting values include "dv1394", "mjpeg", "video4linux2", "vfwcap", and "x11grab" * `OpenCVFrameRecorder` now uses `CV_FOURCC_PROMPT` under Windows as default since `CV_FOURCC_DEFAULT` crashes (issue #49) * Added hack to make sure the temporarily extracted library files get properly deleted under Windows * JavaCPP now loads classes more lazily * Fixed most occurences of `UnsatisfiedLinkError` (issue #54), but some corner cases may require a call to `Loader.load()` on the class one wishes to use * Added (rudimentary) outlier detection and modified zero threshold handling in the image alignment framework * New `JavaCV.hysteresisThreshold()` feature * New `HandMouse` functionality, which depends on the image alignment framework * Fixed `ProjectiveDevice.distort()`, which mistakenly undistorted images instead * New `HoughLines` sample thanks to Jeremy Nicola ### February 19, 2011 * Switched from JNA to JavaCPP, which has a lower overhead and supports C++, bringing hope that future versions of JavaCV will support features of OpenCV available only through the C++ API * Consequently, the syntax of various operations have changed a bit, but the transition should not be too painful * As a happier consequence, this also fixes the problem with SSE instructions on 32-bit x86 (issue #36) * Also, JavaCPP does not have any limitations or performance issues with large data structures (issue #10 and issue #14) * Added support for OpenCV 2.2 (issue #42), but dropped support for all previous versions * Added samples provided by users (issue #1, issue #45, and issue #46) * Added deinterlace setting to `FFmpegFrameGrabber` having it call `avpicture_deinterlace()` (issue #38) * Enhanced a few things of the image alignment algorithm * Tried to fix image format conversion inside `FlyCaptureFrameGrabber`, but this is going to require more careful debugging * Fixed and added various other things I forget ### December 2, 2010 * Now works on Android with the Dalvik VM (for more details, please refer to the FacePreview sample available on the download page) * Added more hacks to `CanvasFrame` in the hope to make it behave better outside the EDT * Made clearer the error messages thrown from `FrameGrabber` objects, when `start()` may not have been called * Fixed version specific declarations of `CvStereoBMState` and related functions * Fixed conditions that could crash `cvkernels` ### November 4, 2010 * Renamed the package namespace to `com.googlecode.javacv`, which makes more sense now that JavaCV has been well anchored at Google Code for more than a year, piggybacking on the unique and easy-to-remember domain name * Included new FFmpeg wrapper classes `avutil`, `avcodec`, `avformat`, `avdevice`, `avfilter`, `postprocess`, and `swscale`, eliminating the need of the separate FFmpeg-Java package * `CanvasFrame` now redraws its `Canvas` after the user resizes the `Frame` * Fixed the `Error` thrown when calling `CanvasFrame.showImage()` from the EDT * Added check to `DC1394FrameGrabber` so that a "Failed to initialize libdc1394" does not crash the JVM * `FFmpegFrameGrabber` does not crash anymore when forgetting to call `start()` before a `grab()` or `trigger()` * `FrameGrabber` now selects the default grabber a bit better * Made sweeping changes (for the better, but still not finalized) to `GNImageAligner`, `ProjectiveTransformer`, `ProjectiveGainBiasTransformer`, and `ProCamTransformer`... * Added to `JavaCV` more methods related to transformation of planes: `perspectiveTransform()`, `getPlaneParameters()`, `getPerspectiveTransform()`, and `HtoRt()`, as well as `ProjectiveDevice.getFrontoParallelH()` * Added a static `autoSynch` flag to all `Structure` classes of `cxcore`, `cv`, and `cvaux`, which you may set to `false` prior to the return of things like big and heavy `CvSeq` to make them load faster and to avoid stack overflows, but accessing fields will then require manual calls to `readField()` and `writeField()` (issue #10 and #14) * Added missing `ByValue` subclasses to `CvSeq`, `CvSet`, `CvContourTree`, and `CvChain`... Any others missing? * Fixed `Exception` thrown from `cvCreateHist()` under JNA 3.2.7 (issue #26) * Enhanced `CvMat.put()`, which now supports setting submatrices * Improved inside `IplImage` the support of `BufferedImage`, especially those using a `DirectColorModel` (issue #23) * Fixed crash in `cvkernels` when color transformation `X` is `null` ### July 30, 2010 * Fixed crash that would occur in `CanvasFrame` for some video drivers * `FFmpegFrameGrabber` now supports other input formats (devices), such as `x11grab` that can be used for screencasting * Added `JavaCV.median()` function, and `JavaCV.fractalTriangleWave()` now respects image ROI * Fixed background subtraction in `cvaux` * Fixed crash inside the code for direct alignment caused by the ROI getting set outside the image plane * Added `deltaScale` and `tryToFixPlane` to `GNImageAligner.Settings` (the first used in `ImageTransformer.Parameters` as increment, randomly selected forward or backward, for finite difference), which sometimes help to jump over local minima ### May 30, 2010 * Removed redundant `CvMemStorage.clearMem()` method, use `cvClearMemStorage()` * Fixed the sample `Test2` class that did not work under Windows * Fixed corruption by the `cvkernels` `transformer` at the borders * Modified `CanvasFrame` constructors and added a `gamma` argument used by `showImage(IplImage)` * `CanvasFrame` now lets users resize the frame, while displayed images are stretched to fit the new size * Renamed `CanvasFrame.acquireGraphics()` to `createGraphics()` for consistency * When `FlyCaptureFrameGrabber` cannot set fastest speed, it now safely fails by setting any supported speed * Added a new `Parallel.loop()` method that can use more threads than the number of CPU cores detected * Added new `numThreads` property to `GNImageAligner` and fixed a few minor inconsistencies as well * Fixed incorrect `Java.HnToRt()`, and added a few `norm()` and `randn()` methods * For functions with `float[]` and `double[]` arguments in `cvaux` and `cv`, added complementary `FloatBuffer` and `DoubleBuffer` declarations * Fixed loading problems with `cvaux` * Fixed and enhanced histogram, back projection, and other CAMSHIFT related functionality * Added code for `CvRNG` * Added "/opt/local/lib/" and "/opt/local/lib64/" (standard on Mac OS X) to the default list of search paths for OpenCV * Added `CvScalar.getVal()` and `CvIntScalar.getVal()`, which simply return the `val` field, convenient for Scala where `val` is a reserved word * Fixed the construction of `IplImage` from a `Pointer` * Removed incorrect cases when an `IplImage` gets converted to a `BufferedImage.TYPE_CUSTOM` * Made `CvArr.PointerByReference` a bit more consistent and general ### April 16, 2010 * Modified `IplImage`, `FrameGrabber`, and `CanvasFrame` to get better default behavior of gamma correction * Fixed `cv.CvHistogram` and related histogram functions * `CameraDevice.Settings.triggerFlushSize` now defaults to 5 (only affects `OpenCVFrameGrabber` and `FFmpegFrameGrabber`) * Replaced `LMImageAligner` by `GNImageAligner`, a more appropriate name for Gauss-Newton with `lineSearch` * Fixed a few things related with `ProjectiveDevice.Settings` ### April 8, 2010 * Added support for OpenCV 2.1 ### April 5, 2010 * Fixed up `clone()` methods to avoid the need to cast * Removed the `fullScreen` argument from `CanvasFrame` constructors, which will now switch to full-screen mode only when a `screenNumber` is explicitly passed * Renamed `FrameGrabber.ColorMode.GRAYSCALE` to `GRAY` * Replaced deprecated functions from `FFmpegFrameGrabber` and `FFmpegFrameRecorder` * `FFmpegFrameGrabber` can now resize images ### March 21, 2010 * Added new classes and methods used by ProCamTracker: `cvkernels`, `JavaCV.fractalTriangleWave()`, `ImageAligner`, `LMImageAligner`, `ImageTransformer`, `ProjectiveTransformer`, `ProjectiveGainBiasTransformer`, `ProCamTransformer`, and `ReflectanceInitializer` * `CameraDevice.Settings` has a new `deviceFile` property (used by a `FrameGrabber`), which brings up a file dialog for some `PropertyEditor`s * Moved in `CameraSettings`, `ProjectorSettings`, and `FrameGrabber.PropertyEditor` from the `procamcalib` package * Added to `CameraDevice.Settings` and `FrameGrabber` a `triggerFlushSize` property to indicate the number of buffers to flush on `trigger()` to compensate for cheap cameras that keep old images in memory indefinitely * Changed the type of `CameraDevice.Settings.deviceNumber` to `Integer` so we may set it to `null` * Fixed and enhanced `CanvasFrame.showImage()` methods a bit * In `triggerMode` `DC1394FrameGrabber` now tries to use a real software trigger and only falls back to one-shot mode on error * Fixed array constructors of `IplImage.PointerByReference()` and `CvImgObsInfo.PointerByReference()` * Added `CvPoint.fillArray()` methods to reuse preallocated arrays and changed `createArray()` a bit as well * Fixed and enhanced all `IplImage.copy*()` methods, including new support for ROIs and subimages, which affects `create*()` and `getBufferedImage()` methods as well * Updated `Marker` to support different size and spacing in X and Y * Added `Settings` to `ObjectFinder` * Fixed distortion problem in `ProjectiveDevice` and `ProCamColorCalibrator` with OpenCV 1.1pre1 * Split `ProjectiveDevice.Settings` into `ProjectiveDevice.CalibrationSettings` (for applications like ProCamCalib) and `ProjectiveDevice.CalibratedSettings` (for applications like ProCamTracker) * Renamed `gamma` to `responseGamma` in `ProjectiveDevice`, and moved previous `nominalDistance` parameter to `Settings` * Added `ProjectiveDevice.rescale()` to rescale calibration parameters when switching a device to a new image size * `ProjectiveDevice.undistort()` and `distort()` can now `useFixedPointMaps` of OpenCV * `ProjectiveDevice` and its subclasses now `throw new Exception()` if the `parameterFile` cannot be read ### February 13, 2010 * Relicensed JavaCV under the GPLv2 with Classpath exception (see LICENSE.txt). Please note that if your application links with code that needs ARToolKitPlus, for example, it will become subject to the full GPL, without Classpath exception * Added `devicePath` setting to `CameraDevice` that works with `FFmpegFrameGrabber`, `OpenCVFrameGrabber`, and other `FrameGrabber` with a String constructor * Added "C:/OpenCV2.0/bin/release/" to the directory list to search for OpenCV DLLs * Moved `cvFindHomography()`, `cvFindExtrinsicCameraParams2()`, `cvReprojectImageTo3D()`, `cvSaveImage()`, and `cvRetrieveFrame()` to version specific classes since their number of arguments differ with the version of OpenCV * Enhanced `CvMat.put(CvMat mat)` to work better even when the matrices are not actually compatible * Added new `IplImage` factory methods `createCompatible(IplImage image)`, `createIfNotCompatible(IplImage image, IplImage template)`, and `createFrom(BufferedImage image)` * Fixed `distortionCoeffs` corruption that might occur in `ProjectiveDevice` ### January 3, 2010 * Added wrapper for the `cvaux` module of OpenCV * Added abstract `FrameRecorder` class and a `OpenCVFrameRecorder` class * Fixed read() problem that might occur within Pointer constructors * Running `java -jar javacv.jar` now displays version information ### December 22, 2009 * Fixed `CanvasFrame` from getting stuck in a maximized window * Removed all `setAutoWrite(false)` from `cxcore` now that the bug appears fixed in JNA * Added `FFmpegFrameGrabber` and `FFmpegFrameRecorder` to easily record live footage and grab back offline into JavaCV ### November 24, 2009 * Added more convenient constructors and factory methods for `CvPoint*`, `CvSize*`, `CvRect`, `CvTermCriteria`, `CvSlice`, and `CvAttrList` * Added _R2_ correlation coefficient field to `ProjectiveDevice` * Enhanced and fixed color conversion spaghetti code in `FlyCaptureFrameGrabber` * Fixed the `CvHaarFeature` Structure * Renamed `CvIntScalar` factory methods to match with `CvScalar` * Enhanced and fixed some problems with gamma correction in `IplImage` * Added a `highgui.CV_FOURCC()` method that takes chars as parameter * Moved `MarkedPlane.drawMarkers()` to `Marker.draw()` for better code reuse * Added `MarkedPlane.getTotalWarp()` with a "useCenters" parameter * Changed default values of `MarkerDetector.binarizationKWhiteMarkers` to 1.0 and `ProjectorDevice.brightnessBackground` to 0.0 * Fixed issue with image width and memory alignment in `MarkerDetector` * `Marker.getCenter()` now computes the actual physical center instead of the centroid * `OpenCVFrameGrabber.getDeviceDescriptions()` now throws `UnsupportedOperationException` * Added support in `OpenCVFrameGrabber` to grab frames from video files * Added `ProjectiveDevice.getRectifyingHomography()` method * Added `JavaCvErrorCallback` to easily catch errors of OpenCV in Java ### October 19, 2009 * Moved the functionality of `CvMatPool` to the `CvMat.take()` and `.pool()` methods * Added color calibration for projector-camera systems (`ProCamColorCalibrator`) * Updated `DC1394FrameGrabber` to handle more conversion use cases automatically * Fixed `CvIntScalar` to mirror `CvScalar` ### October 14, 2009 * Change of plan: JavaCV now works with any of OpenCV 1.0, 1.1pre1, or 2.0! Version specific functionality is enclosed in subclasses, e.g., the class `cv.v20` can access everything from the `cv` module of OpenCV 2.0 * Added a few missing functions and adjusted some mappings to make them closer to the C API * Added a few more helper methods to `CvPoint*` * Added temporary storage to `ObjectFinder` to plug the memory leak ### October 2, 2009 * Fixed problem when loading distortion coefficients with `ProjectiveDevice` * Added automatic read and write for functions with arrays of `Structure` or `PointerByReference` * Added to `cv.java` a few missing functions related to calibration * Fixed up a bit helper methods for `CvPoint*`, `CvScalar`, `CvRect`, `CvBox2D`, `CvMat`, `IplImage`, `CvMemStorage`, `CvSeq`, and `CvSeqBlock` * Added `CvMatPool` to `MarkedPlane` and `Marker` * Added a few new `distort()` methods to `ProjectiveDevice` * Last version to support OpenCV 1.1pre1: Future version will require OpenCV 2.0 ### August 27, 2009 * `IplImage` now flips the buffer on copy if necessary * Added needed Pointer constructor for `CvSURFPoint` and `CvConvexityDefect` * Cleaned up a bit the messy Buffers in `CvMat` ### August 26, 2009 * Added `get*Buffer()` functions to `IplImage` * Added more options for gamma correction in `IplImage` and `ProjectiveDevice` * Further cleaned up the namespace and constructors of `ProjectiveDevices` * `CanvasFrame.waitKey()` now only checks `KeyEvent.KEY_PRESSED` * Added `CvMatPool` to avoid recreating matrices * Moved `CvScalar` functions to `cxcore` ### August 19, 2009 * Switched to using `import static` for relief from namespace hell * Fixed color channel reversal of Bayer images in `DC1394FrameGrabber` ### August 11, 2009 Initial release Acknowledgments --------------- This project was conceived at the [Okutomi & Tanaka Laboratory](http://www.ok.ctrl.titech.ac.jp/), Tokyo Institute of Technology, where I was supported for my doctoral research program by a generous scholarship from the Ministry of Education, Culture, Sports, Science and Technology (MEXT) of the Japanese Government. I extend my gratitude further to all who have reported bugs, donated code, or made suggestions for improvements (details above)! ================================================ FILE: LICENSE.txt ================================================ You may use this work under the terms of either the Apache License, Version 2.0, or the GNU General Public License (GPL), either version 2, or any later version, with "Classpath" exception (details below). You don't have to do anything special to choose one license or the other and you don't have to notify anyone which license you are using. You are free to use this work in any project (even commercial projects) as long as the copyright header is left intact. =============================================================================== Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. =============================================================================== GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. "CLASSPATH" EXCEPTION TO THE GPL Linking this library statically or dynamically with other modules is making a combined work based on this library. Thus, the terms and conditions of the GNU General Public License cover the whole combination. As a special exception, the copyright holders of this library give you permission to link this library with independent modules to produce an executable, regardless of the license terms of these independent modules, and to copy and distribute the resulting executable under terms of your choice, provided that you also meet, for each linked independent module, the terms and conditions of the license of that module. An independent module is a module which is not derived from or based on this library. If you modify this library, you may extend this exception to your version of the library, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. ================================================ FILE: README.md ================================================ JavaCV ====== [![Gitter](https://badges.gitter.im/bytedeco/javacv.svg)](https://gitter.im/bytedeco/javacv) [![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.bytedeco/javacv-platform/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.bytedeco/javacv-platform) [![Sonatype Nexus (Snapshots)](https://img.shields.io/nexus/s/https/oss.sonatype.org/org.bytedeco/javacv.svg)](http://bytedeco.org/builds/) [![Build Status](https://travis-ci.org/bytedeco/javacv.svg?branch=master)](https://travis-ci.org/bytedeco/javacv) Commercial support: [![xscode](https://img.shields.io/badge/Available%20on-xs%3Acode-blue?style=?style=plastic&logo=appveyor&logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAMAAACdt4HsAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAAZQTFRF////////VXz1bAAAAAJ0Uk5T/wDltzBKAAAAlUlEQVR42uzXSwqAMAwE0Mn9L+3Ggtgkk35QwcnSJo9S+yGwM9DCooCbgn4YrJ4CIPUcQF7/XSBbx2TEz4sAZ2q1RAECBAiYBlCtvwN+KiYAlG7UDGj59MViT9hOwEqAhYCtAsUZvL6I6W8c2wcbd+LIWSCHSTeSAAECngN4xxIDSK9f4B9t377Wd7H5Nt7/Xz8eAgwAvesLRjYYPuUAAAAASUVORK5CYII=)](https://xscode.com/bytedeco/javacv) Introduction ------------ JavaCV uses wrappers from the [JavaCPP Presets](https://github.com/bytedeco/javacpp-presets) of commonly used libraries by researchers in the field of computer vision ([OpenCV](http://opencv.org/), [FFmpeg](http://ffmpeg.org/), [libdc1394](http://damien.douxchamps.net/ieee1394/libdc1394/), [FlyCapture](https://www.flir.com/products/flycapture-sdk/), [Spinnaker](https://www.flir.com/products/spinnaker-sdk/), [OpenKinect](http://openkinect.org/), [librealsense](https://github.com/IntelRealSense/librealsense), [CL PS3 Eye Driver](https://codelaboratories.com/downloads/), [videoInput](http://muonics.net/school/spring05/videoInput/), [ARToolKitPlus](https://launchpad.net/artoolkitplus), [flandmark](https://github.com/uricamic/flandmark), [Leptonica](http://www.leptonica.org/), and [Tesseract](https://github.com/tesseract-ocr/tesseract)) and provides utility classes to make their functionality easier to use on the Java platform, including Android. JavaCV also comes with hardware accelerated full-screen image display (`CanvasFrame` and `GLCanvasFrame`), easy-to-use methods to execute code in parallel on multiple cores (`Parallel`), user-friendly geometric and color calibration of cameras and projectors (`GeometricCalibrator`, `ProCamGeometricCalibrator`, `ProCamColorCalibrator`), detection and matching of feature points (`ObjectFinder`), a set of classes that implement direct image alignment of projector-camera systems (mainly `GNImageAligner`, `ProjectiveTransformer`, `ProjectiveColorTransformer`, `ProCamTransformer`, and `ReflectanceInitializer`), a blob analysis package (`Blobs`), as well as miscellaneous functionality in the `JavaCV` class. Some of these classes also have an OpenCL and OpenGL counterpart, their names ending with `CL` or starting with `GL`, i.e.: `JavaCVCL`, `GLCanvasFrame`, etc. To learn how to use the API, since documentation currently lacks, please refer to the [Sample Usage](#sample-usage) section below as well as the [sample programs](https://github.com/bytedeco/javacv/tree/master/samples/), including two for Android (`FacePreview.java` and `RecordActivity.java`), also found in the `samples` directory. You may also find it useful to refer to the source code of [ProCamCalib](https://github.com/bytedeco/procamcalib) and [ProCamTracker](https://github.com/bytedeco/procamtracker) as well as [examples ported from OpenCV2 Cookbook](https://github.com/bytedeco/javacv-examples/) and the associated [wiki pages](https://github.com/bytedeco/javacv-examples/tree/master/OpenCV_Cookbook). Please keep me informed of any updates or fixes you make to the code so that I may integrate them into the next release. Thank you! And feel free to ask questions on [the mailing list](http://groups.google.com/group/javacv) or [the discussion forum](https://github.com/bytedeco/javacv/discussions) if you encounter any problems with the software! I am sure it is far from perfect... Downloads --------- Archives containing JAR files are available as [releases](https://github.com/bytedeco/javacv/releases). The binary archive contains builds for Android, iOS, Linux, Mac OS X, and Windows. The JAR files for specific child modules or platforms can also be obtained individually from the [Maven Central Repository](http://search.maven.org/#search|ga|1|bytedeco). To install manually the JAR files, follow the instructions in the [Manual Installation](#manual-installation) section below. We can also have everything downloaded and installed automatically with: * Maven (inside the `pom.xml` file) ```xml org.bytedeco javacv-platform 1.5.13 ``` * Gradle (inside the `build.gradle.kts` or `build.gradle` file) ```groovy dependencies { implementation("org.bytedeco:javacv-platform:1.5.13") } ``` * Leiningen (inside the `project.clj` file) ```clojure :dependencies [ [org.bytedeco/javacv-platform "1.5.13"] ] ``` * sbt (inside the `build.sbt` file) ```scala libraryDependencies += "org.bytedeco" % "javacv-platform" % "1.5.13" ``` This downloads binaries for all platforms, but to get binaries for only one platform we can set the `javacpp.platform` system property (via the `-D` command line option) to something like `android-arm`, `linux-x86_64`, `macosx-x86_64`, `windows-x86_64`, etc. Please refer to the [README.md file of the JavaCPP Presets](https://github.com/bytedeco/javacpp-presets#downloads) for details. Another option available to Gradle users is [Gradle JavaCPP](https://github.com/bytedeco/gradle-javacpp), and similarly for Scala users there is [SBT-JavaCV](https://github.com/bytedeco/sbt-javacv). Required Software ----------------- To use JavaCV, you will first need to download and install the following software: * An implementation of Java SE 8 or newer: * OpenJDK http://openjdk.java.net/install/ or * Oracle JDK http://www.oracle.com/technetwork/java/javase/downloads/ or * IBM JDK http://www.ibm.com/developerworks/java/jdk/ or * Microsoft JDK https://www.microsoft.com/openjdk etc Further, although not always required, some functionality of JavaCV also relies on: * CL Eye Platform SDK (Windows only) http://codelaboratories.com/downloads/ * Android SDK API 24 or newer http://developer.android.com/sdk/ * JOCL and JOGL from JogAmp http://jogamp.org/ Finally, please make sure everything has the same bitness: **32-bit and 64-bit modules do not mix under any circumstances**. Manual Installation ------------------- Simply put all the desired JAR files (`opencv*.jar`, `ffmpeg*.jar`, etc.), in addition to `javacpp.jar` and `javacv.jar`, somewhere in your class path. Here are some more specific instructions for common cases: NetBeans (Java SE 8 or newer): 1. In the Projects window, right-click the Libraries node of your project, and select "Add JAR/Folder...". 2. Locate the JAR files, select them, and click OK. Eclipse (Java SE 8 or newer): 1. Navigate to Project > Properties > Java Build Path > Libraries and click "Add External JARs...". 2. Locate the JAR files, select them, and click OK. Visual Studio Code (Java SE 8 or newer): 1. Navigate to Java Projects > Referenced Libraries, and click `+`. 2. Locate the JAR files, select them, and click OK. IntelliJ IDEA (Android 7.0 or newer): 1. Follow the instructions on this page: http://developer.android.com/training/basics/firstapp/ 2. Copy all the JAR files into the `app/libs` subdirectory. 3. Navigate to File > Project Structure > app > Dependencies, click `+`, and select "2 File dependency". 4. Select all the JAR files from the `libs` subdirectory. 5. In the AndroidManifest.xml add `android:extractNativeLibs="true"` After that, the wrapper classes for OpenCV and FFmpeg, for example, can automatically access all of their C/C++ APIs: * [OpenCV documentation](http://docs.opencv.org/master/) * [FFmpeg documentation](http://ffmpeg.org/doxygen/trunk/) Sample Usage ------------ The class definitions are basically ports to Java of the original header files in C/C++, and I deliberately decided to keep as much of the original syntax as possible. For example, here is a method that tries to load an image file, smooth it, and save it back to disk: ```java import org.bytedeco.opencv.opencv_core.*; import org.bytedeco.opencv.opencv_imgproc.*; import static org.bytedeco.opencv.global.opencv_core.*; import static org.bytedeco.opencv.global.opencv_imgproc.*; import static org.bytedeco.opencv.global.opencv_imgcodecs.*; public class Smoother { public static void smooth(String filename) { Mat image = imread(filename); if (image != null) { GaussianBlur(image, image, new Size(3, 3), 0); imwrite(filename, image); } } } ``` JavaCV also comes with helper classes and methods on top of OpenCV and FFmpeg to facilitate their integration to the Java platform. Here is a small demo program demonstrating the most frequently useful parts: ```java import java.io.File; import java.net.URL; import org.bytedeco.javacv.*; import org.bytedeco.javacpp.*; import org.bytedeco.javacpp.indexer.*; import org.bytedeco.opencv.opencv_core.*; import org.bytedeco.opencv.opencv_imgproc.*; import org.bytedeco.opencv.opencv_calib3d.*; import org.bytedeco.opencv.opencv_objdetect.*; import static org.bytedeco.opencv.global.opencv_core.*; import static org.bytedeco.opencv.global.opencv_imgproc.*; import static org.bytedeco.opencv.global.opencv_calib3d.*; import static org.bytedeco.opencv.global.opencv_objdetect.*; public class Demo { public static void main(String[] args) throws Exception { String classifierName = null; if (args.length > 0) { classifierName = args[0]; } else { URL url = new URL("https://raw.github.com/opencv/opencv/master/data/haarcascades/haarcascade_frontalface_alt.xml"); File file = Loader.cacheResource(url); classifierName = file.getAbsolutePath(); } // We can "cast" Pointer objects by instantiating a new object of the desired class. CascadeClassifier classifier = new CascadeClassifier(classifierName); if (classifier == null) { System.err.println("Error loading classifier file \"" + classifierName + "\"."); System.exit(1); } // The available FrameGrabber classes include OpenCVFrameGrabber (opencv_videoio), // DC1394FrameGrabber, FlyCapture2FrameGrabber, OpenKinectFrameGrabber, OpenKinect2FrameGrabber, // RealSenseFrameGrabber, RealSense2FrameGrabber, PS3EyeFrameGrabber, VideoInputFrameGrabber, and FFmpegFrameGrabber. FrameGrabber grabber = FrameGrabber.createDefault(0); grabber.start(); // CanvasFrame, FrameGrabber, and FrameRecorder use Frame objects to communicate image data. // We need a FrameConverter to interface with other APIs (Android, Java 2D, JavaFX, Tesseract, OpenCV, etc). OpenCVFrameConverter.ToMat converter = new OpenCVFrameConverter.ToMat(); // FAQ about IplImage and Mat objects from OpenCV: // - For custom raw processing of data, createBuffer() returns an NIO direct // buffer wrapped around the memory pointed by imageData, and under Android we can // also use that Buffer with Bitmap.copyPixelsFromBuffer() and copyPixelsToBuffer(). // - To get a BufferedImage from an IplImage, or vice versa, we can chain calls to // Java2DFrameConverter and OpenCVFrameConverter, one after the other. // - Java2DFrameConverter also has static copy() methods that we can use to transfer // data more directly between BufferedImage and IplImage or Mat via Frame objects. Mat grabbedImage = converter.convert(grabber.grab()); int height = grabbedImage.rows(); int width = grabbedImage.cols(); // Objects allocated with `new`, clone(), or a create*() factory method are automatically released // by the garbage collector, but may still be explicitly released by calling deallocate(). // You shall NOT call cvReleaseImage(), cvReleaseMemStorage(), etc. on objects allocated this way. Mat grayImage = new Mat(height, width, CV_8UC1); Mat rotatedImage = grabbedImage.clone(); // The OpenCVFrameRecorder class simply uses the VideoWriter of opencv_videoio, // but FFmpegFrameRecorder also exists as a more versatile alternative. FrameRecorder recorder = FrameRecorder.createDefault("output.avi", width, height); recorder.start(); // CanvasFrame is a JFrame containing a Canvas component, which is hardware accelerated. // It can also switch into full-screen mode when called with a screenNumber. // We should also specify the relative monitor/camera response for proper gamma correction. CanvasFrame frame = new CanvasFrame("Some Title", CanvasFrame.getDefaultGamma()/grabber.getGamma()); // Let's create some random 3D rotation... Mat randomR = new Mat(3, 3, CV_64FC1), randomAxis = new Mat(3, 1, CV_64FC1); // We can easily and efficiently access the elements of matrices and images // through an Indexer object with the set of get() and put() methods. DoubleIndexer Ridx = randomR.createIndexer(), axisIdx = randomAxis.createIndexer(); axisIdx.put(0, (Math.random() - 0.5) / 4, (Math.random() - 0.5) / 4, (Math.random() - 0.5) / 4); Rodrigues(randomAxis, randomR); double f = (width + height) / 2.0; Ridx.put(0, 2, Ridx.get(0, 2) * f); Ridx.put(1, 2, Ridx.get(1, 2) * f); Ridx.put(2, 0, Ridx.get(2, 0) / f); Ridx.put(2, 1, Ridx.get(2, 1) / f); System.out.println(Ridx); // We can allocate native arrays using constructors taking an integer as argument. Point hatPoints = new Point(3); while (frame.isVisible() && (grabbedImage = converter.convert(grabber.grab())) != null) { // Let's try to detect some faces! but we need a grayscale image... cvtColor(grabbedImage, grayImage, CV_BGR2GRAY); RectVector faces = new RectVector(); classifier.detectMultiScale(grayImage, faces); long total = faces.size(); for (long i = 0; i < total; i++) { Rect r = faces.get(i); int x = r.x(), y = r.y(), w = r.width(), h = r.height(); rectangle(grabbedImage, new Point(x, y), new Point(x + w, y + h), Scalar.RED, 1, CV_AA, 0); // To access or pass as argument the elements of a native array, call position() before. hatPoints.position(0).x(x - w / 10 ).y(y - h / 10); hatPoints.position(1).x(x + w * 11 / 10).y(y - h / 10); hatPoints.position(2).x(x + w / 2 ).y(y - h / 2 ); fillConvexPoly(grabbedImage, hatPoints.position(0), 3, Scalar.GREEN, CV_AA, 0); } // Let's find some contours! but first some thresholding... threshold(grayImage, grayImage, 64, 255, CV_THRESH_BINARY); // To check if an output argument is null we may call either isNull() or equals(null). MatVector contours = new MatVector(); findContours(grayImage, contours, CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE); long n = contours.size(); for (long i = 0; i < n; i++) { Mat contour = contours.get(i); Mat points = new Mat(); approxPolyDP(contour, points, arcLength(contour, true) * 0.02, true); drawContours(grabbedImage, new MatVector(points), -1, Scalar.BLUE); } warpPerspective(grabbedImage, rotatedImage, randomR, rotatedImage.size()); Frame rotatedFrame = converter.convert(rotatedImage); frame.showImage(rotatedFrame); recorder.record(rotatedFrame); } frame.dispose(); recorder.stop(); grabber.stop(); } } ``` Furthermore, after creating a `pom.xml` file with the following content: ```xml 4.0.0 org.bytedeco.javacv demo 1.5.13 1.8 1.8 org.bytedeco javacv-platform 1.5.13 org.bytedeco opencv-platform-gpu 4.13.0-1.5.13 org.bytedeco ffmpeg-platform-gpl 8.0.1-1.5.13 . ``` And by placing the source code above in `Demo.java`, or similarly for other classes found in the [`samples`](samples), we can use the following command to have everything first installed automatically and then executed by Maven: ```bash $ mvn compile exec:java -Dexec.mainClass=Demo ``` **Note**: In case of errors, please make sure that the `artifactId` in the `pom.xml` file reads `javacv-platform`, not `javacv` only, for example. The artifact `javacv-platform` adds all the necessary binary dependencies. Build Instructions ------------------ If the binary files available above are not enough for your needs, you might need to rebuild them from the source code. To this end, the project files were created for: * Maven 3.x http://maven.apache.org/download.html * JavaCPP 1.5.13 https://github.com/bytedeco/javacpp * JavaCPP Presets 1.5.13 https://github.com/bytedeco/javacpp-presets Once installed, simply call the usual `mvn install` command for JavaCPP, its Presets, and JavaCV. By default, no other dependencies than a C++ compiler for JavaCPP are required. Please refer to the comments inside the `pom.xml` files for further details. Instead of building the native libraries manually, we can run `mvn install` for JavaCV only and rely on the snapshot artifacts from the CI builds: * http://bytedeco.org/builds/ ---- Project lead: Samuel Audet [samuel.audet `at` gmail.com](mailto:samuel.audet at gmail.com) Developer site: https://github.com/bytedeco/javacv Discussion group: http://groups.google.com/group/javacv ================================================ FILE: platform/pom.xml ================================================ 4.0.0 org.bytedeco javacpp-presets 1.5.14-SNAPSHOT org.bytedeco javacv-platform JavaCV Platform ${project.version} org.bytedeco javacv ${project.version} org.bytedeco javacpp-platform ${javacpp.version} org.bytedeco openblas-platform 0.3.31-${javacpp.version} org.bytedeco opencv-platform 4.13.0-${javacpp.version} org.bytedeco ffmpeg-platform 8.0.1-${javacpp.version} org.bytedeco flycapture-platform 2.13.3.31-1.5.9 org.bytedeco libdc1394-platform 2.2.6-1.5.9 org.bytedeco libfreenect-platform 0.5.7-1.5.9 org.bytedeco libfreenect2-platform 0.2.0-1.5.9 org.bytedeco librealsense-platform 1.12.4-1.5.9 org.bytedeco librealsense2-platform 2.53.1-1.5.9 org.bytedeco videoinput-platform 0.200-1.5.9 org.bytedeco artoolkitplus-platform 2.3.1-1.5.9 org.bytedeco leptonica-platform 1.87.0-${javacpp.version} org.bytedeco tesseract-platform 5.5.2-${javacpp.version} junit junit 4.13.2 test org.bytedeco opencv-platform-gpu 4.13.0-${javacpp.version} test org.bytedeco ffmpeg-platform-gpl 8.0.1-${javacpp.version} test central-portal-snapshots Central Portal Snapshots https://central.sonatype.com/repository/maven-snapshots/ false true maven-jar-plugin 3.5.0 default-jar javacv.jar javacpp-platform.jar openblas-platform.jar opencv-platform.jar ffmpeg-platform.jar flycapture-platform.jar libdc1394-platform.jar libfreenect-platform.jar libfreenect2-platform.jar librealsense-platform.jar librealsense2-platform.jar videoinput-platform.jar artoolkitplus-platform.jar flandmark-platform.jar leptonica-platform.jar tesseract-platform.jar org/bytedeco/javacv/ empty-javadoc-jar jar javadoc empty-sources-jar jar sources org.moditect moditect-maven-plugin 1.3.0 9 true ${project.build.directory} add-module-infos package add-module-info ${project.build.directory}/${project.artifactId}.jar ${project.basedir}/src/main/java9/module-info.java maven-dependency-plugin 3.10.0 properties properties copy-dependencies copy-dependencies ${project.build.directory} true maven-surefire-plugin 3.5.5 -Xmx2g maven-assembly-plugin 3.8.0 false src/main/assembly/bin.xml src/main/assembly/src.xml package single sign-artifacts performRelease true central-portal-staging Central Portal Staging https://central.sonatype.com/api/v1/publisher/deployments/download/ true false maven-gpg-plugin 3.2.8 sign-artifacts verify sign ${env.GPG_PASSPHRASE} false ================================================ FILE: platform/src/main/assembly/bin.xml ================================================ ${project.version}-bin zip ${project.artifactId}-${project.version}-bin ${project.basedir}/.. / samples/* CHANGELOG* README* LICENSE* NOTICE* ${project.build.directory} / *.jar android*.jar gluegen*.jar hamcrest*.jar junit*.jar jogl*.jar jocl*.jar *-javadoc.jar *-sources.jar 0644 ${project.build.directory}/site docs ================================================ FILE: platform/src/main/assembly/src.xml ================================================ ${project.version}-src zip ${project.artifactId}-${project.version} ${project.basedir}/.. / true **/target/** **/cppbuild/** ================================================ FILE: platform/src/main/java9/module-info.java ================================================ module org.bytedeco.javacv.platform { requires transitive org.bytedeco.javacv; requires org.bytedeco.opencv.platform; requires org.bytedeco.ffmpeg.platform; requires org.bytedeco.flycapture.platform; requires org.bytedeco.libdc1394.platform; requires org.bytedeco.libfreenect.platform; requires org.bytedeco.libfreenect2.platform; requires org.bytedeco.librealsense.platform; requires org.bytedeco.librealsense2.platform; requires org.bytedeco.videoinput.platform; requires org.bytedeco.artoolkitplus.platform; requires org.bytedeco.flandmark.platform; requires org.bytedeco.leptonica.platform; requires org.bytedeco.tesseract.platform; } ================================================ FILE: platform/src/test/java/org/bytedeco/javacv/FrameConverterTest.java ================================================ /* * Copyright (C) 2015-2016 Samuel Audet * * Licensed either under the Apache License, Version 2.0, or (at your option) * under the terms of the GNU General Public License as published by * the Free Software Foundation (subject to the "Classpath" exception), * either version 2, or any later version (collectively, the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * http://www.gnu.org/licenses/ * http://www.gnu.org/software/classpath/license.html * * or as provided in the LICENSE.txt file that accompanied this code. * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.bytedeco.javacv; import java.awt.image.BufferedImage; import java.awt.image.DataBufferByte; import java.awt.image.DataBufferInt; import java.awt.image.WritableRaster; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.IntBuffer; import org.bytedeco.javacpp.BytePointer; import org.bytedeco.javacpp.Loader; import org.bytedeco.javacpp.indexer.Indexer; import org.bytedeco.javacpp.indexer.UByteIndexer; import org.junit.Test; import org.bytedeco.leptonica.PIX; import org.bytedeco.opencv.opencv_core.*; import org.bytedeco.opencv.opencv_imgproc.*; import static org.bytedeco.opencv.global.opencv_core.*; import static org.bytedeco.opencv.global.opencv_imgproc.*; import static org.junit.Assert.*; /** * Test cases for FrameConverter classes. Also uses other classes from JavaCV. * * @author Samuel Audet */ public class FrameConverterTest { @Test public void testAndroidFrameConverter() { System.out.println("AndroidFrameConverter"); AndroidFrameConverter converter = new AndroidFrameConverter(); int width = 512; int height = 1024; byte[] yuvData = new byte[3 * width * height / 2]; for (int i = 0; i < yuvData.length; i++) { yuvData[i] = (byte)i; } Mat yuvImage = new Mat(3 * height / 2, width, CV_8UC1, new BytePointer(yuvData)); Mat bgrImage = new Mat(height, width, CV_8UC3); cvtColor(yuvImage, bgrImage, CV_YUV2BGR_NV21); Frame bgrFrame = converter.convert(yuvData, width, height); UByteIndexer bgrImageIdx = bgrImage.createIndexer(); UByteIndexer bgrFrameIdx = bgrFrame.createIndexer(); assertEquals(bgrImageIdx.rows(), bgrFrameIdx.rows()); assertEquals(bgrImageIdx.cols(), bgrFrameIdx.cols()); assertEquals(bgrImageIdx.channels(), bgrFrameIdx.channels()); for (int i = 0; i < bgrImageIdx.rows(); i++) { for (int j = 0; j < bgrImageIdx.cols(); j++) { for (int k = 0; k < bgrImageIdx.channels(); k++) { assertEquals((float)bgrImageIdx.get(i, j, k), (float)bgrFrameIdx.get(i, j, k), 1.0f); } } } bgrImageIdx.release(); bgrFrameIdx.release(); Frame grayFrame = new Frame(1024 + 1, 768, Frame.DEPTH_UBYTE, 1); Frame colorFrame = new Frame(640 + 1, 480, Frame.DEPTH_UBYTE, 3); UByteIndexer grayFrameIdx = grayFrame.createIndexer(); for (int i = 0; i < grayFrameIdx.rows(); i++) { for (int j = 0; j < grayFrameIdx.cols(); j++) { grayFrameIdx.put(i, j, i + j); } } UByteIndexer colorFrameIdx = colorFrame.createIndexer(); for (int i = 0; i < colorFrameIdx.rows(); i++) { for (int j = 0; j < colorFrameIdx.cols(); j++) { for (int k = 0; k < colorFrameIdx.channels(); k++) { colorFrameIdx.put(i, j, k, i + j + k); } } } width = grayFrame.imageWidth; height = grayFrame.imageHeight; int stride = grayFrame.imageStride; int rowBytes = width * 4; ByteBuffer in = (ByteBuffer)grayFrame.image[0]; ByteBuffer buffer = converter.gray2rgba(in, width, height, stride, rowBytes); for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { // GRAY -> RGBA byte B = in.get(y * stride + x); assertEquals(buffer.get(y * rowBytes + 4 * x ), B); assertEquals(buffer.get(y * rowBytes + 4 * x + 1), B); assertEquals(buffer.get(y * rowBytes + 4 * x + 2), B); assertEquals(buffer.get(y * rowBytes + 4 * x + 3), (byte)0xFF); } } width = colorFrame.imageWidth; height = colorFrame.imageHeight; stride = colorFrame.imageStride; rowBytes = width * 4; in = (ByteBuffer)colorFrame.image[0]; buffer = converter.bgr2rgba(in, width, height, stride, rowBytes); for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { // BGR -> RGBA byte B = in.get(y * stride + 3 * x ); byte G = in.get(y * stride + 3 * x + 1); byte R = in.get(y * stride + 3 * x + 2); assertEquals(buffer.get(y * rowBytes + 4 * x ), R); assertEquals(buffer.get(y * rowBytes + 4 * x + 1), G); assertEquals(buffer.get(y * rowBytes + 4 * x + 2), B); assertEquals(buffer.get(y * rowBytes + 4 * x + 3), (byte)0xFF); } } colorFrameIdx.release(); grayFrameIdx.release(); converter.close(); colorFrame.close(); grayFrame.close(); } @Test public void testJava2DFrameConverter() { System.out.println("Java2DFrameConverter"); int[] depths = {Frame.DEPTH_UBYTE, Frame.DEPTH_SHORT, Frame.DEPTH_FLOAT}; int[] channels = {1, 3, 4}; for (int i = 0; i < depths.length; i++) { for (int j = 0; j < channels.length; j++) { Frame frame = new Frame(640 + 1, 480, depths[i], channels[j]); Java2DFrameConverter converter = new Java2DFrameConverter(); Indexer frameIdx = frame.createIndexer(); for (int y = 0; y < frameIdx.rows(); y++) { for (int x = 0; x < frameIdx.cols(); x++) { for (int z = 0; z < frameIdx.channels(); z++) { frameIdx.putDouble(new long[] {y, x, z}, y + x + z); } } } BufferedImage image = converter.convert(frame); converter.frame = null; Frame frame2 = converter.convert(image); Indexer frame2Idx = frame2.createIndexer(); for (int y = 0; y < frameIdx.rows(); y++) { for (int x = 0; x < frameIdx.cols(); x++) { for (int z = 0; z < frameIdx.channels(); z++) { double value = frameIdx.getDouble(y, x, z); assertEquals(value, frame2Idx.getDouble(y, x, z), 0); } } } try { frame2Idx.getDouble(frameIdx.rows() + 1, frameIdx.cols() + 1); fail("IndexOutOfBoundsException should have been thrown."); } catch (IndexOutOfBoundsException e) { } frameIdx.release(); frame2Idx.release(); converter.close(); frame.close(); } } int[] types = {BufferedImage.TYPE_INT_RGB, BufferedImage.TYPE_INT_ARGB, BufferedImage.TYPE_INT_ARGB_PRE, BufferedImage.TYPE_INT_BGR}; for (int i = 0; i < types.length; i++) { BufferedImage image = new BufferedImage(640 + 1, 480, types[i]); Java2DFrameConverter converter = new Java2DFrameConverter(); WritableRaster raster = image.getRaster(); int[] array = ((DataBufferInt)raster.getDataBuffer()).getData(); for (int j = 0; j < array.length; j++) { array[j] = j; } Frame frame = converter.convert(image); converter.bufferedImage = null; BufferedImage image2 = converter.convert(frame); WritableRaster raster2 = image2.getRaster(); byte[] array2 = ((DataBufferByte)raster2.getDataBuffer()).getData(); for (int j = 0; j < array.length; j++) { int n = ((array2[4 * j ] & 0xFF) << 24) | ((array2[4 * j + 1] & 0xFF) << 16) | ((array2[4 * j + 2] & 0xFF) << 8) | (array2[4 * j + 3] & 0xFF); assertEquals(array[j], n); } converter.close(); } } @Test public void testOpenCVFrameConverter() { System.out.println("OpenCVFrameConverter"); Loader.load(org.bytedeco.opencv.opencv_java.class); for (int depth = 8; depth <= 64; depth *= 2) { assertEquals(depth, OpenCVFrameConverter.getFrameDepth(OpenCVFrameConverter.getIplImageDepth(depth))); assertEquals(depth, OpenCVFrameConverter.getFrameDepth(OpenCVFrameConverter.getMatDepth(depth))); if (depth < 64) { assertEquals(-depth, OpenCVFrameConverter.getFrameDepth(OpenCVFrameConverter.getIplImageDepth(-depth))); assertEquals(-depth, OpenCVFrameConverter.getFrameDepth(OpenCVFrameConverter.getMatDepth(-depth))); } } Frame frame = new Frame(640 + 1, 480, Frame.DEPTH_UBYTE, 3); OpenCVFrameConverter.ToIplImage converter1 = new OpenCVFrameConverter.ToIplImage(); OpenCVFrameConverter.ToMat converter2 = new OpenCVFrameConverter.ToMat(); OpenCVFrameConverter.ToOrgOpenCvCoreMat converter3 = new OpenCVFrameConverter.ToOrgOpenCvCoreMat(); UByteIndexer frameIdx = frame.createIndexer(); for (int i = 0; i < frameIdx.rows(); i++) { for (int j = 0; j < frameIdx.cols(); j++) { for (int k = 0; k < frameIdx.channels(); k++) { frameIdx.put(i, j, k, i + j + k); } } } IplImage image = converter1.convert(frame); Mat mat = converter2.convert(frame); final org.opencv.core.Mat cvmat = converter3.convert(frame); converter1.frame = null; converter2.frame = null; converter3.frame = null; Frame frame1 = converter1.convert(image); Frame frame2 = converter2.convert(mat); Frame frame3 = converter3.convert(cvmat); assertEquals(frame2.opaque, mat); assertEquals(frame3.opaque, cvmat); Mat mat2 = new Mat(mat.rows(), mat.cols(), mat.type(), mat.data(), mat.step()); org.opencv.core.Mat cvmat2 = new org.opencv.core.Mat(cvmat.rows(), cvmat.cols(), cvmat.type(), new BytePointer() { { address = cvmat.dataAddr(); } }.capacity(cvmat.rows() * cvmat.cols() * cvmat.elemSize()).asByteBuffer(), cvmat.step1() * cvmat.elemSize1()); assertNotEquals(mat, mat2); assertNotEquals(cvmat, cvmat2); frame2 = converter2.convert(mat2); frame3 = converter3.convert(cvmat2); assertEquals(frame2.opaque, mat2); assertEquals(frame3.opaque, cvmat2); assertEquals(frame3.imageStride, cvmat2.step1() * cvmat2.elemSize1()); UByteIndexer frame1Idx = frame1.createIndexer(); UByteIndexer frame2Idx = frame2.createIndexer(); UByteIndexer frame3Idx = frame3.createIndexer(); for (int i = 0; i < frameIdx.rows(); i++) { for (int j = 0; j < frameIdx.cols(); j++) { for (int k = 0; k < frameIdx.channels(); k++) { int b = frameIdx.get(i, j, k); assertEquals(b, frame1Idx.get(i, j, k)); assertEquals(b, frame2Idx.get(i, j, k)); assertEquals(b, frame3Idx.get(i, j, k)); } } } try { frame1Idx.get(frameIdx.rows() + 1, frameIdx.cols() + 1); fail("IndexOutOfBoundsException should have been thrown."); } catch (IndexOutOfBoundsException e) { } try { frame2Idx.get(frameIdx.rows() + 1, frameIdx.cols() + 1); fail("IndexOutOfBoundsException should have been thrown."); } catch (IndexOutOfBoundsException e) { } try { frame3Idx.get(frameIdx.rows() + 1, frameIdx.cols() + 1); fail("IndexOutOfBoundsException should have been thrown."); } catch (IndexOutOfBoundsException e) { } frameIdx.release(); frame1Idx.release(); frame2Idx.release(); frame3Idx.release(); converter1.close(); converter2.close(); converter3.close(); frame.close(); } @Test public void testLeptonicaFrameConverter() { System.out.println("LeptonicaFrameConverter"); Frame frame = new Frame(640 + 1, 480, Frame.DEPTH_UBYTE, 3); LeptonicaFrameConverter converter = new LeptonicaFrameConverter(); UByteIndexer frameIdx = frame.createIndexer(); for (int i = 0; i < frameIdx.rows(); i++) { for (int j = 0; j < frameIdx.cols(); j++) { for (int k = 0; k < frameIdx.channels(); k++) { frameIdx.put(i, j, k, i + j + k); } } } PIX pix = converter.convert(frame); converter.frame = null; Frame frame1 = converter.convert(pix); // assertEquals(frame1.opaque, pix); PIX pix2 = PIX.createHeader(pix.w(), pix.h(), pix.d()).data(pix.data()).wpl(pix.wpl()); assertNotEquals(pix, pix2); Frame frame2 = converter.convert(pix2); // assertEquals(frame2.opaque, pix2); IntBuffer frameBuf = ((ByteBuffer)frame.image[0].position(0)).asIntBuffer(); IntBuffer frame1Buf = ((ByteBuffer)frame1.image[0].position(0)).asIntBuffer(); IntBuffer frame2Buf = ((ByteBuffer)frame2.image[0].position(0)).asIntBuffer(); IntBuffer pixBuf = pix.createBuffer().order(ByteOrder.BIG_ENDIAN).asIntBuffer(); IntBuffer pix2Buf = pix2.createBuffer().order(ByteOrder.BIG_ENDIAN).asIntBuffer(); for (int i = 0; i < frameBuf.capacity(); i++) { int j = frameBuf.get(i); assertEquals(j, frame1Buf.get(i)); assertEquals(j, frame2Buf.get(i)); assertEquals(j, pixBuf.get(i)); assertEquals(j, pix2Buf.get(i)); } try { frame1Buf.get(frameBuf.capacity() + 1); fail("IndexOutOfBoundsException should have been thrown."); } catch (IndexOutOfBoundsException e) { } try { frame2Buf.get(frameBuf.capacity() + 1); fail("IndexOutOfBoundsException should have been thrown."); } catch (IndexOutOfBoundsException e) { } try { pixBuf.get(frameBuf.capacity() + 1); fail("IndexOutOfBoundsException should have been thrown."); } catch (IndexOutOfBoundsException e) { } try { pix2Buf.get(frameBuf.capacity() + 1); fail("IndexOutOfBoundsException should have been thrown."); } catch (IndexOutOfBoundsException e) { } pix2.deallocate(); pix.deallocate(); converter.close(); frame.close(); } } ================================================ FILE: platform/src/test/java/org/bytedeco/javacv/FrameFilterTest.java ================================================ /* * Copyright (C) 2018 Samuel Audet * * Licensed either under the Apache License, Version 2.0, or (at your option) * under the terms of the GNU General Public License as published by * the Free Software Foundation (subject to the "Classpath" exception), * either version 2, or any later version (collectively, the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * http://www.gnu.org/licenses/ * http://www.gnu.org/software/classpath/license.html * * or as provided in the LICENSE.txt file that accompanied this code. * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.bytedeco.javacv; import java.io.File; import java.nio.ByteBuffer; import java.nio.ShortBuffer; import org.bytedeco.javacpp.Loader; import org.junit.Test; import static org.bytedeco.ffmpeg.global.avcodec.*; import static org.bytedeco.ffmpeg.global.avutil.*; import static org.junit.Assert.*; /** * Test cases for FrameFilter classes. Also uses other classes from JavaCV. * * @author Samuel Audet */ public class FrameFilterTest { @Test public void testFFmpegFrameFilter() { System.out.println("FFmpegFrameFilter"); File tempFile = new File(Loader.getTempDir(), "test.mov"); try { FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(tempFile, 800, 600, 2); recorder.setFormat("mov"); recorder.setPixelFormat(AV_PIX_FMT_YUV420P); recorder.setFrameRate(30); recorder.setVideoCodec(AV_CODEC_ID_H264); recorder.setVideoQuality(10); recorder.setSampleFormat(AV_SAMPLE_FMT_FLTP); recorder.setSampleRate(48000); recorder.setAudioCodec(AV_CODEC_ID_AAC); recorder.setAudioQuality(10); recorder.start(); int n = 1000; Frame frame = new Frame(800, 600, Frame.DEPTH_UBYTE, 3); for (int i = 0; i < n; i++) { recorder.record(frame); } Frame audioFrame = new Frame(); ShortBuffer audioBuffer = ShortBuffer.allocate(48000 * 2 * n / 30); audioFrame.sampleRate = 48000; audioFrame.audioChannels = 2; audioFrame.samples = new ShortBuffer[] {audioBuffer}; recorder.record(audioFrame); recorder.stop(); recorder.release(); FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(tempFile); grabber.setSampleMode(FrameGrabber.SampleMode.FLOAT); grabber.start(); FFmpegFrameFilter filter = new FFmpegFrameFilter( "scale=400x300,transpose=cclock_flip,format=gray", "volume=0.5,aformat=sample_fmts=u8:channel_layouts=mono", grabber.getImageWidth(), grabber.getImageHeight(), grabber.getAudioChannels()); filter.setPixelFormat(grabber.getPixelFormat()); filter.setSampleFormat(grabber.getSampleFormat()); filter.setFrameRate(grabber.getFrameRate()); filter.setSampleRate(grabber.getSampleRate()); filter.start(); FFmpegFrameFilter nullFilter = new FFmpegFrameFilter(null, null, 0, 0, 0); nullFilter.start(); int a = 0, b = 0, c = 0, d = 0; Frame frame2; while ((frame2 = grabber.grab()) != null) { if (frame2.image != null) { a++; } if (frame2.samples != null) { b++; } filter.push(frame2); Frame frame3; while ((frame3 = filter.pull()) != null) { if (frame3.image != null) { c++; assertEquals(300, frame3.imageWidth); assertEquals(400, frame3.imageHeight); assertEquals(1, frame3.imageChannels); } if (frame3.samples != null) { d++; assertEquals(1, frame3.audioChannels); assertEquals(1, frame3.samples.length); assertTrue(frame3.samples[0] instanceof ByteBuffer); assertEquals(frame2.samples.length, frame3.samples.length); assertEquals(frame2.samples[0].limit() / 2, frame3.samples[0].limit()); } assertEquals(frame2.timestamp, frame3.timestamp); } nullFilter.push(frame2); assertEquals(frame2, nullFilter.pull()); } filter.push(null); assertEquals(null, filter.pull()); assertEquals(a, c); assertEquals(b, d); assertEquals(null, grabber.grab()); filter.stop(); filter.release(); grabber.restart(); grabber.stop(); grabber.release(); frame.close(); } catch (Exception e) { e.printStackTrace(); fail("Exception should not have been thrown: " + e); } finally { tempFile.delete(); } } @Test public void testFFmpegFrameFilterMultipleInputs() { System.out.println("FFmpegFrameFilterMultipleInputs"); File tempFile = new File(Loader.getTempDir(), "test.avi"); try { FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(tempFile, 320, 200, 2); recorder.setVideoCodec(AV_CODEC_ID_VP8); recorder.setAudioCodec(AV_CODEC_ID_VORBIS); recorder.start(); int n = 1000; Frame frame = new Frame(320, 200, Frame.DEPTH_UBYTE, 3); for (int i = 0; i < n; i++) { recorder.record(frame); } Frame audioFrame = new Frame(); ShortBuffer audioBuffer = ShortBuffer.allocate(8000 * 2 * n / 30); audioFrame.sampleRate = 8000; audioFrame.audioChannels = 2; audioFrame.samples = new ShortBuffer[] {audioBuffer}; recorder.record(audioFrame); recorder.stop(); recorder.release(); FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(tempFile); grabber.start(); FFmpegFrameFilter filter = new FFmpegFrameFilter( "[0:v][1:v]hstack=inputs=2[v]", "[0:a][1:a]amerge[a]", grabber.getImageWidth(), grabber.getImageHeight(), grabber.getAudioChannels()); filter.setPixelFormat(grabber.getPixelFormat()); filter.setSampleFormat(grabber.getSampleFormat()); filter.setVideoInputs(2); filter.setAudioInputs(2); filter.start(); int a = 0, b = 0, c = 0, d = 0; Frame frame2; while ((frame2 = grabber.grab()) != null) { if (frame2.image != null) { a++; } if (frame2.samples != null) { b++; } filter.push(0, frame2); filter.push(1, frame2); Frame frame3; while ((frame3 = filter.pull()) != null) { if (frame3.image != null) { c++; assertEquals(640, frame3.imageWidth); assertEquals(200, frame3.imageHeight); assertEquals(3, frame3.imageChannels); } if (frame3.samples != null) { d++; assertEquals(4, frame3.audioChannels); assertEquals(1, frame3.samples.length); assertTrue(frame3.samples[0] instanceof ShortBuffer); assertEquals(frame2.samples.length, frame3.samples.length); assertEquals(2 * frame2.samples[0].limit(), frame3.samples[0].limit()); } } } filter.push(0, null); filter.push(1, null); assertEquals(null, filter.pull()); assertEquals(a, c); assertEquals(b, d); assertEquals(null, grabber.grab()); filter.stop(); filter.release(); grabber.restart(); grabber.stop(); grabber.release(); frame.close(); } catch (Exception e) { e.printStackTrace(); fail("Exception should not have been thrown: " + e); } finally { tempFile.delete(); } } } ================================================ FILE: platform/src/test/java/org/bytedeco/javacv/FrameGrabberChangingResolutionTest.java ================================================ /* * Copyright (C) 2016-2017 Samuel Audet * * Licensed either under the Apache License, Version 2.0, or (at your option) * under the terms of the GNU General Public License as published by * the Free Software Foundation (subject to the "Classpath" exception), * either version 2, or any later version (collectively, the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * http://www.gnu.org/licenses/ * http://www.gnu.org/software/classpath/license.html * * or as provided in the LICENSE.txt file that accompanied this code. * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.bytedeco.javacv; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.nio.FloatBuffer; import java.nio.ShortBuffer; import org.bytedeco.javacpp.Loader; import org.bytedeco.javacpp.indexer.UByteIndexer; import org.junit.Test; import static org.bytedeco.ffmpeg.global.avcodec.*; import static org.bytedeco.ffmpeg.global.avutil.*; import static org.junit.Assert.*; /** * Complex Test case for FrameGrabber classes - change the resolution during runtime. * Also uses other classes from JavaCV. * * @author Samuel Audet, Michael Fritscher */ public class FrameGrabberChangingResolutionTest { private File tempFile = new File(Loader.getTempDir(), "test.mkv"); private File tempTargetFile = new File(Loader.getTempDir(), "target.mkv"); private boolean endRequested; private void makeTestfile() throws Exception { FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(new FileOutputStream(tempFile), 640, 480, 2); recorder.setFormat("matroska"); // mp4 doesn't support streaming recorder.setPixelFormat(AV_PIX_FMT_YUV420P); recorder.setVideoCodec(AV_CODEC_ID_H264); recorder.setVideoQuality(0); // lossless recorder.setFrameRate(30); recorder.startUnsafe(); Frame[] frames = new Frame[60]; for (int n = 0; n < frames.length; n++) { Frame frame = new Frame(640, 480, Frame.DEPTH_UBYTE, 3); UByteIndexer frameIdx = frame.createIndexer(); for (int i = 0; i < frameIdx.rows(); i++) { for (int j = 0; j < frameIdx.cols(); j++) { for (int k = 0; k < frameIdx.channels(); k++) { frameIdx.put(i, j, k, n + i + j + k); } } } recorder.record(frame); frames[n] = frame; } recorder.stop(); recorder.release(); for (int n = 0; n < frames.length; n++) { frames[n].close(); } } final public void setupUDPSender(final int x, final int y, final int bandwidth, final int count) throws IOException { final FFmpegFrameGrabber fg = new FFmpegFrameGrabber(tempFile); fg.setFrameRate(30); final FFmpegFrameRecorder fr = new FFmpegFrameRecorder("udp://127.0.0.1:2345", 0); fr.setVideoCodecName("mpeg2video"); fr.setFormat("mpegts"); fr.setImageWidth(x); fr.setImageHeight(y); fr.setVideoBitrate(bandwidth); fr.setFrameRate(30); fg.startUnsafe(); fr.startUnsafe(); final boolean[] b = new boolean[1]; Thread t = new Thread() { public void run() { try { for (int i = 0; i < count; i++) { /*- System.out.println("S: " + fg.getFrameNumber() + " " + fg.getTimestamp() + " " + fg.getFrameRate() + " " + fg.getImageWidth() + "x" + fg.getImageHeight() + " " + fg.getVideoCodec() + " " + fg.getVideoBitrate() + " " + i); */ Frame source = fg.grabFrame(); fr.record(source); } fg.close(); fr.close(); b[0] = true; } catch (Exception e) { e.printStackTrace(); fail("Exception should not have been thrown: " + e); try { fg.close(); fr.close(); } catch (Exception e1) { e1.printStackTrace(); } b[0] = true; } } }; t.setName("Sender"); t.start(); while (!b[0]) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } final public void setupUDPReceiver() throws IOException { Thread t = new Thread() { public void run() { FFmpegFrameGrabber fg = new FFmpegFrameGrabber("udp://127.0.0.1:2345"); fg.setFrameRate(30); FFmpegFrameRecorder fr = new FFmpegFrameRecorder(tempTargetFile, 0); fr.setVideoCodecName("mpeg2video"); fr.setFormat("mpegts"); fr.setImageWidth(640); fr.setImageHeight(480); fr.setVideoBitrate(8000000); fr.setFrameRate(30); try { fg.startUnsafe(); fr.startUnsafe(); } catch (Exception e) { e.printStackTrace(); } // Tests whether the width of the picture changes trough all // qualities and every step has a few pictures. try { int n = 0; int m = 0; // Pictures in this quality int q = 0; // which quality state? int[] qualities = { 160, 320, 640, 160, 320, 640, 320, 160 }; while (!endRequested) { /*- System.out.println("R: " + fg.getFrameNumber() + " " + fg.getTimestamp() + " " + fg.getFrameRate() + " " + fg.getImageWidth() + "x" + fg.getImageHeight() + " " + fg.getVideoCodec() + " " + fg.getVideoBitrate()); */ Frame source = fg.grabFrame(); n++; m++; // System.out.println("WRITTEN: " + n + " " + m + " " + // q + " " + source.imageWidth); if (source.imageWidth != qualities[q]) { q++; assertEquals(source.imageWidth, qualities[q]); assertTrue(m > 5); assertTrue(m <= 60); m = 0; } fr.record(source); } assertEquals(q, qualities.length - 1); assertTrue(n > 300); assertTrue(n <= 480); fr.close(); } catch (Exception e) { e.printStackTrace(); fail("Exception should not have been thrown: " + e); try { fg.close(); fr.close(); } catch (Exception e1) { e1.printStackTrace(); } } } }; t.setName("Receiver"); t.start(); } @Test public void testFFmpegFrameGrabber() { System.out.println("FFmpegFrameGrabber"); try { makeTestfile(); setupUDPReceiver(); System.out.println("Changing to 160x120"); setupUDPSender(160, 120, 50000, 60); System.out.println("Changing to 320x240"); setupUDPSender(320, 240, 100000, 60); System.out.println("Changing to 640x480"); setupUDPSender(640, 480, 200000, 60); System.out.println("Changing to 160x120"); setupUDPSender(160, 120, 50000, 60); System.out.println("Changing to 320x240"); setupUDPSender(320, 240, 100000, 60); System.out.println("Changing to 640x480"); setupUDPSender(640, 480, 200000, 60); System.out.println("Changing to 320x240"); setupUDPSender(320, 240, 100000, 60); System.out.println("Changing to 160x120"); setupUDPSender(160, 120, 50000, 60); Thread.sleep(3000); endRequested = true; } catch (Exception e) { tempFile.delete(); tempTargetFile.delete(); e.printStackTrace(); fail("Exception should not have been thrown: " + e); } try { FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(new FileInputStream(tempTargetFile)); grabber.setSampleMode(FrameGrabber.SampleMode.FLOAT); grabber.startUnsafe(); int n = 0; Frame frame2; while ((frame2 = grabber.grab()) != null) { if (frame2.image != null) { n++; assertEquals(640, frame2.imageWidth); } } // It seems that ffmpeg lose some frames while switching (ideal // value would be 240) // System.out.println("END NUMBER: " + n); assertTrue(n > 300); assertTrue(n <= 480); assertEquals(null, grabber.grab()); grabber.stop(); grabber.release(); } catch (Exception e) { e.printStackTrace(); fail("Exception should not have been thrown: " + e); } finally { tempFile.delete(); tempTargetFile.delete(); } } } ================================================ FILE: platform/src/test/java/org/bytedeco/javacv/FrameGrabberTest.java ================================================ /* * Copyright (C) 2016-2023 Samuel Audet * * Licensed either under the Apache License, Version 2.0, or (at your option) * under the terms of the GNU General Public License as published by * the Free Software Foundation (subject to the "Classpath" exception), * either version 2, or any later version (collectively, the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * http://www.gnu.org/licenses/ * http://www.gnu.org/software/classpath/license.html * * or as provided in the LICENSE.txt file that accompanied this code. * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.bytedeco.javacv; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.nio.FloatBuffer; import java.nio.ShortBuffer; import java.util.Random; import org.bytedeco.javacpp.Loader; import org.bytedeco.javacpp.PointerScope; import org.bytedeco.javacpp.indexer.UByteIndexer; import org.junit.Test; import static org.bytedeco.ffmpeg.global.avcodec.*; import static org.bytedeco.ffmpeg.global.avutil.*; import static org.junit.Assert.*; /** * Test cases for FrameGrabber classes. Also uses other classes from JavaCV. * * @author Samuel Audet */ public class FrameGrabberTest { @Test public void testFFmpegFrameGrabber() { System.out.println("FFmpegFrameGrabber"); File tempFile = new File(Loader.getTempDir(), "test.mkv"); try { FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(new FileOutputStream(tempFile), 640, 480, 2); recorder.setFormat("matroska"); // mp4 doesn't support streaming recorder.setPixelFormat(AV_PIX_FMT_BGR24); recorder.setVideoCodecName("jpegls"); recorder.setVideoQuality(0); // lossless recorder.setSampleFormat(AV_SAMPLE_FMT_S16); recorder.setSampleRate(44100); recorder.setAudioCodecName("pcm_s16le"); recorder.start(); Frame[] frames = new Frame[1000]; for (int n = 0; n < frames.length; n++) { Frame frame = new Frame(640, 480, Frame.DEPTH_UBYTE, 3); UByteIndexer frameIdx = frame.createIndexer(); for (int i = 0; i < frameIdx.rows(); i++) { for (int j = 0; j < frameIdx.cols(); j++) { for (int k = 0; k < frameIdx.channels(); k++) { frameIdx.put(i, j, k, n + i + j + k); } } } recorder.record(frame); frames[n] = frame; } Frame audioFrame = new Frame(); ShortBuffer audioBuffer = ShortBuffer.allocate(64 * 1024); audioFrame.sampleRate = 44100; audioFrame.audioChannels = 2; audioFrame.samples = new ShortBuffer[] {audioBuffer}; for (int i = 0; i < audioBuffer.capacity(); i++) { audioBuffer.put(i, (short)i); } recorder.record(audioFrame); recorder.stop(); recorder.release(); FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(new FileInputStream(tempFile)); grabber.setSampleMode(FrameGrabber.SampleMode.FLOAT); grabber.start(); int n = 0, m = 0; Frame frame2; long startTime = System.nanoTime(); while ((frame2 = grabber.grabAtFrameRate()) != null) { long delay = frame2.timestamp * 1000 - (System.nanoTime() - startTime); if (delay < -1_000_000_000 / grabber.getFrameRate()) { // skip to catch up with frame rate if (frame2.image != null) { n++; } else { m++; } continue; } Frame clone2 = frame2.clone(); if (frame2.image != null) { Frame frame = frames[n++]; assertEquals(frame.imageWidth, frame2.imageWidth); assertEquals(frame.imageHeight, frame2.imageHeight); assertEquals(frame.imageChannels, frame2.imageChannels); assertEquals(frame.imageWidth, clone2.imageWidth); assertEquals(frame.imageHeight, clone2.imageHeight); assertEquals(frame.imageChannels, clone2.imageChannels); UByteIndexer frameIdx = frame.createIndexer(); UByteIndexer frame2Idx = frame2.createIndexer(); UByteIndexer clone2Idx = clone2.createIndexer(); for (int i = 0; i < frameIdx.rows(); i++) { for (int j = 0; j < frameIdx.cols(); j++) { for (int k = 0; k < frameIdx.channels(); k++) { int b = frameIdx.get(i, j, k); assertEquals(b, frame2Idx.get(i, j, k)); assertEquals(b, clone2Idx.get(i, j, k)); } } } } else { FloatBuffer audioBuffer2 = (FloatBuffer)frame2.samples[0]; FloatBuffer cloneBuffer2 = (FloatBuffer)clone2.samples[0]; while (audioBuffer2.hasRemaining()) { assertEquals((float)audioBuffer.get(m) / (Short.MAX_VALUE + 1), audioBuffer2.get(), 0); assertEquals((float)audioBuffer.get(m) / (Short.MAX_VALUE + 1), cloneBuffer2.get(), 0); m++; } } clone2.close(); } long stopTime = System.nanoTime(); assertEquals(n, (stopTime - startTime) * grabber.getFrameRate() / 1_000_000_000, 3.0); assertEquals(frames.length, n); assertEquals(null, grabber.grab()); grabber.restart(); grabber.stop(); grabber.release(); for (n = 0; n < frames.length; n++) { frames[n].close(); } } catch (Exception e) { e.printStackTrace(); fail("Exception should not have been thrown: " + e); } finally { tempFile.delete(); } } @Test public void testFFmpegFrameGrabberLockingTest() { final boolean[] failed = {false}; final int numberOfInstances = 20; System.out.println("FFmpegFrameGrabberLocking"); Runnable[] runables = new Runnable[numberOfInstances]; Thread[] threads = new Thread[numberOfInstances]; final boolean[] finish = new boolean[numberOfInstances]; for (int instance = 0; instance < numberOfInstances; instance++) { final int instance_final = instance; Runnable r = new Runnable() { public void run() { File tempFile = new File(Loader.getTempDir(), "test" + instance_final + ".mkv"); try (PointerScope scope = new PointerScope()) { FFmpegLogCallback.set(); FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(new FileOutputStream(tempFile), 640, 480, 2); recorder.setFormat("matroska"); // mp4 doesn't support streaming recorder.setPixelFormat(AV_PIX_FMT_BGR24); recorder.setVideoCodecName("jpegls"); recorder.setVideoQuality(0); // lossless recorder.setSampleFormat(AV_SAMPLE_FMT_S16); recorder.setSampleRate(44100); recorder.setAudioCodecName("pcm_s16le"); recorder.startUnsafe(); Frame[] frames = new Frame[10]; for (int n = 0; n < frames.length; n++) { Frame frame = new Frame(640, 480, Frame.DEPTH_UBYTE, 3); UByteIndexer frameIdx = frame.createIndexer(); for (int i = 0; i < frameIdx.rows(); i++) { for (int j = 0; j < frameIdx.cols(); j++) { for (int k = 0; k < frameIdx.channels(); k++) { frameIdx.put(i, j, k, n + i + j + k); } } } recorder.record(frame); frames[n] = frame; } Frame audioFrame = new Frame(); ShortBuffer audioBuffer = ShortBuffer.allocate(64 * 1024); audioFrame.sampleRate = 44100; audioFrame.audioChannels = 2; audioFrame.samples = new ShortBuffer[] { audioBuffer }; for (int i = 0; i < audioBuffer.capacity(); i++) { audioBuffer.put(i, (short) i); } recorder.record(audioFrame); recorder.stop(); recorder.release(); Thread.sleep(1000); FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(new FileInputStream(tempFile)); grabber.setSampleMode(FrameGrabber.SampleMode.FLOAT); grabber.startUnsafe(); int n = 0, m = 0; Frame frame2; while ((frame2 = grabber.grab()) != null) { if (frame2.image != null) { Frame frame = frames[n++]; assertEquals(frame.imageWidth, frame2.imageWidth); assertEquals(frame.imageHeight, frame2.imageHeight); assertEquals(frame.imageChannels, frame2.imageChannels); UByteIndexer frameIdx = frame.createIndexer(); UByteIndexer frame2Idx = frame2.createIndexer(); for (int i = 0; i < frameIdx.rows(); i++) { for (int j = 0; j < frameIdx.cols(); j++) { for (int k = 0; k < frameIdx.channels(); k++) { int b = frameIdx.get(i, j, k); assertEquals(b, frame2Idx.get(i, j, k)); } } } } else { FloatBuffer audioBuffer2 = (FloatBuffer) frame2.samples[0]; while (audioBuffer2.hasRemaining()) { assertEquals((float) audioBuffer.get(m++) / (Short.MAX_VALUE + 1), audioBuffer2.get(), 0); } } } assertEquals(frames.length, n); assertEquals(null, grabber.grab()); grabber.restart(); grabber.stop(); grabber.release(); for (n = 0; n < frames.length; n++) { frames[n].close(); } } catch (Error | Exception e) { failed[0] = true; e.printStackTrace(); fail("Exception should not have been thrown: " + e); } finally { tempFile.delete(); finish[instance_final] = true; } } }; runables[instance_final] = r; } for (int instance = 0; instance < numberOfInstances; instance++) { threads[instance] = new Thread(runables[instance]); threads[instance].setName("Testthread-" + instance); } for (int instance = 0; instance < numberOfInstances; instance++) { threads[instance].start(); } while (true) { boolean finished = true; for (int instance = 0; instance < numberOfInstances; instance++) { if (!finish[instance]) { finished = false; break; } } if (!finished) { System.out.println("Still waiting..."); try { Thread.sleep(500); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } else { break; } } assertFalse(failed[0]); } @Test public void testFFmpegFrameGrabberSeeking() throws IOException { System.out.println("FFmpegFrameGrabberSeeking"); for(int seektestnum = 0; seektestnum < 3; seektestnum++) try (PointerScope scope = new PointerScope()) { FFmpegLogCallback.set(); String fileName = seektestnum==0?"testAV.mp4":seektestnum==1?"testV.mp4":"testA.mp4"; File tempFile = new File(Loader.getTempDir(), fileName); tempFile.deleteOnExit(); FFmpegFrameRecorder recorder = seektestnum == 0? new FFmpegFrameRecorder(tempFile, 640, 480, 2) : seektestnum == 1? new FFmpegFrameRecorder(tempFile, 640, 480, 0) : new FFmpegFrameRecorder(tempFile, 0, 0, 2); recorder.setFormat("mp4"); recorder.setFrameRate(30); recorder.setPixelFormat(AV_PIX_FMT_YUV420P); recorder.setVideoCodec(AV_CODEC_ID_MPEG4); recorder.setVideoQuality(10); recorder.setSampleRate(48000); recorder.setSampleFormat(AV_SAMPLE_FMT_FLTP); recorder.setAudioCodec(AV_CODEC_ID_AAC); recorder.setAudioQuality(0); recorder.setDisplayRotation((seektestnum - 2) * 90.0); recorder.start(); if (seektestnum!=2) { Frame frame = new Frame(640, 480, Frame.DEPTH_UBYTE, 3); UByteIndexer frameIdx = frame.createIndexer(); for (int n = 0; n < 10000; n++) { for (int i = 0; i < frameIdx.rows(); i++) { for (int j = 0; j < frameIdx.cols(); j++) { for (int k = 0; k < frameIdx.channels(); k++) { frameIdx.put(i, j, k, n + i + j + k); } } } recorder.record(frame); if (n == 5000 && seektestnum!=1){ Frame audioFrame = new Frame(); ShortBuffer audioBuffer = ShortBuffer.allocate(48000 * 2 * 10000 / 30); audioFrame.sampleRate = 48000; audioFrame.audioChannels = 2; audioFrame.samples = new ShortBuffer[] {audioBuffer}; for (int i = 0; i < audioBuffer.capacity(); i++) { audioBuffer.put(i, (short)i); } recorder.record(audioFrame); } } frame.close(); } else { Frame audioFrame = new Frame(); ShortBuffer audioBuffer = ShortBuffer.allocate(48000 * 2 * 10000 / 30); audioFrame.sampleRate = 48000; audioFrame.audioChannels = 2; audioFrame.samples = new ShortBuffer[] {audioBuffer}; for (int i = 0; i < audioBuffer.capacity(); i++) { audioBuffer.put(i, (short)i); } recorder.record(audioFrame); } recorder.stop(); recorder.release(); FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(tempFile); grabber.setVideoOption("threads", "1"); // more precise without threads grabber.start(); assertEquals((seektestnum - 2) * 90.0, grabber.getDisplayRotation(), 0); int length = (int) ( grabber.getLengthInTime() - 1000000L); System.out.println(); System.out.println("Seek in file containing "+(seektestnum==0?"video and audio":seektestnum==1?"video only":"audio only")); System.out.println("============================================"); System.out.println("Testing file "+tempFile.getName()); System.out.println("Length = "+grabber.getLengthInTime()); System.out.println("Framerate = "+grabber.getFrameRate()); System.out.println(); System.out.println("has video stream = "+(grabber.hasVideo()?"YES":"NO")+", has audio stream = "+(grabber.hasAudio()?"YES":"NO")); long tolerance = 1000000L + (grabber.getFrameRate() > 0.0? (long) (5000000/grabber.getFrameRate()):500000L); Random random = new Random(29); for (int frametypenum = 0; frametypenum < 4; frametypenum++) { long mindelta = Long.MAX_VALUE; long maxdelta = Long.MIN_VALUE; System.out.println(); System.out.println("Seek by " + (frametypenum == 0 ? "any" : frametypenum == 1 ? "video" : frametypenum == 2 ? "audio" : "old method") + (frametypenum == 0 ? " frames" : "")); System.out.println("--------------------"); for (int i = 0; i < 200; i++) { long timestamp = random.nextInt(length); switch (frametypenum) { case 0: grabber.setTimestamp(timestamp, true); break; case 1: grabber.setVideoTimestamp(timestamp); break; case 2: grabber.setAudioTimestamp(timestamp); break; case 3: grabber.setTimestamp(timestamp); break; } Frame frame = grabber.grab(); long timestamp2 = grabber.getTimestamp(); long delta = timestamp2 - timestamp; if (delta > maxdelta) maxdelta = delta; if (delta < mindelta) mindelta = delta; assertTrue(frame.image != null ^ frame.samples != null); System.out.println(timestamp2 + " - " + timestamp + " = " + delta + " type: " + frame.getTypes()); assertTrue(Math.abs(delta) < tolerance); /* if (seektestnum==0) { boolean wasVideo = frame.image != null; boolean wasAudio = frame.samples != null; Frame frame2 = grabber.grab(); while ((wasVideo && frame2.image != null) || (wasAudio && frame2.samples != null)) { frame2 = grabber.grab(); } assertTrue(wasVideo ^ frame2.image != null); assertTrue(wasAudio ^ frame2.samples != null); long timestamp3 = grabber.getTimestamp(); System.out.println(timestamp3 + " - " + timestamp + " = " + (timestamp3 - timestamp)); assertTrue(timestamp3 >= timestamp - tolerance && timestamp3 < timestamp + tolerance); } */ } System.out.println(); System.out.println("------------------------------------"); System.out.println("delta from " + mindelta + " to " + maxdelta); System.out.println(); } if (seektestnum==0) { System.out.println(); System.out.println("======== Check sequential setVideoFrameNumber (issue #1697) ========"); for (int i = 0; i < 10; i++) { grabber.setVideoFrameNumber(i); long timestamp = grabber.grabImage().timestamp; System.out.println("frame number:" + i + " timestamp:" + timestamp); assertTrue(i == Math.round(timestamp * grabber.getFrameRate() / 1000000L)); } } if (seektestnum==2) { long count1 = 0; long duration = grabber.getLengthInTime(); System.out.println(); System.out.println("======== Check seeking in audio ========"); System.out.println("FrameRate = "+grabber.getFrameRate()+" AudioFrameRate = "+grabber.getAudioFrameRate()+", duration = "+duration+" audio frames = "+grabber.getLengthInAudioFrames()); double deltaTimeStamp=0.0; if (grabber.hasAudio() && grabber.getAudioFrameRate() > 0) { deltaTimeStamp = 1000000.0/grabber.getAudioFrameRate(); } System.out.println("AudioFrameDuration = "+deltaTimeStamp); System.out.println(); System.out.println("======== Check setAudioFrameNumber ========"); count1=0; while (count1++<1000) { int audioFrameToSeek = random.nextInt(grabber.getLengthInAudioFrames()-100); grabber.setAudioFrameNumber(audioFrameToSeek); Frame setFrame = grabber.grabSamples(); if (setFrame == null) { System.out.println("null frame after seek to audio frame"); } else { long audioTs = grabber.getTimestamp(); System.out.println("audioFrame # "+audioFrameToSeek+", timeStamp = "+audioTs+", difference = "+Math.round(audioTs*grabber.getAudioFrameRate()/1000000 - audioFrameToSeek)); assertTrue(Math.abs(audioTs*grabber.getAudioFrameRate()/1000000 - audioFrameToSeek)<10); } } } grabber.stop(); System.out.println(); System.out.println("======= seek in " +fileName+" is finished ===========" ); } } } ================================================ FILE: platform/src/test/java/org/bytedeco/javacv/SeekableByteArrayOutputStreamTest.java ================================================ /* * Copyright (C) 2019 Sven Vorlauf * * Licensed either under the Apache License, Version 2.0, or (at your option) * under the terms of the GNU General Public License as published by * the Free Software Foundation (subject to the "Classpath" exception), * either version 2, or any later version (collectively, the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * http://www.gnu.org/licenses/ * http://www.gnu.org/software/classpath/license.html * * or as provided in the LICENSE.txt file that accompanied this code. * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.bytedeco.javacv; import static org.junit.Assert.*; import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.util.Arrays; import java.util.Random; import org.bytedeco.ffmpeg.global.avcodec; import org.bytedeco.ffmpeg.global.avutil; import org.bytedeco.javacpp.Loader; import org.bytedeco.javacpp.indexer.UByteIndexer; import org.hamcrest.core.IsEqual; import org.hamcrest.core.IsNot; import org.junit.Test; public class SeekableByteArrayOutputStreamTest { private static final int WIDTH = 640; private static final int HEIGHT = 360; private static final int FRAME_COUNT = 100; private int writeByte(byte[] originalBytes, int offset, SeekableByteArrayOutputStream byteArrayOutputStream) { byteArrayOutputStream.write(originalBytes[offset]); return 1; } private int writePartialBytes(byte[] originalBytes, int offset, Random random, SeekableByteArrayOutputStream byteArrayOutputStream) throws IOException { int chunkSize = Math.min(random.nextInt(50), originalBytes.length - offset); byteArrayOutputStream.write(originalBytes, offset, chunkSize); return chunkSize; } private int writeBytes(byte[] originalBytes, int offset, Random random, SeekableByteArrayOutputStream byteArrayOutputStream) throws IOException { int chunkSize = Math.min(random.nextInt(50), originalBytes.length - offset); byteArrayOutputStream.write(Arrays.copyOfRange(originalBytes, offset, offset + chunkSize)); return chunkSize; } private void createVideo(FFmpegFrameRecorder recorder) throws Exception { recorder.setVideoCodec(avcodec.AV_CODEC_ID_MPEG4); recorder.setFormat("mp4"); recorder.setFrameRate(30); recorder.setPixelFormat(avutil.AV_PIX_FMT_YUV420P); recorder.start(); for (int n = 0; n < FRAME_COUNT; n++) { Frame frame = new Frame(WIDTH, HEIGHT, Frame.DEPTH_UBYTE, 3); UByteIndexer frameIdx = frame.createIndexer(); for (int i = 0; i < frameIdx.rows(); i++) { for (int j = 0; j < frameIdx.cols(); j++) { for (int k = 0; k < frameIdx.channels(); k++) { frameIdx.put(i, j, k, n + i + j + k); } } } recorder.record(frame); frame.close(); } recorder.close(); } @Test public void serialWriteByteTest() { System.out.println("SeekableByteArrayOutputStreamSerialWriteByte"); Random random = new Random(-1); byte[] originalBytes = new byte[1000]; random.nextBytes(originalBytes); try (SeekableByteArrayOutputStream byteArrayOutputStream = new SeekableByteArrayOutputStream()) { int offset = 0; while (offset < originalBytes.length) { offset += writeByte(originalBytes, offset, byteArrayOutputStream); } assertArrayEquals(originalBytes, byteArrayOutputStream.toByteArray()); } catch (Exception e) { fail("Exception should not have been thrown: " + e); } } @Test public void serialWriteBytesTest() { System.out.println("SeekableByteArrayOutputStreamSerialWriteBytes"); Random random = new Random(-1); byte[] originalBytes = new byte[1000]; random.nextBytes(originalBytes); try (SeekableByteArrayOutputStream byteArrayOutputStream = new SeekableByteArrayOutputStream()) { int offset = 0; while (offset < originalBytes.length) { offset += writeBytes(originalBytes, offset, random, byteArrayOutputStream); } assertArrayEquals(originalBytes, byteArrayOutputStream.toByteArray()); } catch (Exception e) { fail("Exception should not have been thrown: " + e); } } @Test public void serialWritePartialBytesTest() { System.out.println("SeekableByteArrayOutputStreamSerialWritePartialBytes"); Random random = new Random(-1); byte[] originalBytes = new byte[1000]; random.nextBytes(originalBytes); try (SeekableByteArrayOutputStream byteArrayOutputStream = new SeekableByteArrayOutputStream()) { int offset = 0; while (offset < originalBytes.length) { offset += writePartialBytes(originalBytes, offset, random, byteArrayOutputStream); } assertArrayEquals(originalBytes, byteArrayOutputStream.toByteArray()); } catch (Exception e) { fail("Exception should not have been thrown: " + e); } } @Test public void serialWriteTest() { System.out.println("SeekableByteArrayOutputStreamSerialWrite"); Random random = new Random(-1); byte[] originalBytes = new byte[1000]; random.nextBytes(originalBytes); try (SeekableByteArrayOutputStream byteArrayOutputStream = new SeekableByteArrayOutputStream()) { int offset = 0; while (offset < originalBytes.length) { switch (random.nextInt(3)) { case 0: offset += writeByte(originalBytes, offset, byteArrayOutputStream); break; case 1: offset += writeBytes(originalBytes, offset, random, byteArrayOutputStream); break; case 2: offset += writePartialBytes(originalBytes, offset, random, byteArrayOutputStream); break; } } assertArrayEquals(originalBytes, byteArrayOutputStream.toByteArray()); } catch (Exception e) { fail("Exception should not have been thrown: " + e); } } public void seekWriteTest() { System.out.println("SeekableByteArrayOutputStreamSeekWrite"); Random random = new Random(-1); byte[] originalBytes = new byte[1000]; random.nextBytes(originalBytes); try (SeekableByteArrayOutputStream byteArrayOutputStream = new SeekableByteArrayOutputStream()) { int offset = 0; for (int i = 0; i < 10; i++) { // write 100 bytes byteArrayOutputStream.write(originalBytes, offset, 100); int position = random.nextInt(offset + 20); int newBytesPosition = position + 500 % 1000; int length = 10 + random.nextInt(20); // get current bytes byte[] writtenOriginalBytes = Arrays.copyOfRange(byteArrayOutputStream.toByteArray(), position, position + length); // bytes to write at the new position byte[] newBytes = Arrays.copyOfRange(originalBytes, newBytesPosition, newBytesPosition + length); // just assert that the new bytes are different to the written ones assertThat(writtenOriginalBytes, IsNot.not(IsEqual.equalTo(newBytes))); // replace bytes byteArrayOutputStream.seek(position, 0); byteArrayOutputStream.write(newBytes); byte[] writtenNewBytes = Arrays.copyOfRange(byteArrayOutputStream.toByteArray(), position, position + length); assertThat(newBytes, IsEqual.equalTo(writtenNewBytes)); // write back original bytes byteArrayOutputStream.seek(position, 0); byteArrayOutputStream.write(originalBytes, position, length); // get back to the end of the stream byteArrayOutputStream.seek(offset, 0); offset += 100; } while (offset < originalBytes.length) { switch (random.nextInt(3)) { case 0: offset += writeByte(originalBytes, offset, byteArrayOutputStream); break; case 1: offset += writeBytes(originalBytes, offset, random, byteArrayOutputStream); break; case 2: offset += writePartialBytes(originalBytes, offset, random, byteArrayOutputStream); break; } } assertArrayEquals(originalBytes, byteArrayOutputStream.toByteArray()); } catch (Exception e) { fail("Exception should not have been thrown: " + e); } } @Test public void testVideoBytesEqual() { // if this test fails it might be due to indeterministic multithreaded encoding System.out.println("SeekableByteArrayOutputStreamVideo"); File tempFile = new File(Loader.getTempDir(), "test.mp4"); try { createVideo(new FFmpegFrameRecorder(tempFile, WIDTH, HEIGHT, 0)); byte[] fileBytes = Files.readAllBytes(tempFile.toPath()); SeekableByteArrayOutputStream byteArrayOutputStream = new SeekableByteArrayOutputStream(); createVideo(new FFmpegFrameRecorder(byteArrayOutputStream, WIDTH, HEIGHT, 0)); assertArrayEquals(fileBytes, byteArrayOutputStream.toByteArray()); } catch (Exception e) { fail("Exception should not have been thrown: " + e); } finally { tempFile.delete(); } } } ================================================ FILE: pom.xml ================================================ 4.0.0 org.bytedeco javacv 1.5.14-SNAPSHOT JavaCV Java interface to OpenCV, FFmpeg, and more http://bytedeco.org/javacv/ Apache License, Version 2.0 http://www.apache.org/licenses/LICENSE-2.0 repo GNU General Public License (GPL) version 2, or any later version http://www.gnu.org/licenses/ repo GPLv2 with Classpath exception http://www.gnu.org/software/classpath/license.html repo Samuel Audet samuel.audet@gmail.com https://github.com/bytedeco/javacv scm:git:git://github.com/bytedeco/javacv.git scm:git:ssh://git@github.com/bytedeco/javacv.git UTF-8 yyyyMMddhhmm ${project.version} org.bytedeco javacpp ${javacpp.version} org.bytedeco openblas 0.3.31-${javacpp.version} org.bytedeco opencv 4.13.0-${javacpp.version} org.bytedeco ffmpeg 8.0.1-${javacpp.version} org.bytedeco flycapture 2.13.3.31-1.5.9 org.bytedeco libdc1394 2.2.6-1.5.9 org.bytedeco libfreenect 0.5.7-1.5.9 org.bytedeco libfreenect2 0.2.0-1.5.9 org.bytedeco librealsense 1.12.4-1.5.9 org.bytedeco librealsense2 2.53.1-1.5.9 org.bytedeco videoinput 0.200-1.5.9 org.bytedeco artoolkitplus 2.3.1-1.5.9 org.bytedeco leptonica 1.87.0-${javacpp.version} org.bytedeco tesseract 5.5.2-${javacpp.version} com.google.android android 4.1.1.4 * * true org.jogamp.gluegen gluegen-rt-main 2.6.0 true org.jogamp.jogl jogl-all-main 2.6.0 true org.jogamp.jocl jocl-main 2.6.0 true com.badlogicgames.gdx gdx 1.14.0 true central-portal-snapshots Central Portal Snapshots https://central.sonatype.com/repository/maven-snapshots/ false true ${project.artifactId} maven-compiler-plugin 3.15.0 1.8 1.8 true org/bytedeco/javacv/FFmpegLockCallback.java org/bytedeco/javacv/FlyCaptureFrameGrabber.java maven-jar-plugin 3.5.0 org.bytedeco.javacv.JavaCV true javacpp.jar openblas.jar opencv.jar ffmpeg.jar flycapture.jar libdc1394.jar libfreenect.jar libfreenect2.jar librealsense.jar librealsense2.jar videoinput.jar artoolkitplus.jar flandmark.jar leptonica.jar tesseract.jar ${project.name} Bytedeco ${project.version} ${project.name} Bytedeco ${project.version} true org.moditect moditect-maven-plugin 1.3.0 9 true ${project.build.directory} add-module-infos package add-module-info ${project.build.directory}/${project.artifactId}.jar ${project.basedir}/src/main/java9/module-info.java maven-install-plugin 3.1.4 true maven-source-plugin 3.4.0 attach-sources leave-disabled-to-not-generate-sources-twice-on-release attach-source jar-no-fork maven-javadoc-plugin 3.12.0 attach-javadocs jar http://bytedeco.org/javacpp/apidocs http://bytedeco.org/javacpp-presets/openblas/apidocs http://bytedeco.org/javacpp-presets/opencv/apidocs http://bytedeco.org/javacpp-presets/ffmpeg/apidocs http://bytedeco.org/javacpp-presets/flycapture/apidocs http://bytedeco.org/javacpp-presets/libdc1394/apidocs http://bytedeco.org/javacpp-presets/libfreenect/apidocs http://bytedeco.org/javacpp-presets/libfreenect2/apidocs http://bytedeco.org/javacpp-presets/librealsense/apidocs http://bytedeco.org/javacpp-presets/librealsense2/apidocs http://bytedeco.org/javacpp-presets/videoinput/apidocs http://bytedeco.org/javacpp-presets/artoolkitplus/apidocs http://bytedeco.org/javacpp-presets/flandmark/apidocs http://bytedeco.org/javacpp-presets/leptonica/apidocs http://bytedeco.org/javacpp-presets/tesseract/apidocs https://developer.android.com/reference https://jogamp.org/deployment/v2.3.2/javadoc/gluegen/javadoc https://jogamp.org/deployment/v2.3.2/javadoc/jocl/javadoc https://jogamp.org/deployment/v2.3.2/javadoc/jogl/javadoc http://junit.org/junit4/javadoc/4.13.2 org/bytedeco/javacv/FlyCaptureFrameGrabber.java org/bytedeco/javacv/FFmpegLockCallback.java OpenJFX-8 (,11) net.java.openjfx.backport openjfx-78-backport 1.8.0-ea-b96.1 provided OpenJFX-11 11 org.openjfx javafx-graphics 11 OpenJFX-17 17 org.openjfx javafx-graphics 17 OpenJFX-21 21 org.openjfx javafx-graphics 21 OpenJFX-25 25 org.openjfx javafx-graphics 25 doclint-java8-disable [1.8,) maven-javadoc-plugin none false 8 sign-artifacts performRelease true central-portal-staging Central Portal Staging https://central.sonatype.com/api/v1/publisher/deployments/download/ true false maven-gpg-plugin 3.2.8 sign-artifacts verify sign ${env.GPG_PASSPHRASE} false central-publishing !altDeploymentRepository org.sonatype.central central-publishing-maven-plugin 0.8.0 true central false required ================================================ FILE: samples/AudioSplitMergeHelper.java ================================================ import org.bytedeco.javacv.*; import java.nio.Buffer; import java.nio.ShortBuffer; /** * This code is a sample which split a 2-channel stereo audio into 2 single-channel mono audios * or merge 2 single-channel mono audios into a 2-channel stereo. *

* The code has been tested on s16le audio. *

* s16le means short 16bit little end. For other format, you may need change the ShortBuffer to other Buffer subclass *

* For s16lep, s32lep,xxxxxp format, the sample point arrangement format is no longer in ‘LRLRLR'. * Instead, it is arragement in format 'LLLLLL','RRRRRR'. So you have to change the short copy code. *

*

* /////////////////////////////////////////////////////////////////////////// * JavaCV is an excellent open-source streaming processing framework in the Java field *

* But I see many people, especially in China, making profits for themselves by introducing its usage, * which is not in line with the concept of open source projects. * I hope that If this code helped you, you can share your experience and knowledge with others in the world, rather * than for personal gain. Spread the spirit of open source. * /////////////////////////////////////////////////////////////////////////// *

* Acknowledge: Thanks for my hot girlfriend. * * @author steeveen * @date 2023/7/1 14:32 */ public class AudioSplitMergeHelper { /** * split a 2-channel stereo audio into 2 single-channel mono audios *

* If you want to split this 2-channel stereo to 2 single-channel stereo, you should create 2 2-channel stereos * and fill one channel with 0 data. It is similar in principle, so the code won't go into too much here. * * @param input the file path which is to be splited * @param outputLeft the file path which store the left channel audio file * @param outputRight the file path which store the right channel audio file * @throws FrameGrabber.Exception * @throws FrameRecorder.Exception */ public static void split(String input, String outputLeft, String outputRight) throws FrameGrabber.Exception, FrameRecorder.Exception { //grabber from input FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(input); grabber.start(); //two recorders for two channels FFmpegFrameRecorder leftRecorder = new FFmpegFrameRecorder(outputLeft, 1); leftRecorder.setSampleRate(grabber.getSampleRate()); leftRecorder.start(); FFmpegFrameRecorder rightRecorder = new FFmpegFrameRecorder(outputRight, 1); rightRecorder.setSampleRate(grabber.getSampleRate()); rightRecorder.start(); Frame frame = null; while ((frame = grabber.grabSamples()) != null) { // use s16le for example. so select ShortBuffer to receive the sample ShortBuffer sb = (ShortBuffer) frame.samples[0]; short[] shorts = new short[sb.limit()]; sb.get(shorts); //Split the LRLRLR to LLL in left channel and RRR int right channel Frame leftFrame = frame.clone(); ShortBuffer leftSb = ShortBuffer.allocate(sb.capacity() / 2); leftFrame.samples = new Buffer[]{leftSb}; leftFrame.audioChannels = 1; Frame rightFrame = frame.clone(); ShortBuffer rightSb = ShortBuffer.allocate(sb.capacity() / 2); rightFrame.samples = new Buffer[]{rightSb}; rightFrame.audioChannels = 1; for (int i = 0; i < shorts.length; i++) { if (i % 2 == 0) { leftSb.put(shorts[i]); } else { rightSb.put(shorts[i]); } } // reset the buffer to read mode leftSb.rewind(); rightSb.rewind(); leftRecorder.record(leftFrame); rightRecorder.record(rightFrame); } //release source grabber.close(); leftRecorder.close(); rightRecorder.close(); } /** * Merge 2 single-channel mono audios into a 2-channel stereo. * As usual the two input audios should have the same parameter and length; * * @param inputLeft the left channel to be merged in * @param inputRight the right channel to be merged in * @param output the merged stereo audio * @throws FFmpegFrameGrabber.Exception * @throws FFmpegFrameRecorder.Exception */ public static void merge(String inputLeft, String inputRight, String output) throws FrameGrabber.Exception, FrameRecorder.Exception { FFmpegFrameGrabber leftGrabber = new FFmpegFrameGrabber(inputLeft); leftGrabber.start(); FFmpegFrameGrabber rightGrabber = new FFmpegFrameGrabber(inputRight); rightGrabber.start(); FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(output, 2); //you'd better confirm the two input have the same samplerate. otherwise, you should control it manually by yourself recorder.setSampleRate(leftGrabber.getSampleRate()); recorder.start(); Frame leftFrame = null; Frame rightFrame = null; int index = 0; int maxLength = leftGrabber.getLengthInAudioFrames(); while (index < maxLength) { // carry the bit data from two input into result frame by frame leftFrame = leftGrabber.grabSamples(); rightFrame = rightGrabber.grabSamples(); ShortBuffer leftSb = (ShortBuffer) leftFrame.samples[0]; ShortBuffer rightSb = (ShortBuffer) rightFrame.samples[0]; short[] leftShorts = new short[leftSb.limit()]; short[] rightShorts = new short[rightSb.limit()]; leftSb.get(leftShorts); rightSb.get(rightShorts); ShortBuffer mergeSb = ShortBuffer.allocate(leftSb.capacity() + rightSb.capacity()); // create a template from the existing frame Frame mergeFrame = leftFrame.clone(); // replace the frame tempalte by our merged buffer mergeFrame.samples = new Buffer[]{mergeSb}; mergeFrame.audioChannels = 2; for (int i = 0; i < leftShorts.length; i++) { mergeSb.put(leftShorts[i]); mergeSb.put(rightShorts[i]); } //reset buffer to read mode mergeSb.flip(); recorder.record(mergeFrame); index++; } //release source leftGrabber.close(); rightGrabber.close(); recorder.close(); } } ================================================ FILE: samples/BioInspiredRetina.java ================================================ import java.awt.*; import java.awt.image.BufferedImage; import java.io.File; import javax.imageio.ImageIO; import org.bytedeco.javacpp.tools.Slf4jLogger; import org.bytedeco.javacv.CanvasFrame; import org.bytedeco.javacv.Java2DFrameConverter; import org.bytedeco.javacv.OpenCVFrameConverter; import org.bytedeco.opencv.opencv_core.*; import org.bytedeco.opencv.opencv_imgproc.*; import org.bytedeco.opencv.opencv_bioinspired.*; import static org.bytedeco.opencv.global.opencv_core.*; import static org.bytedeco.opencv.global.opencv_imgproc.*; import static org.bytedeco.opencv.global.opencv_bioinspired.*; /** * Bioinspired Retina demonstration * This retina model allows spatio-temporal image processing * As a summary, these are the retina model properties: * It applies a spectral whithening (mid-frequency details enhancement) * high frequency spatio-temporal noise reduction * low frequency luminance to be reduced (luminance range compression) * local logarithmic luminance compression allows details to be enhanced in low light conditions * * Created by mbetzel on 04.09.2016. */ public class BioInspiredRetina { static { System.setProperty("org.bytedeco.javacpp.logger", "slf4jlogger"); System.setProperty("org.slf4j.simpleLogger.defaultLogLevel", "debug"); } private static final Slf4jLogger logger = (Slf4jLogger) org.bytedeco.javacpp.tools.Logger.create(BioInspiredRetina.class); public static void main(String[] args) { try { logger.info(String.valueOf(logger.isDebugEnabled())); logger.info("Start"); new BioInspiredRetina().execute(args); logger.info("Stop"); } catch (Exception e) { e.printStackTrace(); } } private void execute(String[] args) throws Exception { BufferedImage bufferedImage = args.length >= 1 ? ImageIO.read(new File(args[0])) : ImageIO.read(this.getClass().getResourceAsStream("BlackBalls.jpg")); System.out.println("Image type: " + bufferedImage.getType()); Mat matrix = new OpenCVFrameConverter.ToMat().convert(new Java2DFrameConverter().convert(bufferedImage)); normalize(matrix, matrix, 0, 255, NORM_MINMAX, -1, noArray()); showImage(matrix); matrix.convertTo(matrix, CV_32F); Mat gammaTransformedImage = new Mat(matrix.size(), CV_32F); pow(matrix, 1. / 5, gammaTransformedImage); Retina retina = Retina.create(gammaTransformedImage.size()); Mat retinaOutput_parvo = new Mat(); Mat retinaOutput_magno = new Mat(); retina.clearBuffers(); retina.run(gammaTransformedImage); retina.getParvo(retinaOutput_parvo); retina.getMagno(retinaOutput_magno); showImage(retinaOutput_parvo); showImage(retinaOutput_magno); } private void showImage(Mat matrix) { CanvasFrame canvasFrame = new CanvasFrame("Retina demonstration", 1); canvasFrame.setDefaultCloseOperation(javax.swing.JFrame.EXIT_ON_CLOSE); canvasFrame.setCanvasSize(640, 480); Canvas canvas = canvasFrame.getCanvas(); canvasFrame.getContentPane().removeAll(); ScrollPane scrollPane = new ScrollPane(); scrollPane.add(canvas); canvasFrame.add(scrollPane); canvasFrame.showImage(new OpenCVFrameConverter.ToMat().convert(matrix)); } } ================================================ FILE: samples/BlobDemo.java ================================================ import org.bytedeco.javacv.Blobs; import org.bytedeco.javacv.CanvasFrame; import org.bytedeco.javacv.OpenCVFrameConverter; import org.bytedeco.opencv.opencv_core.*; import org.bytedeco.opencv.opencv_imgproc.*; import static org.bytedeco.opencv.global.opencv_core.*; import static org.bytedeco.opencv.global.opencv_imgcodecs.*; import static org.bytedeco.opencv.global.opencv_imgproc.*; /////////////////////////////////////////////////////////////////// //* *// //* As the author of this code, I place all of this code into *// //* the public domain. Users can use it for any legal purpose. *// //* *// //* - Dave Grossman *// //* *// /////////////////////////////////////////////////////////////////// public class BlobDemo { public static void main(String[] args) { System.out.println("STARTING...\n"); demo(); System.out.println("ALL DONE"); } public static void demo() { int MinArea = 6; int ErodeCount =0; int DilateCount = 0; IplImage RawImage = null; // Read an image. for(int k = 0; k < 7; k++) { if(k == 0) { RawImage = cvLoadImage("BlackBalls.jpg"); MinArea = 250; ErodeCount = 0; DilateCount = 1; } else if(k == 1) { RawImage = cvLoadImage("Shapes1.jpg"); MinArea = 6; ErodeCount = 0; DilateCount = 1; } else if(k == 2) { RawImage = cvLoadImage("Shapes2.jpg"); MinArea = 250; ErodeCount = 0; DilateCount = 1; } else if(k == 3) { RawImage = cvLoadImage("Blob1.jpg"); MinArea = 2800; ErodeCount = 1; DilateCount = 1; } else if(k == 4) { RawImage = cvLoadImage("Blob2.jpg"); MinArea = 2800; ErodeCount = 1; DilateCount = 1; } else if(k == 5) { RawImage = cvLoadImage("Blob3.jpg"); MinArea = 2800; ErodeCount = 1; DilateCount = 1; } else if(k == 6) { RawImage = cvLoadImage("Rice.jpg"); MinArea = 30; ErodeCount = 2; DilateCount = 1; } //ShowImage(RawImage, "RawImage", 512); IplImage GrayImage = cvCreateImage(cvGetSize(RawImage), IPL_DEPTH_8U, 1); cvCvtColor(RawImage, GrayImage, CV_BGR2GRAY); //ShowImage(GrayImage, "GrayImage", 512); IplImage BWImage = cvCreateImage(cvGetSize(GrayImage), IPL_DEPTH_8U, 1); cvThreshold(GrayImage, BWImage, 127, 255, CV_THRESH_BINARY); //ShowImage(BWImage, "BWImage"); IplImage WorkingImage = cvCreateImage(cvGetSize(BWImage), IPL_DEPTH_8U, 1); cvErode(BWImage, WorkingImage, null, ErodeCount); cvDilate(WorkingImage, WorkingImage, null, DilateCount); //ShowImage(WorkingImage, "WorkingImage", 512); //cvSaveImage("Working.jpg", WorkingImage); //PrintGrayImage(WorkingImage, "WorkingImage"); //BinaryHistogram(WorkingImage); Blobs Regions = new Blobs(); Regions.BlobAnalysis( WorkingImage, // image -1, -1, // ROI start col, row -1, -1, // ROI cols, rows 1, // border (0 = black; 1 = white) MinArea); // minarea Regions.PrintRegionData(); for(int i = 1; i <= Blobs.MaxLabel; i++) { double [] Region = Blobs.RegionData[i]; int Parent = (int) Region[Blobs.BLOBPARENT]; int Color = (int) Region[Blobs.BLOBCOLOR]; int MinX = (int) Region[Blobs.BLOBMINX]; int MaxX = (int) Region[Blobs.BLOBMAXX]; int MinY = (int) Region[Blobs.BLOBMINY]; int MaxY = (int) Region[Blobs.BLOBMAXY]; Highlight(RawImage, MinX, MinY, MaxX, MaxY, 1); } ShowImage(RawImage, "RawImage", 512); cvReleaseImage(GrayImage); GrayImage = null; cvReleaseImage(BWImage); BWImage = null; cvReleaseImage(WorkingImage); WorkingImage = null; } cvReleaseImage(RawImage); RawImage = null; } // Versions with 2, 3, and 4 parms respectively public static void ShowImage(IplImage image, String caption) { CvMat mat = image.asCvMat(); int width = mat.cols(); if(width < 1) width = 1; int height = mat.rows(); if(height < 1) height = 1; double aspect = 1.0 * width / height; if(height < 128) { height = 128; width = (int) ( height * aspect ); } if(width < 128) width = 128; height = (int) ( width / aspect ); ShowImage(image, caption, width, height); } public static void ShowImage(IplImage image, String caption, int size) { if(size < 128) size = 128; CvMat mat = image.asCvMat(); int width = mat.cols(); if(width < 1) width = 1; int height = mat.rows(); if(height < 1) height = 1; double aspect = 1.0 * width / height; if(height != size) { height = size; width = (int) ( height * aspect ); } if(width != size) width = size; height = (int) ( width / aspect ); ShowImage(image, caption, width, height); } public static void ShowImage(IplImage image, String caption, int width, int height) { CanvasFrame canvas = new CanvasFrame(caption, 1); // gamma=1 canvas.setDefaultCloseOperation(javax.swing.JFrame.EXIT_ON_CLOSE); canvas.setCanvasSize(width, height); OpenCVFrameConverter converter = new OpenCVFrameConverter.ToIplImage(); canvas.showImage(converter.convert(image)); } public static void Highlight(IplImage image, int [] inVec) { Highlight(image, inVec[0], inVec[1], inVec[2], inVec[3], 1); } public static void Highlight(IplImage image, int [] inVec, int Thick) { Highlight(image, inVec[0], inVec[1], inVec[2], inVec[3], Thick); } public static void Highlight(IplImage image, int xMin, int yMin, int xMax, int yMax) { Highlight(image, xMin, yMin, xMax, yMax, 1); } public static void Highlight(IplImage image, int xMin, int yMin, int xMax, int yMax, int Thick) { CvPoint pt1 = cvPoint(xMin,yMin); CvPoint pt2 = cvPoint(xMax,yMax); CvScalar color = cvScalar(255,0,0,0); // blue [green] [red] cvRectangle(image, pt1, pt2, color, Thick, 4, 0); } public static void PrintGrayImage(IplImage image, String caption) { int size = 512; // impractical to print anything larger CvMat mat = image.asCvMat(); int cols = mat.cols(); if(cols < 1) cols = 1; int rows = mat.rows(); if(rows < 1) rows = 1; double aspect = 1.0 * cols / rows; if(rows > size) { rows = size; cols = (int) ( rows * aspect ); } if(cols > size) cols = size; rows = (int) ( cols / aspect ); PrintGrayImage(image, caption, 0, cols, 0, rows); } public static void PrintGrayImage(IplImage image, String caption, int MinX, int MaxX, int MinY, int MaxY) { int size = 512; // impractical to print anything larger CvMat mat = image.asCvMat(); int cols = mat.cols(); if(cols < 1) cols = 1; int rows = mat.rows(); if(rows < 1) rows = 1; if(MinX < 0) MinX = 0; if(MinX > cols) MinX = cols; if(MaxX < 0) MaxX = 0; if(MaxX > cols) MaxX = cols; if(MinY < 0) MinY = 0; if(MinY > rows) MinY = rows; if(MaxY < 0) MaxY = 0; if(MaxY > rows) MaxY = rows; System.out.println("\n" + caption); System.out.print(" +"); for(int icol = MinX; icol < MaxX; icol++) System.out.print("-"); System.out.println("+"); for(int irow = MinY; irow < MaxY; irow++) { if(irow<10) System.out.print(" "); if(irow<100) System.out.print(" "); System.out.print(irow); System.out.print("|"); for(int icol = MinX; icol < MaxX; icol++) { int val = (int) mat.get(irow,icol); String C = " "; if(val == 0) C = "*"; System.out.print(C); } System.out.println("|"); } System.out.print(" +"); for(int icol = MinX; icol < MaxX; icol++) System.out.print("-"); System.out.println("+"); } public static void PrintImageProperties(IplImage image) { CvMat mat = image.asCvMat(); int cols = mat.cols(); int rows = mat.rows(); int depth = mat.depth(); System.out.println("ImageProperties for " + image + " : cols=" + cols + " rows=" + rows + " depth=" + depth); } public static float BinaryHistogram(IplImage image) { CvScalar Sum = cvSum(image); float WhitePixels = (float) ( Sum.getVal(0) / 255 ); CvMat mat = image.asCvMat(); float TotalPixels = mat.cols() * mat.rows(); //float BlackPixels = TotalPixels - WhitePixels; return WhitePixels / TotalPixels; } // Counterclockwise small angle rotation by skewing - Does not stretch border pixels public static IplImage SkewGrayImage(IplImage Src, double angle) // angle is in radians { //double radians = - Math.PI * angle / 360.0; // Half because skew is horizontal and vertical double sin = - Math.sin(angle); double AbsSin = Math.abs(sin); int nChannels = Src.nChannels(); if(nChannels != 1) { System.out.println("ERROR: SkewGrayImage: Require 1 channel: nChannels=" + nChannels); System.exit(1); } CvMat SrcMat = Src.asCvMat(); int SrcCols = SrcMat.cols(); int SrcRows = SrcMat.rows(); double WidthSkew = AbsSin * SrcRows; double HeightSkew = AbsSin * SrcCols; int DstCols = (int) ( SrcCols + WidthSkew ); int DstRows = (int) ( SrcRows + HeightSkew ); CvMat DstMat = cvCreateMat(DstRows, DstCols, CV_8UC1); // Type matches IPL_DEPTH_8U cvSetZero(DstMat); cvNot(DstMat, DstMat); for(int irow = 0; irow < DstRows; irow++) { int dcol = (int) ( WidthSkew * irow / SrcRows ); for(int icol = 0; icol < DstCols; icol++) { int drow = (int) ( HeightSkew - HeightSkew * icol / SrcCols ); int jrow = irow - drow; int jcol = icol - dcol; if(jrow < 0 || jcol < 0 || jrow >= SrcRows || jcol >= SrcCols) DstMat.put(irow, icol, 255); else DstMat.put(irow, icol, (int) SrcMat.get(jrow,jcol)); } } IplImage Dst = cvCreateImage(cvSize(DstCols, DstRows), IPL_DEPTH_8U, 1); Dst = DstMat.asIplImage(); return Dst; } public static IplImage TransposeImage(IplImage SrcImage) { CvMat mat = SrcImage.asCvMat(); int cols = mat.cols(); int rows = mat.rows(); IplImage DstImage = cvCreateImage(cvSize(rows, cols), IPL_DEPTH_8U, 1); cvTranspose(SrcImage, DstImage); cvFlip(DstImage,DstImage,1); return DstImage; } } ================================================ FILE: samples/CaffeGooglenet.java ================================================ /* * JavaCV version of OpenCV caffe_googlenet.cpp * https://github.com/ludv1x/opencv_contrib/blob/master/modules/dnn/samples/caffe_googlenet.cpp * * Paolo Bolettieri */ import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.IOException; import java.util.ArrayList; import java.util.List; import org.bytedeco.opencv.opencv_core.*; import org.bytedeco.opencv.opencv_dnn.*; import org.bytedeco.opencv.opencv_imgproc.*; import static org.bytedeco.opencv.global.opencv_core.*; import static org.bytedeco.opencv.global.opencv_dnn.*; import static org.bytedeco.opencv.global.opencv_imgcodecs.*; import static org.bytedeco.opencv.global.opencv_imgproc.*; public class CaffeGooglenet { /* Find best class for the blob (i. e. class with maximal probability) */ public static void getMaxClass(Mat probBlob, Point classId, double[] classProb) { Mat probMat = probBlob.reshape(1, 1); //reshape the blob to 1x1000 matrix minMaxLoc(probMat, null, classProb, null, classId, null); } public static List readClassNames() { String filename = "synset_words.txt"; List classNames = null; try (BufferedReader br = new BufferedReader(new FileReader(new File(filename)))) { classNames = new ArrayList(); String name = null; while ((name = br.readLine()) != null) { classNames.add(name.substring(name.indexOf(' ')+1)); } } catch (IOException ex) { System.err.println("File with classes labels not found " + filename); System.exit(-1); } return classNames; } public static void main(String[] args) throws Exception { String modelTxt = "bvlc_googlenet.prototxt"; String modelBin = "bvlc_googlenet.caffemodel"; String imageFile = (args.length > 0) ? args[0] : "space_shuttle.jpg"; //! [Initialize network] Net net = null; try { //Try to import Caffe GoogleNet model net = readNetFromCaffe(modelTxt, modelBin); } catch (Exception e) { //Importer can throw errors, we will catch them e.printStackTrace(); } if (net == null || net.empty()) { System.err.println("Can't load network by using the following files: "); System.err.println("prototxt: " + modelTxt); System.err.println("caffemodel: " + modelBin); System.err.println("bvlc_googlenet.caffemodel can be downloaded here:"); System.err.println("http://dl.caffe.berkeleyvision.org/bvlc_googlenet.caffemodel"); System.exit(-1); } //! [Initialize network] //! [Prepare blob] Mat img = imread(imageFile); if (img.empty()) { System.err.println("Can't read image from the file: " + imageFile); System.exit(-1); } resize(img, img, new Size(224, 224)); //GoogLeNet accepts only 224x224 RGB-images Mat inputBlob = blobFromImage(img); //Convert Mat to 4-dimensional dnn::Blob from image //! [Prepare blob] //! [Set input blob] net.setInput(inputBlob, "data", 1.0, null); //set the network input //! [Set input blob] //! [Make forward pass] Mat prob = net.forward("prob"); //compute output //! [Make forward pass] //! [Gather output] Point classId = new Point(); double[] classProb = new double[1]; getMaxClass(prob, classId, classProb);//find the best class //! [Gather output] //! [Print results] List classNames = readClassNames(); System.out.println("Best class: #" + classId.x() + " '" + classNames.get(classId.x()) + "'"); System.out.println("Best class: #" + classId.x()); System.out.println("Probability: " + classProb[0] * 100 + "%"); //! [Print results] } //main } ================================================ FILE: samples/ColoredObjectTrack.java ================================================ /* * Just an example using the opencv to make a colored object tracking, * i adpted this code to bytedeco/javacv, i think this will help some people. * * Waldemar */ import java.awt.Color; import java.awt.Graphics; import java.awt.image.BufferedImage; import javax.swing.JPanel; import org.bytedeco.javacv.CanvasFrame; import org.bytedeco.javacv.FrameGrabber; import org.bytedeco.javacv.Java2DFrameConverter; import org.bytedeco.javacv.OpenCVFrameConverter; import org.bytedeco.opencv.opencv_core.*; import org.bytedeco.opencv.opencv_imgproc.*; import static org.bytedeco.opencv.global.opencv_core.*; import static org.bytedeco.opencv.global.opencv_imgcodecs.*; import static org.bytedeco.opencv.global.opencv_imgproc.*; public class ColoredObjectTrack implements Runnable { public static void main(String[] args) { ColoredObjectTrack cot = new ColoredObjectTrack(); Thread th = new Thread(cot); th.start(); } final int INTERVAL = 10;// 1sec final int CAMERA_NUM = 0; // Default camera for this time /** * Correct the color range- it depends upon the object, camera quality, * environment. */ static CvScalar rgba_min = cvScalar(0, 0, 130, 0);// RED wide dabur birko static CvScalar rgba_max = cvScalar(80, 80, 255, 0); IplImage image; CanvasFrame canvas = new CanvasFrame("Web Cam Live"); CanvasFrame path = new CanvasFrame("Detection"); int ii = 0; JPanel jp = new JPanel(); public ColoredObjectTrack() { canvas.setDefaultCloseOperation(javax.swing.JFrame.EXIT_ON_CLOSE); path.setDefaultCloseOperation(javax.swing.JFrame.EXIT_ON_CLOSE); path.setContentPane(jp); } @Override public void run() { try { FrameGrabber grabber = FrameGrabber.createDefault(CAMERA_NUM); OpenCVFrameConverter.ToIplImage converter = new OpenCVFrameConverter.ToIplImage(); grabber.start(); IplImage img; int posX = 0; int posY = 0; while (true) { img = converter.convert(grabber.grab()); if (img != null) { // show image on window cvFlip(img, img, 1);// l-r = 90_degrees_steps_anti_clockwise canvas.showImage(converter.convert(img)); IplImage detectThrs = getThresholdImage(img); CvMoments moments = new CvMoments(); cvMoments(detectThrs, moments, 1); double mom10 = cvGetSpatialMoment(moments, 1, 0); double mom01 = cvGetSpatialMoment(moments, 0, 1); double area = cvGetCentralMoment(moments, 0, 0); posX = (int) (mom10 / area); posY = (int) (mom01 / area); // only if its a valid position if (posX > 0 && posY > 0) { paint(img, posX, posY); } } // Thread.sleep(INTERVAL); } } catch (Exception e) { } } private void paint(IplImage img, int posX, int posY) { Graphics g = jp.getGraphics(); path.setSize(img.width(), img.height()); // g.clearRect(0, 0, img.width(), img.height()); g.setColor(Color.RED); // g.fillOval(posX, posY, 20, 20); g.drawOval(posX, posY, 20, 20); System.out.println(posX + " , " + posY); } private IplImage getThresholdImage(IplImage orgImg) { IplImage imgThreshold = cvCreateImage(cvGetSize(orgImg), 8, 1); // cvInRangeS(orgImg, rgba_min, rgba_max, imgThreshold);// red cvSmooth(imgThreshold, imgThreshold, CV_MEDIAN, 15,0,0,0); cvSaveImage(++ii + "dsmthreshold.jpg", imgThreshold); return imgThreshold; } public IplImage Equalize(BufferedImage bufferedimg) { Java2DFrameConverter converter1 = new Java2DFrameConverter(); OpenCVFrameConverter.ToIplImage converter2 = new OpenCVFrameConverter.ToIplImage(); IplImage iploriginal = converter2.convert(converter1.convert(bufferedimg)); IplImage srcimg = IplImage.create(iploriginal.width(), iploriginal.height(), IPL_DEPTH_8U, 1); IplImage destimg = IplImage.create(iploriginal.width(), iploriginal.height(), IPL_DEPTH_8U, 1); cvCvtColor(iploriginal, srcimg, CV_BGR2GRAY); cvEqualizeHist(srcimg, destimg); return destimg; } } ================================================ FILE: samples/DeepLearningFaceDetection.java ================================================ import org.bytedeco.javacpp.indexer.FloatIndexer; import org.bytedeco.javacv.CanvasFrame; import org.bytedeco.javacv.OpenCVFrameConverter; import org.bytedeco.opencv.opencv_core.*; import org.bytedeco.opencv.opencv_dnn.*; import org.bytedeco.opencv.opencv_imgproc.*; import org.bytedeco.opencv.opencv_videoio.*; import static org.bytedeco.opencv.global.opencv_core.*; import static org.bytedeco.opencv.global.opencv_dnn.*; import static org.bytedeco.opencv.global.opencv_imgproc.*; import static org.bytedeco.opencv.global.opencv_videoio.*; /** * Created on Jul 28, 2018 * * @author Taha Emara * Email : taha@emaraic.com * * This example does face detection using deep learning model which provides a * great accuracy compared to OpenCV face detection using Haar cascades. * * This example is based on this code * https://github.com/opencv/opencv/blob/master/modules/dnn/misc/face_detector_accuracy.py * * To run this example you need two files: deploy.prototxt can be downloaded * from * https://github.com/opencv/opencv/blob/master/samples/dnn/face_detector/deploy.prototxt * * and res10_300x300_ssd_iter_140000.caffemodel * https://github.com/opencv/opencv_3rdparty/blob/dnn_samples_face_detector_20170830/res10_300x300_ssd_iter_140000.caffemodel * */ public class DeepLearningFaceDetection { private static final String PROTO_FILE = "deploy.prototxt"; private static final String CAFFE_MODEL_FILE = "res10_300x300_ssd_iter_140000.caffemodel"; private static final OpenCVFrameConverter.ToIplImage converter = new OpenCVFrameConverter.ToIplImage(); private static Net net = null; static { net = readNetFromCaffe(PROTO_FILE, CAFFE_MODEL_FILE); } private static void detectAndDraw(Mat image) {//detect faces and draw a blue rectangle arroung each face resize(image, image, new Size(300, 300));//resize the image to match the input size of the model //create a 4-dimensional blob from image with NCHW (Number of images in the batch -for training only-, Channel, Height, Width) dimensions order, //for more detailes read the official docs at https://docs.opencv.org/trunk/d6/d0f/group__dnn.html#gabd0e76da3c6ad15c08b01ef21ad55dd8 Mat blob = blobFromImage(image, 1.0, new Size(300, 300), new Scalar(104.0, 177.0, 123.0, 0), false, false, CV_32F); net.setInput(blob);//set the input to network model Mat output = net.forward();//feed forward the input to the netwrok to get the output matrix Mat ne = new Mat(new Size(output.size(3), output.size(2)), CV_32F, output.ptr(0, 0));//extract a 2d matrix for 4d output matrix with form of (number of detections x 7) FloatIndexer srcIndexer = ne.createIndexer(); // create indexer to access elements of the matric for (int i = 0; i < output.size(3); i++) {//iterate to extract elements float confidence = srcIndexer.get(i, 2); float f1 = srcIndexer.get(i, 3); float f2 = srcIndexer.get(i, 4); float f3 = srcIndexer.get(i, 5); float f4 = srcIndexer.get(i, 6); if (confidence > .6) { float tx = f1 * 300;//top left point's x float ty = f2 * 300;//top left point's y float bx = f3 * 300;//bottom right point's x float by = f4 * 300;//bottom right point's y rectangle(image, new Rect(new Point((int) tx, (int) ty), new Point((int) bx, (int) by)), new Scalar(255, 0, 0, 0));//print blue rectangle } } } public static void main(String[] args) { VideoCapture capture = new VideoCapture(); capture.set(CAP_PROP_FRAME_WIDTH, 1280); capture.set(CAP_PROP_FRAME_HEIGHT, 720); if (!capture.open(0)) { System.out.println("Can not open the cam !!!"); } Mat colorimg = new Mat(); CanvasFrame mainframe = new CanvasFrame("Face Detection", CanvasFrame.getDefaultGamma() / 2.2); mainframe.setDefaultCloseOperation(javax.swing.JFrame.EXIT_ON_CLOSE); mainframe.setCanvasSize(600, 600); mainframe.setLocationRelativeTo(null); mainframe.setVisible(true); while (true) { while (capture.read(colorimg) && mainframe.isVisible()) { detectAndDraw(colorimg); mainframe.showImage(converter.convert(colorimg)); try { Thread.sleep(50); } catch (InterruptedException ex) { System.out.println(ex.getMessage()); } } } } } ================================================ FILE: samples/DeinterlacedVideoPlayer.java ================================================ import org.bytedeco.javacpp.Loader; import org.bytedeco.javacv.FFmpegFrameFilter; import org.bytedeco.javacv.Frame; import org.bytedeco.javacv.FrameFilter; import org.bytedeco.javacv.FrameGrabber; import org.bytedeco.javacv.FrameGrabber.Exception; import org.bytedeco.javacv.OpenCVFrameGrabber; import org.bytedeco.ffmpeg.global.avutil; public class DeinterlacedVideoPlayer { private static final int DEVICE_ID = 0; private static final int WIDTH = 640; private static final int HEIGHT = 480; private static final int FRAMERATE = 25; private static final int PIXEL_FORMAT = avutil.AV_PIX_FMT_BGR24;; private String ffmpegString = "yadif=mode=0:parity=-1:deint=0,format=bgr24"; private FrameGrabber grabber; public DeinterlacedVideoPlayer() {} public void start() { FrameFilter filter = null; try { startFrameGrabber(); Frame frame = null; while ((frame = grabber.grab()) != null) { if (filter == null) { filter = new FFmpegFrameFilter(ffmpegString, frame.imageWidth, frame.imageHeight); filter.setPixelFormat(PIXEL_FORMAT); filter.start(); } filter.push(frame); frame = filter.pull(); // do something with the filtered frame } } catch (Exception | org.bytedeco.javacv.FrameFilter.Exception e) { throw new RuntimeException(e.getMessage(), e); } finally { releaseGrabberAndFilter(this.grabber, filter); } } private void startFrameGrabber() throws Exception { grabber = new OpenCVFrameGrabber(DEVICE_ID); grabber.setImageWidth(WIDTH); grabber.setImageHeight(HEIGHT); grabber.setFrameRate(FRAMERATE); grabber.setPixelFormat(PIXEL_FORMAT); grabber.start(); } private void releaseGrabberAndFilter(FrameGrabber grabber, FrameFilter filter) { try { if (grabber != null) { grabber.release(); } } catch (Exception e) { throw new RuntimeException("Cannot release frame grabber!", e); } finally { releaseFilter(filter); } } private void releaseFilter(FrameFilter filter) { if (filter == null) { return; } try { filter.close(); } catch (org.bytedeco.javacv.FrameFilter.Exception e) { throw new RuntimeException("Cannot close frame filter!", e); } } } ================================================ FILE: samples/Demo.java ================================================ /* * Copyright (C) 2009-2018 Samuel Audet * * Licensed either under the Apache License, Version 2.0, or (at your option) * under the terms of the GNU General Public License as published by * the Free Software Foundation (subject to the "Classpath" exception), * either version 2, or any later version (collectively, the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * http://www.gnu.org/licenses/ * http://www.gnu.org/software/classpath/license.html * * or as provided in the LICENSE.txt file that accompanied this code. * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import java.io.File; import java.net.URL; import org.bytedeco.javacv.*; import org.bytedeco.javacpp.*; import org.bytedeco.javacpp.indexer.*; import org.bytedeco.opencv.opencv_core.*; import org.bytedeco.opencv.opencv_imgproc.*; import org.bytedeco.opencv.opencv_calib3d.*; import org.bytedeco.opencv.opencv_objdetect.*; import static org.bytedeco.opencv.global.opencv_core.*; import static org.bytedeco.opencv.global.opencv_imgproc.*; import static org.bytedeco.opencv.global.opencv_calib3d.*; import static org.bytedeco.opencv.global.opencv_objdetect.*; public class Demo { public static void main(String[] args) throws Exception { String classifierName = null; if (args.length > 0) { classifierName = args[0]; } else { URL url = new URL("https://raw.github.com/opencv/opencv/master/data/haarcascades/haarcascade_frontalface_alt.xml"); File file = Loader.cacheResource(url); classifierName = file.getAbsolutePath(); } // We can "cast" Pointer objects by instantiating a new object of the desired class. CascadeClassifier classifier = new CascadeClassifier(classifierName); if (classifier == null) { System.err.println("Error loading classifier file \"" + classifierName + "\"."); System.exit(1); } // The available FrameGrabber classes include OpenCVFrameGrabber (opencv_videoio), // DC1394FrameGrabber, FlyCapture2FrameGrabber, OpenKinectFrameGrabber, OpenKinect2FrameGrabber, // RealSenseFrameGrabber, RealSense2FrameGrabber, PS3EyeFrameGrabber, VideoInputFrameGrabber, and FFmpegFrameGrabber. FrameGrabber grabber = FrameGrabber.createDefault(0); grabber.start(); // CanvasFrame, FrameGrabber, and FrameRecorder use Frame objects to communicate image data. // We need a FrameConverter to interface with other APIs (Android, Java 2D, JavaFX, Tesseract, OpenCV, etc). OpenCVFrameConverter.ToMat converter = new OpenCVFrameConverter.ToMat(); // FAQ about IplImage and Mat objects from OpenCV: // - For custom raw processing of data, createBuffer() returns an NIO direct // buffer wrapped around the memory pointed by imageData, and under Android we can // also use that Buffer with Bitmap.copyPixelsFromBuffer() and copyPixelsToBuffer(). // - To get a BufferedImage from an IplImage, or vice versa, we can chain calls to // Java2DFrameConverter and OpenCVFrameConverter, one after the other. // - Java2DFrameConverter also has static copy() methods that we can use to transfer // data more directly between BufferedImage and IplImage or Mat via Frame objects. Mat grabbedImage = converter.convert(grabber.grab()); int height = grabbedImage.rows(); int width = grabbedImage.cols(); // Objects allocated with `new`, clone(), or a create*() factory method are automatically released // by the garbage collector, but may still be explicitly released by calling deallocate(). // You shall NOT call cvReleaseImage(), cvReleaseMemStorage(), etc. on objects allocated this way. Mat grayImage = new Mat(height, width, CV_8UC1); Mat rotatedImage = grabbedImage.clone(); // The OpenCVFrameRecorder class simply uses the VideoWriter of opencv_videoio, // but FFmpegFrameRecorder also exists as a more versatile alternative. FrameRecorder recorder = FrameRecorder.createDefault("output.avi", width, height); recorder.start(); // CanvasFrame is a JFrame containing a Canvas component, which is hardware accelerated. // It can also switch into full-screen mode when called with a screenNumber. // We should also specify the relative monitor/camera response for proper gamma correction. CanvasFrame frame = new CanvasFrame("Some Title", CanvasFrame.getDefaultGamma()/grabber.getGamma()); // Let's create some random 3D rotation... Mat randomR = new Mat(3, 3, CV_64FC1), randomAxis = new Mat(3, 1, CV_64FC1); // We can easily and efficiently access the elements of matrices and images // through an Indexer object with the set of get() and put() methods. DoubleIndexer Ridx = randomR.createIndexer(), axisIdx = randomAxis.createIndexer(); axisIdx.put(0, (Math.random() - 0.5) / 4, (Math.random() - 0.5) / 4, (Math.random() - 0.5) / 4); Rodrigues(randomAxis, randomR); double f = (width + height) / 2.0; Ridx.put(0, 2, Ridx.get(0, 2) * f); Ridx.put(1, 2, Ridx.get(1, 2) * f); Ridx.put(2, 0, Ridx.get(2, 0) / f); Ridx.put(2, 1, Ridx.get(2, 1) / f); System.out.println(Ridx); // We can allocate native arrays using constructors taking an integer as argument. Point hatPoints = new Point(3); while (frame.isVisible() && (grabbedImage = converter.convert(grabber.grab())) != null) { // Let's try to detect some faces! but we need a grayscale image... cvtColor(grabbedImage, grayImage, CV_BGR2GRAY); RectVector faces = new RectVector(); classifier.detectMultiScale(grayImage, faces); long total = faces.size(); for (long i = 0; i < total; i++) { Rect r = faces.get(i); int x = r.x(), y = r.y(), w = r.width(), h = r.height(); rectangle(grabbedImage, new Point(x, y), new Point(x + w, y + h), Scalar.RED, 1, CV_AA, 0); // To access or pass as argument the elements of a native array, call position() before. hatPoints.position(0).x(x - w / 10 ).y(y - h / 10); hatPoints.position(1).x(x + w * 11 / 10).y(y - h / 10); hatPoints.position(2).x(x + w / 2 ).y(y - h / 2 ); fillConvexPoly(grabbedImage, hatPoints.position(0), 3, Scalar.GREEN, CV_AA, 0); } // Let's find some contours! but first some thresholding... threshold(grayImage, grayImage, 64, 255, CV_THRESH_BINARY); // To check if an output argument is null we may call either isNull() or equals(null). MatVector contours = new MatVector(); findContours(grayImage, contours, CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE); long n = contours.size(); for (long i = 0; i < n; i++) { Mat contour = contours.get(i); Mat points = new Mat(); approxPolyDP(contour, points, arcLength(contour, true) * 0.02, true); drawContours(grabbedImage, new MatVector(points), -1, Scalar.BLUE); } warpPerspective(grabbedImage, rotatedImage, randomR, rotatedImage.size()); Frame rotatedFrame = converter.convert(rotatedImage); frame.showImage(rotatedFrame); recorder.record(rotatedFrame); } frame.dispose(); recorder.stop(); grabber.stop(); } } ================================================ FILE: samples/FFmpegStreamingTimeout.java ================================================ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import org.bytedeco.javacpp.Pointer; import org.bytedeco.javacv.FFmpegFrameGrabber; import org.bytedeco.javacv.Frame; import org.bytedeco.javacv.FrameGrabber; import org.bytedeco.ffmpeg.avformat.*; import static org.bytedeco.ffmpeg.global.avformat.*; /** * * @author Dmitriy Gerashenko */ public class FFmpegStreamingTimeout { /** * There is no universal option for streaming timeout. Each of protocols has * its own list of options. */ private static enum TimeoutOption { /** * Depends on protocol (FTP, HTTP, RTMP, RTSP, SMB, SSH, TCP, UDP, or UNIX). * http://ffmpeg.org/ffmpeg-all.html * * Specific for RTSP: * Set socket TCP I/O timeout in microseconds. * http://ffmpeg.org/ffmpeg-all.html#rtsp */ TIMEOUT, /** * Protocols * * Maximum time to wait for (network) read/write operations to complete, * in microseconds. * * http://ffmpeg.org/ffmpeg-all.html#Protocols */ RW_TIMEOUT; public String getKey() { return toString().toLowerCase(); } } private static final String SOURCE_RTSP = "rtsp://184.72.239.149/vod/mp4:BigBuckBunny_115k.mov"; private static final int TIMEOUT = 10; // In seconds. public static void main(String[] args) { rtspStreamingTest(); // testWithCallback(); // This is not working properly. It's just for test. } private static void rtspStreamingTest() { try { FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(SOURCE_RTSP); /** * "rw_timeout" - IS IGNORED when a network cable have been * unplugged before a connection but the option takes effect after a * connection was established. * * "timeout" - works fine. */ grabber.setOption( TimeoutOption.TIMEOUT.getKey(), String.valueOf(TIMEOUT * 1000000) ); // In microseconds. grabber.start(); Frame frame = null; /** * When network is disabled (before grabber was started) grabber * throws exception: "org.bytedeco.javacv.FrameGrabber$Exception: * avformat_open_input() error -138: Could not open input...". * * When connections is lost (after a few grabbed frames) * grabber.grab() returns null without exception. */ while ((frame = grabber.grab()) != null) { System.out.println("frame grabbed at " + grabber.getTimestamp()); } System.out.println("loop end with frame: " + frame); } catch (FrameGrabber.Exception ex) { System.out.println("exception: " + ex); } System.out.println("end"); } private static void testWithCallback() { try { FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(SOURCE_RTSP); /** * grabber.getFormatContext() is null before grabber.start(). * * But if network is disabled grabber.start() will never return. * * That's why interrupt_callback not suitable for "network disabled * case". */ grabber.start(); final AtomicBoolean interruptFlag = new AtomicBoolean(false); AVIOInterruptCB.Callback_Pointer cp = new AVIOInterruptCB.Callback_Pointer() { @Override public int call(Pointer pointer) { // 0 - continue, 1 - exit int interruptFlagInt = interruptFlag.get() ? 1 : 0; System.out.println("callback, interrupt flag == " + interruptFlagInt); return interruptFlagInt; } }; AVFormatContext oc = grabber.getFormatContext(); avformat_alloc_context(); AVIOInterruptCB cb = new AVIOInterruptCB(); cb.callback(cp); oc.interrupt_callback(cb); new Thread(new Runnable() { public void run() { try { TimeUnit.SECONDS.sleep(TIMEOUT); interruptFlag.set(true); System.out.println("interrupt flag was changed"); } catch (InterruptedException ex) { System.out.println("exception in interruption thread: " + ex); } }}).start(); Frame frame = null; /** * On one of my RTSP cams grabber stops calling callback on * connection lost. I think it's has something to do with message: * "[swscaler @ 0000000029af49e0] deprecated pixel format used, make * sure you did set range correctly". * * So there is at least one case when grabber stops calling * callback. */ while ((frame = grabber.grab()) != null) { System.out.println("frame grabbed at " + grabber.getTimestamp()); } System.out.println("loop end with frame: " + frame); } catch (FrameGrabber.Exception ex) { System.out.println("exception: " + ex); } System.out.println("end"); } } ================================================ FILE: samples/FaceApplet.html ================================================ FaceApplet

FaceApplet

================================================ FILE: samples/FaceApplet.java ================================================ import java.applet.Applet; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import org.bytedeco.javacpp.Loader; import org.bytedeco.javacv.Frame; import org.bytedeco.javacv.FrameGrabber; import org.bytedeco.javacv.Java2DFrameConverter; import org.bytedeco.javacv.OpenCVFrameConverter; import org.bytedeco.javacv.OpenCVFrameGrabber; import org.bytedeco.opencv.opencv_core.*; import org.bytedeco.opencv.opencv_imgproc.*; import org.bytedeco.opencv.opencv_objdetect.*; import static org.bytedeco.opencv.global.opencv_core.*; import static org.bytedeco.opencv.global.opencv_imgproc.*; import static org.bytedeco.opencv.global.opencv_objdetect.*; /** * * @author Samuel Audet */ public class FaceApplet extends Applet implements Runnable { private CvHaarClassifierCascade classifier = null; private CvMemStorage storage = null; private FrameGrabber grabber = null; private IplImage grabbedImage = null, grayImage = null, smallImage = null; private CvSeq faces = null; private boolean stop = false; private Exception exception = null; OpenCVFrameConverter.ToIplImage grabberConverter = new OpenCVFrameConverter.ToIplImage(); Java2DFrameConverter paintConverter = new Java2DFrameConverter(); @Override public void init() { try { // Load the classifier file from Java resources. String classiferName = "haarcascade_frontalface_alt.xml"; File classifierFile = Loader.extractResource(classiferName, null, "classifier", ".xml"); if (classifierFile == null || classifierFile.length() <= 0) { throw new IOException("Could not extract \"" + classiferName + "\" from Java resources."); } // Preload the opencv_objdetect module to work around a known bug. Loader.load(opencv_objdetect.class); classifier = new CvHaarClassifierCascade(cvLoad(classifierFile.getAbsolutePath())); classifierFile.delete(); if (classifier.isNull()) { throw new IOException("Could not load the classifier file."); } storage = CvMemStorage.create(); } catch (Exception e) { if (exception == null) { exception = e; repaint(); } } } @Override public void start() { try { new Thread(this).start(); } catch (Exception e) { if (exception == null) { exception = e; repaint(); } } } public void run() { try { try { grabber = FrameGrabber.createDefault(0); grabber.setImageWidth(getWidth()); grabber.setImageHeight(getHeight()); grabber.start(); grabbedImage = grabberConverter.convert(grabber.grab()); } catch (Exception e) { if (grabber != null) grabber.release(); grabber = new OpenCVFrameGrabber(0); grabber.setImageWidth(getWidth()); grabber.setImageHeight(getHeight()); grabber.start(); grabbedImage = grabberConverter.convert(grabber.grab()); } grayImage = IplImage.create(grabbedImage.width(), grabbedImage.height(), IPL_DEPTH_8U, 1); smallImage = IplImage.create(grabbedImage.width()/4, grabbedImage.height()/4, IPL_DEPTH_8U, 1); stop = false; while (!stop && (grabbedImage = grabberConverter.convert(grabber.grab())) != null) { if (faces == null) { cvClearMemStorage(storage); cvCvtColor(grabbedImage, grayImage, CV_BGR2GRAY); cvResize(grayImage, smallImage, CV_INTER_AREA); faces = cvHaarDetectObjects(smallImage, classifier, storage, 1.1, 3, CV_HAAR_FIND_BIGGEST_OBJECT | CV_HAAR_DO_ROUGH_SEARCH); repaint(); } } grabbedImage = grayImage = smallImage = null; grabber.stop(); grabber.release(); grabber = null; } catch (Exception e) { if (exception == null) { exception = e; repaint(); } } } @Override public void update(Graphics g) { paint(g); } @Override public void paint(Graphics g) { if (grabbedImage != null) { Frame frame = grabberConverter.convert(grabbedImage); BufferedImage image = paintConverter.getBufferedImage(frame, 2.2/grabber.getGamma()); Graphics2D g2 = image.createGraphics(); if (faces != null) { g2.setColor(Color.RED); g2.setStroke(new BasicStroke(2)); int total = faces.total(); for (int i = 0; i < total; i++) { CvRect r = new CvRect(cvGetSeqElem(faces, i)); g2.drawRect(r.x()*4, r.y()*4, r.width()*4, r.height()*4); } faces = null; } g.drawImage(image, 0, 0, null); } if (exception != null) { int y = 0, h = g.getFontMetrics().getHeight(); g.drawString(exception.toString(), 5, y += h); for (StackTraceElement e : exception.getStackTrace()) { g.drawString(" at " + e.toString(), 5, y += h); } } } @Override public void stop() { stop = true; } @Override public void destroy() { } } ================================================ FILE: samples/FaceApplet.jnlp ================================================ FaceApplet Samuel Audet ================================================ FILE: samples/FacePreview.java ================================================ /* * Copyright (C) 2010-2019 Samuel Audet * * FacePreview - A fusion of OpenCV's facedetect and Android's CameraPreview samples, * with JavaCV + JavaCPP as the glue in between. * * This file was based on CameraPreview.java that came with the Samples for * Android SDK API 8, revision 1 and contained the following copyright notice: * * Copyright (C) 2007 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * * IMPORTANT - Make sure the AndroidManifest.xml file looks like this: * * * * * * * * * * * * * * * */ package org.bytedeco.javacv.facepreview; import android.app.Activity; import android.app.AlertDialog; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.ImageFormat; import android.graphics.Paint; import android.hardware.Camera; import android.hardware.Camera.Size; import android.os.Bundle; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.view.View; import android.view.Window; import android.view.WindowManager; import android.widget.FrameLayout; import java.io.File; import java.io.IOException; import java.net.URL; import java.nio.ByteBuffer; import java.util.List; import org.bytedeco.javacpp.Loader; import org.bytedeco.opencv.opencv_core.*; import org.bytedeco.opencv.opencv_objdetect.*; import static org.bytedeco.opencv.global.opencv_core.*; import static org.bytedeco.opencv.global.opencv_objdetect.*; // ---------------------------------------------------------------------- public class FacePreview extends Activity { private FrameLayout layout; private FaceView faceView; private Preview mPreview; @Override protected void onCreate(Bundle savedInstanceState) { // Hide the window title. requestWindowFeature(Window.FEATURE_NO_TITLE); super.onCreate(savedInstanceState); getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); // Create our Preview view and set it as the content of our activity. try { layout = new FrameLayout(this); faceView = new FaceView(this); mPreview = new Preview(this, faceView); layout.addView(mPreview); layout.addView(faceView); setContentView(layout); } catch (IOException e) { e.printStackTrace(); new AlertDialog.Builder(this).setMessage(e.getMessage()).create().show(); } } } // ---------------------------------------------------------------------- class FaceView extends View implements Camera.PreviewCallback { public static final int SUBSAMPLING_FACTOR = 4; private Mat grayImage; private CascadeClassifier classifier; private RectVector faces; public FaceView(FacePreview context) throws IOException { super(context); // Load the classifier file from Java resources. File classifierFile = Loader.extractResource(getClass(), "/org/bytedeco/javacv/facepreview/haarcascade_frontalface_alt.xml", context.getCacheDir(), "classifier", ".xml"); if (classifierFile == null || classifierFile.length() <= 0) { throw new IOException("Could not extract the classifier file from Java resource."); } classifier = new CascadeClassifier(classifierFile.getAbsolutePath()); classifierFile.delete(); if (classifier.isNull()) { throw new IOException("Could not load the classifier file."); } } public void onPreviewFrame(final byte[] data, final Camera camera) { try { Camera.Size size = camera.getParameters().getPreviewSize(); processImage(data, size.width, size.height); camera.addCallbackBuffer(data); } catch (RuntimeException e) { // The camera has probably just been released, ignore. } } protected void processImage(byte[] data, int width, int height) { // First, downsample our image and convert it into a grayscale Mat int f = SUBSAMPLING_FACTOR; if (grayImage == null || grayImage.cols() != width/f || grayImage.rows() != height/f) { grayImage = new Mat(height/f, width/f, CV_8UC1); } int imageWidth = grayImage.cols(); int imageHeight = grayImage.rows(); int dataStride = f*width; int imageStride = (int)grayImage.step(0); ByteBuffer imageBuffer = grayImage.createBuffer(); for (int y = 0; y < imageHeight; y++) { int dataLine = y*dataStride; int imageLine = y*imageStride; for (int x = 0; x < imageWidth; x++) { imageBuffer.put(imageLine + x, data[dataLine + f*x]); } } faces = new RectVector(); classifier.detectMultiScale(grayImage, faces); postInvalidate(); } @Override protected void onDraw(Canvas canvas) { Paint paint = new Paint(); paint.setColor(Color.RED); paint.setTextSize(20); String s = "FacePreview - This side up."; float textWidth = paint.measureText(s); canvas.drawText(s, (getWidth()-textWidth)/2, 20, paint); if (faces != null) { paint.setStrokeWidth(2); paint.setStyle(Paint.Style.STROKE); float scaleX = (float)getWidth()/grayImage.cols(); float scaleY = (float)getHeight()/grayImage.rows(); long total = faces.size(); for (long i = 0; i < total; i++) { Rect r = faces.get(i); int x = r.x(), y = r.y(), w = r.width(), h = r.height(); canvas.drawRect(x*scaleX, y*scaleY, (x+w)*scaleX, (y+h)*scaleY, paint); } } } } // ---------------------------------------------------------------------- class Preview extends SurfaceView implements SurfaceHolder.Callback { SurfaceHolder mHolder; Camera mCamera; Camera.PreviewCallback previewCallback; Preview(Context context, Camera.PreviewCallback previewCallback) { super(context); this.previewCallback = previewCallback; // Install a SurfaceHolder.Callback so we get notified when the // underlying surface is created and destroyed. mHolder = getHolder(); mHolder.addCallback(this); mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); } public void surfaceCreated(SurfaceHolder holder) { // The Surface has been created, acquire the camera and tell it where // to draw. mCamera = Camera.open(); try { mCamera.setPreviewDisplay(holder); } catch (IOException exception) { mCamera.release(); mCamera = null; // TODO: add more exception handling logic here } } public void surfaceDestroyed(SurfaceHolder holder) { // Surface will be destroyed when we return, so stop the preview. // Because the CameraDevice object is not a shared resource, it's very // important to release it when the activity is paused. mCamera.stopPreview(); mCamera.release(); mCamera = null; } private Size getOptimalPreviewSize(List sizes, int w, int h) { final double ASPECT_TOLERANCE = 0.05; double targetRatio = (double) w / h; if (sizes == null) return null; Size optimalSize = null; double minDiff = Double.MAX_VALUE; int targetHeight = h; // Try to find an size match aspect ratio and size for (Size size : sizes) { double ratio = (double) size.width / size.height; if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue; if (Math.abs(size.height - targetHeight) < minDiff) { optimalSize = size; minDiff = Math.abs(size.height - targetHeight); } } // Cannot find the one match the aspect ratio, ignore the requirement if (optimalSize == null) { minDiff = Double.MAX_VALUE; for (Size size : sizes) { if (Math.abs(size.height - targetHeight) < minDiff) { optimalSize = size; minDiff = Math.abs(size.height - targetHeight); } } } return optimalSize; } public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { // Now that the size is known, set up the camera parameters and begin // the preview. Camera.Parameters parameters = mCamera.getParameters(); List sizes = parameters.getSupportedPreviewSizes(); Size optimalSize = getOptimalPreviewSize(sizes, w, h); parameters.setPreviewSize(optimalSize.width, optimalSize.height); mCamera.setParameters(parameters); if (previewCallback != null) { mCamera.setPreviewCallbackWithBuffer(previewCallback); Camera.Size size = parameters.getPreviewSize(); byte[] data = new byte[size.width*size.height* ImageFormat.getBitsPerPixel(parameters.getPreviewFormat())/8]; mCamera.addCallbackBuffer(data); } mCamera.startPreview(); } } ================================================ FILE: samples/FaceRecognizerInVideo.java ================================================ import java.io.File; import org.bytedeco.javacpp.IntPointer; import org.bytedeco.javacpp.DoublePointer; import org.bytedeco.javacv.Frame; import org.bytedeco.javacv.FrameGrabber.Exception; import org.bytedeco.javacv.OpenCVFrameConverter; import org.bytedeco.javacv.OpenCVFrameGrabber; import org.bytedeco.opencv.opencv_core.*; import org.bytedeco.opencv.opencv_face.*; import org.bytedeco.opencv.opencv_highgui.*; import org.bytedeco.opencv.opencv_imgproc.*; import org.bytedeco.opencv.opencv_objdetect.*; import static org.bytedeco.opencv.global.opencv_core.*; import static org.bytedeco.opencv.global.opencv_face.*; import static org.bytedeco.opencv.global.opencv_highgui.*; import static org.bytedeco.opencv.global.opencv_imgproc.*; import static org.bytedeco.opencv.global.opencv_objdetect.*; /** * This is an example how to detect face in a video file with javacv * @author Vincent He (chinadragon0515@gmail.com) * */ public class FaceRecognizerInVideo { public static void main(String[] args) throws Exception { OpenCVFrameConverter.ToMat converterToMat = new OpenCVFrameConverter.ToMat(); if (args.length < 2) { System.out.println("Two parameters are required to run this program, first parameter is the analized video and second parameter is the trained result for fisher faces."); } String videoFileName = args[0]; String trainedResult = args[1]; CascadeClassifier face_cascade = new CascadeClassifier( "data\\haarcascade_frontalface_default.xml"); FaceRecognizer lbphFaceRecognizer = LBPHFaceRecognizer.create(); lbphFaceRecognizer.read(trainedResult); File f = new File(videoFileName); OpenCVFrameGrabber grabber = null; try { grabber = OpenCVFrameGrabber.createDefault(f); grabber.start(); } catch (Exception e) { System.err.println("Failed start the grabber."); } Frame videoFrame = null; Mat videoMat = new Mat(); while (true) { videoFrame = grabber.grab(); videoMat = converterToMat.convert(videoFrame); Mat videoMatGray = new Mat(); // Convert the current frame to grayscale: cvtColor(videoMat, videoMatGray, COLOR_BGRA2GRAY); equalizeHist(videoMatGray, videoMatGray); Point p = new Point(); RectVector faces = new RectVector(); // Find the faces in the frame: face_cascade.detectMultiScale(videoMatGray, faces); // At this point you have the position of the faces in // faces. Now we'll get the faces, make a prediction and // annotate it in the video. Cool or what? for (int i = 0; i < faces.size(); i++) { Rect face_i = faces.get(i); Mat face = new Mat(videoMatGray, face_i); // If fisher face recognizer is used, the face need to be // resized. // resize(face, face_resized, new Size(im_width, im_height), // 1.0, 1.0, INTER_CUBIC); // Now perform the prediction, see how easy that is: IntPointer label = new IntPointer(1); DoublePointer confidence = new DoublePointer(1); lbphFaceRecognizer.predict(face, label, confidence); int prediction = label.get(0); // And finally write all we've found out to the original image! // First of all draw a green rectangle around the detected face: rectangle(videoMat, face_i, new Scalar(0, 255, 0, 1)); // Create the text we will annotate the box with: String box_text = "Prediction = " + prediction; // Calculate the position for annotated text (make sure we don't // put illegal values in there): int pos_x = Math.max(face_i.tl().x() - 10, 0); int pos_y = Math.max(face_i.tl().y() - 10, 0); // And now put it into the image: putText(videoMat, box_text, new Point(pos_x, pos_y), FONT_HERSHEY_PLAIN, 1.0, new Scalar(0, 255, 0, 2.0)); } // Show the result: imshow("face_recognizer", videoMat); char key = (char) waitKey(20); // Exit this loop on escape: if (key == 27) { destroyAllWindows(); break; } } } } ================================================ FILE: samples/HoughLines.java ================================================ import javax.swing.JFrame; import org.bytedeco.javacpp.*; import org.bytedeco.javacv.*; import org.bytedeco.opencv.opencv_core.*; import org.bytedeco.opencv.opencv_imgproc.*; import static org.bytedeco.opencv.global.opencv_core.*; import static org.bytedeco.opencv.global.opencv_imgproc.*; import static org.bytedeco.opencv.global.opencv_imgcodecs.*; /** * C to Java translation of the houghlines.c sample provided in the c sample directory of OpenCV 2.1, * using the JavaCV Java wrapper of OpenCV 2.2 developped by Samuel Audet. * * @author Jeremy Nicola * jeremy.nicola@gmail.com */ public class HoughLines { /** * usage: java HoughLines imageDir\imageName TransformType */ public static void main(String[] args) { String fileName = args.length >= 1 ? args[0] : "pic1.png"; // if no params provided, compute the defaut image IplImage src = cvLoadImage(fileName, 0); IplImage dst; IplImage colorDst; CvMemStorage storage = cvCreateMemStorage(0); CvSeq lines = new CvSeq(); CanvasFrame source = new CanvasFrame("Source"); CanvasFrame hough = new CanvasFrame("Hough"); OpenCVFrameConverter.ToIplImage sourceConverter = new OpenCVFrameConverter.ToIplImage(); OpenCVFrameConverter.ToIplImage houghConverter = new OpenCVFrameConverter.ToIplImage(); if (src == null) { System.out.println("Couldn't load source image."); return; } dst = cvCreateImage(cvGetSize(src), src.depth(), 1); colorDst = cvCreateImage(cvGetSize(src), src.depth(), 3); cvCanny(src, dst, 50, 200, 3); cvCvtColor(dst, colorDst, CV_GRAY2BGR); /* * apply the probabilistic hough transform * which returns for each line deteced two points ((x1, y1); (x2,y2)) * defining the detected segment */ if (args.length == 2 && args[1].contentEquals("probabilistic")) { System.out.println("Using the Probabilistic Hough Transform"); lines = cvHoughLines2(dst, storage, CV_HOUGH_PROBABILISTIC, 1, Math.PI / 180, 40, 50, 10, 0, CV_PI); for (int i = 0; i < lines.total(); i++) { // Based on JavaCPP, the equivalent of the C code: // CvPoint* line = (CvPoint*)cvGetSeqElem(lines,i); // CvPoint first=line[0], second=line[1] // is: Pointer line = cvGetSeqElem(lines, i); CvPoint pt1 = new CvPoint(line).position(0); CvPoint pt2 = new CvPoint(line).position(1); System.out.println("Line spotted: "); System.out.println("\t pt1: " + pt1); System.out.println("\t pt2: " + pt2); cvLine(colorDst, pt1, pt2, CV_RGB(255, 0, 0), 3, CV_AA, 0); // draw the segment on the image } } /* * Apply the multiscale hough transform which returns for each line two float parameters (rho, theta) * rho: distance from the origin of the image to the line * theta: angle between the x-axis and the normal line of the detected line */ else if(args.length==2 && args[1].contentEquals("multiscale")){ System.out.println("Using the multiscale Hough Transform"); // lines = cvHoughLines2(dst, storage, CV_HOUGH_MULTI_SCALE, 1, Math.PI / 180, 40, 1, 1, 0, CV_PI); for (int i = 0; i < lines.total(); i++) { CvPoint2D32f point = new CvPoint2D32f(cvGetSeqElem(lines, i)); float rho=point.x(); float theta=point.y(); double a = Math.cos((double) theta), b = Math.sin((double) theta); double x0 = a * rho, y0 = b * rho; CvPoint pt1 = cvPoint((int) Math.round(x0 + 1000 * (-b)), (int) Math.round(y0 + 1000 * (a))), pt2 = cvPoint((int) Math.round(x0 - 1000 * (-b)), (int) Math.round(y0 - 1000 * (a))); System.out.println("Line spoted: "); System.out.println("\t rho= " + rho); System.out.println("\t theta= " + theta); cvLine(colorDst, pt1, pt2, CV_RGB(255, 0, 0), 3, CV_AA, 0); } } /* * Default: apply the standard hough transform. Outputs: same as the multiscale output. */ else { System.out.println("Using the Standard Hough Transform"); lines = cvHoughLines2(dst, storage, CV_HOUGH_STANDARD, 1, Math.PI / 180, 90, 0, 0, 0, CV_PI); for (int i = 0; i < lines.total(); i++) { CvPoint2D32f point = new CvPoint2D32f(cvGetSeqElem(lines, i)); float rho=point.x(); float theta=point.y(); double a = Math.cos((double) theta), b = Math.sin((double) theta); double x0 = a * rho, y0 = b * rho; CvPoint pt1 = cvPoint((int) Math.round(x0 + 1000 * (-b)), (int) Math.round(y0 + 1000 * (a))), pt2 = cvPoint((int) Math.round(x0 - 1000 * (-b)), (int) Math.round(y0 - 1000 * (a))); System.out.println("Line spotted: "); System.out.println("\t rho= " + rho); System.out.println("\t theta= " + theta); cvLine(colorDst, pt1, pt2, CV_RGB(255, 0, 0), 3, CV_AA, 0); } } source.showImage(sourceConverter.convert(src)); hough.showImage(houghConverter.convert(colorDst)); source.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); hough.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } } ================================================ FILE: samples/ImageSegmentation.java ================================================ /* * JavaCV version of OpenCV imageSegmentation.cpp * https://github.com/opencv/opencv/blob/master/samples/cpp/tutorial_code/ImgTrans/imageSegmentation.cpp * * The OpenCV example image is available at the following address * https://github.com/opencv/opencv/blob/master/samples/data/cards.png * * Paolo Bolettieri */ import java.util.ArrayList; import java.util.Arrays; import java.util.List; import org.bytedeco.javacpp.indexer.FloatIndexer; import org.bytedeco.javacpp.indexer.IntIndexer; import org.bytedeco.javacpp.indexer.UByteIndexer; import org.bytedeco.javacv.CanvasFrame; import org.bytedeco.javacv.OpenCVFrameConverter; import org.bytedeco.opencv.opencv_core.*; import org.bytedeco.opencv.opencv_imgproc.*; import static org.bytedeco.opencv.global.opencv_core.*; import static org.bytedeco.opencv.global.opencv_imgcodecs.*; import static org.bytedeco.opencv.global.opencv_imgproc.*; public class ImageSegmentation { private static final int[] WHITE = {255, 255, 255}; private static final int[] BLACK = {0, 0, 0}; public static void main(String[] args) { // Load the image Mat src = imread(args[0]); // Check if everything was fine if (src.data().isNull()) return; // Show source image imshow("Source Image", src); // Change the background from white to black, since that will help later to extract // better results during the use of Distance Transform UByteIndexer srcIndexer = src.createIndexer(); for (int x = 0; x < srcIndexer.rows(); x++) { for (int y = 0; y < srcIndexer.cols(); y++) { int[] values = new int[3]; srcIndexer.get(x, y, values); if (Arrays.equals(values, WHITE)) { srcIndexer.put(x, y, BLACK); } } } // Show output image imshow("Black Background Image", src); // Create a kernel that we will use for accuting/sharpening our image Mat kernel = Mat.ones(3, 3, CV_32F).asMat(); FloatIndexer kernelIndexer = kernel.createIndexer(); kernelIndexer.put(1, 1, -8); // an approximation of second derivative, a quite strong kernel // do the laplacian filtering as it is // well, we need to convert everything in something more deeper then CV_8U // because the kernel has some negative values, // and we can expect in general to have a Laplacian image with negative values // BUT a 8bits unsigned int (the one we are working with) can contain values from 0 to 255 // so the possible negative number will be truncated Mat imgLaplacian = new Mat(); Mat sharp = src; // copy source image to another temporary one filter2D(sharp, imgLaplacian, CV_32F, kernel); src.convertTo(sharp, CV_32F); Mat imgResult = subtract(sharp, imgLaplacian).asMat(); // convert back to 8bits gray scale imgResult.convertTo(imgResult, CV_8UC3); imgLaplacian.convertTo(imgLaplacian, CV_8UC3); // imshow( "Laplace Filtered Image", imgLaplacian ); imshow("New Sharped Image", imgResult); src = imgResult; // copy back // Create binary image from source image Mat bw = new Mat(); cvtColor(src, bw, CV_BGR2GRAY); threshold(bw, bw, 40, 255, CV_THRESH_BINARY | CV_THRESH_OTSU); imshow("Binary Image", bw); // Perform the distance transform algorithm Mat dist = new Mat(); distanceTransform(bw, dist, CV_DIST_L2, 3); // Normalize the distance image for range = {0.0, 1.0} // so we can visualize and threshold it normalize(dist, dist, 0, 1., NORM_MINMAX, -1, null); imshow("Distance Transform Image", dist); // Threshold to obtain the peaks // This will be the markers for the foreground objects threshold(dist, dist, .4, 1., CV_THRESH_BINARY); // Dilate a bit the dist image Mat kernel1 = Mat.ones(3, 3, CV_8UC1).asMat(); dilate(dist, dist, kernel1); imshow("Peaks", dist); // Create the CV_8U version of the distance image // It is needed for findContours() Mat dist_8u = new Mat(); dist.convertTo(dist_8u, CV_8U); // Find total markers MatVector contours = new MatVector(); findContours(dist_8u, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE); // Create the marker image for the watershed algorithm Mat markers = Mat.zeros(dist.size(), CV_32SC1).asMat(); // Draw the foreground markers for (int i = 0; i < contours.size(); i++) drawContours(markers, contours, i, Scalar.all((i) + 1)); // Draw the background marker circle(markers, new Point(5, 5), 3, RGB(255, 255, 255)); imshow("Markers", multiply(markers, 10000).asMat()); // Perform the watershed algorithm watershed(src, markers); Mat mark = Mat.zeros(markers.size(), CV_8UC1).asMat(); markers.convertTo(mark, CV_8UC1); bitwise_not(mark, mark); // imshow("Markers_v2", mark); // uncomment this if you want to see how the mark // image looks like at that point // Generate random colors List colors = new ArrayList(); for (int i = 0; i < contours.size(); i++) { int b = theRNG().uniform(0, 255); int g = theRNG().uniform(0, 255); int r = theRNG().uniform(0, 255); int[] color = { b, g, r }; colors.add(color); } // Create the result image Mat dst = Mat.zeros(markers.size(), CV_8UC3).asMat(); // Fill labeled objects with random colors IntIndexer markersIndexer = markers.createIndexer(); UByteIndexer dstIndexer = dst.createIndexer(); for (int i = 0; i < markersIndexer.rows(); i++) { for (int j = 0; j < markersIndexer.cols(); j++) { int index = markersIndexer.get(i, j); if (index > 0 && index <= contours.size()) dstIndexer.put(i, j, colors.get(index - 1)); else dstIndexer.put(i, j, BLACK); } } // Visualize the final image imshow("Final Result", dst); } //I wrote a custom imshow method for problems using the OpenCV original one private static void imshow(String txt, Mat img) { CanvasFrame canvasFrame = new CanvasFrame(txt); canvasFrame.setDefaultCloseOperation(javax.swing.JFrame.EXIT_ON_CLOSE); canvasFrame.setCanvasSize(img.cols(), img.rows()); canvasFrame.showImage(new OpenCVFrameConverter.ToMat().convert(img)); } } ================================================ FILE: samples/JavaFxPlayVideoAndAudio.java ================================================ import java.nio.ByteBuffer; import java.nio.ShortBuffer; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import java.util.logging.Level; import java.util.logging.Logger; import javafx.application.Application; import javafx.application.Platform; import javafx.scene.Scene; import javafx.scene.image.Image; import javafx.scene.image.ImageView; import javafx.scene.layout.StackPane; import javafx.stage.Stage; import javax.sound.sampled.AudioFormat; import javax.sound.sampled.AudioSystem; import javax.sound.sampled.DataLine; import javax.sound.sampled.SourceDataLine; import org.bytedeco.javacv.FFmpegFrameGrabber; import org.bytedeco.javacv.Frame; import org.bytedeco.javacv.JavaFXFrameConverter; /** * @author Dmitriy Gerashenko * @author Jarek Sacha */ public class JavaFxPlayVideoAndAudio extends Application { private static class PlaybackTimer { private Long startTime = -1L; private final DataLine soundLine; public PlaybackTimer(DataLine soundLine) { this.soundLine = soundLine; } public PlaybackTimer() { this.soundLine = null; } public void start() { if (soundLine == null) { startTime = System.nanoTime(); } } public long elapsedMicros() { if (soundLine == null) { if (startTime < 0) { throw new IllegalStateException("PlaybackTimer not initialized."); } return (System.nanoTime() - startTime) / 1000; } else { return soundLine.getMicrosecondPosition(); } } } private static final Logger LOG = Logger.getLogger(JavaFxPlayVideoAndAudio.class.getName()); private static volatile Thread playThread; public static void main(String[] args) { launch(args); } @Override public void start(final Stage primaryStage) throws Exception { final StackPane root = new StackPane(); final ImageView imageView = new ImageView(); root.getChildren().add(imageView); imageView.fitWidthProperty().bind(primaryStage.widthProperty()); imageView.fitHeightProperty().bind(primaryStage.heightProperty()); final Scene scene = new Scene(root, 640, 480); primaryStage.setTitle("Video + audio"); primaryStage.setScene(scene); primaryStage.show(); playThread = new Thread(new Runnable() { public void run() { try { final String videoFilename = getParameters().getRaw().get(0); final FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(videoFilename); grabber.start(); primaryStage.setWidth(grabber.getImageWidth()); primaryStage.setHeight(grabber.getImageHeight()); final PlaybackTimer playbackTimer; final SourceDataLine soundLine; if (grabber.getAudioChannels() > 0) { final AudioFormat audioFormat = new AudioFormat(grabber.getSampleRate(), 16, grabber.getAudioChannels(), true, true); final DataLine.Info info = new DataLine.Info(SourceDataLine.class, audioFormat); soundLine = (SourceDataLine) AudioSystem.getLine(info); soundLine.open(audioFormat); soundLine.start(); playbackTimer = new PlaybackTimer(soundLine); } else { soundLine = null; playbackTimer = new PlaybackTimer(); } final JavaFXFrameConverter converter = new JavaFXFrameConverter(); final ExecutorService audioExecutor = Executors.newSingleThreadExecutor(); final ExecutorService imageExecutor = Executors.newSingleThreadExecutor(); final long maxReadAheadBufferMicros = 1000 * 1000L; long lastTimeStamp = -1L; while (!Thread.interrupted()) { final Frame frame = grabber.grab(); if (frame == null) { break; } if (lastTimeStamp < 0) { playbackTimer.start(); } lastTimeStamp = frame.timestamp; if (frame.image != null) { final Frame imageFrame = frame.clone(); imageExecutor.submit(new Runnable() { public void run() { final Image image = converter.convert(imageFrame); final long timeStampDeltaMicros = imageFrame.timestamp - playbackTimer.elapsedMicros(); imageFrame.close(); if (timeStampDeltaMicros > 0) { final long delayMillis = timeStampDeltaMicros / 1000L; try { Thread.sleep(delayMillis); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } Platform.runLater(new Runnable() { public void run() { imageView.setImage(image); } }); } }); } else if (frame.samples != null) { if (soundLine == null) { throw new IllegalStateException("Internal error: sound playback not initialized"); } final ShortBuffer channelSamplesShortBuffer = (ShortBuffer) frame.samples[0]; channelSamplesShortBuffer.rewind(); final ByteBuffer outBuffer = ByteBuffer.allocate(channelSamplesShortBuffer.capacity() * 2); for (int i = 0; i < channelSamplesShortBuffer.capacity(); i++) { short val = channelSamplesShortBuffer.get(i); outBuffer.putShort(val); } audioExecutor.submit(new Runnable() { public void run() { soundLine.write(outBuffer.array(), 0, outBuffer.capacity()); outBuffer.clear(); } }); } final long timeStampDeltaMicros = frame.timestamp - playbackTimer.elapsedMicros(); if (timeStampDeltaMicros > maxReadAheadBufferMicros) { Thread.sleep((timeStampDeltaMicros - maxReadAheadBufferMicros) / 1000); } } if (!Thread.interrupted()) { long delay = (lastTimeStamp - playbackTimer.elapsedMicros()) / 1000 + Math.round(1 / grabber.getFrameRate() * 1000); Thread.sleep(Math.max(0, delay)); } grabber.stop(); grabber.release(); if (soundLine != null) { soundLine.stop(); } audioExecutor.shutdownNow(); audioExecutor.awaitTermination(10, TimeUnit.SECONDS); imageExecutor.shutdownNow(); imageExecutor.awaitTermination(10, TimeUnit.SECONDS); Platform.exit(); } catch (Exception exception) { LOG.log(Level.SEVERE, null, exception); System.exit(1); } }}); playThread.start(); } @Override public void stop() { playThread.interrupt(); } } ================================================ FILE: samples/KazemiFacemarkExample.java ================================================ /** * Kazemi Facemark example for JavaCV * * @author Théophile Gonos * * Link to Kazemi model : * https://raw.githubusercontent.com/opencv/opencv_3rdparty/contrib_face_alignment_20170818/face_landmark_model.dat */ import java.io.IOException; import java.net.URISyntaxException; import org.bytedeco.opencv.opencv_core.*; import org.bytedeco.opencv.opencv_face.*; import org.bytedeco.opencv.opencv_highgui.*; import org.bytedeco.opencv.opencv_imgproc.*; import org.bytedeco.opencv.opencv_objdetect.*; import static org.bytedeco.opencv.global.opencv_core.*; import static org.bytedeco.opencv.global.opencv_face.*; import static org.bytedeco.opencv.global.opencv_highgui.*; import static org.bytedeco.opencv.global.opencv_imgcodecs.*; import static org.bytedeco.opencv.global.opencv_imgproc.*; import static org.bytedeco.opencv.global.opencv_objdetect.*; public class KazemiFacemarkExample { public static void main(String[] args) throws IOException, URISyntaxException, InterruptedException { // Load Face Detector CascadeClassifier faceDetector = new CascadeClassifier ("haarcascade_frontalface_alt2.xml"); // Create an instance of Facemark FacemarkKazemi facemark = FacemarkKazemi.create(); // Load landmark detector facemark.loadModel("face_landmark_model.dat"); // Load image Mat img = imread("face.jpg"); // convert to grayscale and equalize histograe for better detection Mat gray = new Mat (); cvtColor(img, gray, COLOR_BGR2GRAY); equalizeHist( gray, gray ); // Find faces on the image RectVector faces = new RectVector (); faceDetector.detectMultiScale(gray, faces); System.out.println ("Faces detected: "+faces.size()); // Variable for landmarks. // Landmarks for one face is a vector of points // There can be more than one face in the image. Point2fVectorVector landmarks = new Point2fVectorVector(); // Run landmark detector boolean success = facemark.fit(img, faces, landmarks); if(success) { // If successful, render the landmarks on each face for (long i = 0; i < landmarks.size(); i++) { Point2fVector v = landmarks.get(i); drawFacemarks(img, v, Scalar.YELLOW); } } // Display results imshow("Kazemi Facial Landmark", img); cvWaitKey(0); // Save results imwrite ("kazemi_landmarks.jpg", img); } } ================================================ FILE: samples/LBFFacemarkExampleWithVideo.java ================================================ /** * LBF Facemark example for JavaCV with Video camera and Transparent API * * @author Théophile Gonos * * you can find the lbfmodel here: * https://raw.githubusercontent.com/kurnianggoro/GSOC2017/master/data/lbfmodel.yaml */ import java.io.IOException; import java.net.URISyntaxException; import org.bytedeco.opencv.opencv_core.*; import org.bytedeco.opencv.opencv_face.*; import org.bytedeco.opencv.opencv_highgui.*; import org.bytedeco.opencv.opencv_imgproc.*; import org.bytedeco.opencv.opencv_objdetect.*; import org.bytedeco.opencv.opencv_videoio.*; import static org.bytedeco.opencv.global.opencv_core.*; import static org.bytedeco.opencv.global.opencv_face.*; import static org.bytedeco.opencv.global.opencv_highgui.*; import static org.bytedeco.opencv.global.opencv_imgproc.*; import static org.bytedeco.opencv.global.opencv_objdetect.*; import static org.bytedeco.opencv.global.opencv_videoio.*; public class LBFFacemarkExampleWithVideo { /** * @param args the command line arguments * @throws java.io.IOException * @throws java.net.URISyntaxException * @throws java.lang.InterruptedException */ public static void main(String[] args) throws IOException, URISyntaxException, InterruptedException { // Load Face Detector CascadeClassifier faceDetector = new CascadeClassifier ("haarcascade_frontalface_alt2.xml"); // Create an instance of Facemark Facemark facemark = FacemarkLBF.create(); // Load landmark detector facemark.loadModel("lbfmodel.yaml"); // Set up webcam for video capture VideoCapture cam = new VideoCapture (0); // Variable to store a video frame and its grayscale Mat frame = new Mat (); // Read a frame while(cam.read(frame)) { // convert to grayscale and equalize histograe for better detection // + use of transparent API UMat gray = new UMat (); frame.copyTo(gray); cvtColor(gray, gray, COLOR_BGR2GRAY); equalizeHist( gray, gray ); // Find faces on the image RectVector faces = new RectVector (); faceDetector.detectMultiScale(gray, faces); System.out.println ("Faces detected: "+faces.size()); // Verify is at least one face is detected // With some Facemark algorithms it crashes if there is no faces if (!faces.empty()) { // Variable for landmarks. // Landmarks for one face is a vector of points // There can be more than one face in the image. Point2fVectorVector landmarks = new Point2fVectorVector(); // Run landmark detector boolean success = facemark.fit(frame, faces, landmarks); if(success) { // If successful, render the landmarks on the face for (long i = 0; i < landmarks.size(); i++) { Point2fVector v = landmarks.get(i); drawFacemarks(frame, v, Scalar.YELLOW); } } } // Display results imshow("LBF Facial Landmark", frame); // Exit loop if ESC is pressed if (waitKey(1) == 27) break; } } } ================================================ FILE: samples/MotionDetector.java ================================================ /* * I developed some code for recognize motion detections with JavaCV. * Actually, it works with an array of Rect, performing, every cicle, an * intersection test with area of difference with the rect of interests * (this array is callad "sa", stands for SizedArea). I hope could this * helps someone. * * Feel free to ask about any question regarding the code above, cheers! * * Angelo Marchesin */ import org.bytedeco.javacpp.*; import org.bytedeco.javacv.*; import org.bytedeco.opencv.opencv_core.*; import org.bytedeco.opencv.opencv_imgproc.*; import static org.bytedeco.opencv.global.opencv_core.*; import static org.bytedeco.opencv.global.opencv_imgproc.*; public class MotionDetector { public static void main(String[] args) throws Exception { OpenCVFrameGrabber grabber = new OpenCVFrameGrabber(0); OpenCVFrameConverter.ToIplImage converter = new OpenCVFrameConverter.ToIplImage(); grabber.start(); IplImage frame = converter.convert(grabber.grab()); IplImage image = null; IplImage prevImage = null; IplImage diff = null; CanvasFrame canvasFrame = new CanvasFrame("Some Title"); canvasFrame.setCanvasSize(frame.width(), frame.height()); CvMemStorage storage = CvMemStorage.create(); while (canvasFrame.isVisible() && (frame = converter.convert(grabber.grab())) != null) { cvClearMemStorage(storage); cvSmooth(frame, frame, CV_GAUSSIAN, 9, 9, 2, 2); if (image == null) { image = IplImage.create(frame.width(), frame.height(), IPL_DEPTH_8U, 1); cvCvtColor(frame, image, CV_RGB2GRAY); } else { prevImage = IplImage.create(frame.width(), frame.height(), IPL_DEPTH_8U, 1); prevImage = image; image = IplImage.create(frame.width(), frame.height(), IPL_DEPTH_8U, 1); cvCvtColor(frame, image, CV_RGB2GRAY); } if (diff == null) { diff = IplImage.create(frame.width(), frame.height(), IPL_DEPTH_8U, 1); } if (prevImage != null) { // perform ABS difference cvAbsDiff(image, prevImage, diff); // do some threshold for wipe away useless details cvThreshold(diff, diff, 64, 255, CV_THRESH_BINARY); canvasFrame.showImage(converter.convert(diff)); // recognize contours CvSeq contour = new CvSeq(null); cvFindContours(diff, storage, contour, Loader.sizeof(CvContour.class), CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE); while (contour != null && !contour.isNull()) { if (contour.elem_size() > 0) { CvBox2D box = cvMinAreaRect2(contour, storage); // test intersection if (box != null) { CvPoint2D32f center = box.center(); CvSize2D32f size = box.size(); /* for (int i = 0; i < sa.length; i++) { if ((Math.abs(center.x - (sa[i].offsetX + sa[i].width / 2))) < ((size.width / 2) + (sa[i].width / 2)) && (Math.abs(center.y - (sa[i].offsetY + sa[i].height / 2))) < ((size.height / 2) + (sa[i].height / 2))) { if (!alarmedZones.containsKey(i)) { alarmedZones.put(i, true); activeAlarms.put(i, 1); } else { activeAlarms.remove(i); activeAlarms.put(i, 1); } System.out.println("Motion Detected in the area no: " + i + " Located at points: (" + sa[i].x + ", " + sa[i].y+ ") -" + " (" + (sa[i].x +sa[i].width) + ", " + (sa[i].y+sa[i].height) + ")"); } } */ } } contour = contour.h_next(); } } } grabber.stop(); canvasFrame.dispose(); } } ================================================ FILE: samples/OpenCVFaceRecognizer.java ================================================ import java.io.File; import java.io.FilenameFilter; import java.nio.IntBuffer; import org.bytedeco.javacpp.BytePointer; import org.bytedeco.javacpp.IntPointer; import org.bytedeco.javacpp.DoublePointer; import org.bytedeco.opencv.opencv_core.*; import org.bytedeco.opencv.opencv_face.*; import static org.bytedeco.opencv.global.opencv_core.*; import static org.bytedeco.opencv.global.opencv_face.*; import static org.bytedeco.opencv.global.opencv_imgcodecs.*; /** * I couldn't find any tutorial on how to perform face recognition using OpenCV and Java, * so I decided to share a viable solution here. The solution is very inefficient in its * current form as the training model is built at each run, however it shows what's needed * to make it work. * * The class below takes two arguments: The path to the directory containing the training * faces and the path to the image you want to classify. Not that all images has to be of * the same size and that the faces already has to be cropped out of their original images * (Take a look here http://fivedots.coe.psu.ac.th/~ad/jg/nui07/index.html if you haven't * done the face detection yet). * * For the simplicity of this post, the class also requires that the training images have * filename format: