Repository: hybridgroup/gocv Branch: release Commit: 274ac8a2d6fc Files: 307 Total size: 2.7 MB Directory structure: gitextract_b1fe3o02/ ├── .astylerc ├── .github/ │ ├── FUNDING.yml │ ├── ISSUE_TEMPLATE.md │ └── workflows/ │ ├── docker-alpine-improved.yml │ ├── docker-static-ffmpeg.yml │ ├── docker-static-gstreamer.yml │ ├── docker-static-opencv-cuda.yml │ ├── docker-static-opencv.yml │ ├── docker.yml │ ├── linux.yml │ ├── macos.yml │ └── windows.yml ├── .gitignore ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── Dockerfile ├── Dockerfile-static ├── Dockerfile-static-alpine ├── Dockerfile-static-builder ├── Dockerfile-test ├── Dockerfile-test.gpu-cuda-10 ├── Dockerfile-test.gpu-cuda-11 ├── Dockerfile-test.gpu-cuda-11.2.2 ├── Dockerfile-test.gpu-cuda-12 ├── Dockerfile-test.gpu-cuda-13 ├── Dockerfile.ffmpeg-static-alpine ├── Dockerfile.gpu ├── Dockerfile.gstreamer-static-alpine ├── Dockerfile.opencv ├── Dockerfile.opencv-gpu-cuda-10 ├── Dockerfile.opencv-gpu-cuda-11 ├── Dockerfile.opencv-gpu-cuda-11.2.2 ├── Dockerfile.opencv-gpu-cuda-12 ├── Dockerfile.opencv-gpu-cuda-13 ├── Dockerfile.opencv-openvino ├── Dockerfile.opencv-static ├── Dockerfile.opencv-static-alpine ├── Dockerfile.opencv-static-alpine-ffmpeg ├── Dockerfile.opencv-ubuntu-18.04 ├── Dockerfile.opencv-ubuntu-20.04 ├── Dockerfile.opencv-ubuntu-22.04 ├── Dockerfile.opencv-ubuntu-24.04 ├── LICENSE.txt ├── Makefile ├── README.md ├── ROADMAP.md ├── aruco.cpp ├── aruco.go ├── aruco.h ├── aruco_dictionaries.go ├── aruco_test.go ├── asyncarray.cpp ├── asyncarray.go ├── asyncarray.h ├── asyncarray_test.go ├── calib3d.cpp ├── calib3d.go ├── calib3d.h ├── calib3d_string.go ├── calib3d_test.go ├── cgo.go ├── cgo_static.go ├── cgo_static_darwin.go ├── cgo_static_windows.go ├── cmd/ │ ├── README.md │ ├── asciicam/ │ │ └── main.go │ ├── basic-drawing/ │ │ └── main.go │ ├── caffe-classifier/ │ │ └── main.go │ ├── captest/ │ │ └── main.go │ ├── capwindow/ │ │ └── main.go │ ├── counter/ │ │ └── main.go │ ├── cuda/ │ │ └── main.go │ ├── dnn-detection/ │ │ └── main.go │ ├── dnn-pose-detection/ │ │ └── main.go │ ├── dnn-style-transfer/ │ │ └── main.go │ ├── faceblur/ │ │ └── main.go │ ├── facedetect/ │ │ └── main.go │ ├── facedetect-from-url/ │ │ └── main.go │ ├── facedetectYN/ │ │ └── main.go │ ├── feature-matching/ │ │ └── main.go │ ├── find-chessboard/ │ │ └── main.go │ ├── find-circles/ │ │ └── main.go │ ├── find-lines/ │ │ └── main.go │ ├── gstreamer-writer/ │ │ └── main.go │ ├── hand-gestures/ │ │ └── main.go │ ├── hello/ │ │ └── main.go │ ├── img-similarity/ │ │ └── main.go │ ├── kalman-filter/ │ │ └── main.go │ ├── mjpeg-streamer/ │ │ └── main.go │ ├── motion-detect/ │ │ └── main.go │ ├── openvino/ │ │ └── ie/ │ │ └── version/ │ │ └── main.go │ ├── saveimage/ │ │ └── main.go │ ├── savevideo/ │ │ └── main.go │ ├── showimage/ │ │ └── main.go │ ├── ssd-facedetect/ │ │ └── main.go │ ├── tf-classifier/ │ │ └── main.go │ ├── tracking/ │ │ └── main.go │ ├── version/ │ │ └── main.go │ ├── xphoto/ │ │ └── main.go │ └── yolo-detection/ │ └── main.go ├── codecov.yml ├── contrib/ │ ├── README.md │ ├── att_faces/ │ │ ├── README │ │ ├── s1/ │ │ │ ├── 1.pgm │ │ │ ├── 2.pgm │ │ │ ├── 3.pgm │ │ │ └── 4.pgm │ │ ├── s2/ │ │ │ ├── 1.pgm │ │ │ ├── 2.pgm │ │ │ ├── 3.pgm │ │ │ ├── 4.pgm │ │ │ └── 5.pgm │ │ └── s3/ │ │ ├── 1.pgm │ │ ├── 10.pgm │ │ ├── 2.pgm │ │ ├── 3.pgm │ │ ├── 4.pgm │ │ ├── 5.pgm │ │ ├── 6.pgm │ │ ├── 7.pgm │ │ ├── 8.pgm │ │ └── 9.pgm │ ├── bgsegm.cpp │ ├── bgsegm.go │ ├── bgsegm.h │ ├── bgsegm_test.go │ ├── cgo.go │ ├── cgo_static.go │ ├── cgo_static_darwin.go │ ├── cgo_static_windows.go │ ├── contrib.go │ ├── errors.go │ ├── face.cpp │ ├── face.go │ ├── face.h │ ├── face_recognizer.go │ ├── face_test.go │ ├── freetype.cpp │ ├── freetype.go │ ├── freetype.h │ ├── freetype_test.go │ ├── img_hash.cpp │ ├── img_hash.go │ ├── img_hash.h │ ├── img_hash_string.go │ ├── img_hash_test.go │ ├── mcc.cpp │ ├── mcc.go │ ├── mcc.h │ ├── mcc_test.go │ ├── tracking.cpp │ ├── tracking.go │ ├── tracking.h │ ├── tracking_test.go │ ├── wechat_qrcode.cpp │ ├── wechat_qrcode.go │ ├── wechat_qrcode.h │ ├── wechat_qrcode_test.go │ ├── xfeatures2d.cpp │ ├── xfeatures2d.go │ ├── xfeatures2d.h │ ├── xfeatures2d_test.go │ ├── ximgproc.cpp │ ├── ximgproc.go │ ├── ximgproc.h │ ├── ximgproc_test.go │ ├── xobjdetect.cpp │ ├── xobjdetect.go │ ├── xobjdetect.h │ ├── xobjdetect_test.go │ ├── xphoto.cpp │ ├── xphoto.go │ ├── xphoto.h │ └── xphoto_test.go ├── core.cpp ├── core.go ├── core.h ├── core_string.go ├── core_test.go ├── cuda/ │ ├── README.md │ ├── arithm.cpp │ ├── arithm.go │ ├── arithm.h │ ├── arithm_test.go │ ├── bgsegm.cpp │ ├── bgsegm.go │ ├── bgsegm.h │ ├── bgsegm_test.go │ ├── cgo.go │ ├── cgo_static.go │ ├── cgo_static_darwin.go │ ├── cgo_static_windows.go │ ├── core.cpp │ ├── core.go │ ├── core.h │ ├── cuda.cpp │ ├── cuda.go │ ├── cuda.h │ ├── cuda_test.go │ ├── errors.go │ ├── filters.cpp │ ├── filters.go │ ├── filters.h │ ├── filters_test.go │ ├── helpers_test.go │ ├── imgproc.cpp │ ├── imgproc.go │ ├── imgproc.h │ ├── imgproc_alphacomptypes.go │ ├── imgproc_test.go │ ├── objdetect.cpp │ ├── objdetect.go │ ├── objdetect.h │ ├── optflow.cpp │ ├── optflow.go │ ├── optflow.h │ ├── optflow_test.go │ ├── warping.cpp │ ├── warping.go │ ├── warping.h │ ├── warping_string.go │ └── warping_test.go ├── data/ │ └── haarcascade_frontalface_default.xml ├── dnn.cpp ├── dnn.go ├── dnn.h ├── dnn_async_openvino.go ├── dnn_ext.go ├── dnn_string.go ├── dnn_test.go ├── env.cmd ├── env.sh ├── features2d.cpp ├── features2d.go ├── features2d.h ├── features2d_string.go ├── features2d_test.go ├── go.mod ├── go.sum ├── gocv.go ├── helpers_test.go ├── highgui.cpp ├── highgui.go ├── highgui_gocv.h ├── highgui_onmouse_test.go ├── highgui_string.go ├── highgui_test.go ├── images/ │ └── multipage.tif ├── imgcodecs.cpp ├── imgcodecs.go ├── imgcodecs.h ├── imgcodecs_test.go ├── imgproc.cpp ├── imgproc.go ├── imgproc.h ├── imgproc_colorcodes.go ├── imgproc_colorcodes_string.go ├── imgproc_string.go ├── imgproc_test.go ├── mat_noprofile.go ├── mat_profile.go ├── matprofile_test.go ├── objdetect.cpp ├── objdetect.go ├── objdetect.h ├── objdetect_test.go ├── openvino/ │ ├── README.md │ ├── env.sh │ ├── ie/ │ │ ├── README.md │ │ ├── ie.go │ │ ├── inference_engine.cpp │ │ ├── inference_engine.go │ │ ├── inference_engine.h │ │ └── inference_engine_test.go │ └── openvino.go ├── patches/ │ └── gstreamer-full.patch ├── persistence.h ├── persistence_filenode.cpp ├── persistence_filenode.go ├── persistence_filestorage.cpp ├── persistence_filestorage.go ├── persistence_test.go ├── photo.cpp ├── photo.go ├── photo.h ├── photo_string.go ├── photo_test.go ├── svd.cpp ├── svd.go ├── svd.h ├── svd_test.go ├── version.cpp ├── version.go ├── version.h ├── version_test.go ├── video.cpp ├── video.go ├── video.h ├── video_test.go ├── videoio.cpp ├── videoio.go ├── videoio.h ├── videoio_string.go ├── videoio_test.go ├── win_build_opencv.cmd └── win_download_opencv.cmd ================================================ FILE CONTENTS ================================================ ================================================ FILE: .astylerc ================================================ --lineend=linux --style=google --indent=spaces=4 --indent-col1-comments --convert-tabs --attach-return-type --attach-namespaces --attach-classes --attach-inlines --add-brackets --add-braces --align-pointer=type --align-reference=type --max-code-length=100 --break-after-logical --pad-comma --pad-oper --unpad-paren --break-blocks --pad-header ================================================ FILE: .github/FUNDING.yml ================================================ patreon: deadprogram ================================================ FILE: .github/ISSUE_TEMPLATE.md ================================================ ## Description ## Steps to Reproduce 1. 2. 3. 4. ## Your Environment * Operating System and version: * OpenCV version used: * How did you install OpenCV? * GoCV version used: * Go version: * Did you run the `env.sh` or `env.cmd` script before trying to `go run` or `go build`? ================================================ FILE: .github/workflows/docker-alpine-improved.yml ================================================ # This is the Github action to build and push the gocv/opencv Docker images. # name: Docker on: push: branches: [build-opencv-alpine, alpine-static-improved] workflow_dispatch: concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: gstreamer: name: gstreamer runs-on: ubuntu-latest permissions: packages: write contents: read steps: - name: Set up QEMU uses: docker/setup-qemu-action@v3 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Check out the repo uses: actions/checkout@v6 - name: Docker meta id: meta uses: docker/metadata-action@v5 with: images: | gocv/gstreamer:1.24-alpine ghcr.io/${{ github.repository_owner }}/gstreamer:1.24-alpine tags: | type=sha,format=long type=raw,value=latest - name: Log in to Docker Hub uses: docker/login-action@v3 with: username: ${{ secrets.DOCKER_HUB_USERNAME }} password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }} - name: Log in to Github Container Registry uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Build and push uses: docker/build-push-action@v6 with: file: Dockerfile.gstreamer-static-alpine platforms: linux/amd64,linux/arm64 context: . push: true tags: | gocv/gstreamer:1.24-alpine ghcr.io/${{ github.repository_owner }}/gstreamer:1.24-alpine labels: ${{ steps.meta.outputs.labels }} cache-from: type=gha cache-to: type=gha,mode=max ffmpeg: name: ffmpeg runs-on: ubuntu-latest permissions: packages: write contents: read steps: - name: Set up QEMU uses: docker/setup-qemu-action@v3 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Check out the repo uses: actions/checkout@v6 - name: Docker meta id: meta uses: docker/metadata-action@v5 with: images: | gocv/ffmpeg:5.16-alpine ghcr.io/${{ github.repository_owner }}/ffmpeg:5.16-alpine tags: | type=sha,format=long type=raw,value=latest - name: Log in to Docker Hub uses: docker/login-action@v3 with: username: ${{ secrets.DOCKER_HUB_USERNAME }} password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }} - name: Log in to Github Container Registry uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Build and push uses: docker/build-push-action@v6 with: file: Dockerfile.ffmpeg-static-alpine platforms: linux/amd64,linux/arm64 context: . push: true tags: | gocv/ffmpeg:5.16-alpine ghcr.io/${{ github.repository_owner }}/ffmpeg:5.16-alpine labels: ${{ steps.meta.outputs.labels }} cache-from: type=gha cache-to: type=gha,mode=max opencv: name: opencv runs-on: ubuntu-latest needs: [gstreamer, ffmpeg] permissions: packages: write contents: read steps: - name: Set up QEMU uses: docker/setup-qemu-action@v3 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Check out the repo uses: actions/checkout@v6 - name: Docker meta id: meta uses: docker/metadata-action@v5 with: images: | gocv/opencv:4.13.0-alpine ghcr.io/${{ github.repository_owner }}/opencv:4.13.0-alpine tags: | type=sha,format=long type=raw,value=latest - name: Log in to Docker Hub uses: docker/login-action@v3 with: username: ${{ secrets.DOCKER_HUB_USERNAME }} password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }} - name: Log in to Github Container Registry uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Build and push uses: docker/build-push-action@v6 with: file: Dockerfile.opencv-static-alpine platforms: linux/amd64,linux/arm64 context: . push: true tags: | gocv/opencv:4.13.0-alpine ghcr.io/${{ github.repository_owner }}/opencv:4.13.0-alpine labels: ${{ steps.meta.outputs.labels }} cache-from: type=gha cache-to: type=gha,mode=max opencv-ffmpeg: name: opencv runs-on: ubuntu-latest needs: [gstreamer, ffmpeg] permissions: packages: write contents: read steps: - name: Set up QEMU uses: docker/setup-qemu-action@v3 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Check out the repo uses: actions/checkout@v6 - name: Docker meta id: meta uses: docker/metadata-action@v5 with: images: | gocv/opencv:4.13.0-alpine-ffmpeg ghcr.io/${{ github.repository_owner }}/opencv:4.13.0-alpine-ffmpeg tags: | type=sha,format=long type=raw,value=latest - name: Log in to Docker Hub uses: docker/login-action@v3 with: username: ${{ secrets.DOCKER_HUB_USERNAME }} password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }} - name: Log in to Github Container Registry uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Build and push uses: docker/build-push-action@v6 with: file: Dockerfile.opencv-static-alpine-ffmpeg platforms: linux/amd64,linux/arm64 context: . push: true tags: | gocv/opencv:4.13.0-alpine-ffmpeg ghcr.io/${{ github.repository_owner }}/opencv:4.13.0-alpine-ffmpeg labels: ${{ steps.meta.outputs.labels }} cache-from: type=gha cache-to: type=gha,mode=max ================================================ FILE: .github/workflows/docker-static-ffmpeg.yml ================================================ # This is the Github action to build and push the ffmpeg Docker images used for static builds. # name: ffmpeg on: workflow_dispatch: concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: ffmpeg: name: ffmpeg runs-on: ubuntu-latest permissions: packages: write contents: read steps: - name: Set up QEMU uses: docker/setup-qemu-action@v3 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Check out the repo uses: actions/checkout@v6 - name: Docker meta id: meta uses: docker/metadata-action@v5 with: images: | gocv/ffmpeg:5.16-alpine ghcr.io/${{ github.repository_owner }}/ffmpeg:5.16-alpine tags: | type=sha,format=long type=raw,value=latest - name: Log in to Docker Hub uses: docker/login-action@v3 with: username: ${{ secrets.DOCKER_HUB_USERNAME }} password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }} - name: Log in to Github Container Registry uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Build and push uses: docker/build-push-action@v6 with: file: Dockerfile.ffmpeg-static-alpine platforms: linux/amd64,linux/arm64 context: . push: true tags: | gocv/ffmpeg:5.16-alpine ghcr.io/${{ github.repository_owner }}/ffmpeg:5.16-alpine labels: ${{ steps.meta.outputs.labels }} cache-from: type=gha cache-to: type=gha,mode=max ================================================ FILE: .github/workflows/docker-static-gstreamer.yml ================================================ # This is the Github action to build and push the GStreamer Docker images used for static builds. # name: GStreamer on: workflow_dispatch: concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: gstreamer: name: gstreamer runs-on: ubuntu-latest permissions: packages: write contents: read steps: - name: Set up QEMU uses: docker/setup-qemu-action@v3 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Check out the repo uses: actions/checkout@v6 - name: Docker meta id: meta uses: docker/metadata-action@v5 with: images: | gocv/gstreamer:1.24-alpine ghcr.io/${{ github.repository_owner }}/gstreamer:1.24-alpine tags: | type=sha,format=long type=raw,value=latest - name: Log in to Docker Hub uses: docker/login-action@v3 with: username: ${{ secrets.DOCKER_HUB_USERNAME }} password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }} - name: Log in to Github Container Registry uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Build and push uses: docker/build-push-action@v6 with: file: Dockerfile.gstreamer-static-alpine platforms: linux/amd64,linux/arm64 context: . push: true tags: | gocv/gstreamer:1.24-alpine ghcr.io/${{ github.repository_owner }}/gstreamer:1.24-alpine labels: ${{ steps.meta.outputs.labels }} cache-from: type=gha cache-to: type=gha,mode=max ================================================ FILE: .github/workflows/docker-static-opencv-cuda.yml ================================================ # This is the Github action to build and push the OpenCV Docker images used for static builds. # name: OpenCV on: workflow_dispatch: concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: opencv: name: opencv runs-on: ubuntu-latest permissions: packages: write contents: read steps: - name: Set up QEMU uses: docker/setup-qemu-action@v3 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Check out the repo uses: actions/checkout@v6 - name: Docker meta id: meta uses: docker/metadata-action@v5 with: images: | gocv/opencv:4.11.0-gpu-cuda-12-static ghcr.io/${{ github.repository_owner }}/opencv:4.11.0-gpu-cuda-12-static tags: | type=sha,format=long type=raw,value=latest - name: Log in to Docker Hub uses: docker/login-action@v3 with: username: ${{ secrets.DOCKER_HUB_USERNAME }} password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }} - name: Log in to Github Container Registry uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Build and push uses: docker/build-push-action@v6 with: file: Dockerfile.opencv-gpu-cuda-12-static platforms: linux/amd64 context: . push: true tags: | gocv/opencv:4.11.0-gpu-cuda-12-static ghcr.io/${{ github.repository_owner }}/opencv:4.11.0-gpu-cuda-12-static labels: ${{ steps.meta.outputs.labels }} cache-from: type=gha cache-to: type=gha,mode=max ================================================ FILE: .github/workflows/docker-static-opencv.yml ================================================ # This is the Github action to build and push the OpenCV Docker images used for static builds. # name: OpenCV on: push: branches: [alpine-static-improved-2] workflow_dispatch: concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: opencv: name: opencv runs-on: ubuntu-latest permissions: packages: write contents: read steps: - name: Set up QEMU uses: docker/setup-qemu-action@v3 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Check out the repo uses: actions/checkout@v6 - name: Docker meta id: meta uses: docker/metadata-action@v5 with: images: | gocv/opencv:4.13.0-alpine-ffmpeg-gstreamer ghcr.io/${{ github.repository_owner }}/opencv:4.13.0-alpine-ffmpeg-gstreamer tags: | type=sha,format=long type=raw,value=latest - name: Log in to Docker Hub uses: docker/login-action@v3 with: username: ${{ secrets.DOCKER_HUB_USERNAME }} password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }} - name: Log in to Github Container Registry uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Build and push uses: docker/build-push-action@v6 with: file: Dockerfile.opencv-static-alpine platforms: linux/amd64,linux/arm64 context: . push: true tags: | gocv/opencv:4.13.0-alpine-ffmpeg-gstreamer ghcr.io/${{ github.repository_owner }}/opencv:4.13.0-alpine-ffmpeg-gstreamer labels: ${{ steps.meta.outputs.labels }} cache-from: type=gha cache-to: type=gha,mode=max ================================================ FILE: .github/workflows/docker.yml ================================================ # This is the Github action to build and push the gocv/opencv Docker images. # name: Docker on: push: branches: [build-opencv-images] workflow_dispatch: concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: opencv: name: opencv runs-on: ubuntu-24.04 permissions: packages: write contents: read steps: - name: Check disk space run: df . -h - name: Free disk space run: | sudo docker rmi $(docker image ls -aq) >/dev/null 2>&1 || true sudo rm -rf \ /usr/share/dotnet /usr/local/lib/android /opt/ghc \ /usr/local/share/powershell /usr/share/swift /usr/local/.ghcup \ /usr/lib/jvm || true echo "extra directories deleted" sudo apt install aptitude -y >/dev/null 2>&1 sudo aptitude purge aria2 ansible azure-cli shellcheck rpm xorriso zsync \ esl-erlang firefox gfortran-8 gfortran-9 google-chrome-stable \ google-cloud-sdk imagemagick \ libmagickcore-dev libmagickwand-dev libmagic-dev ant ant-optional kubectl \ mercurial apt-transport-https mono-complete libmysqlclient \ unixodbc-dev yarn chrpath libssl-dev libxft-dev \ libfreetype6 libfreetype6-dev libfontconfig1 libfontconfig1-dev \ snmp pollinate libpq-dev postgresql-client powershell ruby-full \ sphinxsearch subversion mongodb-org azure-cli microsoft-edge-stable \ -y -f >/dev/null 2>&1 sudo aptitude purge google-cloud-sdk -f -y >/dev/null 2>&1 sudo aptitude purge microsoft-edge-stable -f -y >/dev/null 2>&1 || true sudo apt purge microsoft-edge-stable -f -y >/dev/null 2>&1 || true sudo aptitude purge '~n ^mysql' -f -y >/dev/null 2>&1 sudo aptitude purge '~n ^php' -f -y >/dev/null 2>&1 sudo aptitude purge '~n ^dotnet' -f -y >/dev/null 2>&1 sudo apt-get autoremove -y >/dev/null 2>&1 sudo apt-get autoclean -y >/dev/null 2>&1 echo "extra packages purged" - name: Check disk space run: df . -h - name: Set up QEMU uses: docker/setup-qemu-action@v3 with: image: tonistiigi/binfmt:latest - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Check out the repo uses: actions/checkout@v6 - name: Docker meta id: meta uses: docker/metadata-action@v5 with: images: | gocv/opencv:4.13.0 ghcr.io/${{ github.repository_owner }}/opencv:4.13.0 tags: | type=sha,format=long type=raw,value=latest - name: Log in to Docker Hub uses: docker/login-action@v3 with: username: ${{ secrets.DOCKER_HUB_USERNAME }} password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }} - name: Log in to Github Container Registry uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Build and push uses: docker/build-push-action@v6 with: file: Dockerfile.opencv platforms: linux/amd64,linux/arm64 context: . push: true tags: | gocv/opencv:latest gocv/opencv:4.13.0 ghcr.io/${{ github.repository_owner }}/opencv:latest ghcr.io/${{ github.repository_owner }}/opencv:4.13.0 labels: ${{ steps.meta.outputs.labels }} cache-from: type=gha cache-to: type=gha,mode=max opencv-static: name: opencv-static runs-on: ubuntu-24.04 permissions: packages: write contents: read steps: - name: Check disk space run: df . -h - name: Free disk space run: | sudo docker rmi $(docker image ls -aq) >/dev/null 2>&1 || true sudo rm -rf \ /usr/share/dotnet /usr/local/lib/android /opt/ghc \ /usr/local/share/powershell /usr/share/swift /usr/local/.ghcup \ /usr/lib/jvm || true echo "extra directories deleted" sudo apt install aptitude -y >/dev/null 2>&1 sudo aptitude purge aria2 ansible azure-cli shellcheck rpm xorriso zsync \ esl-erlang firefox gfortran-8 gfortran-9 google-chrome-stable \ google-cloud-sdk imagemagick \ libmagickcore-dev libmagickwand-dev libmagic-dev ant ant-optional kubectl \ mercurial apt-transport-https mono-complete libmysqlclient \ unixodbc-dev yarn chrpath libssl-dev libxft-dev \ libfreetype6 libfreetype6-dev libfontconfig1 libfontconfig1-dev \ snmp pollinate libpq-dev postgresql-client powershell ruby-full \ sphinxsearch subversion mongodb-org azure-cli microsoft-edge-stable \ -y -f >/dev/null 2>&1 sudo aptitude purge google-cloud-sdk -f -y >/dev/null 2>&1 sudo aptitude purge microsoft-edge-stable -f -y >/dev/null 2>&1 || true sudo apt purge microsoft-edge-stable -f -y >/dev/null 2>&1 || true sudo aptitude purge '~n ^mysql' -f -y >/dev/null 2>&1 sudo aptitude purge '~n ^php' -f -y >/dev/null 2>&1 sudo aptitude purge '~n ^dotnet' -f -y >/dev/null 2>&1 sudo apt-get autoremove -y >/dev/null 2>&1 sudo apt-get autoclean -y >/dev/null 2>&1 echo "extra packages purged" - name: Check disk space run: df . -h - name: Set up QEMU uses: docker/setup-qemu-action@v3 with: image: tonistiigi/binfmt:latest - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Check out the repo uses: actions/checkout@v6 - name: Docker meta id: meta uses: docker/metadata-action@v5 with: images: | gocv/opencv:4.13.0-static ghcr.io/${{ github.repository_owner }}/opencv:4.13.0-static tags: | type=sha,format=long type=raw,value=latest - name: Log in to Docker Hub uses: docker/login-action@v3 with: username: ${{ secrets.DOCKER_HUB_USERNAME }} password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }} - name: Log in to Github Container Registry uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Build and push uses: docker/build-push-action@v6 with: file: Dockerfile.opencv-static platforms: linux/amd64,linux/arm64 context: . push: true tags: | gocv/opencv:4.13.0-static ghcr.io/${{ github.repository_owner }}/opencv:4.13.0-static labels: ${{ steps.meta.outputs.labels }} cache-from: type=gha cache-to: type=gha,mode=max opencv-gpu-cuda-11: name: opencv-gpu-cuda-11 runs-on: ubuntu-latest permissions: packages: write contents: read steps: - name: Check disk space run: df . -h - name: Free disk space run: | sudo docker rmi $(docker image ls -aq) >/dev/null 2>&1 || true sudo rm -rf \ /usr/share/dotnet /usr/local/lib/android /opt/ghc \ /usr/local/share/powershell /usr/share/swift /usr/local/.ghcup \ /usr/lib/jvm || true echo "extra directories deleted" sudo apt install aptitude -y >/dev/null 2>&1 sudo aptitude purge aria2 ansible azure-cli shellcheck rpm xorriso zsync \ esl-erlang firefox gfortran-8 gfortran-9 google-chrome-stable \ google-cloud-sdk imagemagick \ libmagickcore-dev libmagickwand-dev libmagic-dev ant ant-optional kubectl \ mercurial apt-transport-https mono-complete libmysqlclient \ unixodbc-dev yarn chrpath libssl-dev libxft-dev \ libfreetype6 libfreetype6-dev libfontconfig1 libfontconfig1-dev \ snmp pollinate libpq-dev postgresql-client powershell ruby-full \ sphinxsearch subversion mongodb-org azure-cli microsoft-edge-stable \ -y -f >/dev/null 2>&1 sudo aptitude purge google-cloud-sdk -f -y >/dev/null 2>&1 sudo aptitude purge microsoft-edge-stable -f -y >/dev/null 2>&1 || true sudo apt purge microsoft-edge-stable -f -y >/dev/null 2>&1 || true sudo aptitude purge '~n ^mysql' -f -y >/dev/null 2>&1 sudo aptitude purge '~n ^php' -f -y >/dev/null 2>&1 sudo aptitude purge '~n ^dotnet' -f -y >/dev/null 2>&1 sudo apt-get autoremove -y >/dev/null 2>&1 sudo apt-get autoclean -y >/dev/null 2>&1 echo "extra packages purged" - name: Check disk space run: df . -h - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Check out the repo uses: actions/checkout@v6 - name: Docker meta id: meta uses: docker/metadata-action@v5 with: images: | gocv/opencv:4.13.0-gpu-cuda-11 ghcr.io/${{ github.repository_owner }}/opencv:4.13.0-gpu-cuda-11 tags: | type=sha,format=long type=raw,value=latest - name: Log in to Docker Hub uses: docker/login-action@v3 with: username: ${{ secrets.DOCKER_HUB_USERNAME }} password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }} - name: Log in to Github Container Registry uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Build and push uses: docker/build-push-action@v6 with: file: Dockerfile.opencv-gpu-cuda-11 platforms: linux/amd64 context: . push: true tags: | gocv/opencv:4.13.0-gpu-cuda-11 ghcr.io/${{ github.repository_owner }}/opencv:4.13.0-gpu-cuda-11 labels: ${{ steps.meta.outputs.labels }} cache-from: type=gha cache-to: type=gha,mode=max opencv-gpu-cuda-11-2-2: name: opencv-gpu-cuda-11-2-2 runs-on: ubuntu-latest permissions: packages: write contents: read steps: - name: Check disk space run: df . -h - name: Free disk space run: | sudo docker rmi $(docker image ls -aq) >/dev/null 2>&1 || true sudo rm -rf \ /usr/share/dotnet /usr/local/lib/android /opt/ghc \ /usr/local/share/powershell /usr/share/swift /usr/local/.ghcup \ /usr/lib/jvm || true echo "extra directories deleted" sudo apt install aptitude -y >/dev/null 2>&1 sudo aptitude purge aria2 ansible azure-cli shellcheck rpm xorriso zsync \ esl-erlang firefox gfortran-8 gfortran-9 google-chrome-stable \ google-cloud-sdk imagemagick \ libmagickcore-dev libmagickwand-dev libmagic-dev ant ant-optional kubectl \ mercurial apt-transport-https mono-complete libmysqlclient \ unixodbc-dev yarn chrpath libssl-dev libxft-dev \ libfreetype6 libfreetype6-dev libfontconfig1 libfontconfig1-dev \ snmp pollinate libpq-dev postgresql-client powershell ruby-full \ sphinxsearch subversion mongodb-org azure-cli microsoft-edge-stable \ -y -f >/dev/null 2>&1 sudo aptitude purge google-cloud-sdk -f -y >/dev/null 2>&1 sudo aptitude purge microsoft-edge-stable -f -y >/dev/null 2>&1 || true sudo apt purge microsoft-edge-stable -f -y >/dev/null 2>&1 || true sudo aptitude purge '~n ^mysql' -f -y >/dev/null 2>&1 sudo aptitude purge '~n ^php' -f -y >/dev/null 2>&1 sudo aptitude purge '~n ^dotnet' -f -y >/dev/null 2>&1 sudo apt-get autoremove -y >/dev/null 2>&1 sudo apt-get autoclean -y >/dev/null 2>&1 echo "extra packages purged" - name: Check disk space run: df . -h - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Check out the repo uses: actions/checkout@v6 - name: Docker meta id: meta uses: docker/metadata-action@v5 with: images: | gocv/opencv:4.13.0-gpu-cuda-11.2.2 ghcr.io/${{ github.repository_owner }}/opencv:4.13.0-gpu-cuda-11.2.2 tags: | type=sha,format=long type=raw,value=latest - name: Log in to Docker Hub uses: docker/login-action@v3 with: username: ${{ secrets.DOCKER_HUB_USERNAME }} password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }} - name: Log in to Github Container Registry uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Build and push uses: docker/build-push-action@v6 with: file: Dockerfile.opencv-gpu-cuda-11.2.2 platforms: linux/amd64 context: . push: true tags: | gocv/opencv:4.13.0-gpu-cuda-11.2.2 ghcr.io/${{ github.repository_owner }}/opencv:4.13.0-gpu-cuda-11.2.2 labels: ${{ steps.meta.outputs.labels }} cache-from: type=gha cache-to: type=gha,mode=max opencv-gpu-cuda-12: name: opencv-gpu-cuda-12 runs-on: ubuntu-latest permissions: packages: write contents: read steps: - name: Check disk space run: df . -h - name: Free disk space run: | sudo docker rmi $(docker image ls -aq) >/dev/null 2>&1 || true sudo rm -rf \ /usr/share/dotnet /usr/local/lib/android /opt/ghc \ /usr/local/share/powershell /usr/share/swift /usr/local/.ghcup \ /usr/lib/jvm || true echo "extra directories deleted" sudo apt install aptitude -y >/dev/null 2>&1 sudo aptitude purge aria2 ansible azure-cli shellcheck rpm xorriso zsync \ esl-erlang firefox gfortran-8 gfortran-9 google-chrome-stable \ google-cloud-sdk imagemagick \ libmagickcore-dev libmagickwand-dev libmagic-dev ant ant-optional kubectl \ mercurial apt-transport-https mono-complete libmysqlclient \ unixodbc-dev yarn chrpath libssl-dev libxft-dev \ libfreetype6 libfreetype6-dev libfontconfig1 libfontconfig1-dev \ snmp pollinate libpq-dev postgresql-client powershell ruby-full \ sphinxsearch subversion mongodb-org azure-cli microsoft-edge-stable \ -y -f >/dev/null 2>&1 sudo aptitude purge google-cloud-sdk -f -y >/dev/null 2>&1 sudo aptitude purge microsoft-edge-stable -f -y >/dev/null 2>&1 || true sudo apt purge microsoft-edge-stable -f -y >/dev/null 2>&1 || true sudo aptitude purge '~n ^mysql' -f -y >/dev/null 2>&1 sudo aptitude purge '~n ^php' -f -y >/dev/null 2>&1 sudo aptitude purge '~n ^dotnet' -f -y >/dev/null 2>&1 sudo apt-get autoremove -y >/dev/null 2>&1 sudo apt-get autoclean -y >/dev/null 2>&1 echo "extra packages purged" - name: Check disk space run: df . -h - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Check out the repo uses: actions/checkout@v6 - name: Docker meta id: meta uses: docker/metadata-action@v5 with: images: | gocv/opencv:4.13.0-gpu-cuda-12 ghcr.io/${{ github.repository_owner }}/opemcv:4.13.0-gpu-cuda-12 tags: | type=sha,format=long type=raw,value=latest - name: Log in to Docker Hub uses: docker/login-action@v3 with: username: ${{ secrets.DOCKER_HUB_USERNAME }} password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }} - name: Log in to Github Container Registry uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Build and push uses: docker/build-push-action@v6 with: file: Dockerfile.opencv-gpu-cuda-12 platforms: linux/amd64 context: . push: true tags: | gocv/opencv:4.13.0-gpu-cuda-12 ghcr.io/${{ github.repository_owner }}/opencv:4.13.0-gpu-cuda-12 labels: ${{ steps.meta.outputs.labels }} cache-from: type=gha cache-to: type=gha,mode=max opencv-gpu-cuda-13: name: opencv-gpu-cuda-13 runs-on: ubuntu-latest permissions: packages: write contents: read steps: - name: Check disk space run: df . -h - name: Free disk space run: | sudo docker rmi $(docker image ls -aq) >/dev/null 2>&1 || true sudo rm -rf \ /usr/share/dotnet /usr/local/lib/android /opt/ghc \ /usr/local/share/powershell /usr/share/swift /usr/local/.ghcup \ /usr/lib/jvm || true echo "extra directories deleted" sudo apt install aptitude -y >/dev/null 2>&1 sudo aptitude purge aria2 ansible azure-cli shellcheck rpm xorriso zsync \ esl-erlang firefox gfortran-8 gfortran-9 google-chrome-stable \ google-cloud-sdk imagemagick \ libmagickcore-dev libmagickwand-dev libmagic-dev ant ant-optional kubectl \ mercurial apt-transport-https mono-complete libmysqlclient \ unixodbc-dev yarn chrpath libssl-dev libxft-dev \ libfreetype6 libfreetype6-dev libfontconfig1 libfontconfig1-dev \ snmp pollinate libpq-dev postgresql-client powershell ruby-full \ sphinxsearch subversion mongodb-org azure-cli microsoft-edge-stable \ -y -f >/dev/null 2>&1 sudo aptitude purge google-cloud-sdk -f -y >/dev/null 2>&1 sudo aptitude purge microsoft-edge-stable -f -y >/dev/null 2>&1 || true sudo apt purge microsoft-edge-stable -f -y >/dev/null 2>&1 || true sudo aptitude purge '~n ^mysql' -f -y >/dev/null 2>&1 sudo aptitude purge '~n ^php' -f -y >/dev/null 2>&1 sudo aptitude purge '~n ^dotnet' -f -y >/dev/null 2>&1 sudo apt-get autoremove -y >/dev/null 2>&1 sudo apt-get autoclean -y >/dev/null 2>&1 echo "extra packages purged" - name: Check disk space run: df . -h - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Check out the repo uses: actions/checkout@v6 - name: Docker meta id: meta uses: docker/metadata-action@v5 with: images: | gocv/opencv:4.13.0-gpu-cuda-13 ghcr.io/${{ github.repository_owner }}/opemcv:4.13.0-gpu-cuda-13 tags: | type=sha,format=long type=raw,value=latest - name: Log in to Docker Hub uses: docker/login-action@v3 with: username: ${{ secrets.DOCKER_HUB_USERNAME }} password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }} - name: Log in to Github Container Registry uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Build and push uses: docker/build-push-action@v6 with: file: Dockerfile.opencv-gpu-cuda-13 platforms: linux/amd64 context: . push: true tags: | gocv/opencv:4.13.0-gpu-cuda-13 ghcr.io/${{ github.repository_owner }}/opencv:4.13.0-gpu-cuda-13 labels: ${{ steps.meta.outputs.labels }} cache-from: type=gha cache-to: type=gha,mode=max opencv-ubuntu-18-04: name: opencv-ubuntu-18-04 runs-on: ubuntu-latest permissions: packages: write contents: read steps: - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Check out the repo uses: actions/checkout@v6 - name: Docker meta id: meta uses: docker/metadata-action@v5 with: images: | gocv/opencv:4.13.0-ubuntu-18.04 ghcr.io/${{ github.repository_owner }}/opencv:4.13.0-ubuntu-18.04 tags: | type=sha,format=long type=raw,value=latest - name: Log in to Docker Hub uses: docker/login-action@v3 with: username: ${{ secrets.DOCKER_HUB_USERNAME }} password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }} - name: Log in to Github Container Registry uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Build and push uses: docker/build-push-action@v6 with: file: Dockerfile.opencv-ubuntu-18.04 platforms: linux/amd64 context: . push: true tags: | gocv/opencv:4.13.0-ubuntu-18.04 ghcr.io/${{ github.repository_owner }}/opencv:4.13.0-ubuntu-18.04 labels: ${{ steps.meta.outputs.labels }} cache-from: type=gha cache-to: type=gha,mode=max opencv-ubuntu-20-04: name: opencv-ubuntu-20-04 runs-on: ubuntu-latest permissions: packages: write contents: read steps: - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Check out the repo uses: actions/checkout@v6 - name: Docker meta id: meta uses: docker/metadata-action@v5 with: images: | gocv/opencv:4.13.0-ubuntu-20.04 ghcr.io/${{ github.repository_owner }}/opencv:4.13.0-ubuntu-20.04 tags: | type=sha,format=long type=raw,value=latest - name: Log in to Docker Hub uses: docker/login-action@v3 with: username: ${{ secrets.DOCKER_HUB_USERNAME }} password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }} - name: Log in to Github Container Registry uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.repository_owner }} password: ${{ secrets.GITHUB_TOKEN }} - name: Build and push uses: docker/build-push-action@v6 with: file: Dockerfile.opencv-ubuntu-20.04 platforms: linux/amd64 context: . push: true tags: | gocv/opencv:4.13.0-ubuntu-20.04 ghcr.io/${{ github.repository_owner }}/opencv:4.13.0-ubuntu-20.04 labels: ${{ steps.meta.outputs.labels }} cache-from: type=gha cache-to: type=gha,mode=max opencv-ubuntu-22-04: name: opencv-ubuntu-22-04 runs-on: ubuntu-latest permissions: packages: write contents: read steps: - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Check out the repo uses: actions/checkout@v6 - name: Docker meta id: meta uses: docker/metadata-action@v5 with: images: | gocv/opencv:4.13.0-ubuntu-22.04 ghcr.io/${{ github.repository_owner }}/opencv:4.13.0-ubuntu-22.04 tags: | type=sha,format=long type=raw,value=latest - name: Log in to Docker Hub uses: docker/login-action@v3 with: username: ${{ secrets.DOCKER_HUB_USERNAME }} password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }} - name: Log in to Github Container Registry uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.repository_owner }} password: ${{ secrets.GITHUB_TOKEN }} - name: Build and push uses: docker/build-push-action@v6 with: file: Dockerfile.opencv-ubuntu-22.04 platforms: linux/amd64 context: . push: true tags: | gocv/opencv:4.13.0-ubuntu-22.04 ghcr.io/${{ github.repository_owner }}/opencv:4.13.0-ubuntu-22.04 labels: ${{ steps.meta.outputs.labels }} cache-from: type=gha cache-to: type=gha,mode=max opencv-ubuntu-24-04: name: opencv-ubuntu-24-04 runs-on: ubuntu-latest permissions: packages: write contents: read steps: - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Check out the repo uses: actions/checkout@v6 - name: Docker meta id: meta uses: docker/metadata-action@v5 with: images: | gocv/opencv:4.13.0-ubuntu-24.04 ghcr.io/${{ github.repository_owner }}/opencv:4.13.0-ubuntu-24.04 tags: | type=sha,format=long type=raw,value=latest - name: Log in to Docker Hub uses: docker/login-action@v3 with: username: ${{ secrets.DOCKER_HUB_USERNAME }} password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }} - name: Log in to Github Container Registry uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.repository_owner }} password: ${{ secrets.GITHUB_TOKEN }} - name: Build and push uses: docker/build-push-action@v6 with: file: Dockerfile.opencv-ubuntu-24.04 platforms: linux/amd64 context: . push: true tags: | gocv/opencv:4.13.0-ubuntu-24.04 ghcr.io/${{ github.repository_owner }}/opencv:4.13.0-ubuntu-24.04 labels: ${{ steps.meta.outputs.labels }} cache-from: type=gha cache-to: type=gha,mode=max ================================================ FILE: .github/workflows/linux.yml ================================================ name: Linux on: pull_request: push: branches: - dev - release jobs: build: runs-on: ubuntu-latest container: ghcr.io/hybridgroup/opencv:4.13.0 steps: - name: Checkout uses: actions/checkout@v6 - name: Enforce Go formatted code run: "test -z $(gofmt -l .) || gofmt -d ." - name: Install dependencies run: apt-get update -yqq && apt-get install xvfb unzip -y - name: Install WeChat test model run: | mkdir -p ${GITHUB_WORKSPACE}/testdata curl -sL https://raw.githubusercontent.com/WeChatCV/opencv_3rdparty/wechat_qrcode/detect.caffemodel > ${GITHUB_WORKSPACE}/testdata/detect.caffemodel curl -sL https://raw.githubusercontent.com/WeChatCV/opencv_3rdparty/wechat_qrcode/detect.prototxt > ${GITHUB_WORKSPACE}/testdata/detect.prototxt curl -sL https://raw.githubusercontent.com/WeChatCV/opencv_3rdparty/wechat_qrcode/sr.caffemodel > ${GITHUB_WORKSPACE}/testdata/sr.caffemodel curl -sL https://raw.githubusercontent.com/WeChatCV/opencv_3rdparty/wechat_qrcode/sr.prototxt > ${GITHUB_WORKSPACE}/testdata/sr.prototxt - name: Install GOTURN test model run: | mkdir -p ${GITHUB_WORKSPACE}/testdata curl -sL https://raw.githubusercontent.com/opencv/opencv_extra/c4219d5eb3105ed8e634278fad312a1a8d2c182d/testdata/tracking/goturn.prototxt > ${GITHUB_WORKSPACE}/testdata/goturn.prototxt curl -sL https://github.com/opencv/opencv_extra/raw/c4219d5eb3105ed8e634278fad312a1a8d2c182d/testdata/tracking/goturn.caffemodel.zip.001 > ${GITHUB_WORKSPACE}/testdata/goturn.caffemodel.zip.001 curl -sL https://github.com/opencv/opencv_extra/raw/c4219d5eb3105ed8e634278fad312a1a8d2c182d/testdata/tracking/goturn.caffemodel.zip.002 > ${GITHUB_WORKSPACE}/testdata/goturn.caffemodel.zip.002 curl -sL https://github.com/opencv/opencv_extra/raw/c4219d5eb3105ed8e634278fad312a1a8d2c182d/testdata/tracking/goturn.caffemodel.zip.003 > ${GITHUB_WORKSPACE}/testdata/goturn.caffemodel.zip.003 curl -sL https://github.com/opencv/opencv_extra/raw/c4219d5eb3105ed8e634278fad312a1a8d2c182d/testdata/tracking/goturn.caffemodel.zip.004 > ${GITHUB_WORKSPACE}/testdata/goturn.caffemodel.zip.004 cat ${GITHUB_WORKSPACE}/testdata/goturn.caffemodel.zip.001 ${GITHUB_WORKSPACE}/testdata/goturn.caffemodel.zip.002 ${GITHUB_WORKSPACE}/testdata/goturn.caffemodel.zip.003 ${GITHUB_WORKSPACE}/testdata/goturn.caffemodel.zip.004 > ${GITHUB_WORKSPACE}/testdata/goturn.caffemodel.zip unzip -o ${GITHUB_WORKSPACE}/testdata/goturn.caffemodel.zip goturn.caffemodel -d ${GITHUB_WORKSPACE}/testdata - name: Install Tensorflow test model run: | mkdir -p ${GITHUB_WORKSPACE}/testdata curl -sL https://storage.googleapis.com/download.tensorflow.org/models/inception5h.zip > ${GITHUB_WORKSPACE}/testdata/inception5h.zip unzip -o ${GITHUB_WORKSPACE}/testdata/inception5h.zip tensorflow_inception_graph.pb -d ${GITHUB_WORKSPACE}/testdata - name: Install ONNX test model run: | mkdir -p ${GITHUB_WORKSPACE}/testdata curl -sL https://huggingface.co/onnxmodelzoo/legacy_models/resolve/main/validated/vision/classification/inception_and_googlenet/googlenet/model/googlenet-9.onnx > ${GITHUB_WORKSPACE}/testdata/googlenet-9.onnx curl -sL https://huggingface.co/opencv/face_recognition_sface/resolve/main/face_recognition_sface_2021dec.onnx > ${GITHUB_WORKSPACE}/testdata/face_recognition_sface_2021dec.onnx curl -sL https://huggingface.co/opencv/face_detection_yunet/resolve/main/face_detection_yunet_2023mar.onnx > ${GITHUB_WORKSPACE}/testdata/face_detection_yunet_2023mar.onnx curl -sL https://huggingface.co/opencv/object_tracking_vittrack/resolve/main/object_tracking_vittrack_2023sep.onnx > ${GITHUB_WORKSPACE}/testdata/object_tracking_vittrack_2023sep.onnx - name: Run main tests run: xvfb-run -a --error-file /var/log/xvfb_error.log --server-args="-screen 0 1024x768x24 +extension RANDR" go test -v -coverprofile=/tmp/coverage.out -count=1 -tags matprofile . env: DISPLAY: 99.0 GOCV_TENSORFLOW_TEST_FILES: ${{ github.workspace }}/testdata GOCV_ONNX_TEST_FILES: ${{ github.workspace }}/testdata GOCV_TRACKER_GOTURN_TEST_FILES: ${{ github.workspace }}/testdata - name: Run contrib tests run: xvfb-run -a --error-file /var/log/xvfb_error.log --server-args="-screen 0 1024x768x24 +extension RANDR" go test -v -coverprofile=/tmp/contrib.out -count=1 -tags matprofile ./contrib env: DISPLAY: 99.0 - name: Code coverage run: | go tool cover -html=/tmp/coverage.out -o /tmp/coverage.html go tool cover -html=/tmp/contrib.out -o /tmp/contrib.html - name: Archive code coverage results uses: actions/upload-artifact@v4 with: name: code-coverage-report path: /tmp/*.html ================================================ FILE: .github/workflows/macos.yml ================================================ name: macOS on: pull_request: push: branches: - dev - release jobs: build: strategy: matrix: os: [macos-14, macos-15] runs-on: ${{ matrix.os }} steps: - name: Install OpenCV run: | brew update brew install opencv - name: Install Go uses: actions/setup-go@v6 with: go-version: '1.25.5' cache: true - name: Checkout uses: actions/checkout@v6 - name: Install WeChat test model run: | mkdir -p ${GITHUB_WORKSPACE}/testdata curl -sL https://raw.githubusercontent.com/WeChatCV/opencv_3rdparty/wechat_qrcode/detect.caffemodel > ${GITHUB_WORKSPACE}/testdata/detect.caffemodel curl -sL https://raw.githubusercontent.com/WeChatCV/opencv_3rdparty/wechat_qrcode/detect.prototxt > ${GITHUB_WORKSPACE}/testdata/detect.prototxt curl -sL https://raw.githubusercontent.com/WeChatCV/opencv_3rdparty/wechat_qrcode/sr.caffemodel > ${GITHUB_WORKSPACE}/testdata/sr.caffemodel curl -sL https://raw.githubusercontent.com/WeChatCV/opencv_3rdparty/wechat_qrcode/sr.prototxt > ${GITHUB_WORKSPACE}/testdata/sr.prototxt - name: Install GOTURN test model run: | mkdir -p ${GITHUB_WORKSPACE}/testdata curl -sL https://raw.githubusercontent.com/opencv/opencv_extra/c4219d5eb3105ed8e634278fad312a1a8d2c182d/testdata/tracking/goturn.prototxt > ${GITHUB_WORKSPACE}/testdata/goturn.prototxt curl -sL https://github.com/opencv/opencv_extra/raw/c4219d5eb3105ed8e634278fad312a1a8d2c182d/testdata/tracking/goturn.caffemodel.zip.001 > ${GITHUB_WORKSPACE}/testdata/goturn.caffemodel.zip.001 curl -sL https://github.com/opencv/opencv_extra/raw/c4219d5eb3105ed8e634278fad312a1a8d2c182d/testdata/tracking/goturn.caffemodel.zip.002 > ${GITHUB_WORKSPACE}/testdata/goturn.caffemodel.zip.002 curl -sL https://github.com/opencv/opencv_extra/raw/c4219d5eb3105ed8e634278fad312a1a8d2c182d/testdata/tracking/goturn.caffemodel.zip.003 > ${GITHUB_WORKSPACE}/testdata/goturn.caffemodel.zip.003 curl -sL https://github.com/opencv/opencv_extra/raw/c4219d5eb3105ed8e634278fad312a1a8d2c182d/testdata/tracking/goturn.caffemodel.zip.004 > ${GITHUB_WORKSPACE}/testdata/goturn.caffemodel.zip.004 cat ${GITHUB_WORKSPACE}/testdata/goturn.caffemodel.zip.001 ${GITHUB_WORKSPACE}/testdata/goturn.caffemodel.zip.002 ${GITHUB_WORKSPACE}/testdata/goturn.caffemodel.zip.003 ${GITHUB_WORKSPACE}/testdata/goturn.caffemodel.zip.004 > ${GITHUB_WORKSPACE}/testdata/goturn.caffemodel.zip unzip -o ${GITHUB_WORKSPACE}/testdata/goturn.caffemodel.zip goturn.caffemodel -d ${GITHUB_WORKSPACE}/testdata - name: Install Tensorflow test model run: | mkdir -p ${GITHUB_WORKSPACE}/testdata curl -sL https://storage.googleapis.com/download.tensorflow.org/models/inception5h.zip > ${GITHUB_WORKSPACE}/testdata/inception5h.zip unzip -o ${GITHUB_WORKSPACE}/testdata/inception5h.zip tensorflow_inception_graph.pb -d ${GITHUB_WORKSPACE}/testdata - name: Install ONNX test model run: | mkdir -p ${GITHUB_WORKSPACE}/testdata curl -sL https://huggingface.co/onnxmodelzoo/legacy_models/resolve/main/validated/vision/classification/inception_and_googlenet/googlenet/model/googlenet-9.onnx > ${GITHUB_WORKSPACE}/testdata/googlenet-9.onnx curl -sL https://huggingface.co/opencv/face_recognition_sface/resolve/main/face_recognition_sface_2021dec.onnx > ${GITHUB_WORKSPACE}/testdata/face_recognition_sface_2021dec.onnx curl -sL https://huggingface.co/opencv/face_detection_yunet/resolve/main/face_detection_yunet_2023mar.onnx > ${GITHUB_WORKSPACE}/testdata/face_detection_yunet_2023mar.onnx curl -sL https://huggingface.co/opencv/object_tracking_vittrack/resolve/main/object_tracking_vittrack_2023sep.onnx > ${GITHUB_WORKSPACE}/testdata/object_tracking_vittrack_2023sep.onnx - name: Run main tests run: go test -v -tags matprofile . env: GOCV_TENSORFLOW_TEST_FILES: ${{ github.workspace }}/testdata GOCV_ONNX_TEST_FILES: ${{ github.workspace }}/testdata GOCV_TRACKER_GOTURN_TEST_FILES: ${{ github.workspace }}/testdata - name: Run contrib tests run: go test -v -tags matprofile ./contrib ================================================ FILE: .github/workflows/windows.yml ================================================ name: Windows on: pull_request: push: branches: - dev - release concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: build-windows: runs-on: windows-2022 steps: - name: Checkout uses: actions/checkout@v6 - name: Install Go uses: actions/setup-go@v5 with: go-version: '1.25.5' cache: true - name: Restore cached OpenCV source uses: actions/cache/restore@v4 id: cache-opencv-source with: key: opencv-source-4130-windows-v3 path: | ./opencv/opencv-4.13.0 ./opencv/opencv_contrib-4.13.0 - name: Download OpenCV source if: steps.cache-opencv-source.outputs.cache-hit != 'true' shell: cmd run: | call .\win_download_opencv.cmd "%GITHUB_WORKSPACE%\opencv" - name: Save cached OpenCV source uses: actions/cache/save@v4 if: steps.cache-opencv-source.outputs.cache-hit != 'true' with: key: ${{ steps.cache-opencv-source.outputs.cache-primary-key }} path: | ./opencv/opencv-4.13.0 ./opencv/opencv_contrib-4.13.0 - name: Restore cached OpenCV build uses: actions/cache/restore@v4 id: cache-opencv-build with: key: opencv-build-4130-windows-v4 path: | ./opencv/build - name: Build OpenCV if: steps.cache-opencv-build.outputs.cache-hit != 'true' shell: cmd run: | call .\win_build_opencv.cmd "%GITHUB_WORKSPACE%\opencv" - name: Save cached OpenCV build uses: actions/cache/save@v4 if: steps.cache-opencv-build.outputs.cache-hit != 'true' with: key: ${{ steps.cache-opencv-build.outputs.cache-primary-key }} path: | ./opencv/build - name: Set GoCV env run: | go env echo "CGO_CXXFLAGS=--std=c++11 -DNDEBUG" >> $env:GITHUB_ENV echo "CGO_CPPFLAGS=-I${env:GITHUB_WORKSPACE}\opencv\build\install\include" >> $env:GITHUB_ENV echo "CGO_LDFLAGS=-L${env:GITHUB_WORKSPACE}\opencv\build\install\x64\mingw\lib -lopencv_core4130 -lopencv_face4130 -lopencv_videoio4130 -lopencv_imgproc4130 -lopencv_highgui4130 -lopencv_imgcodecs4130 -lopencv_objdetect4130 -lopencv_features2d4130 -lopencv_video4130 -lopencv_dnn4130 -lopencv_xfeatures2d4130 -lopencv_plot4130 -lopencv_tracking4130 -lopencv_img_hash4130 -lopencv_calib3d4130 -lopencv_bgsegm4130 -lopencv_photo4130 -lopencv_aruco4130 -lopencv_wechat_qrcode4130 -lopencv_ximgproc4130 -lopencv_xphoto4130 -lopencv_xobjdetect4130 -lopencv_mcc4130" >> $env:GITHUB_ENV echo "${env:GITHUB_WORKSPACE}/opencv/build/install/x64/mingw/bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append - name: Install Tensorflow test model run: | mkdir -p ./testdata curl -sL https://storage.googleapis.com/download.tensorflow.org/models/inception5h.zip > ./testdata/inception5h.zip unzip -o ./testdata/inception5h.zip tensorflow_inception_graph.pb -d ./testdata - name: Install ONNX test model run: | curl -sL https://huggingface.co/onnxmodelzoo/legacy_models/resolve/main/validated/vision/classification/inception_and_googlenet/googlenet/model/googlenet-9.onnx > ./testdata/googlenet-9.onnx curl -sL https://huggingface.co/opencv/face_recognition_sface/resolve/main/face_recognition_sface_2021dec.onnx > ./testdata/face_recognition_sface_2021dec.onnx curl -sL https://huggingface.co/opencv/face_detection_yunet/resolve/main/face_detection_yunet_2023mar.onnx > ./testdata/face_detection_yunet_2023mar.onnx curl -sL https://huggingface.co/opencv/object_tracking_vittrack/resolve/main/object_tracking_vittrack_2023sep.onnx > ./testdata/object_tracking_vittrack_2023sep.onnx - name: Install GOTURN test model shell: bash run: | curl -sL https://raw.githubusercontent.com/opencv/opencv_extra/c4219d5eb3105ed8e634278fad312a1a8d2c182d/testdata/tracking/goturn.prototxt > ./testdata/goturn.prototxt curl -sL https://github.com/opencv/opencv_extra/raw/c4219d5eb3105ed8e634278fad312a1a8d2c182d/testdata/tracking/goturn.caffemodel.zip.001 > ./testdata/goturn.caffemodel.zip.001 curl -sL https://github.com/opencv/opencv_extra/raw/c4219d5eb3105ed8e634278fad312a1a8d2c182d/testdata/tracking/goturn.caffemodel.zip.002 > ./testdata/goturn.caffemodel.zip.002 curl -sL https://github.com/opencv/opencv_extra/raw/c4219d5eb3105ed8e634278fad312a1a8d2c182d/testdata/tracking/goturn.caffemodel.zip.003 > ./testdata/goturn.caffemodel.zip.003 curl -sL https://github.com/opencv/opencv_extra/raw/c4219d5eb3105ed8e634278fad312a1a8d2c182d/testdata/tracking/goturn.caffemodel.zip.004 > ./testdata/goturn.caffemodel.zip.004 cat ./testdata/goturn.caffemodel.zip.00* > ./testdata/goturn.caffemodel.zip unzip -o ./testdata/goturn.caffemodel.zip goturn.caffemodel -d ./testdata/ - name: Set GoCV model env run: | go env echo "GOCV_TENSORFLOW_TEST_FILES=${env:GITHUB_WORKSPACE}\testdata" >> $env:GITHUB_ENV echo "GOCV_ONNX_TEST_FILES=${env:GITHUB_WORKSPACE}\testdata" >> $env:GITHUB_ENV echo "GOCV_TRACKER_GOTURN_TEST_FILES=${env:GITHUB_WORKSPACE}\testdata" >> $env:GITHUB_ENV - name: Test GoCV run: | go test -v -tags="matprofile,customenv" . - name: Test GoCV Contrib run: | go test -v -tags="matprofile,customenv" ./contrib ================================================ FILE: .gitignore ================================================ profile.cov count.out *.swp *.snap /parts /prime /stage .vscode/ /build .idea/ contrib/data.yaml contrib/testOilPainting.png ================================================ FILE: CHANGELOG.md ================================================ 0.43.0 --- * **all** - update to OpenCV 4.13 * **core** - add Copy method to Mat (#1346) - improve implementation for NewPointVectorFromPoints * **cuda** - add implmentations for more arith functions * **imgproc** - added in missing colormaps - paramters types in improc dilate and erode functions - use same test values as OpenCV tests for TestMinAreaRect and TestMinAreaRect2f * **videoio** - add RetrieveChannel function to make it possible to capture both video and audio * **examples** - Fix bugs and memory leaks in yolov8 example (#1349) * **contrib** - add support for Macbeth Chart module (MCC) (#1336) * **install** - windows: split download and build scripts for easier usage/integration 0.42.0 --- * **all** - Update to OpenCV 4.12.0 - Expose GpuMat's underlying object pointer - Add support for reduced size OpenCV builds using build tags for specific modules (cuda, contrib, etc.) - **cuda** - Add LShift and RShift function implementations - Add Compare function implementation - Add implementations for Norm, CalcNorm, and CalcNormDiff functions - Add Cuda Morphology Filter (#1311) - **core** - Add ReshapeWithSize() to provide specific control over the reshape operation - Add MeanStdDevWithMask for cv::meanStdDev with the optional mask - **video** - Add video tracker implementation using Vit DNN - Add cv::stereoRectify binding - **docker** - Update OpenCV containers to 4.12.0 - **docs** - Update ROADMAP links and add missing tracker functions - Update README with new features and usage - **build** - Use build tags for reduced size OpenCV builds with specific modules - **bugfix** - Fix bug where the package name was mismatched with contrib (#1293) 0.41.0 --- * **all** - opencv: patch for gstreamer cmake to handle static linking - **bugfix** - correct ifndef for wrappers to avoid include conflcts - temporary fix for https://github.com/docker/setup-qemu-action/issues/198 - **core** - add exception handling functions and try/catch blocks - return error from calls to OpenCV functions that cause exceptions. The error shows the OpenCV exception description from the exception caught. - **features2d** - Add BRISK with params support (#1280) - Params for features2d (#1283) - **photo** - add Decolor() function - **video** - ApplyWithParams for MOG2 bg subtractor (#1284) - **build** - add manually launched workflows to build ffmpeg, gstreamer, and opencv docker images - add `Dockerfile.opencv-ubuntu-24.04` for Ubuntu 24.04 support - add `opencv-ubuntu-24-04` step for build img workflow - **docker** - add static image with opencv and ffmpeg without gstreamer - gstreamer with a specific set of plugins - use OpenCV patch to build fully static GStreamer with plugins included - **docs** - update ROADMAP for some functions that were completed already - Update wrong links in Readme for face detection from URL and find chessboard - **make** - add install task for Ubuntu Manic Minotaur using @chewxy PR #1157 - update make tasks for jetson based on latest available info - Update Makefile (#1276) 0.40.0 --- * **all** - Add support for OpenCV 4.11.0 - Update license year to 2025 - **bugfix** - Correct signature for FindHomography, since dst is actually target format for the operation, not something changed by the operation - **core** - Added new Mat constructor and tests - Added NewMatFromPoint2fVector function - **videoio** - Change type of VideoCaptureProperties to int32 - Added VideoWriterFile with API and API Params - **docker** - Alpine static improved (#1243) - **make** - Improve Linux distro dtection code, and add specific dependendcies for Ubunutu 24.04 - **examples** - GStreamer VideoWriter example - **build** - Update homebrew when running macOS tests - Update GH actions in linux build to latest versions 0.39.0 --- - **bugfix** - Fixed MinGW link typo in README.md. - Fixed function name typo (#1236). - **core** - Added `FaceDetectorYN` example. - Query I/O API backends registry (#1237). - Face detector YN face recognizer SF (#1232). - **cuda** - Added `createLookUpTable` and `split` functions. - Added missing CUDA `imgproc` standalone functions. - Added `XXXWithStream` standalone functions. - **docker** - Added Dockerfile for container that can perform static builds of your own GoCV project (HighGUI not supported by static builds). - Added Dockerfile example showing how to build using static linking. - Added static build examples. - Updated version for `gocv-static-builder` image. - **build** - Updated workflow for Docker builds to latest versions. - Used most recent NVIDIA CUDA base image. - Used static FFmpeg build for static OpenCV build. - Downgraded static build to Go 1.22 to avoid [Go issue #68976](https://github.com/golang/go/issues/68976). - Modified Dockerfile used for static builds to build own versions for static linking. - Corrected build options for OpenCV on arm64 for static builds. - Separated build tags and linker flags for arm64 and amd64 targets. - Modified LDFLAGS for correct static compilation. - Removed extra file to clear space for static build/standard dev build images. - Added options for Linux arm64 and separate Darwin builds. - **cgo** - Changed tags for static OpenCV to `opencvstatic`. - Added options for Linux arm64 and separate Darwin builds. - Removed unneeded lib from link for Linux/arm64. - Modified LDFLAGS for correct static compilation. - **docs** - Added missing `videoio` functions to ROADMAP. - Updated ROADMAP with missing `objdetect` functions for DNN faces, and moved `aruco` under `objdetect` module. - Simplified the YOLO example. 0.38.0 --- * **bugfix** * aruco: correct test from latest OpenCV update * exclude freetype.cpp file from being included in windows build * feat(demosaicing): release mat when conversion to bayer encounters invalid pattern * imgproc HomographyMethod const values typo fixed * **build** * add macOS build for GH actions CI * adjust make and docker build files to build freetype support * correct ONNX DNN tests on Linux/macOS * move download for GOTURN models into testdata subdirectory * remove Caffe tests * run DNN tests on Windows * make: add task to run all cuda tests * make: build non-free modules when building opencv with cuda support * skip tests on macOS that are not passing due to OpenCV different results on macOS. See https://forum.opencv.org/t/match-template-different-results-on-mac-m1/10026 and other similar issues. * update all generated docker images to Go 1.23.1 * **examples** * add asciicam video to ascii in your terminal * add object detection example using YOLOv8 * **core** * add Closed() function to Mat * add OpenCV types for half-float values * add TransposeND() function * persistance implement Filestorage roadmap (#1208) * RotatedRect type constructors * **dnn** * add BlobFromImageWithParams() and BlobFromImagesWithParams() functions * add BlobRectToImageRect() and BlobRectsToImageRects() functions * allow ReadNet() function to only pass model file, and remove tests for Caffe * **features2d** * SIFT with params (#1186) * **highgui** * added window pollkey function (#1198) * added window WaitKeyEx support (#1195) * Window set mouse callback (#1220) * **imgcodecs** * added immultiread support * **imgproc** * feat(imgproc): demosaicing wrapper * add HomographyMethodRHO HomographyMethod added * **objdetect** * change QRCodeDetector signature to avoid pointer to slice * **video** * added TrackerGOTURN (see roadmap) * **videoio** * Capture from device and file with HW acceleration * **cuda** * add Closed() function to Mat/GpuMat * add DeviceSupports function * add implementations for AddWeighted and CopyMakeBorder functions * add Merge and Transpose functions * add support for convertFp16 function * add tests for demosaicing * feat(imgproc): demosaicing wrapper * correct go fmt error * **contrib/face** * added face recognizer interface (#1211) * BasicFaceRecognizer + EigenFaceRecognizer + FisherFaceRecognizer (#1213) * extra setters and getters for LBPHFaceRecognizer (#1194) * **contrib/freetype** * imported freetype code by lz1998 from PR 873 0.37.0 --- * **all** * Add support for OpenCV 4.10.0 0.36.1 --- * **bugfix** * Correct error in CUDA function signature * **test** * correct CUDA tests * **docker** * add test image for CUDA 12 0.36.0 --- * **all** * Add support for OpenCV 4.9.0 * update Go to version 1.22 * update minimum go version to 1.21 * **bugfix** * aruco: correct test from latest OpenCV update * **build** * add GH action for Windows * remove appveyor * adjusted Makefile to build for debian bookworm * **core** * Add additional signature for MinMaxLoc. * add color conversion alias * add Mahalanobis(), Inv(), Row(), amd Col() functions * add MulTransposed() function * add PCABackProject() and PCAProject() functions * add PSNR() function * add SVBackSubst() and SVDecomp() functions * **calib3d** * add FisheyeCalibrate, FisheyeDistortPoints, and CheckChessboard functions * Add func comments and update readme * add Rodrigues function * add SolvePnP function * Add more smoke tests * Initial commit of more stereo bindings * **feature2d** * Add interface for `Feature2D` algorithms * Asserting some algorithms conform to `Feature2D` * Prepend "Feature2D" prefix to component interfaces of Feature2D * **imgproc** * add CreateHanningWindow() * add EMD() * Add float version of BoxPoints and MinAreaRect * Add new binding for cv::Erode. * **videoio** * add Retrieve function * **contrib/xfeatures2d** * Add BriefDescriptorExtractor to xfeatures2d (#1114) * add NewSURFWithParams func * Add separate "Compute" bindings for detection algorithms (#1117) * **cuda/core** * ADD Cuda MultiplyWithStream (#1142) 0.35.0 --- * **all** * Add support for OpenCV 4.8.1 * correct Go formatting * **features2d** * Add Match method for BFMatcher * **build** * remove extra files from GH actions runner so GPU images builds have enough temp file space to run correctly * **make** * for build_raspi added conditional cmake build for 64 and 32bit platforms * remove ENABLE_VFPV3=ON and add WITH_TBB=ON from 64bit build. * added sudo_pre_install_clean to raspberry pi and jetson installs * change sudo_pre_install_clean to support cleanup on 64bit architechtures (arm and x86) 0.34.0 --- * **all** * Add support for OpenCV 4.8.0 * Add support for Go 1.21 * **build** * update all builds to use OpenCV 4.8.0 * **core** * Adds support for PCACompute * **docker** * add dockerfile for OpenCV static build * **make** * Leave one processor free instead of using all of them when building 0.33.0 --- * **bugfix** * Remove opencv2/aruco.hpp include * **all** * build performance tests with all OpenCV builds * **build** * build and push Ubuntu 22.04 base image with OpenCV 4.7.0 * docker images with opencv * docker production images with opencv 4.7.0 * Docker push to GHCR * **core** * Add ReduceArgMax and ReduceArgMin * **dnn** * improved NMSBoxes code * **docker** * add dockerfile for Ubuntu 22.04 OpenCV base image * updates to migrate to GHCR * **examples** * Deallocate Mats in feature-matching example. * Fix G108 (CWE-200) and G114 (CWE-676) * Fix G304 (CWE-22) and G307 (CWE-703) * Fix G304 (CWE-22) and G307 (CWE-703) * Missed #nosec tag * **make** * Ubuntu Jammy (22) opencv build support. 0.32.0 --- * **all** * update to OpenCV 4.7.0 * **core** * Add the number of thread setter and getter * **calib3d** * add EstimateAffinePartial2DWithParams() * **imgcodecs** * Add IMDecodeIntoMat to reduce heap allocations (#1035) * **imgproc** * add matchShapes function support * **objdetect** * move aruco from contrib and also refactor/update to match current OpenCV API * **photo** * add inpaint function * **video** * cv::KalmanFilter bindings. * **cuda** * add support for cuda::TemplateMatching * **docker** * update all dockerfiles for OpenCV 4.7.0/GoCV 0.32.0 * multiplatform for both amd64 and arm64 * install libjpeg-turbo into docker image * add Ubunutu 18.04 and 20.04 prebuilt OpenCV images * add dockerfile for older version of CUDA for those who cannot upgrade * **ci** * remove circleci * correct actions that trigger build * **make** * change download path for OpenCV release tag * **windows** * Update win_build_opencv.cmd * **docs** * correct docs on building docker * update ROADMAP * typo in comment * update comments style with gofmt * **openvino** * Add openvino Dockerfile * Fix OpenvinoVersion dangling pointer * Update env.sh and README.md for 2022.1 0.31.0 --- * **all** * update to OpenCV 4.6.0 * **build** * Switch to Github Actions for Linux CI build * Use go -tags static when verifying static build * **core** * Add Mat.ElemSize (#964) * avoid index out of range panic in NewPointsVectorFromPoints * **video** * add findTransformECC function * **contrib/ximgproc** * add PeiLinNormalization() function * add anisotropicDiffusion() function * implement edgePreservingFilter() * implement niBlackThreshold and thinning filters 0.30.0 --- * **all** * update to OpenCV 4.5.5 * **build** * add install_nonfree make task to build all opencv_contrib modules * correct download location for onnx test file * Update Makefile for missing version changes * **core** * correct how memory is being allocated for Eye(), Zeros(), and Ones() to address issue #930 * **calib3d** * Adding support for estimateAffine2DWithParams (#924) * **imgproc** * Add DrawContoursWithParams function * **photo** * Add bindings for fastNlMeansDenoising and fastNlMeansDenoisingColored * add detailEnhance function * add EdgePreservingFilter function * add PencilSketch function * add stylization function * **docs** * add godoc comments for FastNlMeansDenoising functions * update README with info on latest mingw-w64 t use for Windows builds * dnn pose detect examples correct the order of the argument variable name * **examples** * Fixed memory leaks in the motion detection example * **openvino** * Update env.sh and README.md * **windows** * use mingw-w64 8.1.0 for protobuf compile * **contrib** * add cv::wechat_qrcode::WeChatQRCode (#949) * Update cgo_static.go 0.29.0 --- * **all** * update to OpenCV 4.5.4 * **build** * add static build ability on windows * use tbb for all builds for CPU accelerated operations * **cuda** * implement a bunch of per-element operations * add get/set/reset device functions * add NewGpuMatWithSize() to preallocate device memory * Reshape() returns a new GpuMat with the changed data * correct use of Stream by adding WaitForCompletion() and passing pre-allocated GpuMats * **docs** * update ROADMAP from recent contributions * **videoio** * Fix open video capture with api test (#895) * **calib3d** * added EstimateAffine2D * findChessboardCornersSB * **aruco** * added many functions as part of initial implementation 0.28.0 --- * **all** * update to OpenCV 4.5.3 * make task and build tag for static build of OpenCV/GoCV on Linux * add Makefile tasks for OpenCV install on Nvidia Jetson * add gotest for more colorful test output running tests from containers * **build** * correcting output format for code coverage report * enforce rule that all Go code is correctly formatted * remove codecov * **core** * add NewPointVectorFromMat() and NewPoint2fVectorFromMat() functions * Fix possible MatProfile race by ordering remove before free. * **cuda** * add core functions for GpuMat like Cols(), Rows(), and Type() * initial implementation for the Flip function * **docs** * update ROADMAP from recent contributions * **examples** * correct list of examples and fix comment * **features2d** * Add NewORBWithParams * **tracking** * change MOSSE to KCF * **highgui** * Add function CreateTrackbarWithValue to Window type. * **imgcodec** * optimize IMEncode avoiding multiple data copies. * **imgproc** * Add CircleWithParams function * Add DilateWithParams() function (#827) * Add EllipseWithParams function * Add FillPolyWithParams function * Add PointPolygonTest function * Add RectangleWithParams function * **photo** * add MergeMertens, AlignMTB and Denoising function (#848) * **xphoto** * Add Xphoto contrib (#844) 0.27.0 --- * **all** * update to OpenCV 4.5.2 * **core** * add Append() to PointsVector/PointVector * add cv::RNG * add implementation for Point2fVector * add rand functions * add test coverage for PointsVector * create new PointsVector/PointVector wrappers to avoid repetitive memory copying for seeming innocent operations involving slices of image.Point * test coverage for Point2f * use PointVector for everything that we can to speed up pipeline when passing around Point vectors * use enum instead of int for Invert Method * **cuda** * adding HoughLinesDetector and HoughSegmentDetector * adding tests for the CannyEdgeDetector * some refactoring of the API * adding dockerfiles for OpenCV 4.5.2 with CUDA 11.2 * add GaussianFilter * correct signature and test for Threshold * implement SobelFilter * move arithm module functions into correct location * rename files to get rid of so many cudas * add abs function implementation * **dnn** * increase test coverage * **docker** * make all Dockerfiles names/tags more consistent * **docs** * add CUDA functions that need implementation to ROADMAP * remove invalid sections and add some missing functions from ROADMAP * **imgproc** * Add FindContoursWithParams function * Add ToImageYUV and ToImageYUVWithParams * **make** * add make task to show changelog for next release * **wechat_qrcode** * disable module in Windows due to linker error 0.26.0 --- * **all** * update to OpenCV 4.5.1 * **core** * add Matrix initializers: eye, ones, zeros (#758) * add multidimensional mat creation * add ndim mat constructor * added accumulators * added norm call with two mats (#600) * keep a reference to a []byte that backs a Mat. (#755) * remove guard for DataPtrUint8 since any Mat can be treated an Uint8 * add Mat IsContinuous() function, and ensure that any Mat data pointers used to create Go slices only apply to continuous Mats * fix buffer size for Go strings for 32-bit operating systems * **build** * bring back codecov.io * **calib3d** * correctly close mat after test * **dnn** * add ReadNetFromONNX and ReadNetFromONNXBytes (#760) * increase test coverage * **docker** * dockerfiles for opencv gpu builds * **docs** * corrected links to CUDA and OpenVINO * list all unimplemented functions in photo module * replace GoDocs with pkg docs * update ROADMAP from recent contributions * **imgproc** * add test coverage for GetTextSizeWithBaseline() * close all Mats even those based on memory slices * close Mat to avoid memory leak in ToImage() * refactoring of ToImage and ImageToMatXX functions * **openvino** * fix dldt repo in makefile for openvino * **os** * adding gcc-c++ package to rpm deps * **photo** * add SeamlessClone function * **profile** * add created mats in Split and ForwardLayers to profile (#780) 0.25.0 --- * **all** * update to opencv release 4.5.0 * **build** * add file dependencies needed for DNN tests * add verbose output for tests on CircleCI * also run unit tests on non-free algorithms. YMMV. * fix build with cuda * remove Travis and switch to CircleCI using Docker based builds * update CI builds to Go 1.15 * **core** * add mixChannels() method to Mat (#746) * Add toGoStrings helper * support ConvertToWithParams method * **dnn** * Add NMSBoxes function (#736) * Added ability to load Torch file. Tested features for extracting 128d vectors * fix using wrong type for unconnectedlayertype * use default ddepth for conversions to blob from image as recommended by @berak * **docker** * use separate dockerfile for opencv to avoid massive rebuild * **docs** * add recent contributions to ROADMAP and also add cuda functions still in need of implementation * display CircleCI badge in README * minor improvements to CUDA docs in READMEs * **features2d** * add FlannBasedMatcher * add drawmatches (#720) * fix memory leak in SIFT * **highgui** * refactored ROI methods * **imgproc** * Add option to return baseline with GetTextSizeWithBaseline * **objdetect** * Add QRCode DetectAndDecodeMulti * **videoio** * Add video capture properties and set preferred api backend (#739) * fix needed as discussed in golang/go issue #32479 0.24.0 --- * **all** * update Makefile and READMEChange constants and corresponding function signatures to have the correct types (#689) * replace master branch terminology with release * update to OpenCV 4.4.0 * **calib3d** * add FindHomography() * add function EstimateAffinePartial2D() * add GetAffineTransform() and GetAffineTransform2f() * add UndistortPoints(), FisheyeUndistortPoints() and EstimateNewCameraMatrixForUndistortRectify() * **core** * add MultiplyWithParams * **docs** * add recent contributions to ROADMAP * create CODE_OF_CONDUCT.md * update copyright year * **features2d** * close returned Mat from SIFT algorithm * fix issue 707 with DrawKeyPoints * SIFT patent now expired so is part of main OpenCV modules * **imgproc** * change struct to remove GNU old-style field designator extension warning 0.23.0 --- * **build** * update Makefile and README * update to use go1.14 * **calib3d** * add draw chessboard * **core** * fix memory leak in Mat.Size() and Mat.Split() (#580) * **cuda** * add build support * add cuda backend/target * add support for: * cv::cuda::CannyEdgeDetector * cv::cuda::CascadeClassifier Class * cv::cuda::HOG Class * remove breaking case statement * **dnn** * avoid parallel test runs * remove attempt at providing grayscale image blog conversion that uses mean adjustment * **docker** * docker file last command change (#505) * **docs** * add recent contributions to ROADMAP * **imgproc** * add ErodeWithParams function * add getGaussianKernel function * add Go Point2f type and update GetPerspectiveTransform() (#589) * add PhaseCorrelate binding (#626) * added Polylines feature * do not free contours data until after we have drawn the needed contours * Threshold() should return a value (#620) * **make** * added raspberry pi zero support to the makefile * **opencv** * update to OpenCV 4.3.0 * **openvino** * add build support * **windows** * add cmake flag for allocator stats counter type to avoid opencv issue #16398 0.22.0 --- * **bgsegm** * Add BackgroundSubtractorCNT * **calib3d** * Added undistort function (#520) * **core** * add functions (singular value decomposition, multiply between matrices, transpose matrix) (#559) * Add new funcs (#578) * add setIdentity() method to Mat * add String method (#552) * MatType: add missing constants * **dnn** * Adding GetLayerNames() * respect the bit depth of the input image to set the expected output when converting an image to a blob * **doc** * change opencv version 3.x to 4.x * **docker** * use Go1.13.5 for image * **imgcodecs** * Fix webp image decode error (#523) imgcodecs: optimize copy of data used for IMDecode method * **imgproc** * Add GetRectSubPix * Added ClipLine * Added InvertAffineTransform * Added LinearPolar function (#524) * correct ksize param used for MedianBlur unit test * Feature/put text with line type (#527) * FitEllipse * In FillPoly and DrawContours functions, remove func() wrap to avoid memory freed before calling opencv functions. (#543) * **objdetect** * Add support QR codes * **opencv** * update to OpenCV 4.2.0 release * **openvino** * Add openvino async * **test** * Tolerate imprecise result in SolvePoly * Tolerate imprecision in TestHoughLines 0.21.0 --- * **build** * added go clean --cache to clean target, see issue 458 * **core** * Add KMeans function * added MeanWithMask function for Mats (#487) * Fix possible resource leak * **cuda** * added cudaoptflow * added NewGpuMatFromMat which creates a GpuMat from a Mat * Support for CUDA Image Warping (#494) * **dnn** * add BlobFromImages (#467) * add ImagesFromBlob (#468) * **docs** * update ROADMAP with all recent contributions. Thank you! * **examples** * face detection from image url by using IMDecode (#499) * better format * **imgproc** * Add calcBackProject * Add CompareHist * Add DistanceTransform and Watershed * Add GrabCut * Add Integral * Add MorphologyExWithParams * **opencv** * update to version 4.1.2 * **openvino** * updates needed for 2019 R3 * **videoio** * Added ToCodec to convert FOURCC string to numeric representation (#485) 0.20.0 --- * **build** * Use Go 1.12.x for build * Update to OpenCV 4.1.0 * **cuda** * Initial cuda implementation * **docs** * Fix the command to install xquartz via brew/cask * **features2d** * Add support for SimpleBlobDetectorParams (#434) * Added FastFeatureDetectorWithParams * **imgproc** * Added function call to cv::morphologyDefaultBorderValue * **test** * Increase test coverage for FP16BlobFromImage() * **video** * Added calcOpticalFlowPyrLKWithParams * Addition of MOG2/KNN constructor with options 0.19.0 --- * **build** * Adds Dockerfile. Updates Makefile and README. * make maintainer tag same as dockerhub organization name * make sure to run tests for non-free contrib algorithms * update Appveyor build to use Go 1.12 * **calib3d** * add func InitUndistortRectifyMap (#405) * **cmd** * correct formatting of code in example * **core** * Added Bitwise Operations With Masks * update to OpenCV4.0.1 * **dnn** * add new backend and target types for NVIDIA and FPGA * Added blobFromImages in ROADMAP.md (#403) * Implement dnn methods for loading in-memory models. * **docker** * update Dockerfile to use OpenCV 4.0.1 * **docs** * update ROADMAP from recent contributions * **examples** * Fixing filename in caffe-classifier example * **imgproc** * Add 'MinEnclosingCircle' function * added BoxPoints function and BorderIsolated const * Added Connected Components * Added the HoughLinesPointSet function. * Implement CLAHE to imgproc * **openvino** * remove lib no longer included during non-FPGA installations * **test** * Add len(kp) == 232 to TestMSER, seems this is necessary for MacOS for some reason. 0.18.0 --- * **build** * add OPENCV_GENERATE_PKGCONFIG flag to generate pkg-config file * Add required curl package to the RPM and DEBS * correct name for zip directory used for code download * Removing linking against face contrib module * update CI to use 4.0.0 release * update Makefile and Windows build command file to OpenCV 4.0.0 * use opencv4 file for pkg-config * **core** * add ScaleAdd() method to Mat * **docs** * replace OpenCV 3.4.3 references with OpenCV 4 * update macOS installation info to refer to new OpenCV 4.0 brew * Updated function documentation with information about errors. * **examples** * Improve accuracy in hand gesture sample * **features2d** * update drawKeypoints() to use new stricter enum * **openvino** * changes to accommodate release 2018R4 * **profile** * add build tag matprofile to allow for conditional inclusion of custom profile * Add Mat profile wrapper in other areas of the library. * Add MatProfile. * Add MatProfileTest. * move MatProfile tests into separate test file so they only run when custom profiler active * **test** * Close images in tests. * More Closes in tests. * test that we are using 4.0.x version now * **videoio** * Return the right type and error when opening VideoCapture fails 0.17.0 --- * **build** * Update Makefile * update version of OpenCV used to 3.4.3 * use link to OpenCV 3.4.3 for Windows builds * **core** * add mulSpectrums wrapper * add PolarToCart() method to Mat * add Reduce() method to Mat * add Repeat() method to Mat * add Solve() method to Mat * add SolveCubic() method to Mat * add SolvePoly() method to Mat * add Sort() method to Mat * add SortIdx() method to Mat * add Trace() method to Mat * Added new MatType * Added Phase function * **dnn** * update test to match OpenCV 3.4.3 behavior * **docs** * Add example of how to run individual test * adding instructions for installing pkgconfig for macOS * fixed GOPATH bug. * update ROADMAP from recent contributions * **examples** * add condition to handle no circle found in circle detection example * **imgcodecs** * Added IMEncodeWithParams function * **imgproc** * Added Filter2D function * Added fitLine function * Added logPolar function * Added Remap function * Added SepFilter2D function * Added Sobel function * Added SpatialGradient function * **xfeatures2d** * do not run SIFT test unless OpenCV was built using OPENCV_ENABLE_NONFREE * do not run SURF test unless OpenCV was built using OPENCV_ENABLE_NONFREE 0.16.0 --- * **build** * add make task for Raspbian install with ARM hardware optimizations * use all available cores to compile OpenCV on Windows as discussed in issue #275 * download performance improvements for OpenCV installs on Windows * correct various errors and issues with OpenCV installs on Fedora and CentOS * **core** * correct spelling error in constant to fix issue #269 * implemented & added test for Mat.SetTo * improve Multiply() GoDoc and test showing Scalar() multiplication * mutator functions for Mat add, subtract, multiply, and divide for uint8 and float32 values. * **dnn** * add FP16BlobFromImage() function to convert an image Mat to a half-float aka FP16 slice of bytes * **docs** * fix a varible error in example code in README 0.15.0 --- * **build** * add max to make -j * improve path for Windows to use currently configured GOPATH * **core** * Add Mat.DataPtr methods for direct access to OpenCV data * Avoid extra copy in Mat.ToBytes + code review feedback * **dnn** * add test coverage for ParseNetBackend and ParseNetTarget * complete test coverage * **docs** * minor cleanup of language for install * use chdir instead of cd in Windows instructions * **examples** * add 'hello, video' example to repo * add HoughLinesP example * correct message on device close to match actual event * small change in display message for when file is input source * use DrawContours in motion detect example * **imgproc** * Add MinAreaRect() function * **test** * filling test coverage gaps * **videoio** * add test coverage for OpenVideoCapture 0.14.0 --- * **build** * Add -lopencv_calib3d341 to the linker * auto-confirm on package installs from make deps command * display PowerShell download status for OpenCV files * obtain caffe test config file from new location in Travis build * remove VS only dependencies from OpenCV build, copy caffe test config file from new location * return back to GoCV directory after OpenCV install * update for release of OpenCV v3.4.2 * use PowerShell for scripted OpenCV install for Windows * win32 version number has not changed yet * **calib3d** * Add Calibrate for Fisheye model(WIP) * **core** * add GetTickCount function * add GetTickFrequency function * add Size() and FromPtr() methods to Mat * add Total method to Mat * Added RotateFlag type * correct CopyTo to use pointer to Mat as destination * functions converting Image to Mat * rename implementation to avoid conflicts with Windows * stricter use of reflect.SliceHeader * **dnn** * add backend/device options to caffe and tensorflow DNN examples * add Close to Layer * add first version of dnn-pose-detection example * add further comments to object detection/tracking DNN example * add GetPerfProfile function to Net * add initial Layer implementation alongside enhancements to Net * add InputNameToIndex to Layer * add new functions allowing DNN backends such as OpenVINO * additional refactoring and comments in dnn-pose-detection example * cleanup DNN face detection example * correct const for device targets to be called Target * correct test that expected init slice with blank entries * do not init slice with blank entries, since added via append * further cleanup of DNN face detection example * make dnn-pose-detection example use Go channels for async operation * refactoring and additional comments for object detection/tracking DNN example * refine comment in header for style transfer example * working style transfer example * added ForwardLayers() to accomodate models with multiple output layers * **docs** * add scripted Windows install info to README * Added a sample gocv workflow contributing guideline * mention docker image in README. * mention work in progress on Android * simplify and add missing step in Linux installation in README * update contributing instructions to match latest version * update ROADMAP from recent calib3d module contribution * update ROADMAP from recent imgproc histogram contribution * **examples** * cleanup header for caffe dnn classifier * show how to use either Caffe or Tensorflow for DNN object detection * further improve dnn samples * rearrange and add comments to dnn style transfer example * remove old copy of pose detector * remove unused example * **features2d** * free memory allocation bug for C.KeyPoints as pointed out by @tzununbekov * Adding opencv::drawKeypoints() support * **imgproc** * add equalizeHist function * Added opencv::calcHist implementation * **openvino** * add needed environment config to execute examples * further details in README explaining how to use * remove opencv contrib references as they are not included in OpenVINO * **videoio** * Add OpenVideoCapture * Use gocv.VideoCaptureFile if string is specified for device. 0.13.0 --- * **build** * Add cgo directives to contrib * contrib subpackage also needs cpp 11 or greater for a warning free build on Linux * Deprecate env scripts and update README * Don't set --std=c++1z on non-macOS * Remove CGO vars from CI and correct Windows cgo directives * Support pkg-config via cgo directives * we actually do need cpp 11 or greater for a warning free build on Linux * **docs** * add a Github issue template to project * provide specific examples of using custom environment * **imgproc** * add HoughLinesPWithParams() function * **openvino** * add build tag specific to openvino * add roadmap info * add smoke test for ie 0.12.0 --- * **build** * convert to CRLF * Enable verbosity for travisCI * Further improvements to Makefile * **core** * Add Rotate, VConcat * Adding InScalarRange and NewMatFromScalarWithSize functions * Changed NewMatFromScalarWithSize to NewMatWithSizeFromScalar * implement CheckRange(), Determinant(), EigenNonSymmetric(), Min(), and MinMaxIdx() functions * implement PerspectiveTransform() and Sqrt() functions * implement Transform() and Transpose() functions * Make toByteArray safe for empty byte slices * Renamed InScalarRange to InRangeWithScalar * **docs** * nicer error if we can't read haarcascade_frontalface_default * correct some ROADMAP links * Fix example command. * Fix executable name in help text. * update ROADMAP from recent contributions * **imgproc** * add BoxFilter and SqBoxFilter functions * Fix the hack to convert C arrays to Go slices. * **videoio** * Add isColor to VideoWriterFile * Check numerical parameters for gocv.VideoWriterFile * CodecString() * **features2d** * add BFMatcher * **img_hash** * Add contrib/img_hash module * add GoDocs for new img_hash module * Add img-similarity as an example for img_hash * **openvino** * adds support for Intel OpenVINO toolkit PVL * starting experimental work on OpenVINO IE * update README files for Intel OpenVINO toolkit support * WIP on IE can load an IR network 0.11.0 --- * **build** * Add astyle config * Astyle cpp/h files * remove duplication in Makefile for astyle * **core** * Add GetVecfAt() function to Mat * Add GetVeciAt() function to Mat * Add Mat.ToImage() * add MeanStdDev() method to Mat * add more functions * Compare Mat Type directly * further cleanup for GoDocs and enforce type for convariance operations * Make borderType in CopyMakeBorder be type BorderType * Mat Type() should return MatType * remove unused convenience functions * use Mat* to indicate when a Mat is mutable aka an output parameter * **dnn** * add a ssd sample and a GetBlobChannel helper * added another helper func and a pose detection demo * **docs** * add some additional detail about adding OpenCV functions to GoCV * updates to contribution guidelines * fill out complete list of needed imgproc functions for sections that have work started * indicate that missing imgproc functions need implementation * mention the WithParams patterns to be used for functions with default params * update README for the Mat* based API changes * update ROADMAP for recent changes especially awesome recent core contributions from @berak * **examples** * Fix tf-classifier example * move new DNN advanced examples into separate folders * Update doc for the face contrib package * Update links in caffe-classifier demo * WIP on hand gestures tracking example * **highgui** * fix constant in NewWindow * **imgproc** * Add Ellipse() and FillPoly() functions * Add HoughCirclesWithParams() func * correct output Mat to for ConvexHull() * rename param being used for Mat image to be modified * **tracking** * add support for TrackerMIL, TrackerBoosting, TrackerMedianFlow, TrackerTLD, TrackerKCF, TrackerMOSSE, TrackerCSRT trackers * removed mutitracker, added Csrt, rebased * update GoDocs and minor renaming based on gometalint output 0.10.0 --- * **build** * install unzip before build * overwrite when unzipping file to install Tensorflow test model * use -DCPU_DISPATCH= flag for build to avoid problem with disabled AVX on Windows * update unzipped file when installing Tensorflow test model * **core** * add Compare() and CountNonZero() functions * add getter/setter using optional params for multi-dimensional Mat using row/col/channel * Add mat subtract function * add new toRectangle function to DRY up conversion from CRects to []image.Rectangle * add split subtract sum wrappers * Add toCPoints() helper function * Added Mat.CopyToWithMask() per #47 * added Pow() method * BatchDistance BorderInterpolate CalcCovarMatrix CartToPolar * CompleteSymm ConvertScaleAbs CopyMakeBorder Dct * divide, multiply * Eigen Exp ExtractChannels * operations on a 3d Mat are not same as a 2d multichannel Mat * resolve merge conflict with duplicate Subtract() function * run gofmt on core tests * Updated type for Mat.GetUCharAt() and Mat.SetUCharAt() to reflect uint8 instead of int8 * **docs** * update ROADMAP of completed functions in core from recent contributions * **env** * check loading resources * Add distribution detection to deps rule * Add needed environment variables for Linux * **highgui** * add some missing test coverage on WaitKey() * **imgproc** * Add adaptive threshold function * Add pyrDown and pyrUp functions * Expose DrawContours() * Expose WarpPerspective and GetPerspectiveTransform * implement ConvexHull() and ConvexityDefects() functions * **opencv** * update to OpenCV version 3.4.1 0.9.0 --- * **bugfix** * correct several errors in size parameter ordering * **build** * add missing opencv_face lib reference to env.sh * Support for non-brew installs of opencv on Darwin * **core** * add Channels() method to Mat * add ConvertTo() and NewMatFromBytes() functions * add Type() method to Mat * implement ConvertFp16() function * **dnn** * use correct size for blob used for Caffe/Tensorflow tests * **docs** * Update copyright date and Apache 2.0 license to include full text * **examples** * cleanup mjpeg streamer code * cleanup motion detector comments * correct use of defer in loop * use correct size for blob used for Caffe/Tensorflow examples * **imgproc** * Add cv::approxPolyDP() bindings. * Add cv::arcLength() bindings. * Add cv::matchTemplate() bindings. * correct comment and link for Blur function * correct docs for BilateralFilter() 0.8.0 --- * **core** * add ColorMapFunctions and their test * add Mat ToBytes * add Reshape and MinMaxLoc functions * also delete points * fix mistake in the norm function by taking NormType instead of int as parameter * SetDoubleAt func and his test * SetFloatAt func and his test * SetIntAt func and his test * SetSCharAt func and his test * SetShortAt func and his test * SetUCharAt fun and his test * use correct delete operator for array of new, eliminates a bunch of memory leaks * **dnn** * add support for loading Tensorflow models * adjust test for Caffe now that we are auto-cropping blob * first pass at adding Caffe support * go back to older function signature to avoid version conflicts with Intel CV SDK * properly close DNN Net class * use approx. value from test result to account forr windows precision differences * **features2d** * implement GFTTDetector, KAZE, and MSER algorithms * modify MSER test for Windows results * **highgui** * un-deprecate WaitKey function needed for CLI apps * **imgcodec** * add fileExt type * **imgproc** * add the norm wrapper and use it in test for WarpAffine and WarpAffineWithParams * GetRotationMatrix2D, WarpAffine and WarpAffineWithParams * use NormL2 in wrap affine * **pvl** * add support for FaceRecognizer * complete wrappers for all missing FaceDetector functions * update instructions to match R3 of Intel CV SDK * **docs** * add more detail about exactly which functions are not yet implememented in the modules that are marked as 'Work Started' * add refernece to Tensorflow example, and also suggest brew upgrade for MacOS * improve ROADMAP to help would-be contributors know where to get started * in the readme, explain compiling to a static library * remove many godoc warnings by improving function descriptions * update all OpenCV 3.3.1 references to v3.4.0 * update CGO_LDFLAGS references to match latest requirements * update contribution guidelines to try to make it more inviting * **examples** * add Caffe classifier example * add Tensorflow classifier example * fixed closing window in examples in infinite loop * fixed format of the examples with gofmt * **test** * add helper function for test : floatEquals * add some attiribution from test function * display OpenCV version in case that test fails * add round function to allow for floating point accuracy differences due to GPU usage. * **build** * improve search for already installed OpenCV on MacOS * update Appveyor build to Opencv 3.4.0 * update to Opencv 3.4.0 0.7.0 --- * **core** * correct Merge implementation * **docs** * change wording and formatting for roadmap * update roadmap for a more complete list of OpenCV functionality * sequence docs in README in same way as the web site, aka by OS * show in README that some work was done on contrib face module * **face** * LBPH facerecognizer bindings * **highgui** * complete implementation for remaining API functions * **imgcodecs** * add IMDecode function * **imgproc** * elaborate on HoughLines & HoughLinesP tests to fetch a few individual results * **objdetect** * add GroupRectangles function * **xfeatures2d** * add SIFT and SURF algorithms from OpenCV contrib * improve description for OpenCV contrib * run tests from OpenCV contrib 0.6.0 --- * **core** * Add cv::LUT binding * **examples** * do not try to go fullscreen, since does not work on OSX * **features2d** * add AKAZE algorithm * add BRISK algorithm * add FastFeatureDetector algorithm * implement AgastFeatureDetector algorithm * implement ORB algorithm * implement SimpleBlobDetector algorithm * **osx** * Fix to get the OpenCV path with "brew info". * **highgui** * use new Window with thread lock, and deprecate WaitKey() in favor of Window.WaitKey() * use Window.WaitKey() in tests * **imgproc** * add tests for HoughCircles * **pvl** * use correct Ptr referencing * **video** * use smart Ptr for Algorithms thanks to @alalek * use unsafe.Pointer for Algorithm * move tests to single file now that they all pass 0.5.0 --- * **core** * add TermCriteria for iterative algorithms * **imgproc** * add CornerSubPix() and GoodFeaturesToTrack() for corner detection * **objdetect** * add DetectMultiScaleWithParams() for HOGDescriptor * add DetectMultiScaleWithParams() to allow override of defaults for CascadeClassifier * **video** * add CalcOpticalFlowFarneback() for Farneback optical flow calculations * add CalcOpticalFlowPyrLK() for Lucas-Kanade optical flow calculations * **videoio** * use temp directory for Windows test compat. * **build** * enable Appveyor build w/cache * **osx** * update env path to always match installed OpenCV from Homebrew 0.4.0 --- * **core** * Added cv::mean binding with single argument * fix the write-strings warning * return temp pointer fix * **examples** * add counter example * add motion-detect command * correct counter * remove redundant cast and other small cleanup * set motion detect example to fullscreen * use MOG2 for continous motion detection, instead of simplistic first frame only * **highgui** * ability to better control the fullscreen window * **imgproc** * add BorderType param type for GaussianBlur * add BoundingRect() function * add ContourArea() function * add FindContours() function along with associated data types * add Laplacian and Scharr functions * add Moments() function * add Threshold function * **pvl** * add needed lib for linker missing in README * **test** * slightly more permissive version test * **videoio** * Add image compression flags for gocv.IMWrite * Fixed possible looping out of compression parameters length * Make dedicated function to run cv::imwrite with compression parameters 0.3.1 --- * **overall** * Update to use OpenCV 3.3.1 0.3.0 --- * **docs** * Correct Windows build location from same @jpfarias fix to gocv-site * **core** * Add Resize * Add Mat merge and Discrete Fourier Transform * Add CopyTo() and Normalize() * Implement various important Mat logical operations * **video** * BackgroundSubtractorMOG2 algorithm now working * Add BackgroundSubtractorKNN algorithm from video module * **videoio** * Add VideoCapture::get * **imgproc** * Add BilateralFilter and MedianBlur * Additional drawing functions implemented * Add HoughCircles filter * Implement various morphological operations * **highgui** * Add Trackbar support * **objdetect** * Add HOGDescriptor * **build** * Remove race from test on Travis, since it causes CGo segfault in MOG2 0.2.0 --- * Switchover to custom domain for package import * Yes, we have Windows 0.1.0 --- Initial release! - [X] Video capture - [X] GUI Window to display video - [X] Image load/save - [X] CascadeClassifier for object detection/face tracking/etc. - [X] Installation instructions for Ubuntu - [X] Installation instructions for OS X - [X] Code example to use VideoWriter - [X] Intel CV SDK PVL FaceTracker support - [X] imgproc Image processing - [X] Travis CI build - [X] At least minimal test coverage for each OpenCV class - [X] Implement more of imgproc Image processing ================================================ FILE: CODE_OF_CONDUCT.md ================================================ # Contributor Covenant Code of Conduct ## Our Pledge In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation. ## Our Standards Examples of behavior that contributes to creating a positive environment include: * Using welcoming and inclusive language * Being respectful of differing viewpoints and experiences * Gracefully accepting constructive criticism * Focusing on what is best for the community * Showing empathy towards other community members Examples of unacceptable behavior by participants include: * The use of sexualized language or imagery and unwelcome sexual attention or advances * Trolling, insulting/derogatory comments, and personal or political attacks * Public or private harassment * Publishing others' private information, such as a physical or electronic address, without explicit permission * Other conduct which could reasonably be considered inappropriate in a professional setting ## Our Responsibilities Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. ## Scope This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at info@hybridgroup.com. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. ## Attribution This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html [homepage]: https://www.contributor-covenant.org For answers to common questions about this code of conduct, see https://www.contributor-covenant.org/faq ================================================ FILE: CONTRIBUTING.md ================================================ # How to contribute Thank you for your interest in improving GoCV. We would like your help to make this project better, so we appreciate any contributions. See if one of the following descriptions matches your situation: ### Newcomer to GoCV, to OpenCV, or to computer vision in general We'd love to get your feedback on getting started with GoCV. Run into any difficulty, confusion, or anything else? You are not alone. We want to know about your experience, so we can help the next people. Please open a Github issue with your questions, or get in touch directly with us. ### Something in GoCV is not working as you expect Please open a Github issue with your problem, and we will be happy to assist. ### Something you want/need from OpenCV does not appear to be in GoCV We probably have not implemented it yet. Please take a look at our [ROADMAP.md](ROADMAP.md). Your pull request adding the functionality to GoCV would be greatly appreciated. ### You found some Python code on the Internet that performs some computer vision task, and you want to do it using GoCV Please open a Github issue with your needs, and we can see what we can do. ## How to use our Github repository The `release` branch of this repo will always have the latest released version of GoCV. All of the active development work for the next release will take place in the `dev` branch. GoCV will use semantic versioning and will create a tag/release for each release. Here is how to contribute back some code or documentation: - Fork repo - Create a feature branch off of the `dev` branch - Make some useful change - Submit a pull request against the `dev` branch. - Be kind ## How to add a function from OpenCV to GoCV Here are a few basic guidelines on how to add a function from OpenCV to GoCV: - Please open a Github issue. We want to help, and also make sure that there is no duplications of efforts. Sometimes what you need is already being worked on by someone else. - Use the proper Go style naming `MissingFunction()` for the Go wrapper. - Make any output parameters `Mat*` to indicate to developers that the underlying OpenCV data will be changed by the function. - Use Go types when possible as parameters for example `image.Point` and then convert to the appropriate OpenCV struct. Also define a new type based on `int` and `const` values instead of just passing "magic numbers" as params. For example, the `VideoCaptureProperties` type used in `videoio.go`. - Always add the function to the GoCV file named the same as the OpenCV module to which the function belongs. - If the new function is in a module that is not yet implemented by GoCV, a new set of files for that module will need to be added. - Always add a "smoke" test for the new function being added. We are not testing OpenCV itself, but just the GoCV wrapper, so all that is needed generally is just exercising the new function. - If OpenCV has any default params for a function, we have been implementing 2 versions of the function since Go does not support overloading. For example, with a OpenCV function: ```c opencv::xYZ(int p1, int p2, int p3=2, int p4=3); ``` We would define 2 functions in GoCV: ```go // uses default param values XYZ(p1, p2) // sets each param XYZWithParams(p2, p2, p3, p4) ``` ## How to run tests To run the tests: ``` go test . go test ./contrib/. ``` If you want to run an individual test, you can provide a RegExp to the `-run` argument: ``` go test -run TestMat ``` If you are using Intel OpenVINO, you can run those tests using: ``` go test ./openvino/... ``` ## Contributing workflow This section provides a short description of one of many possible workflows you can follow to contribute to `GoCV`. This workflow is based on multiple [git remotes](https://git-scm.com/docs/git-remote) and it's by no means the only workflow you can use to contribute to `GoCV`. However, it's an option that might help you get started quickly without too much hassle as this workflow lets you work off the `gocv` repo directory path! Assuming you have already forked the `gocv` repo, you need to add a new `git remote` which will point to your GitHub fork. Notice below that you **must** `cd` to `gocv` repo directory before you add the new `git remote`: ```shell cd $GOPATH/src/gocv.io/x/gocv git remote add gocv-fork https://github.com/YOUR_GH_HANDLE/gocv.git ``` Note, that in the command above we called our new `git remote`, **gocv-fork** for convenience so we can easily recognize it. You are free to choose any remote name of your liking. You should now see your new `git remote` when running the command below: ```shell git remote -v gocv-fork https://github.com/YOUR_GH_HANDLE/gocv.git (fetch) gocv-fork https://github.com/YOUR_GH_HANDLE/gocv.git (push) origin https://github.com/hybridgroup/gocv (fetch) origin https://github.com/hybridgroup/gocv (push) ``` Before you create a new branch from `dev` you should fetch the latests commits from the `dev` branch: ```shell git fetch origin dev ``` You want the `dev` branch in your `gocv` fork to be in sync with the `dev` branch of `gocv`, so push the earlier fetched commits to your GitHub fork as shown below. Note, the `-f` force switch might not be needed: ```shell git push gocv-fork dev -f ``` Create a new feature branch from `dev`: ```shell git checkout -b new-feature ``` After you've made your changes you can run the tests using the `make` command listed below. Note, you're still working off the `gocv` project root directory, hence running the command below does not require complicated `$GOPATH` rewrites or whatnot: ```shell make test ``` Once the tests have passed, commit your new code to the `new-feature` branch and push it to your fork running the command below: ```shell git push gocv-fork new-feature ``` You can now open a new PR from `new-feature` branch in your forked repo against the `dev` branch of `gocv`. ================================================ FILE: Dockerfile ================================================ # to build this docker image: # docker build . FROM ghcr.io/hybridgroup/opencv:4.13.0 ENV GOPATH /go COPY . /go/src/gocv.io/x/gocv/ WORKDIR /go/src/gocv.io/x/gocv RUN go build -tags example -o /build/gocv_version ./cmd/version/ CMD ["/build/gocv_version"] ================================================ FILE: Dockerfile-static ================================================ # to build this docker image: # docker buildx build -f Dockerfile-static -t gocv-static --platform=linux/amd64,linux/arm64 . # FROM --platform=$BUILDPLATFORM ghcr.io/hybridgroup/opencv:4.13.0-static AS gocv-build ENV GOPATH /go COPY . /go/src/gocv.io/x/gocv/ WORKDIR /go/src/gocv.io/x/gocv RUN --mount=target=. \ --mount=type=cache,target=/root/.cache/go-build \ --mount=type=cache,target=/go/pkg/mod \ go build -tags static -o /build/gocv_version ./cmd/version/ FROM debian:bullseye AS final COPY --from=gocv-build /build/gocv_version /run/gocv_version CMD ["/run/gocv_version"] ================================================ FILE: Dockerfile-static-alpine ================================================ # syntax=docker/dockerfile:1.3 # To build release: # docker buildx build -f Dockerfile.static-alpine -t gocv-static-alpine --platform=linux/arm64,linux/amd64 --load . FROM --platform=$BUILDPLATFORM ghcr.io/hybridgroup/opencv:4.11-alpine AS builder-amd64 RUN apk update && apk add --no-cache \ build-base \ cmake \ git \ wget \ unzip \ pkgconfig # Install Go ARG GO_VERSION=1.22.8 RUN wget https://golang.org/dl/go${GO_VERSION}.linux-amd64.tar.gz && \ tar -C /usr/local -xzf go${GO_VERSION}.linux-amd64.tar.gz && \ rm go${GO_VERSION}.linux-amd64.tar.gz ENV PATH="/usr/local/go/bin:${PATH}" ENV GOPATH /go # Copy the GoCV source code COPY . /go/src/gocv.io/x/gocv/ WORKDIR /go/src/gocv.io/x/gocv ENV CGO_CXXFLAGS="--std=c++11" ENV CGO_CPPFLAGS="-I/usr/local/include/opencv4" ENV CGO_LDFLAGS="-static -L/usr/local/lib -lopencv_gapi -lopencv_stitching -lopencv_alphamat -lopencv_aruco -lopencv_bgsegm -lopencv_bioinspired -lopencv_ccalib -lopencv_dnn_objdetect -lopencv_dnn_superres -lopencv_dpm -lopencv_face -lopencv_fuzzy -lopencv_hfs -lopencv_img_hash -lopencv_intensity_transform -lopencv_line_descriptor -lopencv_mcc -lopencv_quality -lopencv_rapid -lopencv_reg -lopencv_rgbd -lopencv_saliency -lopencv_signal -lopencv_stereo -lopencv_structured_light -lopencv_phase_unwrapping -lopencv_superres -lopencv_optflow -lopencv_surface_matching -lopencv_tracking -lopencv_highgui -lopencv_datasets -lopencv_text -lopencv_plot -lopencv_videostab -lopencv_videoio -lopencv_wechat_qrcode -lopencv_xfeatures2d -lopencv_shape -lopencv_ml -lopencv_ximgproc -lopencv_video -lopencv_xobjdetect -lopencv_objdetect -lopencv_calib3d -lopencv_imgcodecs -lopencv_features2d -lopencv_dnn -lopencv_flann -lopencv_xphoto -lopencv_photo -lopencv_imgproc -lopencv_core -L/usr/local/lib/opencv4/3rdparty -llibprotobuf -lade -littnotify -llibwebp -llibtiff -llibopenjp2 -lippiw -lippicv -llibjpeg-turbo -llibpng -L/lib -lzlib -lIlmImf -ldl -lm -lpthread -lrt -lavdevice -lm -latomic -lavfilter -pthread -lm -latomic -lswscale -lm -latomic -lpostproc -lm -latomic -lavformat -lm -latomic -lavcodec -lvpx -lx264 -lswresample -lm -latomic -lavutil -lbz2_static -llzma" # Build the GoCV version command RUN --mount=target=. \ --mount=type=cache,target=/root/.cache/go-build \ --mount=type=cache,target=/go/pkg/mod \ go build -tags customenv -o /build/gocv_version ./cmd/version/ # Stage 3: Final image FROM alpine:3.20 AS final # Copy the GoCV version command COPY --from=builder /build/gocv_version /run/gocv_version # Run the GoCV version command CMD ["/run/gocv_version"] ================================================ FILE: Dockerfile-static-builder ================================================ # to build this docker image: # docker build -f Dockerfile-static-builder -t gocv-static-builder . # or for multi-arch builds: # docker buildx build -f Dockerfile-static-builder -t ghcr.io/hybridgroup/gocv-static-builder --platform=linux/amd64,linux/arm64 --push . # # to use this docker image: # cd /path/to/my/project # docker run --rm -e "BINARYNAME=mjpeg-streamer" -e "SRCPATH=./cmd/mjpeg-streamer" -v $(pwd):/src -v $(pwd)/build:/build -a stdout -a stderr --platform linux/amd64 gocv-static-builder # # NOTE that you cannot use highgui from the static build! # FROM --platform=$BUILDPLATFORM ghcr.io/hybridgroup/opencv:4.13.0-static AS gocv-static-builder WORKDIR /src ENV BINARYNAME=gocv_static_binary ENV SRCPATH=. CMD go build -tags static -o /build/$BINARYNAME -buildvcs=false $SRCPATH ================================================ FILE: Dockerfile-test ================================================ # To build: # docker build -f Dockerfile-test -t gocv-test . # # To run tests: # xhost + # docker run -it --rm -e DISPLAY=$DISPLAY -v /tmp/.X11-unix:/tmp/.X11-unix gocv-test-4.x # xhost - # FROM ghcr.io/hybridgroup/opencv:4.13.0 AS gocv-test-4.13 ENV GOPATH /go COPY . /go/src/gocv.io/x/gocv/ WORKDIR /go/src/gocv.io/x/gocv RUN go install github.com/rakyll/gotest@latest ENTRYPOINT ["gotest", "-v", ".", "./contrib/..."] ================================================ FILE: Dockerfile-test.gpu-cuda-10 ================================================ # To build: # docker build -f Dockerfile-test.gpu-cuda-10 -t gocv-test-gpu-cuda-10 . # # To run tests: # docker run -it --rm --gpus all gocv-test-gpu-cuda-10 # FROM ghcr.io/hybridgroup/opencv:4.13.0-gpu-cuda-10 AS gocv-gpu-test-cuda-10 ENV GOPATH /go ENV PATH="${PATH}:/go/bin" COPY . /go/src/gocv.io/x/gocv/ WORKDIR /go/src/gocv.io/x/gocv RUN go install github.com/rakyll/gotest@latest ENTRYPOINT ["gotest", "-v", "./cuda/..."] ================================================ FILE: Dockerfile-test.gpu-cuda-11 ================================================ # To build: # docker build -f Dockerfile-test.gpu-cuda-11 -t gocv-test-gpu-cuda-11 . # # To run tests: # docker run -it --rm --gpus all gocv-test-gpu-cuda-11 # FROM ghcr.io/hybridgroup/opencv:4.13.0-gpu-cuda-11 AS gocv-gpu-test-cuda-11 ENV GOPATH /go ENV PATH="${PATH}:/go/bin" COPY . /go/src/gocv.io/x/gocv/ WORKDIR /go/src/gocv.io/x/gocv RUN go install github.com/rakyll/gotest@latest ENTRYPOINT ["gotest", "-v", "./cuda/..."] ================================================ FILE: Dockerfile-test.gpu-cuda-11.2.2 ================================================ # To build: # docker build -f Dockerfile-test.gpu-cuda-11.2.2 -t gocv-test-gpu-cuda-11.2.2 . # # To run tests: # docker run -it --rm --gpus all gocv-test-gpu-cuda-11.2.2 # FROM ghcr.io/hybridgroup/opencv:4.13.0-gpu-cuda-11.2.2 AS gocv-gpu-test-cuda-11 ENV GOPATH /go ENV PATH="${PATH}:/go/bin" COPY . /go/src/gocv.io/x/gocv/ WORKDIR /go/src/gocv.io/x/gocv RUN go install github.com/rakyll/gotest@latest ENTRYPOINT ["gotest", "-v", "./cuda/..."] ================================================ FILE: Dockerfile-test.gpu-cuda-12 ================================================ # To build: # docker build -f Dockerfile-test.gpu-cuda-12 -t gocv-test-gpu-cuda-12 . # # To run tests: # docker run -it --rm --gpus all gocv-test-gpu-cuda-12 # FROM ghcr.io/hybridgroup/opencv:4.13.0-gpu-cuda-12 AS gocv-gpu-test-cuda-12 ENV GOPATH /go ENV PATH="${PATH}:/go/bin" COPY . /go/src/gocv.io/x/gocv/ WORKDIR /go/src/gocv.io/x/gocv RUN go install github.com/rakyll/gotest@latest ENTRYPOINT ["gotest", "-v", "./cuda/..."] ================================================ FILE: Dockerfile-test.gpu-cuda-13 ================================================ # To build: # docker build -f Dockerfile-test.gpu-cuda-13 -t gocv-test-gpu-cuda-13 . # # To run tests: # docker run -it --rm --gpus all gocv-test-gpu-cuda-13 # FROM ghcr.io/hybridgroup/opencv:4.13.0-gpu-cuda-13 AS gocv-gpu-test-cuda-13 ENV GOPATH /go ENV PATH="${PATH}:/go/bin" COPY . /go/src/gocv.io/x/gocv/ WORKDIR /go/src/gocv.io/x/gocv RUN go install github.com/rakyll/gotest@latest ENTRYPOINT ["gotest", "-v", "./cuda/..."] ================================================ FILE: Dockerfile.ffmpeg-static-alpine ================================================ # syntax=docker/dockerfile:1.3 # To build release: # docker buildx build -f Dockerfile.ffmpeg-static-alpine -t ghcr.io/hybridgroup/ffmpeg:5.16-alpine --platform=linux/arm64,linux/amd64 --load . # linux/amd64 build FROM --platform=linux/amd64 alpine:3.20 AS builder-amd64 WORKDIR / ARG FFMPEG_VERSION=5.1.6 ARG XZ_VERSION=5.6.3 # download xz RUN wget -O xz-${XZ_VERSION}.tar.bz2 "https://github.com/tukaani-project/xz/releases/download/v${XZ_VERSION}/xz-${XZ_VERSION}.tar.bz2" && \ tar -xf xz-${XZ_VERSION}.tar.bz2 # download bzip2 RUN wget -O bzip2-master.tar.bz2 "https://gitlab.com/bzip2/bzip2/-/archive/master/bzip2-master.tar.bz2" && \ tar -xf bzip2-master.tar.bz2 # download ffmpeg source RUN wget -O ffmpeg-5.0.tar.bz2 "https://www.ffmpeg.org/releases/ffmpeg-${FFMPEG_VERSION}.tar.bz2" && \ tar -xf ffmpeg-5.0.tar.bz2 # Install dependencies RUN apk update && apk add --no-cache \ build-base \ cmake \ git \ diffutils \ perl \ wget \ unzip \ pkgconfig \ libjpeg-turbo-dev \ libpng-dev \ libwebp-dev \ eigen-dev \ nasm yasm \ bzip2 xz zlib-dev x264-dev libvpx-dev \ opus-dev dav1d-dev python3 # Build and install xz RUN cd xz-${XZ_VERSION} && \ ./configure --disable-shared && \ make && make install # Build and install bzip2 RUN cd bzip2-master && \ mkdir build && cd build && \ cmake .. -DCMAKE_BUILD_TYPE="Release" -DENABLE_STATIC_LIB=ON -DENABLE_LIB_ONLY=ON && \ cmake --build . --target install # Build and install libvpx RUN cd ffmpeg-${FFMPEG_VERSION} && \ git -C libvpx pull 2> /dev/null || git clone --depth 1 https://chromium.googlesource.com/webm/libvpx.git && \ cd libvpx && \ ./configure --enable-static --disable-examples --disable-unit-tests --enable-vp9-highbitdepth --as=yasm && \ make -j $(nproc --all) && make install # Now finish building ffmpeg RUN cd ffmpeg-${FFMPEG_VERSION} && \ ./configure --pkg-config-flags="--static" \ --enable-static --disable-shared --enable-gpl --enable-libx264 --enable-libvpx --enable-zlib \ --disable-sdl2 --disable-vaapi --disable-vdpau --disable-v4l2-m2m --disable-doc && \ make -j $(nproc --all) && make install # linux/arm64 build FROM --platform=linux/arm64 alpine:3.20 AS builder-arm64 WORKDIR / ARG FFMPEG_VERSION=5.1.6 ARG XZ_VERSION=5.6.3 # download xz RUN wget -O xz-${XZ_VERSION}.tar.bz2 "https://github.com/tukaani-project/xz/releases/download/v${XZ_VERSION}/xz-${XZ_VERSION}.tar.bz2" && \ tar -xf xz-${XZ_VERSION}.tar.bz2 # download bzip2 RUN wget -O bzip2-master.tar.bz2 "https://gitlab.com/bzip2/bzip2/-/archive/master/bzip2-master.tar.bz2" && \ tar -xf bzip2-master.tar.bz2 # download ffmpeg source RUN wget -O ffmpeg-5.0.tar.bz2 "https://www.ffmpeg.org/releases/ffmpeg-${FFMPEG_VERSION}.tar.bz2" && \ tar -xf ffmpeg-5.0.tar.bz2 # Install dependencies RUN apk update && apk add --no-cache \ build-base \ cmake \ git \ diffutils \ perl \ wget \ unzip \ pkgconfig \ libjpeg-turbo-dev \ libpng-dev \ libwebp-dev \ eigen-dev \ nasm yasm \ bzip2 xz zlib-dev x264-dev libvpx-dev \ opus-dev dav1d-dev python3 # Build and install xz RUN cd xz-${XZ_VERSION} && \ ./configure --disable-shared && \ make && make install # Build and install bzip2 RUN cd bzip2-master && \ mkdir build && cd build && \ cmake .. -DCMAKE_BUILD_TYPE="Release" -DENABLE_STATIC_LIB=ON -DENABLE_LIB_ONLY=ON && \ cmake --build . --target install # Build and install libvpx RUN cd ffmpeg-${FFMPEG_VERSION} && \ git -C libvpx pull 2> /dev/null || git clone --depth 1 https://chromium.googlesource.com/webm/libvpx.git && \ cd libvpx && \ ./configure --enable-static --disable-examples --disable-unit-tests --enable-vp9-highbitdepth --as=yasm && \ make -j $(nproc --all) && make install # Now finish building ffmpeg RUN cd ffmpeg-${FFMPEG_VERSION} && \ ./configure --pkg-config-flags="--static" \ --enable-static --disable-shared --enable-gpl --enable-libx264 --enable-libvpx --enable-zlib \ --disable-sdl2 --disable-vaapi --disable-vdpau --disable-v4l2-m2m --disable-doc && \ make -j $(nproc --all) && make install # Stage 2: Create final image FROM builder-${TARGETARCH} AS final CMD ["ffmpeg"] ================================================ FILE: Dockerfile.gpu ================================================ # to build this docker image: # docker build -f Dockerfile.gpu . FROM ghcr.io/hybridgroup/opencv:4.13.0-gpu-cuda-11 AS gocv-gpu ENV GOPATH /go COPY . /go/src/gocv.io/x/gocv/ WORKDIR /go/src/gocv.io/x/gocv RUN go build -tags cuda -o /build/gocv_cuda_version ./cmd/cuda/ CMD ["/build/gocv_cuda_version"] ================================================ FILE: Dockerfile.gstreamer-static-alpine ================================================ # To build release: # docker buildx build -f Dockerfile.gstreamer-static-alpine -t ghcr.io/hybridgroup/gstreamer:1.24-alpine --platform=linux/arm64,linux/amd64 --progress plain --load . FROM --platform=linux/amd64 alpine:3.20 AS builder-amd64 WORKDIR /gstreamer ARG GST_BUILD_VERSION=1.24 RUN wget https://gitlab.freedesktop.org/gstreamer/gstreamer/-/archive/${GST_BUILD_VERSION}/gstreamer-${GST_BUILD_VERSION}.tar.gz && \ tar -xzf gstreamer-${GST_BUILD_VERSION}.tar.gz WORKDIR /gstreamer/gstreamer-${GST_BUILD_VERSION} RUN apk update && apk add build-base \ libxml2-dev \ bison \ flex \ glib-dev \ gobject-introspection-dev \ libcap-dev \ libcap-utils \ meson \ perl \ wget \ git cmake \ nasm harfbuzz-static harfbuzz-dev fribidi-static fribidi-dev RUN meson --default-library=static --prefix=/gstbin \ -Dgst-full-target-type=static_library \ -Dgst-full=enabled \ -Dauto_features=disabled \ -Dgst-plugins-base:app=enabled \ -Dgst-plugins-base:playback=enabled \ -Dgst-plugins-base:rawparse=enabled \ -Dgst-plugins-base:tcp=enabled \ -Dgst-plugins-base:videoconvertscale=enabled \ -Dgst-plugins-base:videotestsrc=enabled \ -Dgst-plugins-good:isomp4=enabled \ -Dgst-plugins-good:rtp=enabled \ -Dgst-plugins-good:udp=enabled \ -Dgst-plugins-good:rtsp=enabled \ -Dgst-plugins-good:rtpmanager=enabled \ -Dgst-plugins-good:audioparsers=enabled \ -Dgst-plugins-bad:videoparsers=enabled \ -Dgst-plugins-bad:codectimestamper=enabled \ -Dgst-plugins-bad:openh264=enabled \ -Dtools=enabled \ build RUN meson compile -C build RUN meson install -C build FROM --platform=linux/arm64 alpine:3.20 AS builder-arm64 WORKDIR /gstreamer ARG GST_BUILD_VERSION=1.24 RUN wget https://gitlab.freedesktop.org/gstreamer/gstreamer/-/archive/${GST_BUILD_VERSION}/gstreamer-${GST_BUILD_VERSION}.tar.gz && \ tar -xzf gstreamer-${GST_BUILD_VERSION}.tar.gz WORKDIR /gstreamer/gstreamer-${GST_BUILD_VERSION} RUN apk update && apk add build-base \ libxml2-dev \ bison \ flex \ glib-dev \ gobject-introspection-dev \ libcap-dev \ libcap-utils \ meson \ perl \ wget \ git cmake \ nasm harfbuzz-static harfbuzz-dev fribidi-static fribidi-dev RUN meson --default-library=static --prefix=/gstbin \ -Dgst-full-target-type=static_library \ -Dgst-full=enabled \ -Dauto_features=disabled \ -Dgst-plugins-base:app=enabled \ -Dgst-plugins-base:playback=enabled \ -Dgst-plugins-base:tcp=enabled \ -Dgst-plugins-base:rawparse=enabled \ -Dgst-plugins-base:videoconvertscale=enabled \ -Dgst-plugins-base:videotestsrc=enabled \ -Dgst-plugins-good:isomp4=enabled \ -Dgst-plugins-good:rtp=enabled \ -Dgst-plugins-good:udp=enabled \ -Dgst-plugins-good:rtsp=enabled \ -Dgst-plugins-good:rtpmanager=enabled \ -Dgst-plugins-good:audioparsers=enabled \ -Dgst-plugins-bad:videoparsers=enabled \ -Dgst-plugins-bad:codectimestamper=enabled \ -Dgst-plugins-bad:openh264=enabled \ -Dtools=enabled \ build RUN meson compile -C build RUN meson install -C build ARG TARGETARCH FROM builder-${TARGETARCH} AS final ENV PATH=/gstbin/bin:${PATH} ENV PKG_CONFIG_PATH=/gstbin/lib/pkgconfig ================================================ FILE: Dockerfile.opencv ================================================ # OpenCV 4 prebuilt multiarchitecture image # # To build release: # docker buildx build -f Dockerfile.opencv -t ghcr.io/hybridgroup/opencv:4.13.0 -t ghcr.io/hybridgroup/opencv:latest --platform=linux/arm64,linux/amd64 --push . # # To build prerelease: # docker buildx build --build-arg OPENCV_VERSION="4.x" --build-arg OPENCV_FILE="https://github.com/opencv/opencv/archive/refs/heads/4.x.zip" --build-arg OPENCV_CONTRIB_FILE="https://github.com/opencv/opencv_contrib/archive/refs/heads/4.x.zip" -f Dockerfile.opencv -t ghcr.io/hybridgroup/opencv:4.13.0-dev --platform=linux/arm64,linux/amd64 --push . ################### # amd64 build stage ################### FROM --platform=linux/amd64 golang:1.25-bookworm AS opencv-base-amd64 LABEL maintainer="hybridgroup" RUN apt-get update && apt-get install -y \ git build-essential cmake pkg-config unzip libgtk2.0-dev \ curl ca-certificates libcurl4-openssl-dev libssl-dev \ libavcodec-dev libavformat-dev libswscale-dev libtbbmalloc2 libtbb-dev \ libharfbuzz-dev libfreetype6-dev \ libjpeg62-turbo-dev libpng-dev libtiff-dev libdc1394-dev nasm && \ rm -rf /var/lib/apt/lists/* FROM --platform=linux/amd64 opencv-base-amd64 AS opencv-build-amd64 ARG OPENCV_VERSION="4.13.0" ENV OPENCV_VERSION $OPENCV_VERSION ARG OPENCV_FILE="https://github.com/opencv/opencv/archive/${OPENCV_VERSION}.zip" ENV OPENCV_FILE $OPENCV_FILE ARG OPENCV_CONTRIB_FILE="https://github.com/opencv/opencv_contrib/archive/${OPENCV_VERSION}.zip" ENV OPENCV_CONTRIB_FILE $OPENCV_CONTRIB_FILE RUN curl -Lo opencv.zip ${OPENCV_FILE} && \ unzip -q opencv.zip && \ curl -Lo opencv_contrib.zip ${OPENCV_CONTRIB_FILE} && \ unzip -q opencv_contrib.zip && \ rm opencv.zip opencv_contrib.zip RUN cd opencv-${OPENCV_VERSION} && \ mkdir build && cd build && \ cmake -D CMAKE_BUILD_TYPE=RELEASE \ -D WITH_IPP=OFF \ -D WITH_OPENGL=OFF \ -D WITH_QT=OFF \ -D WITH_FREETYPE=ON \ -D CMAKE_INSTALL_PREFIX=/usr/local \ -D OPENCV_EXTRA_MODULES_PATH=../../opencv_contrib-${OPENCV_VERSION}/modules \ -D OPENCV_ENABLE_NONFREE=ON \ -D WITH_JASPER=OFF \ -D WITH_TBB=ON \ -D BUILD_JPEG=ON \ -D WITH_SIMD=ON \ -D ENABLE_LIBJPEG_TURBO_SIMD=ON \ -D BUILD_DOCS=OFF \ -D BUILD_EXAMPLES=OFF \ -D BUILD_TESTS=OFF \ -D BUILD_PERF_TESTS=ON \ -D BUILD_opencv_java=NO \ -D BUILD_opencv_python=NO \ -D BUILD_opencv_python2=NO \ -D BUILD_opencv_python3=NO \ -D OPENCV_GENERATE_PKGCONFIG=ON .. && \ make -j $(( $(nproc) - 1 )) && \ make preinstall && make install && ldconfig && \ cd / && rm -rf opencv* ################### # arm64 build stage ################### FROM --platform=linux/arm64 golang:1.25-bookworm AS opencv-base-arm64 LABEL maintainer="hybridgroup" RUN apt-get update && apt-get install -y --no-install-recommends \ git build-essential cmake pkg-config unzip libgtk2.0-dev \ curl ca-certificates libcurl4-openssl-dev libssl-dev \ libavcodec-dev libavformat-dev libswscale-dev libtbbmalloc2 libtbb-dev \ libharfbuzz-dev libfreetype6-dev \ libjpeg62-turbo-dev libpng-dev libtiff-dev libdc1394-dev && \ apt-get autoremove -y && apt-get autoclean -y FROM --platform=linux/arm64 opencv-base-arm64 AS opencv-build-arm64 ARG OPENCV_VERSION="4.13.0" ENV OPENCV_VERSION $OPENCV_VERSION ARG OPENCV_FILE="https://github.com/opencv/opencv/archive/${OPENCV_VERSION}.zip" ENV OPENCV_FILE $OPENCV_FILE ARG OPENCV_CONTRIB_FILE="https://github.com/opencv/opencv_contrib/archive/${OPENCV_VERSION}.zip" ENV OPENCV_CONTRIB_FILE $OPENCV_CONTRIB_FILE RUN curl -Lo opencv.zip ${OPENCV_FILE} && \ unzip -q opencv.zip && \ curl -Lo opencv_contrib.zip ${OPENCV_CONTRIB_FILE} && \ unzip -q opencv_contrib.zip && \ rm opencv.zip opencv_contrib.zip RUN cd opencv-${OPENCV_VERSION} && \ mkdir build && cd build && \ cmake -D CMAKE_BUILD_TYPE=RELEASE \ -D CMAKE_INSTALL_PREFIX=/usr/local \ -D OPENCV_EXTRA_MODULES_PATH=../../opencv_contrib-${OPENCV_VERSION}/modules \ -D ENABLE_NEON=ON \ -D WITH_FFMPEG=ON \ -D WITH_TBB=ON \ -D BUILD_TBB=ON \ -D BUILD_TESTS=OFF \ -D WITH_EIGEN=OFF \ -D WITH_GSTREAMER=OFF \ -D WITH_V4L=ON \ -D WITH_LIBV4L=ON \ -D WITH_VTK=OFF \ -D WITH_QT=OFF \ -D WITH_FREETYPE=ON \ -D BUILD_JPEG=ON \ -D OPENCV_ENABLE_NONFREE=ON \ -D BUILD_DOCS=OFF \ -D BUILD_EXAMPLES=OFF \ -D BUILD_TESTS=OFF \ -D BUILD_PERF_TESTS=ON \ -D BUILD_opencv_java=NO \ -D BUILD_opencv_python=NO \ -D BUILD_opencv_python2=NO \ -D BUILD_opencv_python3=NO \ -D OPENCV_GENERATE_PKGCONFIG=ON \ -D CMAKE_TOOLCHAIN_FILE=../platforms/linux/aarch64-gnu.toolchain.cmake .. && \ make -j $(( $(nproc) - 1 )) && \ make preinstall && make install && ldconfig && \ cd / && rm -rf opencv* ARG TARGETARCH ################### # multiarch build stage ################### FROM opencv-build-${TARGETARCH} as opencv-final CMD ["opencv_version", "-b"] ================================================ FILE: Dockerfile.opencv-gpu-cuda-10 ================================================ # to build this docker image: # docker build -f Dockerfile.opencv-gpu-cuda-10 -t ghcr.io/hybridgroup/opencv:4.13.0-gpu-cuda-10 . FROM nvidia/cuda:10.2-cudnn8-devel AS opencv-gpu-base LABEL maintainer="hybridgroup" # needed for cuda repo key rotation. see: # https://forums.developer.nvidia.com/t/notice-cuda-linux-repository-key-rotation/212771 # RUN apt-key adv --fetch-keys http://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64/3bf863cc.pub RUN apt-get update && apt-get install -y --no-install-recommends \ git build-essential cmake pkg-config unzip libgtk2.0-dev \ wget curl ca-certificates libcurl4-openssl-dev libssl-dev \ libavcodec-dev libavformat-dev libswscale-dev libtbb2 libtbb-dev \ libjpeg-dev libpng-dev libtiff-dev libdc1394-22-dev && \ rm -rf /var/lib/apt/lists/* ARG OPENCV_VERSION="4.13.0" ENV OPENCV_VERSION $OPENCV_VERSION RUN curl -Lo opencv.zip https://github.com/opencv/opencv/archive/${OPENCV_VERSION}.zip && \ unzip -q opencv.zip && \ curl -Lo opencv_contrib.zip https://github.com/opencv/opencv_contrib/archive/${OPENCV_VERSION}.zip && \ unzip -q opencv_contrib.zip && \ rm opencv.zip opencv_contrib.zip && \ cd opencv-${OPENCV_VERSION} && \ mkdir build && cd build && \ cmake -D CMAKE_BUILD_TYPE=RELEASE \ -D WITH_IPP=OFF \ -D WITH_OPENGL=OFF \ -D WITH_QT=OFF \ -D CMAKE_INSTALL_PREFIX=/usr/local \ -D OPENCV_EXTRA_MODULES_PATH=../../opencv_contrib-${OPENCV_VERSION}/modules \ -D OPENCV_ENABLE_NONFREE=ON \ -D WITH_JASPER=OFF \ -D BUILD_DOCS=OFF \ -D BUILD_EXAMPLES=OFF \ -D BUILD_TESTS=OFF \ -D BUILD_PERF_TESTS=ON \ -D BUILD_opencv_java=NO \ -D BUILD_opencv_python=NO \ -D BUILD_opencv_python2=NO \ -D BUILD_opencv_python3=NO \ -D WITH_TBB=ON \ -D WITH_CUDA=ON \ -D ENABLE_FAST_MATH=1 \ -D CUDA_FAST_MATH=1 \ -D WITH_CUBLAS=1 \ -D CUDA_TOOLKIT_ROOT_DIR=/usr/local/cuda/ \ -D BUILD_opencv_cudacodec=OFF \ -D WITH_CUDNN=ON \ -D OPENCV_DNN_CUDA=ON \ -D CUDA_GENERATION=Auto \ -D OPENCV_GENERATE_PKGCONFIG=ON .. && \ make -j $(nproc --all) && \ make preinstall && make install && ldconfig && \ cd / && rm -rf opencv* # install golang here FROM opencv-gpu-base AS opencv-gpu-golang ENV GO_RELEASE=1.25.5 RUN wget https://dl.google.com/go/go${GO_RELEASE}.linux-amd64.tar.gz && \ tar xfv go${GO_RELEASE}.linux-amd64.tar.gz -C /usr/local && \ rm go${GO_RELEASE}.linux-amd64.tar.gz ENV PATH="${PATH}:/usr/local/go/bin" CMD ["go version"] ================================================ FILE: Dockerfile.opencv-gpu-cuda-11 ================================================ # to build this docker image: # docker build -f Dockerfile.opencv-gpu-cuda-11 -t ghcr.io/hybridgroup/opencv:4.13.0-gpu-cuda-11 . # docker build --build-arg OPENCV_VERSION="4.x" --build-arg OPENCV_FILE="https://github.com/opencv/opencv/archive/refs/heads/4.x.zip" --build-arg OPENCV_CONTRIB_FILE="https://github.com/opencv/opencv_contrib/archive/refs/heads/4.x.zip" -f Dockerfile.opencv-gpu-cuda-11.2.2 -t ghcr.io/hybridgroup/opencv:4.13.0-dev-gpu-cuda-11 . FROM nvidia/cuda:11.8.0-cudnn8-devel-ubuntu20.04 AS opencv-gpu-cuda-11-base LABEL maintainer="hybridgroup" ENV DEBIAN_FRONTEND=noninteractive RUN apt-get update && apt-get install -y --no-install-recommends \ git build-essential cmake pkg-config unzip libgtk2.0-dev \ wget curl ca-certificates libcurl4-openssl-dev libssl-dev \ libavcodec-dev libavformat-dev libswscale-dev libtbb2 libtbb-dev \ libharfbuzz-dev libfreetype6-dev \ libjpeg-turbo8-dev libpng-dev libtiff-dev libdc1394-22-dev nasm && \ rm -rf /var/lib/apt/lists/* ARG OPENCV_VERSION="4.13.0" ENV OPENCV_VERSION $OPENCV_VERSION ARG OPENCV_FILE="https://github.com/opencv/opencv/archive/${OPENCV_VERSION}.zip" ENV OPENCV_FILE $OPENCV_FILE ARG OPENCV_CONTRIB_FILE="https://github.com/opencv/opencv_contrib/archive/${OPENCV_VERSION}.zip" ENV OPENCV_CONTRIB_FILE $OPENCV_CONTRIB_FILE RUN curl -Lo opencv.zip ${OPENCV_FILE} && \ unzip -q opencv.zip && \ curl -Lo opencv_contrib.zip ${OPENCV_CONTRIB_FILE} && \ unzip -q opencv_contrib.zip && \ rm opencv.zip opencv_contrib.zip && \ cd opencv-${OPENCV_VERSION} && \ mkdir build && cd build && \ cmake -D CMAKE_BUILD_TYPE=RELEASE \ -D WITH_IPP=OFF \ -D WITH_OPENGL=OFF \ -D WITH_QT=OFF \ -D WITH_FREETYPE=ON \ -D CMAKE_INSTALL_PREFIX=/usr/local \ -D OPENCV_EXTRA_MODULES_PATH=../../opencv_contrib-${OPENCV_VERSION}/modules \ -D OPENCV_ENABLE_NONFREE=ON \ -D WITH_JASPER=OFF \ -D BUILD_DOCS=OFF \ -D BUILD_EXAMPLES=OFF \ -D BUILD_TESTS=OFF \ -D BUILD_PERF_TESTS=ON \ -D BUILD_opencv_java=NO \ -D BUILD_opencv_python=NO \ -D BUILD_opencv_python2=NO \ -D BUILD_opencv_python3=NO \ -D WITH_TBB=ON \ -D BUILD_JPEG=ON \ -D WITH_SIMD=ON \ -D WITH_LIBJPEG_TURBO_SIMD=ON \ -D WITH_CUDA=ON \ -D ENABLE_FAST_MATH=1 \ -D CUDA_FAST_MATH=1 \ -D WITH_CUBLAS=1 \ -D CUDA_TOOLKIT_ROOT_DIR=/usr/local/cuda/ \ -D BUILD_opencv_cudacodec=OFF \ -D WITH_CUDNN=ON \ -D OPENCV_DNN_CUDA=ON \ -D CUDA_ARCH_BIN=6.0,6.1,7.0,7.5,8.0,8.6 \ -D OPENCV_GENERATE_PKGCONFIG=ON .. && \ make -j $(nproc --all) && \ make preinstall && make install && ldconfig && \ cd / && rm -rf opencv* # install golang here FROM opencv-gpu-cuda-11-base AS opencv-gpu-cuda-11-golang ENV GO_RELEASE=1.25.5 RUN wget https://dl.google.com/go/go${GO_RELEASE}.linux-amd64.tar.gz && \ tar xfv go${GO_RELEASE}.linux-amd64.tar.gz -C /usr/local && \ rm go${GO_RELEASE}.linux-amd64.tar.gz ENV PATH="${PATH}:/usr/local/go/bin" CMD ["go version"] ================================================ FILE: Dockerfile.opencv-gpu-cuda-11.2.2 ================================================ # to build this docker image: # docker build -f Dockerfile.opencv-gpu-cuda-11 -t ghcr.io/hybridgroup/opencv:4.13.0-gpu-cuda-11.2.2 . # docker build --build-arg OPENCV_VERSION="4.x" --build-arg OPENCV_FILE="https://github.com/opencv/opencv/archive/refs/heads/4.x.zip" --build-arg OPENCV_CONTRIB_FILE="https://github.com/opencv/opencv_contrib/archive/refs/heads/4.x.zip" -f Dockerfile.opencv-gpu-cuda-11.2.2 -t ghcr.io/hybridgroup/opencv:4.13.0-dev-gpu-cuda-11.2.2 . FROM nvidia/cuda:11.2.2-cudnn8-devel-ubuntu20.04 AS opencv-gpu-cuda-11-base LABEL maintainer="hybridgroup" ENV DEBIAN_FRONTEND=noninteractive RUN apt-get update && apt-get install -y --no-install-recommends \ git build-essential cmake pkg-config unzip libgtk2.0-dev \ wget curl ca-certificates libcurl4-openssl-dev libssl-dev \ libavcodec-dev libavformat-dev libswscale-dev libtbb2 libtbb-dev \ libharfbuzz-dev libfreetype6-dev \ libjpeg-turbo8-dev libpng-dev libtiff-dev libdc1394-22-dev nasm && \ rm -rf /var/lib/apt/lists/* ARG OPENCV_VERSION="4.13.0" ENV OPENCV_VERSION $OPENCV_VERSION ARG OPENCV_FILE="https://github.com/opencv/opencv/archive/${OPENCV_VERSION}.zip" ENV OPENCV_FILE $OPENCV_FILE ARG OPENCV_CONTRIB_FILE="https://github.com/opencv/opencv_contrib/archive/${OPENCV_VERSION}.zip" ENV OPENCV_CONTRIB_FILE $OPENCV_CONTRIB_FILE RUN curl -Lo opencv.zip ${OPENCV_FILE} && \ unzip -q opencv.zip && \ curl -Lo opencv_contrib.zip ${OPENCV_CONTRIB_FILE} && \ unzip -q opencv_contrib.zip && \ rm opencv.zip opencv_contrib.zip && \ cd opencv-${OPENCV_VERSION} && \ mkdir build && cd build && \ cmake -D CMAKE_BUILD_TYPE=RELEASE \ -D WITH_IPP=OFF \ -D WITH_OPENGL=OFF \ -D WITH_QT=OFF \ -D WITH_FREETYPE=ON \ -D CMAKE_INSTALL_PREFIX=/usr/local \ -D OPENCV_EXTRA_MODULES_PATH=../../opencv_contrib-${OPENCV_VERSION}/modules \ -D OPENCV_ENABLE_NONFREE=ON \ -D WITH_JASPER=OFF \ -D BUILD_DOCS=OFF \ -D BUILD_EXAMPLES=OFF \ -D BUILD_TESTS=OFF \ -D BUILD_PERF_TESTS=ON \ -D BUILD_opencv_java=NO \ -D BUILD_opencv_python=NO \ -D BUILD_opencv_python2=NO \ -D BUILD_opencv_python3=NO \ -D WITH_TBB=ON \ -D BUILD_JPEG=ON \ -D WITH_SIMD=ON \ -D WITH_LIBJPEG_TURBO_SIMD=ON \ -D WITH_CUDA=ON \ -D ENABLE_FAST_MATH=1 \ -D CUDA_FAST_MATH=1 \ -D WITH_CUBLAS=1 \ -D CUDA_TOOLKIT_ROOT_DIR=/usr/local/cuda/ \ -D BUILD_opencv_cudacodec=OFF \ -D WITH_CUDNN=ON \ -D OPENCV_DNN_CUDA=ON \ -D CUDA_ARCH_BIN=6.0,6.1,7.0,7.5,8.0,8.6 \ -D OPENCV_GENERATE_PKGCONFIG=ON .. && \ make -j $(nproc --all) && \ make preinstall && make install && ldconfig && \ cd / && rm -rf opencv* # install golang here FROM opencv-gpu-cuda-11-base AS opencv-gpu-cuda-11-golang ENV GO_RELEASE=1.25.5 RUN wget https://dl.google.com/go/go${GO_RELEASE}.linux-amd64.tar.gz && \ tar xfv go${GO_RELEASE}.linux-amd64.tar.gz -C /usr/local && \ rm go${GO_RELEASE}.linux-amd64.tar.gz ENV PATH="${PATH}:/usr/local/go/bin" CMD ["go version"] ================================================ FILE: Dockerfile.opencv-gpu-cuda-12 ================================================ # to build this docker image: # docker build -f Dockerfile.opencv-gpu-cuda-12 -t ghcr.io/hybridgroup/opencv:4.13.0-gpu-cuda-12 . # docker build --build-arg OPENCV_VERSION="4.x" --build-arg OPENCV_FILE="https://github.com/opencv/opencv/archive/refs/heads/4.x.zip" --build-arg OPENCV_CONTRIB_FILE="https://github.com/opencv/opencv_contrib/archive/refs/heads/4.x.zip" -f Dockerfile.opencv-gpu-cuda-12 -t ghcr.io/hybridgroup/opencv:4.13.0-dev-gpu-cuda-12 . FROM nvidia/cuda:12.6.1-cudnn-devel-ubuntu22.04 AS opencv-gpu-cuda-12-base LABEL maintainer="hybridgroup" ENV DEBIAN_FRONTEND=noninteractive RUN apt-get update && apt-get install -y --no-install-recommends \ git build-essential cmake pkg-config unzip libgtk2.0-dev \ wget curl ca-certificates libcurl4-openssl-dev libssl-dev \ libavcodec-dev libavformat-dev libswscale-dev libtbb2 libtbb-dev \ libharfbuzz-dev libfreetype6-dev \ libjpeg-turbo8-dev libpng-dev libtiff-dev libdc1394-dev nasm && \ rm -rf /var/lib/apt/lists/* ARG OPENCV_VERSION="4.13.0" ENV OPENCV_VERSION $OPENCV_VERSION ARG OPENCV_FILE="https://github.com/opencv/opencv/archive/${OPENCV_VERSION}.zip" ENV OPENCV_FILE $OPENCV_FILE ARG OPENCV_CONTRIB_FILE="https://github.com/opencv/opencv_contrib/archive/${OPENCV_VERSION}.zip" ENV OPENCV_CONTRIB_FILE $OPENCV_CONTRIB_FILE RUN curl -Lo opencv.zip ${OPENCV_FILE} && \ unzip -q opencv.zip && \ curl -Lo opencv_contrib.zip ${OPENCV_CONTRIB_FILE} && \ unzip -q opencv_contrib.zip && \ rm opencv.zip opencv_contrib.zip && \ cd opencv-${OPENCV_VERSION} && \ mkdir build && cd build && \ cmake -D CMAKE_BUILD_TYPE=RELEASE \ -D WITH_IPP=OFF \ -D WITH_OPENGL=OFF \ -D WITH_QT=OFF \ -D WITH_FREETYPE=ON \ -D CMAKE_INSTALL_PREFIX=/usr/local \ -D OPENCV_EXTRA_MODULES_PATH=../../opencv_contrib-${OPENCV_VERSION}/modules \ -D OPENCV_ENABLE_NONFREE=ON \ -D WITH_JASPER=OFF \ -D BUILD_DOCS=OFF \ -D BUILD_EXAMPLES=OFF \ -D BUILD_TESTS=OFF \ -D BUILD_PERF_TESTS=ON \ -D BUILD_opencv_java=NO \ -D BUILD_opencv_python=NO \ -D BUILD_opencv_python2=NO \ -D BUILD_opencv_python3=NO \ -D WITH_TBB=ON \ -D BUILD_JPEG=ON \ -D WITH_SIMD=ON \ -D WITH_LIBJPEG_TURBO_SIMD=ON \ -D WITH_CUDA=ON \ -D ENABLE_FAST_MATH=1 \ -D CUDA_FAST_MATH=1 \ -D WITH_CUBLAS=1 \ -D CUDA_TOOLKIT_ROOT_DIR=/usr/local/cuda/ \ -D BUILD_opencv_cudacodec=OFF \ -D WITH_CUDNN=ON \ -D OPENCV_DNN_CUDA=ON \ -D CUDA_ARCH_BIN=6.0,6.1,7.0,7.5,8.0,8.6,8.9,9.0 \ -D OPENCV_GENERATE_PKGCONFIG=ON .. && \ make -j $(nproc --all) && \ make preinstall && make install && ldconfig && \ cd / && rm -rf opencv* # install golang here FROM opencv-gpu-cuda-12-base AS opencv-gpu-cuda-12-golang ENV GO_RELEASE=1.25.5 RUN wget https://dl.google.com/go/go${GO_RELEASE}.linux-amd64.tar.gz && \ tar xfv go${GO_RELEASE}.linux-amd64.tar.gz -C /usr/local && \ rm go${GO_RELEASE}.linux-amd64.tar.gz ENV PATH="${PATH}:/usr/local/go/bin" CMD ["go version"] ================================================ FILE: Dockerfile.opencv-gpu-cuda-13 ================================================ # to build this docker image: # docker build -f Dockerfile.opencv-gpu-cuda-13 -t ghcr.io/hybridgroup/opencv:4.13.0-gpu-cuda-13 . # docker build --build-arg OPENCV_VERSION="4.x" --build-arg OPENCV_FILE="https://github.com/opencv/opencv/archive/refs/heads/4.x.zip" --build-arg OPENCV_CONTRIB_FILE="https://github.com/opencv/opencv_contrib/archive/refs/heads/4.x.zip" -f Dockerfile.opencv-gpu-cuda-13 -t ghcr.io/hybridgroup/opencv:4.13.0-dev-gpu-cuda-13 . FROM nvidia/cuda:13.0.2-cudnn-devel-ubuntu24.04 AS opencv-gpu-cuda-13-base LABEL maintainer="hybridgroup" ENV DEBIAN_FRONTEND=noninteractive RUN apt-get update && apt-get install -y --no-install-recommends \ git build-essential cmake pkg-config unzip libgtk2.0-dev \ wget curl ca-certificates libcurl4-openssl-dev libssl-dev \ libavcodec-dev libavformat-dev libswscale-dev libtbbmalloc2 libtbb-dev \ libharfbuzz-dev libfreetype6-dev \ libjpeg-turbo8-dev libpng-dev libtiff-dev libdc1394-dev nasm && \ rm -rf /var/lib/apt/lists/* ARG OPENCV_VERSION="4.13.0" ENV OPENCV_VERSION $OPENCV_VERSION ARG OPENCV_FILE="https://github.com/opencv/opencv/archive/${OPENCV_VERSION}.zip" ENV OPENCV_FILE $OPENCV_FILE ARG OPENCV_CONTRIB_FILE="https://github.com/opencv/opencv_contrib/archive/${OPENCV_VERSION}.zip" ENV OPENCV_CONTRIB_FILE $OPENCV_CONTRIB_FILE RUN curl -Lo opencv.zip ${OPENCV_FILE} && \ unzip -q opencv.zip && \ curl -Lo opencv_contrib.zip ${OPENCV_CONTRIB_FILE} && \ unzip -q opencv_contrib.zip && \ rm opencv.zip opencv_contrib.zip && \ cd opencv-${OPENCV_VERSION} && \ mkdir build && cd build && \ cmake -D CMAKE_BUILD_TYPE=RELEASE \ -D WITH_IPP=OFF \ -D WITH_OPENGL=OFF \ -D WITH_QT=OFF \ -D WITH_FREETYPE=ON \ -D CMAKE_INSTALL_PREFIX=/usr/local \ -D OPENCV_EXTRA_MODULES_PATH=../../opencv_contrib-${OPENCV_VERSION}/modules \ -D OPENCV_ENABLE_NONFREE=ON \ -D WITH_JASPER=OFF \ -D BUILD_DOCS=OFF \ -D BUILD_EXAMPLES=OFF \ -D BUILD_TESTS=OFF \ -D BUILD_PERF_TESTS=ON \ -D BUILD_opencv_java=NO \ -D BUILD_opencv_python=NO \ -D BUILD_opencv_python2=NO \ -D BUILD_opencv_python3=NO \ -D WITH_TBB=ON \ -D BUILD_JPEG=ON \ -D WITH_SIMD=ON \ -D WITH_LIBJPEG_TURBO_SIMD=ON \ -D WITH_CUDA=ON \ -D ENABLE_FAST_MATH=1 \ -D CUDA_FAST_MATH=1 \ -D WITH_CUBLAS=1 \ -D CUDA_TOOLKIT_ROOT_DIR=/usr/local/cuda/ \ -D BUILD_opencv_cudacodec=OFF \ -D WITH_CUDNN=ON \ -D OPENCV_DNN_CUDA=ON \ -D CUDA_ARCH_BIN=7.5,8.0,8.6,8.9,9.0,10.0,10.3,11.0,12.0,12.1 \ -D OPENCV_GENERATE_PKGCONFIG=ON .. && \ make -j $(nproc --all) && \ make preinstall && make install && ldconfig && \ cd / && rm -rf opencv* # install golang here FROM opencv-gpu-cuda-13-base AS opencv-gpu-cuda-13-golang ENV GO_RELEASE=1.25.5 RUN wget https://dl.google.com/go/go${GO_RELEASE}.linux-amd64.tar.gz && \ tar xfv go${GO_RELEASE}.linux-amd64.tar.gz -C /usr/local && \ rm go${GO_RELEASE}.linux-amd64.tar.gz ENV PATH="${PATH}:/usr/local/go/bin" CMD ["go version"] ================================================ FILE: Dockerfile.opencv-openvino ================================================ # to build this docker image: # docker build -f Dockerfile.opencv-openvino -t ghcr.io/hybridgroup/opencv:4.13.0-openvino FROM openvino/ubuntu20_dev:2022.1.0 AS opencv-openvino-base LABEL maintainer="hybridgroup" ENV DEBIAN_FRONTEND=noninteractive USER root RUN apt-get update && apt-get install -y --no-install-recommends \ git build-essential cmake pkg-config unzip libgtk2.0-dev \ wget curl ca-certificates libcurl4-openssl-dev libssl-dev \ libavcodec-dev libavformat-dev libswscale-dev libtbb2 libtbb-dev \ libjpeg-dev libpng-dev libtiff-dev libdc1394-22-dev && \ rm -rf /var/lib/apt/lists/* ARG OPENCV_VERSION="4.13.0" ENV OPENCV_VERSION $OPENCV_VERSION RUN curl -Lo opencv.zip https://github.com/opencv/opencv/archive/${OPENCV_VERSION}.zip && \ unzip -q opencv.zip && \ curl -Lo opencv_contrib.zip https://github.com/opencv/opencv_contrib/archive/${OPENCV_VERSION}.zip && \ unzip -q opencv_contrib.zip && \ rm opencv.zip opencv_contrib.zip && \ cd opencv-${OPENCV_VERSION} && \ mkdir build && cd build && \ cmake -D CMAKE_BUILD_TYPE=RELEASE \ -D WITH_IPP=OFF \ -D WITH_OPENGL=OFF \ -D WITH_QT=OFF \ -D CMAKE_INSTALL_PREFIX=/usr/local \ -D OPENCV_EXTRA_MODULES_PATH=../../opencv_contrib-${OPENCV_VERSION}/modules \ -D OPENCV_ENABLE_NONFREE=ON \ -D WITH_JASPER=OFF \ -D BUILD_DOCS=OFF \ -D BUILD_EXAMPLES=OFF \ -D BUILD_TESTS=OFF \ -D BUILD_PERF_TESTS=ON \ -D BUILD_opencv_java=NO \ -D BUILD_opencv_python=NO \ -D BUILD_opencv_python2=NO \ -D BUILD_opencv_python3=NO \ -D WITH_TBB=ON \ -D WITH_OPENVINO=1 \ -D ENABLE_FAST_MATH=1 \ -D OPENCV_GENERATE_PKGCONFIG=ON .. && \ make -j $(nproc --all) && \ make preinstall && make install && ldconfig && \ cd / && rm -rf opencv* # install golang here FROM opencv-openvino-base AS opencv-openvino-golang ENV GO_RELEASE=1.25.5 RUN wget https://dl.google.com/go/go${GO_RELEASE}.linux-amd64.tar.gz && \ tar xfv go${GO_RELEASE}.linux-amd64.tar.gz -C /usr/local && \ rm go${GO_RELEASE}.linux-amd64.tar.gz ENV PATH="${PATH}:/usr/local/go/bin" USER openvino CMD ["go version"] ================================================ FILE: Dockerfile.opencv-static ================================================ # OpenCV 4 prebuilt multiarchitecture image # # To build release: # docker buildx build -f Dockerfile.opencv-static -t ghcr.io/hybridgroup/opencv:4.13.0-static --platform=linux/arm64,linux/amd64 --push . # # To build prerelease: # docker buildx build --build-arg OPENCV_VERSION="4.x" --build-arg OPENCV_FILE="https://github.com/opencv/opencv/archive/refs/heads/4.x.zip" --build-arg OPENCV_CONTRIB_FILE="https://github.com/opencv/opencv_contrib/archive/refs/heads/4.x.zip" -f Dockerfile.opencv-static -t ghcr.io/hybridgroup/opencv:4.13.0-static-dev --platform=linux/arm64,linux/amd64 --push . ################### # amd64 build stage ################### FROM --platform=linux/amd64 golang:1.25-bookworm AS opencv-base-amd64 LABEL maintainer="hybridgroup" RUN apt-get update && apt-get -y install \ autoconf automake libass-dev libgnutls28-dev \ libmp3lame-dev libtool libvorbis-dev \ meson ninja-build pkg-config \ texinfo wget yasm \ zlib1g-dev libx264-dev libvpx-dev \ libopus-dev libdav1d-dev \ git build-essential cmake pkg-config unzip \ curl ca-certificates libcurl4-openssl-dev libssl-dev \ libharfbuzz-dev libfreetype6-dev \ nasm && \ rm -rf /var/lib/apt/lists/* RUN wget -O ffmpeg-5.0.tar.bz2 "https://www.ffmpeg.org/releases/ffmpeg-5.1.6.tar.bz2" && \ tar -xf ffmpeg-5.0.tar.bz2 RUN cd ffmpeg-5.1.6 && \ ./configure --pkg-config-flags="--static" \ --enable-static --disable-shared --enable-gpl --enable-libx264 --enable-libvpx --enable-zlib \ --disable-sdl2 --disable-vaapi --disable-vdpau --disable-v4l2-m2m --disable-doc && \ make -j $(nproc --all) && make install && ldconfig FROM --platform=linux/amd64 opencv-base-amd64 AS opencv-build-amd64 ARG OPENCV_VERSION="4.13.0" ENV OPENCV_VERSION $OPENCV_VERSION ARG OPENCV_FILE="https://github.com/opencv/opencv/archive/${OPENCV_VERSION}.zip" ENV OPENCV_FILE $OPENCV_FILE ARG OPENCV_CONTRIB_FILE="https://github.com/opencv/opencv_contrib/archive/${OPENCV_VERSION}.zip" ENV OPENCV_CONTRIB_FILE $OPENCV_CONTRIB_FILE RUN curl -Lo opencv.zip ${OPENCV_FILE} && \ unzip -q opencv.zip && \ curl -Lo opencv_contrib.zip ${OPENCV_CONTRIB_FILE} && \ unzip -q opencv_contrib.zip && \ rm opencv.zip opencv_contrib.zip RUN cd opencv-${OPENCV_VERSION} && \ mkdir build && cd build && \ cmake -D CMAKE_BUILD_TYPE=RELEASE \ -D WITH_IPP=ON \ -D BUILD_WITH_DYNAMIC_IPP=OFF \ -D BUILD_IPP_IW=ON \ -D WITH_OPENGL=ON \ -D BUILD_OPENGL=ON \ -D WITH_QT=OFF \ -D WITH_FREETYPE=ON \ -D CMAKE_INSTALL_PREFIX=/usr/local \ -D BUILD_SHARED_LIBS=OFF \ -D OPENCV_EXTRA_MODULES_PATH=../../opencv_contrib-${OPENCV_VERSION}/modules \ -D OPENCV_ENABLE_NONFREE=ON \ -D WITH_JASPER=OFF \ -D WITH_TBB=ON \ -D BUILD_TBB=ON \ -D BUILD_JPEG=ON \ -D WITH_SIMD=ON \ -D ENABLE_LIBJPEG_TURBO_SIMD=OFF \ -D WITH_QUIRC=ON \ -D WITH_GTK=OFF \ -D WITH_FFMPEG=ON \ -D WITH_1394=ON \ -D BUILD_1394=ON \ -D WITH_WEBP=ON \ -D BUILD_WEBP=ON \ -D WITH_OPENJPEG=ON \ -D BUILD_OPENJPEG=ON \ -D WITH_TIFF=ON \ -D BUILD_TIFF=ON \ -D BUILD_DOCS=OFF \ -D BUILD_EXAMPLES=OFF \ -D BUILD_TESTS=OFF \ -D BUILD_PERF_TESTS=OFF \ -D BUILD_opencv_java=NO \ -D BUILD_opencv_python=NO \ -D BUILD_opencv_python2=NO \ -D BUILD_opencv_python3=NO \ -D OPENCV_GENERATE_PKGCONFIG=ON .. && \ make -j $(( $(nproc) - 1 )) && \ make preinstall && make install && ldconfig && \ cd / && rm -rf opencv* ################### # arm64 build stage ################### FROM --platform=linux/arm64 golang:1.25-bookworm AS opencv-base-arm64 LABEL maintainer="hybridgroup" RUN apt-get update && apt-get -y install \ autoconf automake libass-dev libgnutls28-dev \ libmp3lame-dev libtool libvorbis-dev \ meson ninja-build pkg-config \ texinfo wget yasm \ zlib1g-dev libx264-dev libvpx-dev \ libopus-dev libdav1d-dev \ git build-essential cmake pkg-config unzip \ curl ca-certificates libcurl4-openssl-dev libssl-dev \ libharfbuzz-dev libfreetype6-dev \ nasm && \ rm -rf /var/lib/apt/lists/* RUN wget -O ffmpeg-5.0.tar.bz2 "https://www.ffmpeg.org/releases/ffmpeg-5.1.6.tar.bz2" && \ tar -xf ffmpeg-5.0.tar.bz2 RUN cd ffmpeg-5.1.6 && \ ./configure --pkg-config-flags="--static" \ --enable-static --disable-shared --enable-gpl --enable-libx264 --enable-libvpx --enable-zlib \ --disable-sdl2 --disable-vaapi --disable-vdpau --disable-v4l2-m2m --disable-doc && \ make -j $(nproc --all) && make install && ldconfig FROM --platform=linux/arm64 opencv-base-arm64 AS opencv-build-arm64 ARG OPENCV_VERSION="4.13.0" ENV OPENCV_VERSION $OPENCV_VERSION ARG OPENCV_FILE="https://github.com/opencv/opencv/archive/${OPENCV_VERSION}.zip" ENV OPENCV_FILE $OPENCV_FILE ARG OPENCV_CONTRIB_FILE="https://github.com/opencv/opencv_contrib/archive/${OPENCV_VERSION}.zip" ENV OPENCV_CONTRIB_FILE $OPENCV_CONTRIB_FILE RUN curl -Lo opencv.zip ${OPENCV_FILE} && \ unzip -q opencv.zip && \ curl -Lo opencv_contrib.zip ${OPENCV_CONTRIB_FILE} && \ unzip -q opencv_contrib.zip && \ rm opencv.zip opencv_contrib.zip RUN cd opencv-${OPENCV_VERSION} && \ mkdir build && cd build && \ cmake -D CMAKE_BUILD_TYPE=RELEASE \ -D WITH_IPP=OFF \ -D WITH_OPENGL=ON \ -D BUILD_OPENGL=ON \ -D WITH_QT=OFF \ -D WITH_FREETYPE=ON \ -D CMAKE_INSTALL_PREFIX=/usr/local \ -D BUILD_SHARED_LIBS=OFF \ -D OPENCV_EXTRA_MODULES_PATH=../../opencv_contrib-${OPENCV_VERSION}/modules \ -D OPENCV_ENABLE_NONFREE=ON \ -D WITH_JASPER=OFF \ -D ENABLE_NEON=ON \ -D WITH_TBB=ON \ -D BUILD_TBB=ON \ -D BUILD_JPEG=ON \ -D WITH_SIMD=ON \ -D ENABLE_LIBJPEG_TURBO_SIMD=OFF \ -D WITH_QUIRC=ON \ -D WITH_GTK=OFF \ -D WITH_FFMPEG=ON \ -D WITH_1394=ON \ -D BUILD_1394=ON \ -D WITH_WEBP=ON \ -D BUILD_WEBP=ON \ -D WITH_OPENJPEG=ON \ -D BUILD_OPENJPEG=ON \ -D WITH_TIFF=ON \ -D BUILD_TIFF=ON \ -D BUILD_DOCS=OFF \ -D BUILD_EXAMPLES=OFF \ -D BUILD_TESTS=OFF \ -D BUILD_PERF_TESTS=OFF \ -D BUILD_opencv_java=NO \ -D BUILD_opencv_python=NO \ -D BUILD_opencv_python2=NO \ -D BUILD_opencv_python3=NO \ -D OPENCV_GENERATE_PKGCONFIG=ON .. && \ make -j $(( $(nproc) - 1 )) && \ make preinstall && make install && ldconfig && \ cd / && rm -rf opencv* ARG TARGETARCH ################### # multiarch build stage ################### FROM opencv-build-${TARGETARCH} AS opencv-final CMD ["opencv_version", "-b"] ================================================ FILE: Dockerfile.opencv-static-alpine ================================================ # syntax=docker/dockerfile:1.3 # To build release: # docker buildx build -f Dockerfile.opencv-static-alpine -t ghcr.io/hybridgroup/opencv:4.11-alpine --platform=linux/arm64,linux/amd64 --load . # linux/amd64 build FROM --platform=linux/amd64 ghcr.io/hybridgroup/gstreamer:1.24-alpine AS gstreamer-amd64 # Stage 1: Build OpenCV FROM --platform=linux/amd64 ghcr.io/hybridgroup/ffmpeg:5.16-alpine AS builder-amd64 # Set OpenCV version ARG OPENCV_VERSION=4.13.0 # Download OpenCV source code WORKDIR /opencv RUN wget -O opencv.zip https://github.com/opencv/opencv/archive/${OPENCV_VERSION}.zip && \ unzip -q opencv.zip && \ mv opencv-${OPENCV_VERSION} opencv WORKDIR /opencv_contrib RUN wget -O opencv_contrib.zip https://github.com/opencv/opencv_contrib/archive/${OPENCV_VERSION}.zip && \ unzip -q opencv_contrib.zip && \ mv opencv_contrib-${OPENCV_VERSION} opencv_contrib # Install dependencies RUN apk update && apk add --no-cache \ build-base \ cmake \ git \ diffutils \ perl \ wget \ unzip \ pkgconfig \ libjpeg-turbo-dev \ libpng-dev \ libwebp-dev \ eigen-dev \ nasm yasm \ bzip2 xz zlib-dev x264-dev libvpx-dev \ opus-dev dav1d-dev openssl \ libxml2-dev \ bison \ flex \ glib-dev glib-static \ gobject-introspection-dev \ libcap-dev \ libcap-utils \ meson # copy gstreamer COPY --from=gstreamer-amd64 /gstbin/lib /usr/local/lib COPY --from=gstreamer-amd64 /gstbin/include/gstreamer-1.0/gst /usr/local/include/gst # patch opencv for static gstreamer COPY ./patches/gstreamer-full.patch /opencv/opencv RUN cd /opencv/opencv && \ patch -p1 < gstreamer-full.patch # Build OpenCV ENV PKG_CONFIG_PATH=/usr/local/lib/gstreamer-1.0/pkgconfig:/usr/local/lib/pkgconfig ENV GSTREAMER_STATIC_LIB=/usr/local/lib/gstreamer-1.0 WORKDIR /opencv/opencv/build RUN cmake -D CMAKE_BUILD_TYPE=Release \ -D CMAKE_INSTALL_PREFIX=/usr/local \ -D WITH_IPP=ON \ -D BUILD_WITH_DYNAMIC_IPP=OFF \ -D BUILD_IPP_IW=ON \ -D WITH_OPENGL=ON \ -D BUILD_OPENGL=ON \ -D WITH_QT=OFF \ -D WITH_FREETYPE=OFF \ -D OPENCV_EXTRA_MODULES_PATH=/opencv_contrib/opencv_contrib/modules \ -D OPENCV_ENABLE_NONFREE=ON \ -D BUILD_SHARED_LIBS=OFF \ -D WITH_FFMPEG=ON \ -D WITH_GSTREAMER=ON \ -D WITH_TBB=ON \ -D WITH_SIMD=ON \ -D BUILD_EXAMPLES=OFF \ -D BUILD_TESTS=OFF \ -D BUILD_PERF_TESTS=OFF \ -D OPENCV_GENERATE_PKGCONFIG=ON \ -D WITH_WEBP=ON \ -D BUILD_WEBP=ON \ -D WITH_OPENJPEG=ON \ -D BUILD_OPENJPEG=ON \ -D BUILD_TIFF=ON \ -D BUILD_PNG=ON \ -D BUILD_ZLIB=ON \ -D BUILD_JPEG=ON \ -D WITH_SIMD=ON \ -D ENABLE_LIBJPEG_TURBO_SIMD=OFF \ -D BUILD_opencv_java=NO \ -D BUILD_opencv_python=NO \ -D BUILD_opencv_python2=NO \ -D BUILD_opencv_python3=NO \ .. && \ make -j$(nproc) && \ make install # linux/arm64 build FROM --platform=linux/arm64 ghcr.io/hybridgroup/gstreamer:1.24-alpine AS gstreamer-arm64 FROM --platform=linux/arm64 ghcr.io/hybridgroup/ffmpeg:5.16-alpine AS builder-arm64 # Set OpenCV version ARG OPENCV_VERSION=4.13.0 # Download OpenCV source code WORKDIR /opencv RUN wget -O opencv.zip https://github.com/opencv/opencv/archive/${OPENCV_VERSION}.zip && \ unzip -q opencv.zip && \ mv opencv-${OPENCV_VERSION} opencv WORKDIR /opencv_contrib RUN wget -O opencv_contrib.zip https://github.com/opencv/opencv_contrib/archive/${OPENCV_VERSION}.zip && \ unzip -q opencv_contrib.zip && \ mv opencv_contrib-${OPENCV_VERSION} opencv_contrib # Install dependencies RUN apk update && apk add --no-cache \ build-base \ cmake \ git \ diffutils \ perl \ wget \ unzip \ pkgconfig \ libjpeg-turbo-dev \ libpng-dev \ libwebp-dev \ eigen-dev \ nasm yasm \ bzip2 xz zlib-dev x264-dev libvpx-dev \ opus-dev dav1d-dev openssl \ libxml2-dev \ bison \ flex \ glib-dev glib-static \ gobject-introspection-dev \ libcap-dev \ libcap-utils \ meson # copy gstreamer COPY --from=gstreamer-arm64 /gstbin/lib /usr/local/lib COPY --from=gstreamer-arm64 /gstbin/include/gstreamer-1.0/gst /usr/local/include/gst # patch opencv for static gstreamer COPY ./patches/gstreamer-full.patch /opencv/opencv RUN cd /opencv/opencv && \ patch -p1 < gstreamer-full.patch # Build OpenCV ENV PKG_CONFIG_PATH=/usr/local/lib/gstreamer-1.0/pkgconfig:/usr/local/lib/pkgconfig ENV GSTREAMER_STATIC_LIB=/usr/local/lib/gstreamer-1.0 WORKDIR /opencv/opencv/build RUN cmake -D CMAKE_BUILD_TYPE=Release \ -D CMAKE_INSTALL_PREFIX=/usr/local \ -D WITH_IPP=OFF \ -D ENABLE_NEON=ON \ -D WITH_OPENGL=ON \ -D BUILD_OPENGL=ON \ -D WITH_QT=OFF \ -D WITH_FREETYPE=OFF \ -D OPENCV_EXTRA_MODULES_PATH=/opencv_contrib/opencv_contrib/modules \ -D OPENCV_ENABLE_NONFREE=ON \ -D BUILD_SHARED_LIBS=OFF \ -D WITH_FFMPEG=ON \ -D WITH_GSTREAMER=ON \ -D WITH_TBB=ON \ -D WITH_SIMD=ON \ -D ENABLE_LIBJPEG_TURBO_SIMD=OFF \ -D BUILD_EXAMPLES=OFF \ -D BUILD_TESTS=OFF \ -D BUILD_PERF_TESTS=OFF \ -D OPENCV_GENERATE_PKGCONFIG=ON \ -D WITH_WEBP=ON \ -D BUILD_WEBP=ON \ -D WITH_OPENJPEG=ON \ -D BUILD_OPENJPEG=ON \ -D BUILD_TIFF=ON \ -D BUILD_PNG=ON \ -D BUILD_ZLIB=ON \ -D BUILD_JPEG=ON \ -D WITH_SIMD=ON \ -D ENABLE_LIBJPEG_TURBO_SIMD=OFF \ -D BUILD_opencv_java=NO \ -D BUILD_opencv_python=NO \ -D BUILD_opencv_python2=NO \ -D BUILD_opencv_python3=NO \ .. && \ make -j$(nproc) && \ make install # Stage 2: Create final image FROM builder-${TARGETARCH} AS final # Set environment variables ENV LD_LIBRARY_PATH=/usr/local/lib:/usr/local/lib/opencv4/3rdparty:${LD_LIBRARY_PATH} CMD ["opencv_version", "-b"] ================================================ FILE: Dockerfile.opencv-static-alpine-ffmpeg ================================================ # syntax=docker/dockerfile:1.3 # To build release: # docker buildx build -f Dockerfile.opencv-static-alpine-ffmpeg -t ghcr.io/hybridgroup/opencv:4.10-alpine-ffmpeg --platform=linux/arm64,linux/amd64 --load . # linux/amd64 build # Stage 1: Build OpenCV FROM --platform=linux/amd64 ghcr.io/hybridgroup/ffmpeg:5.16-alpine AS builder-amd64 # Set OpenCV version ARG OPENCV_VERSION=4.13.0 # Download OpenCV source code WORKDIR /opencv RUN wget -O opencv.zip https://github.com/opencv/opencv/archive/${OPENCV_VERSION}.zip && \ unzip -q opencv.zip && \ mv opencv-${OPENCV_VERSION} opencv WORKDIR /opencv_contrib RUN wget -O opencv_contrib.zip https://github.com/opencv/opencv_contrib/archive/${OPENCV_VERSION}.zip && \ unzip -q opencv_contrib.zip && \ mv opencv_contrib-${OPENCV_VERSION} opencv_contrib # Install dependencies RUN apk update && apk add --no-cache \ build-base \ cmake \ git \ diffutils \ perl \ wget \ unzip \ pkgconfig \ libjpeg-turbo-dev \ libpng-dev \ libwebp-dev \ eigen-dev \ nasm yasm \ bzip2 xz zlib-dev x264-dev libvpx-dev \ opus-dev dav1d-dev openssl \ libxml2-dev \ bison \ flex \ glib-dev \ gobject-introspection-dev \ libcap-dev \ libcap-utils \ meson # Build OpenCV WORKDIR /opencv/opencv/build RUN cmake -D CMAKE_BUILD_TYPE=Release \ -D CMAKE_INSTALL_PREFIX=/usr/local \ -D WITH_IPP=ON \ -D BUILD_WITH_DYNAMIC_IPP=OFF \ -D BUILD_IPP_IW=ON \ -D WITH_OPENGL=ON \ -D BUILD_OPENGL=ON \ -D WITH_QT=OFF \ -D WITH_FREETYPE=OFF \ -D OPENCV_EXTRA_MODULES_PATH=/opencv_contrib/opencv_contrib/modules \ -D OPENCV_ENABLE_NONFREE=ON \ -D BUILD_SHARED_LIBS=OFF \ -D WITH_FFMPEG=ON \ -D WITH_GSTREAMER=OFF \ -D WITH_TBB=ON \ -D WITH_SIMD=ON \ -D BUILD_EXAMPLES=OFF \ -D BUILD_TESTS=OFF \ -D BUILD_PERF_TESTS=OFF \ -D OPENCV_GENERATE_PKGCONFIG=ON \ -D WITH_WEBP=ON \ -D BUILD_WEBP=ON \ -D WITH_OPENJPEG=ON \ -D BUILD_OPENJPEG=ON \ -D BUILD_TIFF=ON \ -D BUILD_PNG=ON \ -D BUILD_ZLIB=ON \ -D BUILD_JPEG=ON \ -D WITH_SIMD=ON \ -D ENABLE_LIBJPEG_TURBO_SIMD=OFF \ -D BUILD_opencv_java=NO \ -D BUILD_opencv_python=NO \ -D BUILD_opencv_python2=NO \ -D BUILD_opencv_python3=NO \ .. && \ make -j$(nproc) && \ make install # linux/arm64 build FROM --platform=linux/arm64 ghcr.io/hybridgroup/ffmpeg:5.16-alpine AS builder-arm64 # Set OpenCV version ARG OPENCV_VERSION=4.13.0 # Download OpenCV source code WORKDIR /opencv RUN wget -O opencv.zip https://github.com/opencv/opencv/archive/${OPENCV_VERSION}.zip && \ unzip -q opencv.zip && \ mv opencv-${OPENCV_VERSION} opencv WORKDIR /opencv_contrib RUN wget -O opencv_contrib.zip https://github.com/opencv/opencv_contrib/archive/${OPENCV_VERSION}.zip && \ unzip -q opencv_contrib.zip && \ mv opencv_contrib-${OPENCV_VERSION} opencv_contrib # Install dependencies RUN apk update && apk add --no-cache \ build-base \ cmake \ git \ diffutils \ perl \ wget \ unzip \ pkgconfig \ libjpeg-turbo-dev \ libpng-dev \ libwebp-dev \ eigen-dev \ nasm yasm \ bzip2 xz zlib-dev x264-dev libvpx-dev \ opus-dev dav1d-dev openssl \ libxml2-dev \ bison \ flex \ glib-dev \ gobject-introspection-dev \ libcap-dev \ libcap-utils \ meson # Build OpenCV WORKDIR /opencv/opencv/build RUN cmake -D CMAKE_BUILD_TYPE=Release \ -D CMAKE_INSTALL_PREFIX=/usr/local \ -D WITH_IPP=OFF \ -D ENABLE_NEON=ON \ -D WITH_OPENGL=ON \ -D BUILD_OPENGL=ON \ -D WITH_QT=OFF \ -D WITH_FREETYPE=OFF \ -D OPENCV_EXTRA_MODULES_PATH=/opencv_contrib/opencv_contrib/modules \ -D OPENCV_ENABLE_NONFREE=ON \ -D BUILD_SHARED_LIBS=OFF \ -D WITH_FFMPEG=ON \ -D WITH_GSTREAMER=OFF \ -D WITH_TBB=ON \ -D WITH_SIMD=ON \ -D ENABLE_LIBJPEG_TURBO_SIMD=OFF \ -D BUILD_EXAMPLES=OFF \ -D BUILD_TESTS=OFF \ -D BUILD_PERF_TESTS=OFF \ -D OPENCV_GENERATE_PKGCONFIG=ON \ -D WITH_WEBP=ON \ -D BUILD_WEBP=ON \ -D WITH_OPENJPEG=ON \ -D BUILD_OPENJPEG=ON \ -D BUILD_TIFF=ON \ -D BUILD_PNG=ON \ -D BUILD_ZLIB=ON \ -D BUILD_JPEG=ON \ -D WITH_SIMD=ON \ -D ENABLE_LIBJPEG_TURBO_SIMD=OFF \ -D BUILD_opencv_java=NO \ -D BUILD_opencv_python=NO \ -D BUILD_opencv_python2=NO \ -D BUILD_opencv_python3=NO \ .. && \ make -j$(nproc) && \ make install # Stage 2: Create final image FROM builder-${TARGETARCH} AS final # Set environment variables ENV LD_LIBRARY_PATH=/usr/local/lib:/usr/local/lib/opencv4/3rdparty:${LD_LIBRARY_PATH} CMD ["opencv_version", "-b"] ================================================ FILE: Dockerfile.opencv-ubuntu-18.04 ================================================ # to build this docker image: # docker build -f Dockerfile.opencv-ubuntu-18.04 -t ghcr.io/hybridgroup/opencv:4.13.0-ubuntu-18.04 . # docker build --build-arg OPENCV_VERSION="4.x" --build-arg OPENCV_FILE="https://github.com/opencv/opencv/archive/refs/heads/4.x.zip" --build-arg OPENCV_CONTRIB_FILE="https://github.com/opencv/opencv_contrib/archive/refs/heads/4.x.zip" -f Dockerfile.opencv-ubuntu-18.04 -t ghcr.io/hybridgroup/opencv:4.13.0-dev-ubuntu-18.04 . FROM ubuntu:18.04 AS opencv-base LABEL maintainer="hybridgroup" RUN apt-get update && apt-get install -y --no-install-recommends \ git build-essential cmake pkg-config wget unzip libgtk2.0-dev \ curl ca-certificates libcurl4-openssl-dev libssl-dev \ libavcodec-dev libavformat-dev libswscale-dev libtbb2 libtbb-dev \ libharfbuzz-dev libfreetype6-dev \ libjpeg-turbo8-dev libpng-dev libtiff-dev libdc1394-22-dev nasm && \ rm -rf /var/lib/apt/lists/* ARG OPENCV_VERSION="4.13.0" ENV OPENCV_VERSION $OPENCV_VERSION ARG OPENCV_FILE="https://github.com/opencv/opencv/archive/${OPENCV_VERSION}.zip" ENV OPENCV_FILE $OPENCV_FILE ARG OPENCV_CONTRIB_FILE="https://github.com/opencv/opencv_contrib/archive/${OPENCV_VERSION}.zip" ENV OPENCV_CONTRIB_FILE $OPENCV_CONTRIB_FILE RUN curl -Lo opencv.zip ${OPENCV_FILE} && \ unzip -q opencv.zip && \ curl -Lo opencv_contrib.zip ${OPENCV_CONTRIB_FILE} && \ unzip -q opencv_contrib.zip && \ rm opencv.zip opencv_contrib.zip && \ cd opencv-${OPENCV_VERSION} && \ mkdir build && cd build && \ cmake -D CMAKE_BUILD_TYPE=RELEASE \ -D WITH_IPP=OFF \ -D WITH_OPENGL=OFF \ -D WITH_QT=OFF \ -D WITH_FREETYPE=ON \ -D CMAKE_INSTALL_PREFIX=/usr/local \ -D OPENCV_EXTRA_MODULES_PATH=../../opencv_contrib-${OPENCV_VERSION}/modules \ -D OPENCV_ENABLE_NONFREE=ON \ -D WITH_JASPER=OFF \ -D WITH_TBB=ON \ -D BUILD_JPEG=ON \ -D WITH_SIMD=ON \ -D ENABLE_LIBJPEG_TURBO_SIMD=ON \ -D BUILD_DOCS=OFF \ -D BUILD_EXAMPLES=OFF \ -D BUILD_TESTS=OFF \ -D BUILD_PERF_TESTS=ON \ -D BUILD_opencv_java=NO \ -D BUILD_opencv_python=NO \ -D BUILD_opencv_python2=NO \ -D BUILD_opencv_python3=NO \ -D OPENCV_GENERATE_PKGCONFIG=ON .. && \ make -j $(nproc --all) && \ make preinstall && make install && ldconfig && \ cd / && rm -rf opencv* CMD ["opencv_version", "-b"] ================================================ FILE: Dockerfile.opencv-ubuntu-20.04 ================================================ # to build this docker image: # docker build -f Dockerfile.opencv-ubuntu-20.04 -t ghcr.io/hybridgroup/opencv:4.13.0-ubuntu-20.04 . # docker build --build-arg OPENCV_VERSION="4.x" --build-arg OPENCV_FILE="https://github.com/opencv/opencv/archive/refs/heads/4.x.zip" --build-arg OPENCV_CONTRIB_FILE="https://github.com/opencv/opencv_contrib/archive/refs/heads/4.x.zip" -f Dockerfile.opencv-ubuntu-20.04 -t ghcr.io/hybridgroup/opencv:4.13.0-dev-ubuntu-20.04 . FROM ubuntu:20.04 AS opencv-base LABEL maintainer="hybridgroup" ENV TZ=Europe/Madrid RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone RUN apt-get update && apt-get install -y --no-install-recommends \ tzdata git build-essential cmake pkg-config wget unzip libgtk2.0-dev \ curl ca-certificates libcurl4-openssl-dev libssl-dev \ libavcodec-dev libavformat-dev libswscale-dev libtbb2 libtbb-dev \ libharfbuzz-dev libfreetype6-dev \ libjpeg-turbo8-dev libpng-dev libtiff-dev libdc1394-22-dev nasm && \ rm -rf /var/lib/apt/lists/* ARG OPENCV_VERSION="4.13.0" ENV OPENCV_VERSION $OPENCV_VERSION ARG OPENCV_FILE="https://github.com/opencv/opencv/archive/${OPENCV_VERSION}.zip" ENV OPENCV_FILE $OPENCV_FILE ARG OPENCV_CONTRIB_FILE="https://github.com/opencv/opencv_contrib/archive/${OPENCV_VERSION}.zip" ENV OPENCV_CONTRIB_FILE $OPENCV_CONTRIB_FILE RUN curl -Lo opencv.zip ${OPENCV_FILE} && \ unzip -q opencv.zip && \ curl -Lo opencv_contrib.zip ${OPENCV_CONTRIB_FILE} && \ unzip -q opencv_contrib.zip && \ rm opencv.zip opencv_contrib.zip && \ cd opencv-${OPENCV_VERSION} && \ mkdir build && cd build && \ cmake -D CMAKE_BUILD_TYPE=RELEASE \ -D WITH_IPP=OFF \ -D WITH_OPENGL=OFF \ -D WITH_QT=OFF \ -D WITH_FREETYPE=ON \ -D CMAKE_INSTALL_PREFIX=/usr/local \ -D OPENCV_EXTRA_MODULES_PATH=../../opencv_contrib-${OPENCV_VERSION}/modules \ -D OPENCV_ENABLE_NONFREE=ON \ -D WITH_JASPER=OFF \ -D WITH_TBB=ON \ -D BUILD_JPEG=ON \ -D WITH_SIMD=ON \ -D ENABLE_LIBJPEG_TURBO_SIMD=ON \ -D BUILD_DOCS=OFF \ -D BUILD_EXAMPLES=OFF \ -D BUILD_TESTS=OFF \ -D BUILD_PERF_TESTS=ON \ -D BUILD_opencv_java=NO \ -D BUILD_opencv_python=NO \ -D BUILD_opencv_python2=NO \ -D BUILD_opencv_python3=NO \ -D OPENCV_GENERATE_PKGCONFIG=ON .. && \ make -j $(nproc --all) && \ make preinstall && make install && ldconfig && \ cd / && rm -rf opencv* CMD ["opencv_version", "-b"] ================================================ FILE: Dockerfile.opencv-ubuntu-22.04 ================================================ # to build this docker image: # docker build -f Dockerfile.opencv-ubuntu-22.04 -t ghcr.io/hybridgroup/opencv:4.13.0-ubuntu-22.04 . # docker build --build-arg OPENCV_VERSION="4.x" --build-arg OPENCV_FILE="https://github.com/opencv/opencv/archive/refs/heads/4.x.zip" --build-arg OPENCV_CONTRIB_FILE="https://github.com/opencv/opencv_contrib/archive/refs/heads/4.x.zip" -f Dockerfile.opencv-ubuntu-20.04 -t ghcr.io/hybridgroup/opencv:4.13.0-dev-ubuntu-20.04 . FROM ubuntu:22.04 AS opencv-base LABEL maintainer="hybridgroup" ENV TZ=Europe/Madrid RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone RUN apt-get update && apt-get install -y --no-install-recommends \ tzdata git build-essential cmake pkg-config wget unzip libgtk2.0-dev \ curl ca-certificates libcurl4-openssl-dev libssl-dev \ libavcodec-dev libavformat-dev libswscale-dev libtbb2 libtbb-dev \ libharfbuzz-dev libfreetype6-dev \ libjpeg-turbo8-dev libpng-dev libtiff-dev libdc1394-dev nasm && \ rm -rf /var/lib/apt/lists/* ARG OPENCV_VERSION="4.13.0" ENV OPENCV_VERSION $OPENCV_VERSION ARG OPENCV_FILE="https://github.com/opencv/opencv/archive/${OPENCV_VERSION}.zip" ENV OPENCV_FILE $OPENCV_FILE ARG OPENCV_CONTRIB_FILE="https://github.com/opencv/opencv_contrib/archive/${OPENCV_VERSION}.zip" ENV OPENCV_CONTRIB_FILE $OPENCV_CONTRIB_FILE RUN curl -Lo opencv.zip ${OPENCV_FILE} && \ unzip -q opencv.zip && \ curl -Lo opencv_contrib.zip ${OPENCV_CONTRIB_FILE} && \ unzip -q opencv_contrib.zip && \ rm opencv.zip opencv_contrib.zip && \ cd opencv-${OPENCV_VERSION} && \ mkdir build && cd build && \ cmake -D CMAKE_BUILD_TYPE=RELEASE \ -D WITH_IPP=OFF \ -D WITH_OPENGL=OFF \ -D WITH_QT=OFF \ -D WITH_FREETYPE=ON \ -D CMAKE_INSTALL_PREFIX=/usr/local \ -D OPENCV_EXTRA_MODULES_PATH=../../opencv_contrib-${OPENCV_VERSION}/modules \ -D OPENCV_ENABLE_NONFREE=ON \ -D WITH_JASPER=OFF \ -D WITH_TBB=ON \ -D BUILD_JPEG=ON \ -D WITH_SIMD=ON \ -D ENABLE_LIBJPEG_TURBO_SIMD=ON \ -D BUILD_DOCS=OFF \ -D BUILD_EXAMPLES=OFF \ -D BUILD_TESTS=OFF \ -D BUILD_PERF_TESTS=ON \ -D BUILD_opencv_java=NO \ -D BUILD_opencv_python=NO \ -D BUILD_opencv_python2=NO \ -D BUILD_opencv_python3=NO \ -D OPENCV_GENERATE_PKGCONFIG=ON .. && \ make -j $(nproc --all) && \ make preinstall && make install && ldconfig && \ cd / && rm -rf opencv* CMD ["opencv_version", "-b"] ================================================ FILE: Dockerfile.opencv-ubuntu-24.04 ================================================ # to build this docker image: # docker build -f Dockerfile.opencv-ubuntu-24.04 -t ghcr.io/hybridgroup/opencv:4.13.0-ubuntu-24.04 . # docker build --build-arg OPENCV_VERSION="4.x" --build-arg OPENCV_FILE="https://github.com/opencv/opencv/archive/refs/heads/4.x.zip" --build-arg OPENCV_CONTRIB_FILE="https://github.com/opencv/opencv_contrib/archive/refs/heads/4.x.zip" -f Dockerfile.opencv-ubuntu-20.04 -t ghcr.io/hybridgroup/opencv:4.13.0-dev-ubuntu-20.04 . FROM ubuntu:24.04 AS opencv-base LABEL maintainer="hybridgroup" ENV TZ=Europe/Madrid RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone RUN apt-get update && apt-get install -y --no-install-recommends \ tzdata git build-essential cmake pkg-config wget unzip libgtk2.0-dev \ curl ca-certificates libcurl4-openssl-dev libssl-dev \ libavcodec-dev libavformat-dev libswscale-dev libtbbmalloc2 libtbb-dev \ libharfbuzz-dev libfreetype6-dev \ libjpeg-turbo8-dev libpng-dev libtiff-dev libdc1394-dev nasm && \ rm -rf /var/lib/apt/lists/* ARG OPENCV_VERSION="4.13.0" ENV OPENCV_VERSION $OPENCV_VERSION ARG OPENCV_FILE="https://github.com/opencv/opencv/archive/${OPENCV_VERSION}.zip" ENV OPENCV_FILE $OPENCV_FILE ARG OPENCV_CONTRIB_FILE="https://github.com/opencv/opencv_contrib/archive/${OPENCV_VERSION}.zip" ENV OPENCV_CONTRIB_FILE $OPENCV_CONTRIB_FILE RUN curl -Lo opencv.zip ${OPENCV_FILE} && \ unzip -q opencv.zip && \ curl -Lo opencv_contrib.zip ${OPENCV_CONTRIB_FILE} && \ unzip -q opencv_contrib.zip && \ rm opencv.zip opencv_contrib.zip && \ cd opencv-${OPENCV_VERSION} && \ mkdir build && cd build && \ cmake -D CMAKE_BUILD_TYPE=RELEASE \ -D WITH_IPP=OFF \ -D WITH_OPENGL=OFF \ -D WITH_QT=OFF \ -D WITH_FREETYPE=ON \ -D CMAKE_INSTALL_PREFIX=/usr/local \ -D OPENCV_EXTRA_MODULES_PATH=../../opencv_contrib-${OPENCV_VERSION}/modules \ -D OPENCV_ENABLE_NONFREE=ON \ -D WITH_JASPER=OFF \ -D WITH_TBB=ON \ -D BUILD_JPEG=ON \ -D WITH_SIMD=ON \ -D ENABLE_LIBJPEG_TURBO_SIMD=ON \ -D BUILD_DOCS=OFF \ -D BUILD_EXAMPLES=OFF \ -D BUILD_TESTS=OFF \ -D BUILD_PERF_TESTS=ON \ -D BUILD_opencv_java=NO \ -D BUILD_opencv_python=NO \ -D BUILD_opencv_python2=NO \ -D BUILD_opencv_python3=NO \ -D OPENCV_GENERATE_PKGCONFIG=ON .. && \ make -j $(nproc --all) && \ make preinstall && make install && ldconfig && \ cd / && rm -rf opencv* CMD ["opencv_version", "-b"] ================================================ FILE: LICENSE.txt ================================================ Copyright (c) The Hybrid Group and friends 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. ================================================ FILE: Makefile ================================================ .ONESHELL: .PHONY: test deps download build clean astyle cmds docker # GoCV version to use. GOCV_VERSION?="v0.43.0" # OpenCV version to use. OPENCV_VERSION?=4.13.0 # Go version to use when building Docker image GOVERSION?=1.25.5 # Temporary directory to put files into. TMP_DIR?=/tmp/ # Build shared or static library BUILD_SHARED_LIBS?=ON # Package list for each well-known Linux distribution RPMS=cmake curl wget git gtk2-devel libpng-devel libjpeg-devel libtiff-devel tbb tbb-devel libdc1394-devel unzip gcc-c++ DEBS=unzip wget build-essential cmake curl git libgtk2.0-dev pkg-config libavcodec-dev libavformat-dev libswscale-dev libtbb2 libtbb-dev libjpeg-dev libpng-dev libtiff-dev libdc1394-22-dev libharfbuzz-dev libfreetype6-dev DEBS_BOOKWORM=unzip wget build-essential cmake curl git libgtk2.0-dev pkg-config libavcodec-dev libavformat-dev libswscale-dev libtbbmalloc2 libtbb-dev libjpeg-dev libpng-dev libtiff-dev libharfbuzz-dev libfreetype6-dev DEBS_UBUNTU_JAMMY=unzip wget build-essential cmake curl git libgtk2.0-dev pkg-config libavcodec-dev libavformat-dev libswscale-dev libtbb2 libtbb-dev libjpeg-dev libpng-dev libtiff-dev libdc1394-dev libharfbuzz-dev libfreetype6-dev DEBS_UBUNTU_MANTIC=unzip wget build-essential cmake curl git libgtk2.0-dev pkg-config libavcodec-dev libavformat-dev libswscale-dev libtbbmalloc2 libtbb-dev libjpeg-dev libpng-dev libtiff-dev libdc1394-dev libharfbuzz-dev libfreetype6-dev DEBS_UBUNTU_NUMBAT=unzip wget build-essential cmake curl git libgtk2.0-dev pkg-config libavcodec-dev libavformat-dev libswscale-dev libtbb-dev libjpeg-dev libpng-dev libtiff-dev libdc1394-dev libharfbuzz-dev libfreetype-dev JETSON=build-essential cmake git unzip pkg-config libjpeg-dev libpng-dev libtiff-dev libavcodec-dev libavformat-dev libswscale-dev libgtk2.0-dev libcanberra-gtk* libxvidcore-dev libx264-dev libgtk-3-dev libtbb2 libtbb-dev libdc1394-dev libv4l-dev v4l-utils libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev libavresample-dev libvorbis-dev libxine2-dev libfaac-dev libmp3lame-dev libtheora-dev libopencore-amrnb-dev libopencore-amrwb-dev libopenblas-dev libatlas-base-dev libblas-dev liblapack-dev libeigen3-dev gfortran libhdf5-dev protobuf-compiler libprotobuf-dev libgoogle-glog-dev libgflags-dev explain: @echo "For quick install with typical defaults of both OpenCV and GoCV, run 'make install'" # Detect Linux distribution distro_deps= ifneq ($(shell which dnf 2>/dev/null),) distro_deps=deps_fedora endif ifneq ($(shell which yum 2>/dev/null),) distro_deps=deps_rh_centos endif ifneq ($(shell which apt-get 2>/dev/null),) ifneq ($(shell cat /etc/os-release 2>/dev/null | grep "Jammy Jellyfish"),) distro_deps=deps_ubuntu_jammy endif ifneq ($(shell cat /etc/os-release 2>/dev/null | grep "Mantic Minotaur"),) distro_deps=deps_ubuntu_mantic endif ifneq ($(shell cat /etc/os-release 2>/dev/null | grep "Noble Numbat"),) distro_deps=deps_ubuntu_numbat endif ifneq ($(shell cat /etc/debian_version 2>/dev/null | grep "11."),) distro_deps=deps_debian_bullseye endif ifneq ($(shell cat /etc/debian_version 2>/dev/null | grep "12."),) distro_deps=deps_debian_bookworm endif endif # Install all necessary dependencies. deps: $(distro_deps) deps_rh_centos: sudo yum -y install pkgconfig $(RPMS) deps_fedora: sudo dnf -y install pkgconf-pkg-config $(RPMS) deps_debian_bookworm: sudo apt-get -y update sudo apt-get -y install $(DEBS_BOOKWORM) deps_debian_bullseye: sudo apt-get -y update sudo apt-get -y install $(DEBS_BULLSEYE) deps_ubuntu_jammy: sudo apt-get -y update sudo apt-get -y install $(DEBS_UBUNTU_JAMMY) deps_ubuntu_mantic: sudo apt-get -y update sudo apt-get -y install $(DEBS_UBUNTU_MANTIC) deps_ubuntu_numbat: sudo apt-get -y update sudo apt-get -y install $(DEBS_UBUNTU_NUMBAT) deps_jetson: sudo sh -c "echo '/usr/local/cuda/lib64' >> /etc/ld.so.conf.d/nvidia-tegra.conf" sudo ldconfig sudo apt-get -y update sudo apt-get -y install $(JETSON) # Download OpenCV source tarballs. download: rm -rf $(TMP_DIR)opencv mkdir $(TMP_DIR)opencv cd $(TMP_DIR)opencv curl -Lo opencv.zip https://github.com/opencv/opencv/archive/refs/tags/$(OPENCV_VERSION).zip unzip -q opencv.zip curl -Lo opencv_contrib.zip https://github.com/opencv/opencv_contrib/archive/refs/tags/$(OPENCV_VERSION).zip unzip -q opencv_contrib.zip rm opencv.zip opencv_contrib.zip cd - # Download openvino source tarballs. download_openvino: sudo rm -rf /usr/local/dldt/ sudo rm -rf /usr/local/openvino/ sudo git clone https://github.com/openvinotoolkit/openvino -b 2019_R3.1 /usr/local/openvino/ # Build openvino. build_openvino_package: cd /usr/local/openvino/inference-engine sudo git submodule init sudo git submodule update --recursive sudo ./install_dependencies.sh sudo mv -f thirdparty/clDNN/common/intel_ocl_icd/6.3/linux/Release thirdparty/clDNN/common/intel_ocl_icd/6.3/linux/RELEASE sudo mkdir build cd build sudo rm -rf * sudo cmake -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX=/usr/local -D BUILD_SHARED_LIBS=${BUILD_SHARED_LIBS} -D ENABLE_VPU=ON -D ENABLE_MKL_DNN=ON -D ENABLE_CLDNN=ON .. sudo $(MAKE) -j $(shell nproc --all --ignore 1) sudo touch VERSION sudo mkdir -p src/ngraph sudo cp thirdparty/ngraph/src/ngraph/version.hpp src/ngraph cd - # Build OpenCV. build: cd $(TMP_DIR)opencv/opencv-$(OPENCV_VERSION) mkdir build cd build rm -rf * cmake -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX=/usr/local -D BUILD_SHARED_LIBS=${BUILD_SHARED_LIBS} -D OPENCV_EXTRA_MODULES_PATH=$(TMP_DIR)opencv/opencv_contrib-$(OPENCV_VERSION)/modules -D BUILD_DOCS=OFF -D BUILD_EXAMPLES=OFF -D BUILD_TESTS=OFF -D BUILD_PERF_TESTS=ON -D BUILD_opencv_java=NO -D BUILD_opencv_python=NO -D BUILD_opencv_python2=NO -D BUILD_opencv_python3=NO -D WITH_JASPER=OFF -D WITH_TBB=ON -DOPENCV_GENERATE_PKGCONFIG=ON .. $(MAKE) -j $(shell nproc --all --ignore 1) $(MAKE) preinstall cd - # Build OpenCV on Raspbian with ARM hardware optimizations. build_raspi: cd $(TMP_DIR)opencv/opencv-$(OPENCV_VERSION) mkdir build cd build rm -rf * ifneq ($(shell uname -m | grep "aarch64"),) cmake -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX=/usr/local -D BUILD_SHARED_LIBS=${BUILD_SHARED_LIBS} -D OPENCV_EXTRA_MODULES_PATH=$(TMP_DIR)opencv/opencv_contrib-$(OPENCV_VERSION)/modules -D BUILD_DOCS=OFF -D BUILD_EXAMPLES=OFF -D BUILD_TESTS=OFF -D BUILD_PERF_TESTS=ON -D BUILD_opencv_java=OFF -D BUILD_opencv_python=NO -D BUILD_opencv_python2=NO -D BUILD_opencv_python3=NO -D ENABLE_NEON=ON -D WITH_JASPER=OFF -D WITH_TBB=ON -D OPENCV_GENERATE_PKGCONFIG=ON -D WITH_FREETYPE=ON .. else cmake -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX=/usr/local -D BUILD_SHARED_LIBS=${BUILD_SHARED_LIBS} -D OPENCV_EXTRA_MODULES_PATH=$(TMP_DIR)opencv/opencv_contrib-$(OPENCV_VERSION)/modules -D BUILD_DOCS=OFF -D BUILD_EXAMPLES=OFF -D BUILD_TESTS=OFF -D BUILD_PERF_TESTS=ON -D BUILD_opencv_java=OFF -D BUILD_opencv_python=NO -D BUILD_opencv_python2=NO -D BUILD_opencv_python3=NO -D ENABLE_NEON=ON -D ENABLE_VFPV3=ON -D WITH_JASPER=OFF -D OPENCV_GENERATE_PKGCONFIG=ON -D WITH_FREETYPE=ON .. endif $(MAKE) -j $(shell nproc --all --ignore 1) $(MAKE) preinstall cd - # Build OpenCV on Raspberry pi zero which has ARMv6. build_raspi_zero: cd $(TMP_DIR)opencv/opencv-$(OPENCV_VERSION) mkdir build cd build rm -rf * cmake -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX=/usr/local -D BUILD_SHARED_LIBS=${BUILD_SHARED_LIBS} -D OPENCV_EXTRA_MODULES_PATH=$(TMP_DIR)opencv/opencv_contrib-$(OPENCV_VERSION)/modules -D BUILD_DOCS=OFF -D BUILD_EXAMPLES=OFF -D BUILD_TESTS=OFF -D BUILD_PERF_TESTS=ON -D BUILD_opencv_java=OFF -D BUILD_opencv_python=NO -D BUILD_opencv_python2=NO -D BUILD_opencv_python3=NO -D ENABLE_VFPV2=ON -D WITH_JASPER=OFF -D OPENCV_GENERATE_PKGCONFIG=ON .. $(MAKE) -j $(shell nproc --all --ignore 1) $(MAKE) preinstall cd - # Build OpenCV for NVidia Jetson with CUDA. build_jetson: cd $(TMP_DIR)opencv/opencv-$(OPENCV_VERSION) mkdir build cd build rm -rf * cmake -D CMAKE_BUILD_TYPE=RELEASE \ -D CMAKE_INSTALL_PREFIX=/usr/local \ -D EIGEN_INCLUDE_PATH=/usr/include/eigen3 \ -D BUILD_SHARED_LIBS=${BUILD_SHARED_LIBS} \ -D OPENCV_EXTRA_MODULES_PATH=$(TMP_DIR)opencv/opencv_contrib-$(OPENCV_VERSION)/modules \ -D BUILD_DOCS=OFF -D BUILD_EXAMPLES=OFF -D BUILD_TESTS=OFF -D BUILD_PERF_TESTS=ON -D BUILD_opencv_java=OFF -D BUILD_opencv_python=NO -D BUILD_opencv_python2=NO -D BUILD_opencv_python3=NO \ -D WITH_OPENCL=OFF \ -D WITH_CUDA=ON \ -D CUDA_ARCH_BIN=5.3 \ -D CUDA_ARCH_PTX="" \ -D WITH_CUDNN=ON \ -D WITH_CUBLAS=ON \ -D ENABLE_FAST_MATH=ON \ -D CUDA_FAST_MATH=ON \ -D OPENCV_DNN_CUDA=ON \ -D ENABLE_NEON=ON \ -D WITH_QT=OFF \ -D WITH_OPENMP=ON \ -D WITH_OPENGL=ON \ -D BUILD_TIFF=ON \ -D WITH_FFMPEG=ON \ -D WITH_GSTREAMER=ON \ -D WITH_TBB=ON \ -D BUILD_TBB=ON \ -D BUILD_TESTS=OFF \ -D WITH_EIGEN=ON \ -D WITH_V4L=ON \ -D WITH_LIBV4L=ON \ -D OPENCV_GENERATE_PKGCONFIG=ON .. $(MAKE) -j $(shell nproc --all --ignore 1) $(MAKE) preinstall cd - # Build OpenCV with non-free contrib modules. build_nonfree: cd $(TMP_DIR)opencv/opencv-$(OPENCV_VERSION) mkdir build cd build rm -rf * cmake -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX=/usr/local -D BUILD_SHARED_LIBS=${BUILD_SHARED_LIBS} -D OPENCV_EXTRA_MODULES_PATH=$(TMP_DIR)opencv/opencv_contrib-$(OPENCV_VERSION)/modules -D BUILD_DOCS=OFF -D BUILD_EXAMPLES=OFF -D BUILD_TESTS=OFF -D BUILD_PERF_TESTS=ON -D BUILD_opencv_java=NO -D BUILD_opencv_python=NO -D BUILD_opencv_python2=NO -D BUILD_opencv_python3=NO -D WITH_JASPER=OFF -D WITH_TBB=ON -DOPENCV_GENERATE_PKGCONFIG=ON -DOPENCV_ENABLE_NONFREE=ON .. $(MAKE) -j $(shell nproc --all --ignore 1) $(MAKE) preinstall cd - # Build OpenCV with openvino. build_openvino: cd $(TMP_DIR)opencv/opencv-$(OPENCV_VERSION) mkdir build cd build rm -rf * cmake -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX=/usr/local -D BUILD_SHARED_LIBS=${BUILD_SHARED_LIBS} -D ENABLE_CXX11=ON -D OPENCV_EXTRA_MODULES_PATH=$(TMP_DIR)opencv/opencv_contrib-$(OPENCV_VERSION)/modules -D WITH_INF_ENGINE=ON -D InferenceEngine_DIR=/usr/local/dldt/inference-engine/build -D BUILD_DOCS=OFF -D BUILD_EXAMPLES=OFF -D BUILD_TESTS=OFF -D BUILD_PERF_TESTS=ON -D BUILD_opencv_java=NO -D BUILD_opencv_python=NO -D BUILD_opencv_python2=NO -D BUILD_opencv_python3=NO -D WITH_JASPER=OFF -D WITH_TBB=ON -DOPENCV_GENERATE_PKGCONFIG=ON -DOPENCV_ENABLE_NONFREE=ON .. $(MAKE) -j $(shell nproc --all --ignore 1) $(MAKE) preinstall cd - # Build OpenCV with cuda. build_cuda: cd $(TMP_DIR)opencv/opencv-$(OPENCV_VERSION) mkdir build cd build rm -rf * cmake -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX=/usr/local -D BUILD_SHARED_LIBS=${BUILD_SHARED_LIBS} -D OPENCV_EXTRA_MODULES_PATH=$(TMP_DIR)opencv/opencv_contrib-$(OPENCV_VERSION)/modules -D BUILD_DOCS=OFF -D BUILD_EXAMPLES=OFF -D BUILD_TESTS=OFF -D BUILD_PERF_TESTS=ON -D BUILD_opencv_java=NO -D BUILD_opencv_python=NO -D BUILD_opencv_python2=NO -D BUILD_opencv_python3=NO -D WITH_JASPER=OFF -D WITH_TBB=ON -DOPENCV_GENERATE_PKGCONFIG=ON -DWITH_CUDA=ON -DENABLE_FAST_MATH=1 -DCUDA_FAST_MATH=1 -DWITH_CUBLAS=ON -DCUDA_TOOLKIT_ROOT_DIR=/usr/local/cuda/ -DBUILD_opencv_cudacodec=OFF -D WITH_CUDNN=ON -D OPENCV_DNN_CUDA=ON -D CUDA_GENERATION=Auto -DOPENCV_ENABLE_NONFREE=ON -D WITH_GSTREAMER=ON .. $(MAKE) -j $(shell nproc --all --ignore 1) $(MAKE) preinstall cd - # Build OpenCV statically linked build_static: cd $(TMP_DIR)opencv/opencv-$(OPENCV_VERSION) mkdir build cd build rm -rf * cmake -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX=/usr/local -D BUILD_SHARED_LIBS=OFF -D OPENCV_EXTRA_MODULES_PATH=$(TMP_DIR)opencv/opencv_contrib-$(OPENCV_VERSION)/modules -D BUILD_DOCS=OFF -D BUILD_EXAMPLES=OFF -D BUILD_TESTS=OFF -D BUILD_PERF_TESTS=ON -D BUILD_opencv_java=NO -D BUILD_opencv_python=NO -D BUILD_opencv_python2=NO -D BUILD_opencv_python3=NO -DWITH_JASPER=OFF -DWITH_QT=OFF -DWITH_GTK=OFF -DWITH_FFMPEG=OFF -DWITH_TIFF=OFF -DWITH_WEBP=OFF -DWITH_PNG=OFF -DWITH_1394=OFF -DWITH_OPENJPEG=OFF -DOPENCV_GENERATE_PKGCONFIG=ON .. $(MAKE) -j $(shell nproc --all --ignore 1) $(MAKE) preinstall cd - # Build OpenCV with cuda. build_all: cd $(TMP_DIR)opencv/opencv-$(OPENCV_VERSION) mkdir build cd build rm -rf * cmake -j $(shell nproc --all --ignore 1) -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX=/usr/local -D BUILD_SHARED_LIBS=${BUILD_SHARED_LIBS} -D ENABLE_CXX11=ON -D OPENCV_EXTRA_MODULES_PATH=$(TMP_DIR)opencv/opencv_contrib-$(OPENCV_VERSION)/modules -D WITH_INF_ENGINE=ON -D InferenceEngine_DIR=/usr/local/dldt/inference-engine/build -D BUILD_DOCS=OFF -D BUILD_EXAMPLES=OFF -D BUILD_TESTS=OFF -D BUILD_PERF_TESTS=ON -D BUILD_opencv_java=NO -D BUILD_opencv_python=NO -D BUILD_opencv_python2=NO -D BUILD_opencv_python3=NO -D WITH_JASPER=OFF -D WITH_TBB=ON -DOPENCV_GENERATE_PKGCONFIG=ON -DWITH_CUDA=ON -DENABLE_FAST_MATH=1 -DCUDA_FAST_MATH=1 -DWITH_CUBLAS=1 -DCUDA_TOOLKIT_ROOT_DIR=/usr/local/cuda/ -DBUILD_opencv_cudacodec=OFF -D WITH_CUDNN=ON -D OPENCV_DNN_CUDA=ON -D CUDA_GENERATION=Auto .. $(MAKE) -j $(shell nproc --all --ignore 1) $(MAKE) preinstall cd - # Cleanup temporary build files. clean: go clean --cache rm -rf $(TMP_DIR)opencv # Cleanup old library files. sudo_pre_install_clean: ifneq (,$(wildcard /usr/local/lib/libopencv*)) sudo rm -rf /usr/local/lib/cmake/opencv4/ sudo rm -rf /usr/local/lib/libopencv* sudo rm -rf /usr/local/lib/pkgconfig/opencv* sudo rm -rf /usr/local/include/opencv* else ifneq (,$(wildcard /usr/local/lib64/libopencv*)) sudo rm -rf /usr/local/lib64/cmake/opencv4/ sudo rm -rf /usr/local/lib64/libopencv* sudo rm -rf /usr/local/lib64/pkgconfig/opencv* sudo rm -rf /usr/local/include/opencv* else ifneq (,$(wildcard /usr/local/lib/aarch64-linux-gnu/libopencv*)) sudo rm -rf /usr/local/lib/aarch64-linux-gnu/cmake/opencv4/ sudo rm -rf /usr/local/lib/aarch64-linux-gnu/libopencv* sudo rm -rf /usr/local/lib/aarch64-linux-gnu/pkgconfig/opencv* sudo rm -rf /usr/local/include/opencv* endif endif endif # Do everything. install: ifeq ($(shell uname -s),Darwin) @echo "Detected macOS. Installing dependencies..." brew install opencv brew install pkgconfig endif @$(MAKE) deps download sudo_pre_install_clean build sudo_install clean verify @go run ./cmd/version/main.go # Do everything on Raspbian. install_raspi: deps download sudo_pre_install_clean build_raspi sudo_install clean verify # Do everything on the raspberry pi zero. install_raspi_zero: deps download sudo_pre_install_clean build_raspi_zero sudo_install clean verify # Do everything on Jetson. install_jetson: deps_jetson download sudo_pre_install_clean build_jetson sudo_install clean verify # Do everything with cuda. install_cuda: deps download sudo_pre_install_clean build_cuda sudo_install clean verify verify_cuda # Do everything with openvino. install_openvino: deps download download_openvino sudo_pre_install_clean build_openvino_package sudo_install_openvino build_openvino sudo_install clean verify_openvino # Do everything statically. install_static: deps download sudo_pre_install_clean build_static sudo_install clean verify_static # Do everything with non-free modules from cpencv_contrib. install_nonfree: deps download sudo_pre_install_clean build_nonfree sudo_install clean verify # Do everything with openvino and cuda. install_all: deps download download_openvino sudo_pre_install_clean build_openvino_package sudo_install_openvino build_all sudo_install clean verify_openvino verify_cuda # Install system wide. sudo_install: cd $(TMP_DIR)opencv/opencv-$(OPENCV_VERSION)/build sudo $(MAKE) install sudo ldconfig cd - # Install system wide. sudo_install_openvino: cd /usr/local/openvino/inference-engine/build sudo $(MAKE) install sudo ldconfig cd - # Build a minimal Go app to confirm gocv works. verify: go run ./cmd/version/main.go # Build a minimal Go app to confirm gocv works with statically built OpenCV. verify_static: go run -tags static ./cmd/version/main.go # Build a minimal Go app to confirm gocv cuda works. verify_cuda: go run ./cmd/cuda/main.go # Build a minimal Go app to confirm gocv openvino works. verify_openvino: go run -tags openvino ./cmd/version/main.go # testdata. .PHONY: create_testdata_dir download_wechat_testdata download_onnx_testdata download_goturn_testdata testdata create_testdata_dir: mkdir -p ./testdata download_wechat_testdata: create_testdata_dir curl -sL https://raw.githubusercontent.com/WeChatCV/opencv_3rdparty/wechat_qrcode/detect.caffemodel > ./testdata/detect.caffemodel curl -sL https://raw.githubusercontent.com/WeChatCV/opencv_3rdparty/wechat_qrcode/detect.prototxt > ./testdata/detect.prototxt curl -sL https://raw.githubusercontent.com/WeChatCV/opencv_3rdparty/wechat_qrcode/sr.caffemodel > ./testdata/sr.caffemodel curl -sL https://raw.githubusercontent.com/WeChatCV/opencv_3rdparty/wechat_qrcode/sr.prototxt > ./testdata/sr.prototxt download_onnx_testdata: create_testdata_dir curl -sL https://github.com/onnx/models/raw/main/validated/vision/classification/inception_and_googlenet/googlenet/model/googlenet-9.onnx > ./testdata/googlenet-9.onnx curl -sL https://github.com/opencv/opencv_zoo/raw/refs/heads/main/models/face_recognition_sface/face_recognition_sface_2021dec.onnx > ./testdata/face_recognition_sface_2021dec.onnx curl -sL https://github.com/opencv/opencv_zoo/raw/refs/heads/main/models/face_detection_yunet/face_detection_yunet_2023mar.onnx > ./testdata/face_detection_yunet_2023mar.onnx curl -sL https://github.com/opencv/opencv_zoo/raw/refs/heads/main/models/object_tracking_vittrack/object_tracking_vittrack_2023sep.onnx > ./testdata/object_tracking_vittrack_2023sep.onnx download_goturn_testdata: create_testdata_dir curl -sL https://raw.githubusercontent.com/opencv/opencv_extra/c4219d5eb3105ed8e634278fad312a1a8d2c182d/testdata/tracking/goturn.prototxt > ./testdata/goturn.prototxt curl -sL https://github.com/opencv/opencv_extra/raw/c4219d5eb3105ed8e634278fad312a1a8d2c182d/testdata/tracking/goturn.caffemodel.zip.001 > ./testdata/goturn.caffemodel.zip.001 curl -sL https://github.com/opencv/opencv_extra/raw/c4219d5eb3105ed8e634278fad312a1a8d2c182d/testdata/tracking/goturn.caffemodel.zip.002 > ./testdata/goturn.caffemodel.zip.002 curl -sL https://github.com/opencv/opencv_extra/raw/c4219d5eb3105ed8e634278fad312a1a8d2c182d/testdata/tracking/goturn.caffemodel.zip.003 > ./testdata/goturn.caffemodel.zip.003 curl -sL https://github.com/opencv/opencv_extra/raw/c4219d5eb3105ed8e634278fad312a1a8d2c182d/testdata/tracking/goturn.caffemodel.zip.004 > ./testdata/goturn.caffemodel.zip.004 cat ./testdata/goturn.caffemodel.zip.001 ./testdata/goturn.caffemodel.zip.002 ./testdata/goturn.caffemodel.zip.003 ./testdata/goturn.caffemodel.zip.004 > ./testdata/goturn.caffemodel.zip unzip -o ./testdata/goturn.caffemodel.zip goturn.caffemodel -d ./testdata testdata: create_testdata_dir download_wechat_testdata download_onnx_testdata download_goturn_testdata # Runs tests. test: go test -tags matprofile . ./contrib test_cuda: go test -tags matprofile ./cuda docker: docker build --build-arg OPENCV_VERSION=$(OPENCV_VERSION) --build-arg GOVERSION=$(GOVERSION) . astyle: astyle --project=.astylerc --recursive *.cpp,*.h releaselog: git log --pretty=format:"%s" $(GOCV_VERSION)..HEAD CMDS=basic-drawing caffe-classifier captest capwindow counter dnn-detection dnn-pose-detection dnn-style-transfer faceblur facedetect facedetect-from-url feature-matching find-chessboard find-circles find-lines hand-gestures hello img-similarity mjpeg-streamer motion-detect saveimage savevideo showimage ssd-facedetect tf-classifier tracking version xphoto cmds: for cmd in $(CMDS) ; do \ go build -o build/$$cmd cmd/$$cmd/main.go ; done ; \ ================================================ FILE: README.md ================================================ # GoCV [![GoCV](https://raw.githubusercontent.com/hybridgroup/gocv/release/images/gocvlogo.jpg)](http://gocv.io/) [![Go Reference](https://pkg.go.dev/badge/gocv.io/x/gocv.svg)](https://pkg.go.dev/gocv.io/x/gocv) [![Linux](https://github.com/hybridgroup/gocv/actions/workflows/linux.yml/badge.svg?branch=dev)](https://github.com/hybridgroup/gocv/actions/workflows/linux.yml) [![macOS](https://github.com/hybridgroup/gocv/actions/workflows/macos.yml/badge.svg?branch=dev)](https://github.com/hybridgroup/gocv/actions/workflows/macos.yml) [![Windows](https://github.com/hybridgroup/gocv/actions/workflows/windows.yml/badge.svg?branch=dev)](https://github.com/hybridgroup/gocv/actions/workflows/windows.yml) [![Go Report Card](https://goreportcard.com/badge/github.com/hybridgroup/gocv)](https://goreportcard.com/report/github.com/hybridgroup/gocv) [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://github.com/hybridgroup/gocv/blob/release/LICENSE.txt) The GoCV package provides Go language bindings for the [OpenCV 4](http://opencv.org/) computer vision library. The GoCV package supports the latest releases of Go and OpenCV (v4.12.0) on Linux, Docker, macOS, and Windows. Our ongoing mission is help the Go programming language be a "first-class" client compatible with the latest developments in the OpenCV ecosystem. GoCV supports [CUDA](https://en.wikipedia.org/wiki/CUDA) for hardware acceleration using Nvidia GPUs. Check out the [CUDA README](./cuda/README.md) for more info on how to use GoCV with OpenCV/CUDA. GoCV also supports [Intel OpenVINO](https://software.intel.com/en-us/openvino-toolkit). Check out the [OpenVINO README](./openvino/README.md) for more info on how to use GoCV with the Intel OpenVINO toolkit. ## How to use ### Hello, video This example opens a video capture device using device "0", reads frames, and shows the video in a GUI window: ```go package main import ( "gocv.io/x/gocv" ) func main() { webcam, _ := gocv.OpenVideoCapture(0) window := gocv.NewWindow("Hello") img := gocv.NewMat() for { webcam.Read(&img) window.IMShow(img) window.WaitKey(1) } } ``` ### Face detect ![GoCV](https://raw.githubusercontent.com/hybridgroup/gocv/release/images/face-detect.jpg) This is a more complete example that opens a video capture device using device "0". It also uses the CascadeClassifier class to load an external data file containing the classifier data. The program grabs each frame from the video, then uses the classifier to detect faces. If any faces are found, it draws a green rectangle around each one, then displays the video in an output window: ```go package main import ( "fmt" "image/color" "gocv.io/x/gocv" ) func main() { // set to use a video capture device 0 deviceID := 0 // open webcam webcam, err := gocv.OpenVideoCapture(deviceID) if err != nil { fmt.Println(err) return } defer webcam.Close() // open display window window := gocv.NewWindow("Face Detect") defer window.Close() // prepare image matrix img := gocv.NewMat() defer img.Close() // color for the rect when faces detected blue := color.RGBA{0, 0, 255, 0} // load classifier to recognize faces classifier := gocv.NewCascadeClassifier() defer classifier.Close() if !classifier.Load("data/haarcascade_frontalface_default.xml") { fmt.Println("Error reading cascade file: data/haarcascade_frontalface_default.xml") return } fmt.Printf("start reading camera device: %v\n", deviceID) for { if ok := webcam.Read(&img); !ok { fmt.Printf("cannot read device %v\n", deviceID) return } if img.Empty() { continue } // detect faces rects := classifier.DetectMultiScale(img) fmt.Printf("found %d faces\n", len(rects)) // draw a rectangle around each face on the original image for _, r := range rects { gocv.Rectangle(&img, r, blue, 3) } // show the image in the window, and wait 1 millisecond window.IMShow(img) window.WaitKey(1) } } ``` ### More examples There are examples in the [cmd directory](./cmd) of this repo in the form of various useful command line utilities, such as [capturing an image file](./cmd/saveimage), [streaming mjpeg video](./cmd/mjpeg-streamer), [counting objects that cross a line](./cmd/counter), and [using OpenCV with a DNN for face tracking](./cmd/facedetectYN). ## How to install To install GoCV, you must first have the matching version of OpenCV installed on your system. The current release of GoCV requires OpenCV 4.12.0. We have instructions for Linux, macOS, Windows, and other platform options as well. ### Linux Please see our web site at https://gocv.io/getting-started/linux/ ### macOS Please see our web site at https://gocv.io/getting-started/macos/ ### Windows Please see our web site at https://gocv.io/getting-started/windows/ ### Docker Please see our web site at https://gocv.io/getting-started/docker/ ### Android There is some work in progress for running GoCV on Android using Gomobile. For information on how to install OpenCV/GoCV for Android, please see: https://gist.github.com/ogero/c19458cf64bd3e91faae85c3ac8874120 See original discussion here: https://github.com/hybridgroup/gocv/issues/235 ## Profiling Since memory allocations for images in GoCV are done through C based code, the go garbage collector will not clean all resources associated with a `Mat`. As a result, any `Mat` created _must_ be closed to avoid memory leaks. To ease the detection and repair of the resource leaks, GoCV provides a `Mat` profiler that records when each `Mat` is created and closed. Each time a `Mat` is allocated, the stack trace is added to the profile. When it is closed, the stack trace is removed. See the [runtime/pprof documentation](https://golang.org/pkg/runtime/pprof/#Profile). In order to include the MatProfile custom profiler, you MUST build or run your application or tests using the `-tags matprofile` build tag. For example: go run -tags matprofile cmd/version/main.go You can get the profile's count at any time using: ```go gocv.MatProfile.Count() ``` You can display the current entries (the stack traces) with: ```go var b bytes.Buffer gocv.MatProfile.WriteTo(&b, 1) fmt.Print(b.String()) ``` This can be very helpful to track down a leak. For example, suppose you have the following nonsense program: ```go package main import ( "bytes" "fmt" "gocv.io/x/gocv" ) func leak() { gocv.NewMat() } func main() { fmt.Printf("initial MatProfile count: %v\n", gocv.MatProfile.Count()) leak() fmt.Printf("final MatProfile count: %v\n", gocv.MatProfile.Count()) var b bytes.Buffer gocv.MatProfile.WriteTo(&b, 1) fmt.Print(b.String()) } ``` Running this program produces the following output: ``` initial MatProfile count: 0 final MatProfile count: 1 gocv.io/x/gocv.Mat profile: total 1 1 @ 0x40b936c 0x40b93b7 0x40b94e2 0x40b95af 0x402cd87 0x40558e1 # 0x40b936b gocv.io/x/gocv.newMat+0x4b /go/src/gocv.io/x/gocv/core.go:153 # 0x40b93b6 gocv.io/x/gocv.NewMat+0x26 /go/src/gocv.io/x/gocv/core.go:159 # 0x40b94e1 main.leak+0x21 /go/src/github.com/dougnd/gocvprofexample/main.go:11 # 0x40b95ae main.main+0xae /go/src/github.com/dougnd/gocvprofexample/main.go:16 # 0x402cd86 runtime.main+0x206 /usr/local/Cellar/go/1.11.1/libexec/src/runtime/proc.go:201 ``` We can see that this program would leak memory. As it exited, it had one `Mat` that was never closed. The stack trace points to exactly which line the allocation happened on (line 11, the `gocv.NewMat()`). Furthermore, if the program is a long running process or if GoCV is being used on a web server, it may be helpful to install the HTTP interface )). For example: ```go package main import ( "net/http" _ "net/http/pprof" "time" "gocv.io/x/gocv" ) func leak() { gocv.NewMat() } func main() { go func() { ticker := time.NewTicker(time.Second) for { <-ticker.C leak() } }() http.ListenAndServe("localhost:6060", nil) } ``` This will leak a `Mat` once per second. You can see the current profile count and stack traces by going to the installed HTTP debug interface: [http://localhost:6060/debug/pprof/gocv.io/x/gocv.Mat](http://localhost:6060/debug/pprof/gocv.io/x/gocv.Mat?debug=1). ## How to contribute Please take a look at our [CONTRIBUTING.md](./CONTRIBUTING.md) document to understand our contribution guidelines. Then check out our [ROADMAP.md](./ROADMAP.md) document to know what to work on next. ## Why this project exists The [https://github.com/go-opencv/go-opencv](https://github.com/go-opencv/go-opencv) package for Go and OpenCV did not support any version above OpenCV 2.x, and work on adding support for OpenCV 3 had stalled for over a year, mostly due to the complexity of [SWIG](http://swig.org/). That is why we started this project. The GoCV package uses a C-style wrapper around the OpenCV 4 C++ classes to avoid having to deal with applying SWIG to a huge existing codebase. The mappings are intended to match as closely as possible to the original OpenCV project structure, to make it easier to find things, and to be able to figure out where to add support to GoCV for additional OpenCV image filters, algorithms, and other features. For example, the [OpenCV `videoio` module](https://github.com/opencv/opencv/tree/master/modules/videoio) wrappers can be found in the GoCV package in the `videoio.*` files. This package was inspired by the original https://github.com/go-opencv/go-opencv project, the blog post https://medium.com/@peterleyssens/using-opencv-3-from-golang-5510c312a3c and the repo at https://github.com/sensorbee/opencv thank you all! ## License Licensed under the Apache 2.0 license. Copyright (c) 2017-2026 The Hybrid Group. Logo generated by GopherizeMe - https://gopherize.me ================================================ FILE: ROADMAP.md ================================================ # Roadmap This is a list of all of the functionality areas within OpenCV, and OpenCV Contrib. Any section listed with an "X" means that all of the relevant OpenCV functionality has been wrapped for use within GoCV. Any section listed with **WORK STARTED** indicates that some work has been done, but not all functionality in that module has been completed. If there are any functions listed under a section marked **WORK STARTED**, it indicates that that function still requires a wrapper implemented. And any section that is simply listed, indicates that so far, no work has been done on that module. Your pull requests will be greatly appreciated! ## Modules list - [ ] **core. Core functionality - WORK STARTED** - [X] **Basic structures** - [X] **Operations on arrays** - [X] **XML/YAML Persistence** - [ ] **Clustering - WORK STARTED**. The following functions still need implementation: - [ ] [partition](https://docs.opencv.org/4.x/d5/d38/group__core__cluster.html#ga2037c989e69b499c1aa271419f3a9b34) - [ ] Optimization Algorithms - [ ] [ConjGradSolver](https://docs.opencv.org/4.x/d0/d21/classcv_1_1ConjGradSolver.html) - [ ] [DownhillSolver](https://docs.opencv.org/4.x/d4/d43/classcv_1_1DownhillSolver.html) - [ ] [solveLP](https://docs.opencv.org/4.x/da/d01/group__core__optim.html#ga9a06d237a9d38ace891efa1ca1b5d00a) - [ ] **imgproc. Image processing - WORK STARTED** - [ ] **Image Filtering - WORK STARTED** The following functions still need implementation: - [ ] [buildPyramid](https://docs.opencv.org/4.x/d4/d86/group__imgproc__filter.html#gacfdda2bc1ac55e96de7e9f0bce7238c0) - [ ] [getDerivKernels](https://docs.opencv.org/4.x/d4/d86/group__imgproc__filter.html#ga6d6c23f7bd3f5836c31cfae994fc4aea) - [ ] [getGaborKernel](https://docs.opencv.org/4.x/d4/d86/group__imgproc__filter.html#gae84c92d248183bd92fa713ce51cc3599) - [ ] [pyrMeanShiftFiltering](https://docs.opencv.org/4.x/d4/d86/group__imgproc__filter.html#ga9fabdce9543bd602445f5db3827e4cc0) - [ ] **Geometric Image Transformations - WORK STARTED** The following functions still need implementation: - [ ] [convertMaps](https://docs.opencv.org/4.x/da/d54/group__imgproc__transform.html#ga9156732fa8f01be9ebd1a194f2728b7f) - [ ] [getDefaultNewCameraMatrix](https://docs.opencv.org/4.x/da/d54/group__imgproc__transform.html#ga744529385e88ef7bc841cbe04b35bfbf) - [ ] [initUndistortRectifyMap](https://docs.opencv.org/4.x/da/d54/group__imgproc__transform.html#ga7dfb72c9cf9780a347fbe3d1c47e5d5a) - [ ] [initWideAngleProjMap](https://docs.opencv.org/4.x/da/d54/group__imgproc__transform.html#gaceb049ec48898d1dadd5b50c604429c8) - [ ] [undistort](https://docs.opencv.org/4.x/da/d54/group__imgproc__transform.html#ga69f2545a8b62a6b0fc2ee060dc30559d) - [ ] **Miscellaneous Image Transformations - WORK STARTED** The following functions still need implementation: - [ ] [blendLinear](https://docs.opencv.org/4.x/d7/d1b/group__imgproc__misc.html#ga5e76540a679333d7c6cd0617c452c23d) - [ ] [cvtColorTwoPlane](https://docs.opencv.org/4.x/d8/d01/group__imgproc__color__conversions.html#ga8d4cb64f7c6f03cc2b1f2356734b909d) - [ ] [floodFill](https://docs.opencv.org/4.x/d7/d1b/group__imgproc__misc.html#ga366aae45a6c1289b341d140839f18717) - [ ] **Drawing Functions - WORK STARTED** The following functions still need implementation: - [ ] [drawMarker](https://docs.opencv.org/4.x/d6/d6e/group__imgproc__draw.html#ga482fa7b0f578fcdd8a174904592a6250) - [ ] [ellipse2Poly](https://docs.opencv.org/4.x/d6/d6e/group__imgproc__draw.html#ga727a72a3f6a625a2ae035f957c61051f) - [ ] [fillConvexPoly](https://docs.opencv.org/4.x/d6/d6e/group__imgproc__draw.html#ga906aae1606ea4ed2f27bec1537f6c5c2) - [ ] [getFontScaleFromHeight](https://docs.opencv.org/4.x/d6/d6e/group__imgproc__draw.html#ga442ff925c1a957794a1309e0ed3ba2c3) - [X] **ColorMaps in OpenCV** - [ ] Planar Subdivision - [ ] [Subdiv2D](https://docs.opencv.org/4.10.0/df/dbf/classcv_1_1Subdiv2D.html) - [X] **Histograms** - [ ] **Structural Analysis and Shape Descriptors - WORK STARTED** The following functions still need implementation: - [ ] [fitEllipseAMS](https://docs.opencv.org/4.x/d3/dc0/group__imgproc__shape.html#ga69e90cda55c4e192a8caa0b99c3e4550) - [ ] [fitEllipseDirect](https://docs.opencv.org/4.x/d3/dc0/group__imgproc__shape.html#ga6421884fd411923a74891998bbe9e813) - [ ] [HuMoments](https://docs.opencv.org/4.x/d3/dc0/group__imgproc__shape.html#gab001db45c1f1af6cbdbe64df04c4e944) - [ ] [intersectConvexConvex](https://docs.opencv.org/4.x/d3/dc0/group__imgproc__shape.html#ga8e840f3f3695613d32c052bec89e782c) - [ ] [isContourConvex](https://docs.opencv.org/4.x/d3/dc0/group__imgproc__shape.html#ga8abf8010377b58cbc16db6734d92941b) - [ ] [minEnclosingTriangle](https://docs.opencv.org/4.x/d3/dc0/group__imgproc__shape.html#ga1513e72f6bbdfc370563664f71e0542f) - [ ] [rotatedRectangleIntersection](https://docs.opencv.org/4.x/d3/dc0/group__imgproc__shape.html#ga8740e7645628c59d238b0b22c2abe2d4) - [X] **Motion Analysis and Object Tracking** - [ ] **Feature Detection - WORK STARTED** The following functions still need implementation: - [ ] [cornerEigenValsAndVecs](https://docs.opencv.org/4.x/dd/d1a/group__imgproc__feature.html#ga4055896d9ef77dd3cacf2c5f60e13f1c) - [ ] [cornerHarris](https://docs.opencv.org/4.x/dd/d1a/group__imgproc__feature.html#gac1fc3598018010880e370e2f709b4345) - [ ] [cornerMinEigenVal](https://docs.opencv.org/4.x/dd/d1a/group__imgproc__feature.html#ga3dbce297c1feb859ee36707e1003e0a8) - [ ] [createLineSegmentDetector](https://docs.opencv.org/4.x/dd/d1a/group__imgproc__feature.html#ga6b2ad2353c337c42551b521a73eeae7d) - [ ] [preCornerDetect](https://docs.opencv.org/4.x/dd/d1a/group__imgproc__feature.html#gaa819f39b5c994871774081803ae22586) - [X] **Object Detection** - [X] **imgcodecs. Image file reading and writing.** - [X] **videoio. Video I/O** - [X] **highgui. High-level GUI** - [ ] **video. Video Analysis - WORK STARTED** - [X] **Motion Analysis** - [ ] **Object Tracking - WORK STARTED** The following functions still need implementation: - [ ] [buildOpticalFlowPyramid](https://docs.opencv.org/4.x/dc/d6b/group__video__track.html#ga86640c1c470f87b2660c096d2b22b2ce) - [ ] [estimateRigidTransform](https://docs.opencv.org/4.x/dc/d6b/group__video__track.html#ga762cbe5efd52cf078950196f3c616d48) - [ ] [findTransformECC](https://docs.opencv.org/4.x/dc/d6b/group__video__track.html#ga7ded46f9a55c0364c92ccd2019d43e3a) - [ ] [meanShift](https://docs.opencv.org/4.x/dc/d6b/group__video__track.html#ga7ded46f9a55c0364c92ccd2019d43e3a) - [ ] [CamShift](https://docs.opencv.org/4.x/dc/d6b/group__video__track.html#gaef2bd39c8356f423124f1fe7c44d54a1) - [ ] [DualTVL1OpticalFlow](https://docs.opencv.org/4.x/dc/d47/classcv_1_1DualTVL1OpticalFlow.html) - [ ] [FarnebackOpticalFlow](https://docs.opencv.org/4.x/de/d9e/classcv_1_1FarnebackOpticalFlow.html) - [ ] [SparsePyrLKOpticalFlow](https://docs.opencv.org/4.x/d7/d08/classcv_1_1SparsePyrLKOpticalFlow.html) - [ ] [TrackerDaSiamRPN](https://docs.opencv.org/4.x/de/d93/classcv_1_1TrackerDaSiamRPN.html) - [ ] [TrackerNano](https://docs.opencv.org/4.x/d8/d69/classcv_1_1TrackerNano.html) - [ ] **calib3d. Camera Calibration and 3D Reconstruction - WORK STARTED**. The following functions still need implementation: - [ ] **Camera Calibration - WORK STARTED** The following functions still need implementation: - [ ] [calibrateCameraRO](https://docs.opencv.org/4.x/d9/d0c/group__calib3d.html#gacb6b35670216b24b67c70fcd21519ead) - [ ] [calibrateHandEye](https://docs.opencv.org/4.x/d9/d0c/group__calib3d.html#gaebfc1c9f7434196a374c382abf43439b) - [ ] [calibrateRobotWorldHandEye](https://docs.opencv.org/4.x/d9/d0c/group__calib3d.html#ga41b1a8dd70eae371eba707d101729c36) - [ ] [calibrationMatrixValues](https://docs.opencv.org/4.x/d9/d0c/group__calib3d.html) - [ ] [composeRT](https://docs.opencv.org/4.x/d9/d0c/group__calib3d.html) - [ ] [computeCorrespondEpilines](https://docs.opencv.org/4.x/d9/d0c/group__calib3d.html) - [ ] [convertPointsHomogeneous](https://docs.opencv.org/4.x/d9/d0c/group__calib3d.html) - [ ] [convertPointsToHomogeneous](https://docs.opencv.org/4.x/d9/d0c/group__calib3d.html) - [ ] [correctMatches](https://docs.opencv.org/4.x/d9/d0c/group__calib3d.html) - [ ] [decomposeEssentialMat](https://docs.opencv.org/4.x/d9/d0c/group__calib3d.html) - [ ] [decomposeHomographyMat](https://docs.opencv.org/4.x/d9/d0c/group__calib3d.html) - [ ] [decomposeProjectionMatrix](https://docs.opencv.org/4.x/d9/d0c/group__calib3d.html) - [ ] [drawChessboardCorners](https://docs.opencv.org/4.x/d9/d0c/group__calib3d.html) - [ ] [drawFrameAxes](https://docs.opencv.org/4.x/d9/d0c/group__calib3d.html) - [ ] [estimateAffine3D](https://docs.opencv.org/4.x/d9/d0c/group__calib3d.html) - [ ] [filterHomographyDecompByVisibleRefpoints](https://docs.opencv.org/4.x/d9/d0c/group__calib3d.html) - [ ] [filterSpeckles](https://docs.opencv.org/4.x/d9/d0c/group__calib3d.html) - [ ] [find4QuadCornerSubpix](https://docs.opencv.org/4.x/d9/d0c/group__calib3d.html) - [ ] [findCirclesGrid](https://docs.opencv.org/4.x/d9/d0c/group__calib3d.html) - [ ] [findEssentialMat](https://docs.opencv.org/4.x/d9/d0c/group__calib3d.html) - [ ] [findFundamentalMat](https://docs.opencv.org/4.x/d9/d0c/group__calib3d.html) - [ ] [getDefaultNewCameraMatrix](https://docs.opencv.org/4.x/d9/d0c/group__calib3d.html) - [ ] [getOptimalNewCameraMatrix](https://docs.opencv.org/4.x/d9/d0c/group__calib3d.html) - [ ] [getValidDisparityROI](https://docs.opencv.org/4.x/d9/d0c/group__calib3d.html) - [ ] [initCameraMatrix2D](https://docs.opencv.org/4.x/d9/d0c/group__calib3d.html) - [ ] [initUndistortRectifyMap](https://docs.opencv.org/4.x/d9/d0c/group__calib3d.html) - [ ] [initWideAngleProjMap](https://docs.opencv.org/4.x/d9/d0c/group__calib3d.html) - [ ] [matMulDeriv](https://docs.opencv.org/4.x/d9/d0c/group__calib3d.html) - [ ] [projectPoints](https://docs.opencv.org/4.x/d9/d0c/group__calib3d.html) - [ ] [recoverPose](https://docs.opencv.org/4.x/d9/d0c/group__calib3d.html) - [ ] [rectify3Collinear](https://docs.opencv.org/4.x/d9/d0c/group__calib3d.html) - [ ] [reprojectImageTo3D](https://docs.opencv.org/4.x/d9/d0c/group__calib3d.html) - [ ] [RQDecomp3x3](https://docs.opencv.org/4.x/d9/d0c/group__calib3d.html) - [ ] [sampsonDistance](https://docs.opencv.org/4.x/d9/d0c/group__calib3d.html) - [ ] [solveP3P](https://docs.opencv.org/4.x/d9/d0c/group__calib3d.html) - [ ] [solvePnPGeneric](https://docs.opencv.org/4.x/d9/d0c/group__calib3d.html) - [ ] [solvePnPRansac](https://docs.opencv.org/4.x/d9/d0c/group__calib3d.html) - [ ] [solvePnPRefineLM](https://docs.opencv.org/4.x/d9/d0c/group__calib3d.html) - [ ] [solvePnPRefineVVS](https://docs.opencv.org/4.x/d9/d0c/group__calib3d.html) - [ ] [stereoCalibrate](https://docs.opencv.org/4.x/d9/d0c/group__calib3d.html) - [ ] [stereoRectifyUncalibrated](https://docs.opencv.org/4.x/d9/d0c/group__calib3d.html) - [ ] [validateDisparity](https://docs.opencv.org/4.x/d9/d0c/group__calib3d.html) - [ ] **Fisheye - WORK STARTED** The following functions still need implementation: - [ ] [projectPoints](https://docs.opencv.org/4.x/db/d58/group__calib3d__fisheye.html#gab1ad1dc30c42ee1a50ce570019baf2c4) - [ ] [stereoCalibrate](https://docs.opencv.org/4.x/db/d58/group__calib3d__fisheye.html#gadbb3a6ca6429528ef302c784df47949b) - [ ] [stereoRectify](https://docs.opencv.org/4.x/db/d58/group__calib3d__fisheye.html#gac1af58774006689056b0f2ef1db55ecc) - [ ] **features2d. 2D Features Framework - WORK STARTED** - [X] **Feature Detection and Description** - [X] **Descriptor Matchers** - [X] **Drawing Function of Keypoints and Matches** - [ ] Object Categorization - [ ] [BOWImgDescriptorExtractor](https://docs.opencv.org/4.x/d2/d6b/classcv_1_1BOWImgDescriptorExtractor.html) - [ ] [BOWKMeansTrainer](https://docs.opencv.org/4.x/d4/d72/classcv_1_1BOWKMeansTrainer.html) - [ ] **objdetect. Object Detection** - [X] **Face Detection** - [ ] **aruco. ArUco Marker Detection - WORK STARTED** - [ ] [refineDetectedMarkers](https://docs.opencv.org/4.x/d2/d1a/classcv_1_1aruco_1_1ArucoDetector.html#ad806c9310cfc826a178b0aefdf09bab6) - [ ] [refineDetectedMarkers](https://docs.opencv.org/4.x/d2/d1a/classcv_1_1aruco_1_1ArucoDetector.html#ad806c9310cfc826a178b0aefdf09bab6) - [ ] [drawDetectedCornersCharuco](https://docs.opencv.org/4.x/de/d67/group__objdetect__aruco.html#ga7225eee644190f791e1583c499b7ab10) - [ ] [drawDetectedDiamonds](https://docs.opencv.org/4.x/de/d67/group__objdetect__aruco.html#ga0dbf27203267fb8e9f282554cf0d3433) - [ ] [extendDictionary](https://docs.opencv.org/4.x/de/d67/group__objdetect__aruco.html#ga928c031e9a782b18405af56c851d9549) - [ ] [CharucoDetector](https://docs.opencv.org/4.x/d9/df5/classcv_1_1aruco_1_1CharucoDetector.html#ad7647d1c3d0e2db97bedc31f743e796b) - [ ] [detectBoard](https://docs.opencv.org/4.x/d9/df5/classcv_1_1aruco_1_1CharucoDetector.html#aacbea601612a3a0feaa45ebb7fb255fd) - [ ] [detectDiamonds](https://docs.opencv.org/4.x/d9/df5/classcv_1_1aruco_1_1CharucoDetector.html#a50342803f68deb1e6b0b79f61d4b1a73) - [X] **dnn. Deep Neural Network module** - [ ] ml. Machine Learning - [ ] [ANN_MLP](https://docs.opencv.org/4.x/d0/dce/classcv_1_1ml_1_1ANN__MLP.html) - [ ] [Boost](https://docs.opencv.org/4.x/d6/d7a/classcv_1_1ml_1_1Boost.html) - [ ] [DTrees](https://docs.opencv.org/4.x/d8/d89/classcv_1_1ml_1_1DTrees.html) - [ ] [EM](https://docs.opencv.org/4.x/d1/dfb/classcv_1_1ml_1_1EM.html) - [ ] [KNearest](https://docs.opencv.org/4.x/dd/de1/classcv_1_1ml_1_1KNearest.html) - [ ] [LogisticRegression](https://docs.opencv.org/4.x/d6/df9/classcv_1_1ml_1_1LogisticRegression.html) - [ ] [NormalBayesClassifier](https://docs.opencv.org/4.x/d4/d8e/classcv_1_1ml_1_1NormalBayesClassifier.html) - [ ] [ParamGrid](https://docs.opencv.org/4.x/d6/dca/classcv_1_1ml_1_1ParamGrid.html) - [ ] [RTrees](https://docs.opencv.org/4.x/d0/d65/classcv_1_1ml_1_1RTrees.html) - [ ] [SimulatedAnnealingSolverSystem](https://docs.opencv.org/4.x/dc/db4/structcv_1_1ml_1_1SimulatedAnnealingSolverSystem.html) - [ ] [SVM](https://docs.opencv.org/4.x/d1/d2d/classcv_1_1ml_1_1SVM.html) - [ ] [SVMSVG](https://docs.opencv.org/4.x/de/d54/classcv_1_1ml_1_1SVMSGD.html) - [ ] [TrainData](https://docs.opencv.org/4.x/dc/d32/classcv_1_1ml_1_1TrainData.html) - [ ] flann. Clustering and Search in Multi-Dimensional Spaces - [ ] [hierarchicalClustering](https://docs.opencv.org/4.x/dc/de5/group__flann.html#gaf89c8914eb439855c9a24c3de01bfd82) - [ ] **photo. Computational Photography - WORK STARTED** The following functions still need implementation: - [ ] [denoise_TVL1](https://docs.opencv.org/4.x/d1/d79/group__photo__denoise.html#ga7602ed5ae17b7de40152b922227c4e4f) - [ ] [createCalibrateDebevec](https://docs.opencv.org/4.x/d6/df5/group__photo__hdr.html#ga7fed9707ad5f2cc0e633888867109f90) - [ ] [createCalibrateRobertson](https://docs.opencv.org/4.x/d6/df5/group__photo__hdr.html#gae77813a21cd351a596619e5ff013be5d) - [ ] [createMergeDebevec](https://docs.opencv.org/4.x/d6/df5/group__photo__hdr.html#gaa8eab36bc764abb2a225db7c945f87f9) - [ ] [createMergeRobertson](https://docs.opencv.org/4.x/d6/df5/group__photo__hdr.html#ga460d4a1df1a7e8cdcf7445bb87a8fb78) - [ ] [createTonemap](https://docs.opencv.org/4.x/d6/df5/group__photo__hdr.html#gabcbd653140b93a1fa87ccce94548cd0d) - [ ] [createTonemapDrago](https://docs.opencv.org/4.x/d6/df5/group__photo__hdr.html#ga72bf92bb6b8653ee4be650ac01cf50b6) - [ ] [createTonemapMantiuk](https://docs.opencv.org/4.x/d6/df5/group__photo__hdr.html#ga3b3f3bf083b7515802f039a6a70f2d21) - [ ] [createTonemapReinhard](https://docs.opencv.org/4.x/d6/df5/group__photo__hdr.html#gadabe7f6bf1fa96ad0fd644df9182c2fb) - [ ] stitching. Images stitching - [ ] [Stitcher](https://docs.opencv.org/4.x/d2/d8d/classcv_1_1Stitcher.html) ## CUDA - [X] **core** - [ ] **cudaarithm. Operations on Matrices - WORK STARTED** The following functions still need implementation: - [X] **core** - [ ] **per-element operations - WORK STARTED** The following functions still need implementation: - [ ] [cv::cuda::cartToPolar](https://docs.opencv.org/4.x/d8/d34/group__cudaarithm__elem.html#ga82210c7d1c1d42e616e554bf75a53480) - [ ] [cv::cuda::inRange](https://docs.opencv.org/4.x/d8/d34/group__cudaarithm__elem.html#gaf611ab6b1d85e951feb6f485b1ed9672) - [ ] [cv::cuda::magnitude](https://docs.opencv.org/4.x/d8/d34/group__cudaarithm__elem.html#ga3d17f4fcd79d7c01fadd217969009463) - [ ] [cv::cuda::magnitudeSqr](https://docs.opencv.org/4.x/d8/d34/group__cudaarithm__elem.html#ga7613e382d257e150033d0ce4d6098f6a) - [ ] [cv::cuda::phase](https://docs.opencv.org/4.x/d8/d34/group__cudaarithm__elem.html#ga5b75ec01be06dcd6e27ada09a0d4656a) - [ ] [cv::cuda::polarToCart](https://docs.opencv.org/4.x/d8/d34/group__cudaarithm__elem.html#ga01516a286a329c303c2db746513dd9df) - [ ] [cv::cuda::pow](https://docs.opencv.org/4.x/d8/d34/group__cudaarithm__elem.html#ga82d04ef4bcc4dfa9bfbe76488007c6c4) - [ ] **matrix reductions - WORK STARTED** The following functions still need implementation: - [ ] [cv::cuda::calcSqrSum](https://docs.opencv.org/4.x/d5/de6/group__cudaarithm__reduce.html#gac998c83597f6c206c78cee16aa87946f) - [ ] [cv::cuda::calcSum](https://docs.opencv.org/4.x/d5/de6/group__cudaarithm__reduce.html#ga98a09144047f09f5cb1d6b6ea8e0856f) - [ ] [cv::cuda::countNonZero](https://docs.opencv.org/4.x/d5/de6/group__cudaarithm__reduce.html#ga98a09144047f09f5cb1d6b6ea8e0856f) - [ ] [cv::cuda::integral](https://docs.opencv.org/4.x/d5/de6/group__cudaarithm__reduce.html#ga07e5104eba4bf45212ac9dbc5bf72ba6) - [ ] [cv::cuda::meanStdDev](https://docs.opencv.org/4.x/d5/de6/group__cudaarithm__reduce.html#ga990a4db4c6d7e8f0f3a6685ba48fbddc) - [ ] [cv::cuda::rectStdDev](https://docs.opencv.org/4.x/d5/de6/group__cudaarithm__reduce.html#gac311484a4e57cab2ce2cfdc195fda7ee) - [ ] [cv::cuda::reduce](https://docs.opencv.org/4.x/d5/de6/group__cudaarithm__reduce.html#ga21d57f661db7be093caf2c4378be2007) - [ ] [cv::cuda::sqrIntegral](https://docs.opencv.org/4.x/d5/de6/group__cudaarithm__reduce.html#ga40c75196202706399a60bf6ba7a052ac) - [ ] [cv::cuda::sqlSum](https://docs.opencv.org/4.x/d5/de6/group__cudaarithm__reduce.html#ga056c804ebf5d2eb9f6f35e3dcb01524c) - [ ] [cv::cuda::sum](https://docs.opencv.org/4.x/d5/de6/group__cudaarithm__reduce.html#ga1f582844670199281e8012733b50c582) - [ ] **Operations on matrices - WORK STARTED** The following functions still need implementation: - [ ] [cv::cuda::createConvolution](https://docs.opencv.org/4.5.0/d9/d88/group__cudaarithm__arithm.html#ga2695e05ef624bf3ce03cfbda383a821d) - [ ] [cv::cuda::createDFT](https://docs.opencv.org/4.5.0/d9/d88/group__cudaarithm__arithm.html#ga0f72d063b73c8bb995678525eb076f10) - [ ] [cv::cuda::dft](https://docs.opencv.org/4.5.0/d9/d88/group__cudaarithm__arithm.html#gadea99cb15a715c983bcc2870d65a2e78) - [ ] [cv::cuda::gemm](https://docs.opencv.org/4.5.0/d9/d88/group__cudaarithm__arithm.html#ga42efe211d7a43bbc922da044c4f17130) - [ ] [cv::cuda::mulAndScaleSpectrums](https://docs.opencv.org/4.5.0/d9/d88/group__cudaarithm__arithm.html#ga5704c25b8be4f19da812e6d98c8ee464) - [ ] [cv::cuda::mulSpectrums](https://docs.opencv.org/4.5.0/d9/d88/group__cudaarithm__arithm.html#gab3e8900d67c4f59bdc137a0495206cd8) - [X] **cudabgsegm. Background Segmentation** - [ ] **cudacodec** Video Encoding/Decoding. The following functions still need implementation: - [ ] [cv::cuda::VideoReader](https://docs.opencv.org/4.x/db/ded/classcv_1_1cudacodec_1_1VideoReader.html) - [ ] [cv::cuda::VideoWriter](https://docs.opencv.org/4.x/df/dde/classcv_1_1cudacodec_1_1VideoWriter.html) - [ ] **cudafeatures2d** Feature Detection and Description. The following functions still need implementation: - [ ] [cv::cuda::FastFeatureDetector](https://docs.opencv.org/4.x/d4/d6a/classcv_1_1cuda_1_1FastFeatureDetector.html) - [ ] [cv::cuda::ORB](https://docs.opencv.org/4.x/da/d44/classcv_1_1cuda_1_1ORB.html) - [ ] **cudafilters. Image Filtering - WORK STARTED** The following functions still need implementation: - [ ] [cv::cuda::createBoxFilter](https://docs.opencv.org/4.x/dc/d66/group__cudafilters.html#ga3113b66e289bad7caef412e6e13ec2be) - [ ] [cv::cuda::createBoxMaxFilter](https://docs.opencv.org/4.x/dc/d66/group__cudafilters.html#gaaf4740c51128d23a37f6f1b22cee49e8) - [ ] [cv::cuda::createBoxMinFilter](https://docs.opencv.org/4.x/dc/d66/group__cudafilters.html#ga77fd36949bc8d92aabc120b4b1cfaafa) - [ ] [cv::cuda::createColumnSumFilter](https://docs.opencv.org/4.x/dc/d66/group__cudafilters.html#gac13bf7c41a34bfde2a7f33ad8caacfdf) - [ ] [cv::cuda::createDerivFilter](https://docs.opencv.org/4.x/dc/d66/group__cudafilters.html#ga14d76dc6982ce739c67198f52bc16ee1) - [ ] [cv::cuda::createLaplacianFilter](https://docs.opencv.org/4.x/dc/d66/group__cudafilters.html#ga53126e88bb7e6185dcd5628e28e42cd2) - [ ] [cv::cuda::createLinearFilter](https://docs.opencv.org/4.x/dc/d66/group__cudafilters.html#ga57cb1804ad9d1280bf86433858daabf9) - [ ] [cv::cuda::createMorphologyFilter](https://docs.opencv.org/4.x/dc/d66/group__cudafilters.html#gae58694e07be6bdbae126f36c75c08ee6) - [ ] [cv::cuda::createRowSumFilter](https://docs.opencv.org/4.x/dc/d66/group__cudafilters.html#gaf735de273ccb5072f3c27816fb97a53a) - [ ] [cv::cuda::createScharrFilter](https://docs.opencv.org/4.x/dc/d66/group__cudafilters.html#ga4ac8df158e5771ddb0bd5c9091188ce6) - [ ] [cv::cuda::createSeparableLinearFilter](https://docs.opencv.org/4.x/dc/d66/group__cudafilters.html#gaf7b79a9a92992044f328dad07a52c4bf) - [ ] **cudaimgproc. Image Processing - WORK STARTED** The following functions still need implementation: - [ ] [cv::cuda::CLAHE](https://docs.opencv.org/4.x/db/d79/classcv_1_1cuda_1_1CLAHE.html) - [ ] [cv::cuda::HoughCirclesDetector](https://docs.opencv.org/4.x/da/d80/classcv_1_1cuda_1_1HoughCirclesDetector.html) - [ ] [cv::cuda::createGoodFeaturesToTrackDetector](https://docs.opencv.org/4.x/dc/d6d/group__cudaimgproc__feature.html#ga478b474a598ece101f7e706fee2c8e91) - [ ] [cv::cuda::createHarrisCorner](https://docs.opencv.org/4.x/dc/d6d/group__cudaimgproc__feature.html#ga3e5878a803e9bba51added0c10101979) - [ ] [cv::cuda::createMinEigenValCorner](https://docs.opencv.org/4.x/dc/d6d/group__cudaimgproc__feature.html#ga7457fd4b53b025f990b1c1dd1b749915) - [X] **cudaobjdetect. Object Detection** - [ ] **cudaoptflow. Optical Flow - WORK STARTED** The following functions still need implementation: - [ ] [BroxOpticalFlow](https://docs.opencv.org/4.x/d7/d18/classcv_1_1cuda_1_1BroxOpticalFlow.html) - [ ] [DenseOpticalFlow](https://docs.opencv.org/4.x/d6/d4a/classcv_1_1cuda_1_1DenseOpticalFlow.html) - [ ] [DensePyrLKOpticalFlow](https://docs.opencv.org/4.x/d0/da4/classcv_1_1cuda_1_1DensePyrLKOpticalFlow.html) - [ ] [FarnebackOpticalFlow](https://docs.opencv.org/4.x/d9/d30/classcv_1_1cuda_1_1FarnebackOpticalFlow.html) - [ ] [NvidiaHWOpticalFlow](https://docs.opencv.org/4.x/d5/d26/classcv_1_1cuda_1_1NvidiaHWOpticalFlow.html) - [ ] [NvidiaOpticalFlow_1_0](https://docs.opencv.org/4.x/dc/d9d/classcv_1_1cuda_1_1NvidiaOpticalFlow__1__0.html) - [ ] [SparseOpticalFlow](https://docs.opencv.org/4.x/d5/dcf/classcv_1_1cuda_1_1SparseOpticalFlow.html) - [ ] **[SparsePyrLKOpticalFlow](https://docs.opencv.org/4.x/d7/d05/classcv_1_1cuda_1_1SparsePyrLKOpticalFlow.html) - WORK STARTED** - [ ] **cudastereo** Stereo Correspondence - [ ] [cv::cuda::createDisparityBilateralFilter](https://docs.opencv.org/4.x/dd/d47/group__cudastereo.html#gaafb5f9902f7a9e74cb2cd4e680569590) - [ ] [cv::cuda::createStereoBeliefPropagation](https://docs.opencv.org/4.x/dd/d47/group__cudastereo.html#ga8d22dd80bdfb4e3d7d2ac09e8a07c22b) - [ ] [cv::cuda::createStereoBM](https://docs.opencv.org/4.x/dd/d47/group__cudastereo.html#ga77edc901350dd0a7f46ec5aca4138039) - [ ] [cv::cuda::createStereoConstantSpaceBP](https://docs.opencv.org/4.x/dd/d47/group__cudastereo.html#gaec3b49c7cf9f7701a6f549a227be4df2) - [ ] [cv::cuda::createStereoSGM](https://docs.opencv.org/4.x/dd/d47/group__cudastereo.html#gafb7e5284de5f488d664c3155acb12c93) - [ ] [cv::cuda::drawColorDisp](https://docs.opencv.org/4.x/dd/d47/group__cudastereo.html#ga469b23a77938dd7c06861e59cecc08c5) - [ ] [cv::cuda::reprojectImageTo3D](https://docs.opencv.org/4.x/dd/d47/group__cudastereo.html#gaff851e3932da0f3e74d1be1d8855f094) - [X] **cudawarping. Image Warping** ## Contrib modules list - [ ] alphamat. Alpha Matting - [ ] barcode. Barcode detecting and decoding methods - [ ] **bgsegm. Improved Background-Foreground Segmentation Methods - WORK STARTED** - [ ] bioinspired. Biologically inspired vision models and derivated tools - [ ] ccalib. Custom Calibration Pattern for 3D reconstruction - [ ] cnn_3dobj. 3D object recognition and pose estimation API - [ ] cvv. GUI for Interactive Visual Debugging of Computer Vision Programs - [ ] datasets. Framework for working with different datasets - [ ] dnn_modern. Deep Learning Modern Module - [ ] dnn_objdetect. DNN used for object detection - [ ] dnn_superres. DNN used for super resolution - [ ] dpm. Deformable Part-based Models - [ ] **face. Face Recognition - WORK STARTED** - [X] **freetype. Drawing UTF-8 strings with freetype/harfbuzz** - [ ] fuzzy. Image processing based on fuzzy mathematics - [ ] hdf. Hierarchical Data Format I/O routines - [ ] hfs. Hierarchical Feature Selection for Efficient Image Segmentation - [X] **img_hash. The module brings implementations of different image hashing algorithms.** - [ ] intensity_transform. The module brings implementations of intensity transformation algorithms to adjust image contrast. - [ ] line_descriptor. Binary descriptors for lines extracted from an image - [X] **mcc. Macbeth Chart module** - [ ] optflow. Optical Flow Algorithms - [ ] ovis. OGRE 3D Visualiser - [ ] phase_unwrapping. Phase Unwrapping API - [ ] plot. Plot function for Mat data - [ ] quality. Image Quality Analysis (IQA) API - [ ] rapid. silhouette based 3D object tracking - [ ] reg. Image Registration - [ ] rgbd. RGB-Depth Processing - [ ] saliency. Saliency API - [ ] sfm. Structure From Motion - [ ] shape. Shape Distance and Matching - [ ] signal. Signal Processing - [ ] stereo. Stereo Correspondance Algorithms - [ ] structured_light. Structured Light API - [ ] superres. Super Resolution - [ ] surface_matching. Surface Matching - [ ] text. Scene Text Detection and Recognition - [ ] **tracking. Tracking API - WORK STARTED** - [ ] videostab. Video Stabilization - [ ] viz. 3D Visualizer - [X] **wechat_qrcode. WeChat QR code detector for detecting and parsing QR code** - [ ] **xfeatures2d. Extra 2D Features Framework - WORK STARTED** - [ ] **ximgproc. Extended Image Processing - WORK STARTED** - [X] **xobjdetect. Extended object detection** - [X] **xphoto. Additional photo processing algorithms** ================================================ FILE: aruco.cpp ================================================ //go:build !gocv_specific_modules || (gocv_specific_modules && gocv_aruco) #include "aruco.h" ArucoDetector ArucoDetector_New() { try { return new cv::aruco::ArucoDetector(); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } ArucoDetector ArucoDetector_NewWithParams(ArucoDictionary dictionary, ArucoDetectorParameters params) { try { return new cv::aruco::ArucoDetector(*dictionary, *params); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } void ArucoDetector_Close(ArucoDetector ad) { delete ad; } void ArucoDetector_DetectMarkers(ArucoDetector ad, Mat inputArr, Points2fVector markerCorners, IntVector *markerIds, Points2fVector rejectedCandidates) { try { std::vector _markerIds; ad->detectMarkers(*inputArr, *markerCorners, _markerIds, *rejectedCandidates); int *ids = new int[_markerIds.size()]; for (size_t i = 0; i < _markerIds.size(); ++i) { ids[i] = _markerIds[i]; } markerIds->length = _markerIds.size(); markerIds->val = ids; } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); } } ArucoDetectorParameters ArucoDetectorParameters_Create() { try { return new cv::aruco::DetectorParameters(); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } void ArucoDetectorParameters_SetAdaptiveThreshWinSizeMin(ArucoDetectorParameters ap, int adaptiveThreshWinSizeMin) { ap->adaptiveThreshWinSizeMin = adaptiveThreshWinSizeMin; } int ArucoDetectorParameters_GetAdaptiveThreshWinSizeMin(ArucoDetectorParameters ap) { return ap->adaptiveThreshWinSizeMin; } void ArucoDetectorParameters_SetAdaptiveThreshWinSizeMax(ArucoDetectorParameters ap, int adaptiveThreshWinSizeMax) { ap->adaptiveThreshWinSizeMax = adaptiveThreshWinSizeMax; } int ArucoDetectorParameters_GetAdaptiveThreshWinSizeMax(ArucoDetectorParameters ap) { return ap->adaptiveThreshWinSizeMax; } void ArucoDetectorParameters_SetAdaptiveThreshWinSizeStep(ArucoDetectorParameters ap, int adaptiveThreshWinSizeStep) { ap->adaptiveThreshWinSizeStep = adaptiveThreshWinSizeStep; } int ArucoDetectorParameters_GetAdaptiveThreshWinSizeStep(ArucoDetectorParameters ap) { return ap->adaptiveThreshWinSizeStep; } void ArucoDetectorParameters_SetAdaptiveThreshConstant(ArucoDetectorParameters ap, double adaptiveThreshConstant) { ap->adaptiveThreshConstant = adaptiveThreshConstant; } double ArucoDetectorParameters_GetAdaptiveThreshConstant(ArucoDetectorParameters ap) { return ap->adaptiveThreshConstant; } void ArucoDetectorParameters_SetMinMarkerPerimeterRate(ArucoDetectorParameters ap, double minMarkerPerimeterRate) { ap->minMarkerPerimeterRate = minMarkerPerimeterRate; } double ArucoDetectorParameters_GetMinMarkerPerimeterRate(ArucoDetectorParameters ap){ return ap->minMarkerPerimeterRate; } void ArucoDetectorParameters_SetMaxMarkerPerimeterRate(ArucoDetectorParameters ap, double maxMarkerPerimeterRate) { ap->maxMarkerPerimeterRate = maxMarkerPerimeterRate; } double ArucoDetectorParameters_GetMaxMarkerPerimeterRate(ArucoDetectorParameters ap){ return ap->maxMarkerPerimeterRate; } void ArucoDetectorParameters_SetPolygonalApproxAccuracyRate(ArucoDetectorParameters ap, double polygonalApproxAccuracyRate) { ap->polygonalApproxAccuracyRate = polygonalApproxAccuracyRate; } double ArucoDetectorParameters_GetPolygonalApproxAccuracyRate(ArucoDetectorParameters ap){ return ap->polygonalApproxAccuracyRate; } void ArucoDetectorParameters_SetMinCornerDistanceRate(ArucoDetectorParameters ap, double minCornerDistanceRate) { ap->minCornerDistanceRate = minCornerDistanceRate; } double ArucoDetectorParameters_GetMinCornerDistanceRate(ArucoDetectorParameters ap) { return ap->minCornerDistanceRate; } void ArucoDetectorParameters_SetMinDistanceToBorder(ArucoDetectorParameters ap, int minDistanceToBorder) { ap->minDistanceToBorder = minDistanceToBorder; } int ArucoDetectorParameters_GetMinDistanceToBorder(ArucoDetectorParameters ap) { return ap->minDistanceToBorder; } void ArucoDetectorParameters_SetMinMarkerDistanceRate(ArucoDetectorParameters ap, double minMarkerDistanceRate) { ap->minMarkerDistanceRate = minMarkerDistanceRate; } double ArucoDetectorParameters_GetMinMarkerDistanceRate(ArucoDetectorParameters ap) { return ap->minMarkerDistanceRate; } void ArucoDetectorParameters_SetCornerRefinementMethod(ArucoDetectorParameters ap, int cornerRefinementMethod) { ap->cornerRefinementMethod = cv::aruco::CornerRefineMethod(cornerRefinementMethod); } int ArucoDetectorParameters_GetCornerRefinementMethod(ArucoDetectorParameters ap) { return ap->cornerRefinementMethod; } void ArucoDetectorParameters_SetCornerRefinementWinSize(ArucoDetectorParameters ap, int cornerRefinementWinSize) { ap->cornerRefinementWinSize = cornerRefinementWinSize; } int ArucoDetectorParameters_GetCornerRefinementWinSize(ArucoDetectorParameters ap) { return ap->cornerRefinementWinSize; } void ArucoDetectorParameters_SetCornerRefinementMaxIterations(ArucoDetectorParameters ap, int cornerRefinementMaxIterations) { ap->cornerRefinementMaxIterations = cornerRefinementMaxIterations; } int ArucoDetectorParameters_GetCornerRefinementMaxIterations(ArucoDetectorParameters ap) { return ap->cornerRefinementMaxIterations; } void ArucoDetectorParameters_SetCornerRefinementMinAccuracy(ArucoDetectorParameters ap, double cornerRefinementMinAccuracy) { ap->cornerRefinementMinAccuracy = cornerRefinementMinAccuracy; } double ArucoDetectorParameters_GetCornerRefinementMinAccuracy(ArucoDetectorParameters ap) { return ap->cornerRefinementMinAccuracy; } void ArucoDetectorParameters_SetMarkerBorderBits(ArucoDetectorParameters ap, int markerBorderBits) { ap->markerBorderBits = markerBorderBits; } int ArucoDetectorParameters_GetMarkerBorderBits(ArucoDetectorParameters ap) { return ap->markerBorderBits; } void ArucoDetectorParameters_SetPerspectiveRemovePixelPerCell(ArucoDetectorParameters ap, int perspectiveRemovePixelPerCell) { ap->perspectiveRemovePixelPerCell = perspectiveRemovePixelPerCell; } int ArucoDetectorParameters_GetPerspectiveRemovePixelPerCell(ArucoDetectorParameters ap) { return ap->perspectiveRemovePixelPerCell; } void ArucoDetectorParameters_SetPerspectiveRemoveIgnoredMarginPerCell(ArucoDetectorParameters ap, double perspectiveRemoveIgnoredMarginPerCell) { ap->perspectiveRemoveIgnoredMarginPerCell = perspectiveRemoveIgnoredMarginPerCell; } double ArucoDetectorParameters_GetPerspectiveRemoveIgnoredMarginPerCell(ArucoDetectorParameters ap) { return ap->perspectiveRemoveIgnoredMarginPerCell; } void ArucoDetectorParameters_SetMaxErroneousBitsInBorderRate(ArucoDetectorParameters ap, double maxErroneousBitsInBorderRate) { ap->maxErroneousBitsInBorderRate = maxErroneousBitsInBorderRate; } double ArucoDetectorParameters_GetMaxErroneousBitsInBorderRate(ArucoDetectorParameters ap) { return ap->maxErroneousBitsInBorderRate; } void ArucoDetectorParameters_SetMinOtsuStdDev(ArucoDetectorParameters ap, double minOtsuStdDev) { ap->minOtsuStdDev = minOtsuStdDev; } double ArucoDetectorParameters_GetMinOtsuStdDev(ArucoDetectorParameters ap) { return ap->minOtsuStdDev; } void ArucoDetectorParameters_SetErrorCorrectionRate(ArucoDetectorParameters ap, double errorCorrectionRate) { ap->errorCorrectionRate = errorCorrectionRate; } double ArucoDetectorParameters_GetErrorCorrectionRate(ArucoDetectorParameters ap) { return ap->errorCorrectionRate; } void ArucoDetectorParameters_SetAprilTagQuadDecimate(ArucoDetectorParameters ap, float aprilTagQuadDecimate) { ap->aprilTagQuadDecimate = aprilTagQuadDecimate; } float ArucoDetectorParameters_GetAprilTagQuadDecimate(ArucoDetectorParameters ap) { return ap->aprilTagQuadDecimate; } void ArucoDetectorParameters_SetAprilTagQuadSigma(ArucoDetectorParameters ap, float aprilTagQuadSigma) { ap->aprilTagQuadSigma = aprilTagQuadSigma; } float ArucoDetectorParameters_GetAprilTagQuadSigma(ArucoDetectorParameters ap) { return ap->aprilTagQuadSigma; } void ArucoDetectorParameters_SetAprilTagMinClusterPixels(ArucoDetectorParameters ap, int aprilTagMinClusterPixels) { ap->aprilTagMinClusterPixels = aprilTagMinClusterPixels; } int ArucoDetectorParameters_GetAprilTagMinClusterPixels(ArucoDetectorParameters ap) { return ap->aprilTagMinClusterPixels; } void ArucoDetectorParameters_SetAprilTagMaxNmaxima(ArucoDetectorParameters ap, int aprilTagMaxNmaxima) { ap->aprilTagMaxNmaxima = aprilTagMaxNmaxima; } int ArucoDetectorParameters_GetAprilTagMaxNmaxima(ArucoDetectorParameters ap) { return ap->aprilTagMaxNmaxima; } void ArucoDetectorParameters_SetAprilTagCriticalRad(ArucoDetectorParameters ap, float aprilTagCriticalRad) { ap->aprilTagCriticalRad = aprilTagCriticalRad; } float ArucoDetectorParameters_GetAprilTagCriticalRad(ArucoDetectorParameters ap) { return ap->aprilTagCriticalRad; } void ArucoDetectorParameters_SetAprilTagMaxLineFitMse(ArucoDetectorParameters ap, float aprilTagMaxLineFitMse) { ap->aprilTagMaxLineFitMse = aprilTagMaxLineFitMse; } float ArucoDetectorParameters_GetAprilTagMaxLineFitMse(ArucoDetectorParameters ap) { return ap->aprilTagMaxLineFitMse; } void ArucoDetectorParameters_SetAprilTagMinWhiteBlackDiff(ArucoDetectorParameters ap, int aprilTagMinWhiteBlackDiff) { ap->aprilTagMinWhiteBlackDiff = aprilTagMinWhiteBlackDiff; } int ArucoDetectorParameters_GetAprilTagMinWhiteBlackDiff(ArucoDetectorParameters ap) { return ap->aprilTagMinWhiteBlackDiff; } void ArucoDetectorParameters_SetAprilTagDeglitch(ArucoDetectorParameters ap, int aprilTagDeglitch) { ap->aprilTagDeglitch = aprilTagDeglitch; } int ArucoDetectorParameters_GetAprilTagDeglitch(ArucoDetectorParameters ap) { return ap->aprilTagDeglitch; } void ArucoDetectorParameters_SetDetectInvertedMarker(ArucoDetectorParameters ap, bool detectInvertedMarker) { ap->detectInvertedMarker = detectInvertedMarker; } bool ArucoDetectorParameters_GetDetectInvertedMarker(ArucoDetectorParameters ap) { return ap->detectInvertedMarker; } OpenCVResult ArucoDrawDetectedMarkers(Mat image, Points2fVector markerCorners, IntVector markerIds, Scalar borderColor) { try { std::vector _markerIds; for (int i = 0, *v = markerIds.val; i < markerIds.length; ++v, ++i) { _markerIds.push_back(*v); } cv::Scalar _borderColor = cv::Scalar(borderColor.val1, borderColor.val2, borderColor.val3); cv::aruco::drawDetectedMarkers(*image, *markerCorners, _markerIds, _borderColor); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult ArucoGenerateImageMarker(int dictionaryId, int id, int sidePixels, Mat img, int borderBits) { try { cv::aruco::Dictionary dict = cv::aruco::getPredefinedDictionary(dictionaryId); cv::aruco::generateImageMarker(dict, id, sidePixels, *img, borderBits); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } ArucoDictionary getPredefinedDictionary(int dictionaryId) { try { return new cv::aruco::Dictionary(cv::aruco::getPredefinedDictionary(dictionaryId)); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } ================================================ FILE: aruco.go ================================================ //go:build !gocv_specific_modules || (gocv_specific_modules && gocv_aruco) package gocv /* #include #include "aruco.h" #include "core.h" */ import "C" import ( "reflect" "unsafe" ) type ArucoDetector struct { p C.ArucoDetector } // NewArucoDetector returns a new ArucoDetector. func NewArucoDetector() ArucoDetector { return ArucoDetector{p: C.ArucoDetector_New()} } // NewArucoDetectorWithParams returns a new ArucoDetector. func NewArucoDetectorWithParams(dictionary ArucoDictionary, params ArucoDetectorParameters) ArucoDetector { return ArucoDetector{p: C.ArucoDetector_NewWithParams(dictionary.p, params.p)} } // Close deletes the ArucoDetector's pointer. func (a *ArucoDetector) Close() error { C.ArucoDetector_Close(a.p) a.p = nil return nil } // DetectMarkers does basic marker detection. // // For further details, please see: // https://docs.opencv.org/master/d9/d6a/group__aruco.html#gab9159aa69250d8d3642593e508cb6baa func (a *ArucoDetector) DetectMarkers(input Mat) ( markerCorners [][]Point2f, markerIds []int, rejectedCandidates [][]Point2f, ) { pvsCorners := NewPoints2fVector() defer pvsCorners.Close() pvsRejected := NewPoints2fVector() defer pvsRejected.Close() cmarkerIds := C.IntVector{} defer C.free(unsafe.Pointer(cmarkerIds.val)) C.ArucoDetector_DetectMarkers(a.p, C.Mat(input.Ptr()), C.Points2fVector(pvsCorners.P()), &cmarkerIds, C.Points2fVector(pvsRejected.P())) h := &reflect.SliceHeader{ Data: uintptr(unsafe.Pointer(cmarkerIds.val)), Len: int(cmarkerIds.length), Cap: int(cmarkerIds.length), } pcids := *(*[]C.int)(unsafe.Pointer(h)) markerIds = []int{} for i := 0; i < int(cmarkerIds.length); i++ { markerIds = append(markerIds, int(pcids[i])) } return pvsCorners.ToPoints(), markerIds, pvsRejected.ToPoints() } func ArucoDrawDetectedMarkers(img Mat, markerCorners [][]Point2f, markerIds []int, borderColor Scalar) error { cMarkerIds := make([]C.int, len(markerIds)) for i, s := range markerIds { cMarkerIds[i] = C.int(s) } markerIdsIntVec := C.IntVector{ val: (*C.int)(&cMarkerIds[0]), length: C.int(len(cMarkerIds)), } _markerCorners := NewPoints2fVectorFromPoints(markerCorners) cBorderColor := C.struct_Scalar{ val1: C.double(borderColor.Val1), val2: C.double(borderColor.Val2), val3: C.double(borderColor.Val3), val4: C.double(borderColor.Val4), } return OpenCVResult(C.ArucoDrawDetectedMarkers( C.Mat(img.Ptr()), C.Points2fVector(_markerCorners.P()), markerIdsIntVec, cBorderColor, )) } func ArucoGenerateImageMarker(dictionaryId ArucoDictionaryCode, id int, sidePixels int, img Mat, borderBits int) error { return OpenCVResult(C.ArucoGenerateImageMarker(C.int(dictionaryId), C.int(id), C.int(sidePixels), C.Mat(img.Ptr()), C.int(borderBits))) } type ArucoDetectorParameters struct { p C.ArucoDetectorParameters } // NewArucoDetectorParameters returns the default parameters for the SimpleBobDetector func NewArucoDetectorParameters() ArucoDetectorParameters { return ArucoDetectorParameters{p: C.ArucoDetectorParameters_Create()} } func (ap *ArucoDetectorParameters) SetAdaptiveThreshWinSizeMin(adaptiveThreshWinSizeMin int) { C.ArucoDetectorParameters_SetAdaptiveThreshWinSizeMin(ap.p, C.int(adaptiveThreshWinSizeMin)) } func (ap *ArucoDetectorParameters) GetAdaptiveThreshWinSizeMin() int { return int(C.ArucoDetectorParameters_GetAdaptiveThreshWinSizeMin(ap.p)) } func (ap *ArucoDetectorParameters) SetAdaptiveThreshWinSizeMax(adaptiveThreshWinSizeMax int) { C.ArucoDetectorParameters_SetAdaptiveThreshWinSizeMax(ap.p, C.int(adaptiveThreshWinSizeMax)) } func (ap *ArucoDetectorParameters) GetAdaptiveThreshWinSizeMax() int { return int(C.ArucoDetectorParameters_GetAdaptiveThreshWinSizeMax(ap.p)) } func (ap *ArucoDetectorParameters) SetAdaptiveThreshWinSizeStep(adaptiveThreshWinSizeStep int) { C.ArucoDetectorParameters_SetAdaptiveThreshWinSizeStep(ap.p, C.int(adaptiveThreshWinSizeStep)) } func (ap *ArucoDetectorParameters) GetAdaptiveThreshWinSizeStep() int { return int(C.ArucoDetectorParameters_GetAdaptiveThreshWinSizeStep(ap.p)) } func (ap *ArucoDetectorParameters) SetAdaptiveThreshConstant(adaptiveThreshConstant float64) { C.ArucoDetectorParameters_SetAdaptiveThreshConstant(ap.p, C.double(adaptiveThreshConstant)) } func (ap *ArucoDetectorParameters) GetAdaptiveThreshConstant() float64 { return float64(C.ArucoDetectorParameters_GetAdaptiveThreshConstant(ap.p)) } func (ap *ArucoDetectorParameters) SetMinMarkerPerimeterRate(minMarkerPerimeterRate float64) { C.ArucoDetectorParameters_SetMinMarkerPerimeterRate(ap.p, C.double(minMarkerPerimeterRate)) } func (ap *ArucoDetectorParameters) GetMinMarkerPerimeterRate() float64 { return float64(C.ArucoDetectorParameters_GetMinMarkerPerimeterRate(ap.p)) } func (ap *ArucoDetectorParameters) SetMaxMarkerPerimeterRate(maxMarkerPerimeterRate float64) { C.ArucoDetectorParameters_SetMaxMarkerPerimeterRate(ap.p, C.double(maxMarkerPerimeterRate)) } func (ap *ArucoDetectorParameters) GetMaxMarkerPerimeterRate() float64 { return float64(C.ArucoDetectorParameters_GetMaxMarkerPerimeterRate(ap.p)) } func (ap *ArucoDetectorParameters) SetPolygonalApproxAccuracyRate(polygonalApproxAccuracyRate float64) { C.ArucoDetectorParameters_SetPolygonalApproxAccuracyRate(ap.p, C.double(polygonalApproxAccuracyRate)) } func (ap *ArucoDetectorParameters) GetPolygonalApproxAccuracyRate() float64 { return float64(C.ArucoDetectorParameters_GetPolygonalApproxAccuracyRate(ap.p)) } func (ap *ArucoDetectorParameters) SetMinCornerDistanceRate(minCornerDistanceRate float64) { C.ArucoDetectorParameters_SetMinCornerDistanceRate(ap.p, C.double(minCornerDistanceRate)) } func (ap *ArucoDetectorParameters) GetMinCornerDistanceRate() float64 { return float64(C.ArucoDetectorParameters_GetMinCornerDistanceRate(ap.p)) } func (ap *ArucoDetectorParameters) SetMinDistanceToBorder(minDistanceToBorder int) { C.ArucoDetectorParameters_SetMinDistanceToBorder(ap.p, C.int(minDistanceToBorder)) } func (ap *ArucoDetectorParameters) GetMinDistanceToBorder() int { return int(C.ArucoDetectorParameters_GetMinDistanceToBorder(ap.p)) } func (ap *ArucoDetectorParameters) SetMinMarkerDistanceRate(minMarkerDistanceRate float64) { C.ArucoDetectorParameters_SetMinMarkerDistanceRate(ap.p, C.double(minMarkerDistanceRate)) } func (ap *ArucoDetectorParameters) GetMinMarkerDistanceRate() float64 { return float64(C.ArucoDetectorParameters_GetMinMarkerDistanceRate(ap.p)) } func (ap *ArucoDetectorParameters) SetCornerRefinementMethod(cornerRefinementMethod int) { C.ArucoDetectorParameters_SetCornerRefinementMethod(ap.p, C.int(cornerRefinementMethod)) } func (ap *ArucoDetectorParameters) GetCornerRefinementMethod() int { return int(C.ArucoDetectorParameters_GetCornerRefinementMethod(ap.p)) } func (ap *ArucoDetectorParameters) SetCornerRefinementWinSize(cornerRefinementWinSize int) { C.ArucoDetectorParameters_SetCornerRefinementWinSize(ap.p, C.int(cornerRefinementWinSize)) } func (ap *ArucoDetectorParameters) GetCornerRefinementWinSize() int { return int(C.ArucoDetectorParameters_GetCornerRefinementWinSize(ap.p)) } func (ap *ArucoDetectorParameters) SetCornerRefinementMaxIterations(cornerRefinementMaxIterations int) { C.ArucoDetectorParameters_SetCornerRefinementMaxIterations(ap.p, C.int(cornerRefinementMaxIterations)) } func (ap *ArucoDetectorParameters) GetCornerRefinementMaxIterations() int { return int(C.ArucoDetectorParameters_GetCornerRefinementMaxIterations(ap.p)) } func (ap *ArucoDetectorParameters) SetCornerRefinementMinAccuracy(cornerRefinementMinAccuracy float64) { C.ArucoDetectorParameters_SetCornerRefinementMinAccuracy(ap.p, C.double(cornerRefinementMinAccuracy)) } func (ap *ArucoDetectorParameters) GetCornerRefinementMinAccuracy() float64 { return float64(C.ArucoDetectorParameters_GetCornerRefinementMinAccuracy(ap.p)) } func (ap *ArucoDetectorParameters) SetMarkerBorderBits(markerBorderBits int) { C.ArucoDetectorParameters_SetMarkerBorderBits(ap.p, C.int(markerBorderBits)) } func (ap *ArucoDetectorParameters) GetMarkerBorderBits() int { return int(C.ArucoDetectorParameters_GetMarkerBorderBits(ap.p)) } func (ap *ArucoDetectorParameters) SetPerspectiveRemovePixelPerCell(perspectiveRemovePixelPerCell int) { C.ArucoDetectorParameters_SetPerspectiveRemovePixelPerCell(ap.p, C.int(perspectiveRemovePixelPerCell)) } func (ap *ArucoDetectorParameters) GetPerspectiveRemovePixelPerCell() int { return int(C.ArucoDetectorParameters_GetPerspectiveRemovePixelPerCell(ap.p)) } func (ap *ArucoDetectorParameters) SetPerspectiveRemoveIgnoredMarginPerCell(perspectiveRemoveIgnoredMarginPerCell float64) { C.ArucoDetectorParameters_SetPerspectiveRemoveIgnoredMarginPerCell(ap.p, C.double(perspectiveRemoveIgnoredMarginPerCell)) } func (ap *ArucoDetectorParameters) GetPerspectiveRemoveIgnoredMarginPerCell() float64 { return float64(C.ArucoDetectorParameters_GetPerspectiveRemoveIgnoredMarginPerCell(ap.p)) } func (ap *ArucoDetectorParameters) SetMaxErroneousBitsInBorderRate(maxErroneousBitsInBorderRate float64) { C.ArucoDetectorParameters_SetMaxErroneousBitsInBorderRate(ap.p, C.double(maxErroneousBitsInBorderRate)) } func (ap *ArucoDetectorParameters) GetMaxErroneousBitsInBorderRate() float64 { return float64(C.ArucoDetectorParameters_GetMaxErroneousBitsInBorderRate(ap.p)) } func (ap *ArucoDetectorParameters) SetMinOtsuStdDev(minOtsuStdDev float64) { C.ArucoDetectorParameters_SetMinOtsuStdDev(ap.p, C.double(minOtsuStdDev)) } func (ap *ArucoDetectorParameters) GetMinOtsuStdDev() float64 { return float64(C.ArucoDetectorParameters_GetMinOtsuStdDev(ap.p)) } func (ap *ArucoDetectorParameters) SetErrorCorrectionRate(errorCorrectionRate float64) { C.ArucoDetectorParameters_SetErrorCorrectionRate(ap.p, C.double(errorCorrectionRate)) } func (ap *ArucoDetectorParameters) GetErrorCorrectionRate() float64 { return float64(C.ArucoDetectorParameters_GetErrorCorrectionRate(ap.p)) } func (ap *ArucoDetectorParameters) SetAprilTagQuadDecimate(aprilTagQuadDecimate float32) { C.ArucoDetectorParameters_SetAprilTagQuadDecimate(ap.p, C.float(aprilTagQuadDecimate)) } func (ap *ArucoDetectorParameters) GetAprilTagQuadDecimate() float32 { return float32(C.ArucoDetectorParameters_GetAprilTagQuadDecimate(ap.p)) } func (ap *ArucoDetectorParameters) SetAprilTagQuadSigma(aprilTagQuadSigma float32) { C.ArucoDetectorParameters_SetAprilTagQuadSigma(ap.p, C.float(aprilTagQuadSigma)) } func (ap *ArucoDetectorParameters) GetAprilTagQuadSigma() float32 { return float32(C.ArucoDetectorParameters_GetAprilTagQuadSigma(ap.p)) } func (ap *ArucoDetectorParameters) SetAprilTagMinClusterPixels(aprilTagMinClusterPixels int) { C.ArucoDetectorParameters_SetAprilTagMinClusterPixels(ap.p, C.int(aprilTagMinClusterPixels)) } func (ap *ArucoDetectorParameters) GetAprilTagMinClusterPixels() int { return int(C.ArucoDetectorParameters_GetAprilTagMinClusterPixels(ap.p)) } func (ap *ArucoDetectorParameters) SetAprilTagMaxNmaxima(aprilTagMaxNmaxima int) { C.ArucoDetectorParameters_SetAprilTagMaxNmaxima(ap.p, C.int(aprilTagMaxNmaxima)) } func (ap *ArucoDetectorParameters) GetAprilTagMaxNmaxima() int { return int(C.ArucoDetectorParameters_GetAprilTagMaxNmaxima(ap.p)) } func (ap *ArucoDetectorParameters) SetAprilTagCriticalRad(aprilTagCriticalRad float32) { C.ArucoDetectorParameters_SetAprilTagCriticalRad(ap.p, C.float(aprilTagCriticalRad)) } func (ap *ArucoDetectorParameters) GetAprilTagCriticalRad() float32 { return float32(C.ArucoDetectorParameters_GetAprilTagCriticalRad(ap.p)) } func (ap *ArucoDetectorParameters) SetAprilTagMaxLineFitMse(aprilTagMaxLineFitMse float32) { C.ArucoDetectorParameters_SetAprilTagMaxLineFitMse(ap.p, C.float(aprilTagMaxLineFitMse)) } func (ap *ArucoDetectorParameters) GetAprilTagMaxLineFitMse() float32 { return float32(C.ArucoDetectorParameters_GetAprilTagMaxLineFitMse(ap.p)) } func (ap *ArucoDetectorParameters) SetAprilTagMinWhiteBlackDiff(aprilTagMinWhiteBlackDiff int) { C.ArucoDetectorParameters_SetAprilTagMinWhiteBlackDiff(ap.p, C.int(aprilTagMinWhiteBlackDiff)) } func (ap *ArucoDetectorParameters) GetAprilTagMinWhiteBlackDiff() int { return int(C.ArucoDetectorParameters_GetAprilTagMinWhiteBlackDiff(ap.p)) } func (ap *ArucoDetectorParameters) SetAprilTagDeglitch(aprilTagDeglitch int) { C.ArucoDetectorParameters_SetAprilTagDeglitch(ap.p, C.int(aprilTagDeglitch)) } func (ap *ArucoDetectorParameters) GetAprilTagDeglitch() int { return int(C.ArucoDetectorParameters_GetAprilTagDeglitch(ap.p)) } func (ap *ArucoDetectorParameters) SetDetectInvertedMarker(detectInvertedMarker bool) { C.ArucoDetectorParameters_SetDetectInvertedMarker(ap.p, C.bool(detectInvertedMarker)) } func (ap *ArucoDetectorParameters) GetDetectInvertedMarker() bool { return bool(C.ArucoDetectorParameters_GetDetectInvertedMarker(ap.p)) } ================================================ FILE: aruco.h ================================================ #ifndef _OPENCV3_ARUCO_H_ #define _OPENCV3_ARUCO_H_ #ifdef __cplusplus #include extern "C" { #endif #include "core.h" #ifdef __cplusplus typedef cv::aruco::Dictionary* ArucoDictionary; typedef cv::aruco::DetectorParameters* ArucoDetectorParameters; typedef cv::aruco::ArucoDetector* ArucoDetector; #else typedef void *ArucoDictionary; typedef void *ArucoDetectorParameters; typedef void *ArucoDetector; #endif ArucoDetectorParameters ArucoDetectorParameters_Create(); void ArucoDetectorParameters_SetAdaptiveThreshWinSizeMin(ArucoDetectorParameters ap, int adaptiveThreshWinSizeMin); int ArucoDetectorParameters_GetAdaptiveThreshWinSizeMin(ArucoDetectorParameters ap); void ArucoDetectorParameters_SetAdaptiveThreshWinSizeMax(ArucoDetectorParameters ap, int adaptiveThreshWinSizeMax); int ArucoDetectorParameters_GetAdaptiveThreshWinSizeMax(ArucoDetectorParameters ap); void ArucoDetectorParameters_SetAdaptiveThreshWinSizeStep(ArucoDetectorParameters ap, int adaptiveThreshWinSizeStep); int ArucoDetectorParameters_GetAdaptiveThreshWinSizeStep(ArucoDetectorParameters ap); void ArucoDetectorParameters_SetAdaptiveThreshConstant(ArucoDetectorParameters ap, double adaptiveThreshConstant); double ArucoDetectorParameters_GetAdaptiveThreshConstant(ArucoDetectorParameters ap); void ArucoDetectorParameters_SetMinMarkerPerimeterRate(ArucoDetectorParameters ap, double minMarkerPerimeterRate); double ArucoDetectorParameters_GetMinMarkerPerimeterRate(ArucoDetectorParameters ap); void ArucoDetectorParameters_SetMaxMarkerPerimeterRate(ArucoDetectorParameters ap, double maxMarkerPerimeterRate); double ArucoDetectorParameters_GetMaxMarkerPerimeterRate(ArucoDetectorParameters ap); void ArucoDetectorParameters_SetPolygonalApproxAccuracyRate(ArucoDetectorParameters ap, double polygonalApproxAccuracyRate); double ArucoDetectorParameters_GetPolygonalApproxAccuracyRate(ArucoDetectorParameters ap); void ArucoDetectorParameters_SetMinCornerDistanceRate(ArucoDetectorParameters ap, double minCornerDistanceRate); double ArucoDetectorParameters_GetMinCornerDistanceRate(ArucoDetectorParameters ap); void ArucoDetectorParameters_SetMinDistanceToBorder(ArucoDetectorParameters ap, int minDistanceToBorder); int ArucoDetectorParameters_GetMinDistanceToBorder(ArucoDetectorParameters ap); void ArucoDetectorParameters_SetMinMarkerDistanceRate(ArucoDetectorParameters ap, double minMarkerDistanceRate); double ArucoDetectorParameters_GetMinMarkerDistanceRate(ArucoDetectorParameters ap); void ArucoDetectorParameters_SetCornerRefinementMethod(ArucoDetectorParameters ap, int cornerRefinementMethod); int ArucoDetectorParameters_GetCornerRefinementMethod(ArucoDetectorParameters ap); void ArucoDetectorParameters_SetCornerRefinementWinSize(ArucoDetectorParameters ap, int cornerRefinementWinSize); int ArucoDetectorParameters_GetCornerRefinementWinSize(ArucoDetectorParameters ap); void ArucoDetectorParameters_SetCornerRefinementMaxIterations(ArucoDetectorParameters ap, int cornerRefinementMaxIterations); int ArucoDetectorParameters_GetCornerRefinementMaxIterations(ArucoDetectorParameters ap); void ArucoDetectorParameters_SetCornerRefinementMinAccuracy(ArucoDetectorParameters ap, double cornerRefinementMinAccuracy); double ArucoDetectorParameters_GetCornerRefinementMinAccuracy(ArucoDetectorParameters ap); void ArucoDetectorParameters_SetMarkerBorderBits(ArucoDetectorParameters ap, int markerBorderBits); int ArucoDetectorParameters_GetMarkerBorderBits(ArucoDetectorParameters ap); void ArucoDetectorParameters_SetPerspectiveRemovePixelPerCell(ArucoDetectorParameters ap, int perspectiveRemovePixelPerCell); int ArucoDetectorParameters_GetPerspectiveRemovePixelPerCell(ArucoDetectorParameters ap); void ArucoDetectorParameters_SetPerspectiveRemoveIgnoredMarginPerCell(ArucoDetectorParameters ap, double perspectiveRemoveIgnoredMarginPerCell); double ArucoDetectorParameters_GetPerspectiveRemoveIgnoredMarginPerCell(ArucoDetectorParameters ap); void ArucoDetectorParameters_SetMaxErroneousBitsInBorderRate(ArucoDetectorParameters ap, double maxErroneousBitsInBorderRate); double ArucoDetectorParameters_GetMaxErroneousBitsInBorderRate(ArucoDetectorParameters ap); void ArucoDetectorParameters_SetMinOtsuStdDev(ArucoDetectorParameters ap, double minOtsuStdDev); double ArucoDetectorParameters_GetMinOtsuStdDev(ArucoDetectorParameters ap); void ArucoDetectorParameters_SetErrorCorrectionRate(ArucoDetectorParameters ap, double errorCorrectionRate); double ArucoDetectorParameters_GetErrorCorrectionRate(ArucoDetectorParameters ap); void ArucoDetectorParameters_SetAprilTagQuadDecimate(ArucoDetectorParameters ap, float aprilTagQuadDecimate); float ArucoDetectorParameters_GetAprilTagQuadDecimate(ArucoDetectorParameters ap); void ArucoDetectorParameters_SetAprilTagQuadSigma(ArucoDetectorParameters ap, float aprilTagQuadSigma); float ArucoDetectorParameters_GetAprilTagQuadSigma(ArucoDetectorParameters ap); void ArucoDetectorParameters_SetAprilTagMinClusterPixels(ArucoDetectorParameters ap, int aprilTagMinClusterPixels); int ArucoDetectorParameters_GetAprilTagMinClusterPixels(ArucoDetectorParameters ap); void ArucoDetectorParameters_SetAprilTagMaxNmaxima(ArucoDetectorParameters ap, int aprilTagMaxNmaxima); int ArucoDetectorParameters_GetAprilTagMaxNmaxima(ArucoDetectorParameters ap); void ArucoDetectorParameters_SetAprilTagCriticalRad(ArucoDetectorParameters ap, float aprilTagCriticalRad); float ArucoDetectorParameters_GetAprilTagCriticalRad(ArucoDetectorParameters ap); void ArucoDetectorParameters_SetAprilTagMaxLineFitMse(ArucoDetectorParameters ap, float aprilTagMaxLineFitMse); float ArucoDetectorParameters_GetAprilTagMaxLineFitMse(ArucoDetectorParameters ap); void ArucoDetectorParameters_SetAprilTagMinWhiteBlackDiff(ArucoDetectorParameters ap, int aprilTagMinWhiteBlackDiff); int ArucoDetectorParameters_GetAprilTagMinWhiteBlackDiff(ArucoDetectorParameters ap); void ArucoDetectorParameters_SetAprilTagDeglitch(ArucoDetectorParameters ap, int aprilTagDeglitch); int ArucoDetectorParameters_GetAprilTagDeglitch(ArucoDetectorParameters ap); void ArucoDetectorParameters_SetDetectInvertedMarker(ArucoDetectorParameters ap, bool detectInvertedMarker); bool ArucoDetectorParameters_GetDetectInvertedMarker(ArucoDetectorParameters ap); ArucoDictionary getPredefinedDictionary(int dictionaryId); ArucoDetector ArucoDetector_New(); ArucoDetector ArucoDetector_NewWithParams(ArucoDictionary dictionary, ArucoDetectorParameters params); void ArucoDetector_Close(ArucoDetector ad); void ArucoDetector_DetectMarkers(ArucoDetector ad, Mat inputArr, Points2fVector markerCorners, IntVector *markerIds, Points2fVector rejectedCandidates); OpenCVResult ArucoDrawDetectedMarkers(Mat image, Points2fVector markerCorners, IntVector markerIds, Scalar borderColor); OpenCVResult ArucoGenerateImageMarker(int dictionaryId, int id, int sidePixels, Mat img, int borderBits); #ifdef __cplusplus } #endif #endif //_OPENCV3_ARUCO_H_ ================================================ FILE: aruco_dictionaries.go ================================================ //go:build !gocv_specific_modules || (gocv_specific_modules && gocv_aruco) package gocv /* #include #include "aruco.h" #include "core.h" */ import "C" type ArucoDictionaryCode int const ( ArucoDict4x4_50 ArucoDictionaryCode = iota ArucoDict4x4_100 ArucoDictionaryCode = iota ArucoDict4x4_250 ArucoDictionaryCode = iota ArucoDict4x4_1000 ArucoDictionaryCode = iota ArucoDict5x5_50 ArucoDictionaryCode = iota ArucoDict5x5_100 ArucoDictionaryCode = iota ArucoDict5x5_250 ArucoDictionaryCode = iota ArucoDict5x5_1000 ArucoDictionaryCode = iota ArucoDict6x6_50 ArucoDictionaryCode = iota ArucoDict6x6_100 ArucoDictionaryCode = iota ArucoDict6x6_250 ArucoDictionaryCode = iota ArucoDict6x6_1000 ArucoDictionaryCode = iota ArucoDict7x7_50 ArucoDictionaryCode = iota ArucoDict7x7_100 ArucoDictionaryCode = iota ArucoDict7x7_250 ArucoDictionaryCode = iota ArucoDict7x7_1000 ArucoDictionaryCode = iota ArucoDictArucoOriginal ArucoDictionaryCode = iota ArucoDictAprilTag_16h5 ArucoDictionaryCode = iota ///< 4x4 bits, minimum hamming distance between any two codes = 5, 30 codes ArucoDictAprilTag_25h9 ArucoDictionaryCode = iota ///< 5x5 bits, minimum hamming distance between any two codes = 9, 35 codes ArucoDictAprilTag_36h10 ArucoDictionaryCode = iota ///< 6x6 bits, minimum hamming distance between any two codes = 10, 2320 codes ArucoDictAprilTag_36h11 ArucoDictionaryCode = iota ///< 6x6 bits, minimum hamming distance between any two codes = 11, 587 codes ) type ArucoDictionary struct { p C.ArucoDictionary } func GetPredefinedDictionary(dictionaryId ArucoDictionaryCode) ArucoDictionary { var p C.ArucoDictionary = C.getPredefinedDictionary(C.int(dictionaryId)) return ArucoDictionary{p: p} } ================================================ FILE: aruco_test.go ================================================ //go:build !gocv_specific_modules || (gocv_specific_modules && gocv_aruco) package gocv import ( "errors" "fmt" "reflect" "testing" ) const ( arucoImage6X6_250 = "./images/aruco_6X6_250_6.png" arucoImage6X6_250_contour = "./images/aruco_6X6_250_6_contour.png" arucoImage6X6_250_1 = "./images/aruco_6X6_250_1.png" ) func TestArucoDetectorParams(t *testing.T) { adaptiveThreshWinSizeMin := 4 adaptiveThreshWinSizeMax := 22 adaptiveThreshWinSizeStep := 1 adaptiveThreshConstant := 1.0 minMarkerPerimeterRate := 0.2 maxMarkerPerimeterRate := 0.5 polygonalApproxAccuracyRate := 1.0 minCornerDistanceRate := 0.1 minDistanceToBorder := 0 minMarkerDistanceRate := 1.0 cornerRefinementMethod := 1 cornerRefinementWinSize := 1 cornerRefinementMaxIterations := 1 cornerRefinementMinAccuracy := 0.5 markerBorderBits := 1 perspectiveRemovePixelPerCell := 1 perspectiveRemoveIgnoredMarginPerCell := 1.0 maxErroneousBitsInBorderRate := 0.5 minOtsuStdDev := .5 errorCorrectionRate := 0.2 aprilTagQuadDecimate := float32(0.5) aprilTagQuadSigma := float32(1) aprilTagMinClusterPixels := 1 aprilTagMaxNmaxima := 1 aprilTagCriticalRad := float32(0.2) aprilTagMaxLineFitMse := float32(0.2) aprilTagMinWhiteBlackDiff := 1 aprilTagDeglitch := 1 detectInvertedMarker := false params := NewArucoDetectorParameters() params.SetAdaptiveThreshWinSizeMin(adaptiveThreshWinSizeMin) params.SetAdaptiveThreshWinSizeMax(adaptiveThreshWinSizeMax) params.SetAdaptiveThreshWinSizeStep(adaptiveThreshWinSizeStep) params.SetAdaptiveThreshConstant(adaptiveThreshConstant) params.SetMinMarkerPerimeterRate(minMarkerPerimeterRate) params.SetMaxMarkerPerimeterRate(maxMarkerPerimeterRate) params.SetPolygonalApproxAccuracyRate(polygonalApproxAccuracyRate) params.SetMinCornerDistanceRate(minCornerDistanceRate) params.SetMinDistanceToBorder(minDistanceToBorder) params.SetMinMarkerDistanceRate(minMarkerDistanceRate) params.SetCornerRefinementMethod(cornerRefinementMethod) params.SetCornerRefinementWinSize(cornerRefinementWinSize) params.SetCornerRefinementMaxIterations(cornerRefinementMaxIterations) params.SetCornerRefinementMinAccuracy(cornerRefinementMinAccuracy) params.SetMarkerBorderBits(markerBorderBits) params.SetPerspectiveRemovePixelPerCell(perspectiveRemovePixelPerCell) params.SetPerspectiveRemoveIgnoredMarginPerCell(perspectiveRemoveIgnoredMarginPerCell) params.SetMaxErroneousBitsInBorderRate(maxErroneousBitsInBorderRate) params.SetMinOtsuStdDev(minOtsuStdDev) params.SetErrorCorrectionRate(errorCorrectionRate) params.SetAprilTagQuadDecimate(aprilTagQuadDecimate) params.SetAprilTagQuadSigma(aprilTagQuadSigma) params.SetAprilTagMinClusterPixels(aprilTagMinClusterPixels) params.SetAprilTagMaxNmaxima(aprilTagMaxNmaxima) params.SetAprilTagCriticalRad(aprilTagCriticalRad) params.SetAprilTagMaxLineFitMse(aprilTagMaxLineFitMse) params.SetAprilTagMinWhiteBlackDiff(aprilTagMinWhiteBlackDiff) params.SetAprilTagDeglitch(aprilTagDeglitch) params.SetDetectInvertedMarker(detectInvertedMarker) if params.GetAdaptiveThreshWinSizeMin() != adaptiveThreshWinSizeMin { t.Error(fmt.Sprintf("AdaptiveThreshWinSizeMin expected %v got %v", adaptiveThreshWinSizeMin, params.GetAdaptiveThreshWinSizeMin())) } if params.GetAdaptiveThreshWinSizeMax() != adaptiveThreshWinSizeMax { t.Error(fmt.Sprintf("AdaptiveThreshWinSizeMax expected %v got %v", adaptiveThreshWinSizeMax, params.GetAdaptiveThreshWinSizeMax())) } if params.GetAdaptiveThreshWinSizeStep() != adaptiveThreshWinSizeStep { t.Error(fmt.Sprintf("AdaptiveThreshWinSizeStep expected %v got %v", adaptiveThreshWinSizeStep, params.GetAdaptiveThreshWinSizeStep())) } if params.GetAdaptiveThreshConstant() != adaptiveThreshConstant { t.Error(fmt.Sprintf("AdaptiveThreshConstant expected %v got %v", adaptiveThreshConstant, params.GetAdaptiveThreshConstant())) } if params.GetMinMarkerPerimeterRate() != minMarkerPerimeterRate { t.Error(fmt.Sprintf("MinMarkerPerimeterRate expected %v got %v", minMarkerPerimeterRate, params.GetMinMarkerPerimeterRate())) } if params.GetMaxMarkerPerimeterRate() != maxMarkerPerimeterRate { t.Error(fmt.Sprintf("MaxMarkerPerimeterRate expected %v got %v", maxMarkerPerimeterRate, params.GetMaxMarkerPerimeterRate())) } if params.GetPolygonalApproxAccuracyRate() != polygonalApproxAccuracyRate { t.Error(fmt.Sprintf("PolygonalApproxAccuracyRate expected %v got %v", polygonalApproxAccuracyRate, params.GetPolygonalApproxAccuracyRate())) } if params.GetMinCornerDistanceRate() != minCornerDistanceRate { t.Error(fmt.Sprintf("MinCornerDistanceRate expected %v got %v", minCornerDistanceRate, params.GetMinCornerDistanceRate())) } if params.GetMinDistanceToBorder() != minDistanceToBorder { t.Error(fmt.Sprintf("MinDistanceToBorder expected %v got %v", minDistanceToBorder, params.GetMinDistanceToBorder())) } if params.GetMinMarkerDistanceRate() != minMarkerDistanceRate { t.Error(fmt.Sprintf("MinMarkerDistanceRate expected %v got %v", minMarkerDistanceRate, params.GetMinMarkerDistanceRate())) } if params.GetCornerRefinementMethod() != cornerRefinementMethod { t.Error(fmt.Sprintf("CornerRefinementMethod expected %v got %v", cornerRefinementMethod, params.GetCornerRefinementMethod())) } if params.GetCornerRefinementWinSize() != cornerRefinementWinSize { t.Error(fmt.Sprintf("CornerRefinementWinSize expected %v got %v", cornerRefinementWinSize, params.GetCornerRefinementWinSize())) } if params.GetCornerRefinementMaxIterations() != cornerRefinementMaxIterations { t.Error(fmt.Sprintf("CornerRefinementMaxIterations expected %v got %v", cornerRefinementMaxIterations, params.GetCornerRefinementMaxIterations())) } if params.GetCornerRefinementMinAccuracy() != cornerRefinementMinAccuracy { t.Error(fmt.Sprintf("CornerRefinementMinAccuracy expected %v got %v", cornerRefinementMinAccuracy, params.GetCornerRefinementMinAccuracy())) } if params.GetMarkerBorderBits() != markerBorderBits { t.Error(fmt.Sprintf("MarkerBorderBits expected %v got %v", markerBorderBits, params.GetMarkerBorderBits())) } if params.GetPerspectiveRemovePixelPerCell() != perspectiveRemovePixelPerCell { t.Error(fmt.Sprintf("PerspectiveRemovePixelPerCell expected %v got %v", perspectiveRemovePixelPerCell, params.GetPerspectiveRemovePixelPerCell())) } if params.GetPerspectiveRemoveIgnoredMarginPerCell() != perspectiveRemoveIgnoredMarginPerCell { t.Error(fmt.Sprintf("PerspectiveRemoveIgnoredMarginPerCell expected %v got %v", perspectiveRemoveIgnoredMarginPerCell, params.GetPerspectiveRemoveIgnoredMarginPerCell())) } if params.GetMaxErroneousBitsInBorderRate() != maxErroneousBitsInBorderRate { t.Error(fmt.Sprintf("MaxErroneousBitsInBorderRate expected %v got %v", maxErroneousBitsInBorderRate, params.GetMaxErroneousBitsInBorderRate())) } if params.GetMinOtsuStdDev() != minOtsuStdDev { t.Error(fmt.Sprintf("MinOtsuStdDev expected %v got %v", minOtsuStdDev, params.GetMinOtsuStdDev())) } if params.GetErrorCorrectionRate() != errorCorrectionRate { t.Error(fmt.Sprintf("ErrorCorrectionRate expected %v got %v", errorCorrectionRate, params.GetErrorCorrectionRate())) } if params.GetAprilTagQuadDecimate() != aprilTagQuadDecimate { t.Error(fmt.Sprintf("AprilTagQuadDecimate expected %v got %v", aprilTagQuadDecimate, params.GetAprilTagQuadDecimate())) } if params.GetAprilTagQuadSigma() != aprilTagQuadSigma { t.Error(fmt.Sprintf("AprilTagQuadSigma expected %v got %v", aprilTagQuadSigma, params.GetAprilTagQuadSigma())) } if params.GetAprilTagMinClusterPixels() != aprilTagMinClusterPixels { t.Error(fmt.Sprintf("AprilTagMinClusterPixels expected %v got %v", aprilTagMinClusterPixels, params.GetAprilTagMinClusterPixels())) } if params.GetAprilTagMaxNmaxima() != aprilTagMaxNmaxima { t.Error(fmt.Sprintf("AprilTagMaxNmaxima expected %v got %v", aprilTagMaxNmaxima, params.GetAprilTagMaxNmaxima())) } if params.GetAprilTagCriticalRad() != aprilTagCriticalRad { t.Error(fmt.Sprintf("AprilTagCriticalRad expected %v got %v", aprilTagCriticalRad, params.GetAprilTagCriticalRad())) } if params.GetAprilTagMaxLineFitMse() != aprilTagMaxLineFitMse { t.Error(fmt.Sprintf("AprilTagMaxLineFitMse expected %v got %v", aprilTagMaxLineFitMse, params.GetAprilTagMaxLineFitMse())) } if params.GetAprilTagMinWhiteBlackDiff() != aprilTagMinWhiteBlackDiff { t.Error(fmt.Sprintf("AprilTagMinWhiteBlackDiff expected %v got %v", aprilTagMinWhiteBlackDiff, params.GetAprilTagMinWhiteBlackDiff())) } if params.GetAprilTagDeglitch() != aprilTagDeglitch { t.Error(fmt.Sprintf("AprilTagDeglitch expected %v got %v", aprilTagDeglitch, params.GetAprilTagDeglitch())) } if params.GetDetectInvertedMarker() != detectInvertedMarker { t.Error(fmt.Sprintf("DetectInvertedMarker expected %v got %v", detectInvertedMarker, params.GetDetectInvertedMarker())) } } func TestDetectMarkers(t *testing.T) { path := arucoImage6X6_250 img := IMRead(path, IMReadColor) if img.Empty() { t.Error(errors.New("Invalid input")) } defer img.Close() dict := GetPredefinedDictionary(ArucoDict6x6_250) params := NewArucoDetectorParameters() detector := NewArucoDetectorWithParams(dict, params) defer detector.Close() _, markerIds, _ := detector.DetectMarkers(img) expected := []int{40, 98, 62, 23, 124, 203} if !reflect.DeepEqual(markerIds, expected) { t.Error(fmt.Sprintf("Marker id expected %v got %v", expected, markerIds)) } } func TestDrawDetectedMarkers(t *testing.T) { borderColor := NewScalar(200, 0, 0, 0) img := IMRead(arucoImage6X6_250, IMReadColor) defer img.Close() if img.Empty() { t.Error(errors.New("Invalid input")) } defer img.Close() imgExpected := IMRead(arucoImage6X6_250_contour, IMReadColor) if imgExpected.Empty() { t.Error(errors.New("Invalid input")) } defer imgExpected.Close() dict := GetPredefinedDictionary(ArucoDict6x6_250) params := NewArucoDetectorParameters() detector := NewArucoDetectorWithParams(dict, params) defer detector.Close() markerCorners, markerIds, _ := detector.DetectMarkers(img) ArucoDrawDetectedMarkers(img, markerCorners, markerIds, borderColor) diff := NewMat() defer diff.Close() AbsDiff(img, imgExpected, &diff) gray := NewMat() defer gray.Close() CvtColor(diff, &gray, ColorBGRToGray) if CountNonZero(gray) > 0 { t.Errorf("expected output to match %s", arucoImage6X6_250_contour) } } func TestArucoGenerateImageMarker(t *testing.T) { imgExpected := IMRead(arucoImage6X6_250_1, IMReadGrayScale) if imgExpected.Empty() { t.Error(fmt.Errorf("Invalid marker image '%s'", arucoImage6X6_250_1)) } defer imgExpected.Close() img := NewMat() defer img.Close() ArucoGenerateImageMarker(ArucoDict6x6_250, 1, 200, img, 1) diff := NewMat() defer diff.Close() AbsDiff(img, imgExpected, &diff) if CountNonZero(diff) > 0 { t.Errorf("expected output to match %s", arucoImage6X6_250_1) } } ================================================ FILE: asyncarray.cpp ================================================ // +build openvino #include #include "asyncarray.h" // AsyncArray_New creates a new empty AsyncArray AsyncArray AsyncArray_New() { try { return new cv::AsyncArray(); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } // AsyncArray_Close deletes an existing AsyncArray void AsyncArray_Close(AsyncArray a) { delete a; } const char* AsyncArray_GetAsync(AsyncArray async_out,Mat out) { try { async_out->get(*out); } catch(const cv::Exception& ex) { return ex.what(); } return ""; } AsyncArray Net_forwardAsync(Net net, const char* outputName) { try { return new cv::AsyncArray(net->forwardAsync(outputName)); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } ================================================ FILE: asyncarray.go ================================================ //go:build openvino // +build openvino package gocv import ( "errors" ) /* #include #include "dnn.h" #include "asyncarray.h" #include "core.h" */ import "C" type AsyncArray struct { p C.AsyncArray } // NewAsyncArray returns a new empty AsyncArray. func NewAsyncArray() AsyncArray { return newAsyncArray(C.AsyncArray_New()) } // Ptr returns the AsyncArray's underlying object pointer. func (a *AsyncArray) Ptr() C.AsyncArray { return a.p } // Get async returns the Mat func (m *AsyncArray) Get(mat *Mat) error { result := C.AsyncArray_GetAsync(m.p, mat.p) err := C.GoString(result) if len(err) > 0 { return errors.New(err) } return nil } // newAsyncArray returns a new AsyncArray from a C AsyncArray func newAsyncArray(p C.AsyncArray) AsyncArray { return AsyncArray{p: p} } // Close the AsyncArray object. func (a *AsyncArray) Close() error { C.AsyncArray_Close(a.p) a.p = nil return nil } ================================================ FILE: asyncarray.h ================================================ #ifdef __cplusplus #include extern "C" { #endif #include "core.h" #include "dnn.h" #ifdef __cplusplus typedef cv::AsyncArray* AsyncArray; #else typedef void* AsyncArray; #endif AsyncArray AsyncArray_New(); const char* AsyncArray_GetAsync(AsyncArray async_out,Mat out); void AsyncArray_Close(AsyncArray a); AsyncArray Net_forwardAsync(Net net, const char* outputName); #ifdef __cplusplus } #endif ================================================ FILE: asyncarray_test.go ================================================ //go:build openvino // +build openvino package gocv import ( "testing" ) func TestAsyncArray(t *testing.T) { asyncarray := NewAsyncArray() defer asyncarray.Close() if asyncarray.Ptr() == nil { t.Error("New AsyncArray should not be nil") } } ================================================ FILE: calib3d.cpp ================================================ //go:build !gocv_specific_modules || (gocv_specific_modules && gocv_calib3d) #include "calib3d.h" double Fisheye_Calibrate(Points3fVector objectPoints, Points2fVector imagePoints, Size size, Mat k, Mat d, Mat rvecs, Mat tvecs, int flags) { try { cv::Size sz(size.width, size.height); return cv::fisheye::calibrate(*objectPoints, *imagePoints, sz, *k, *d, *rvecs, *tvecs, flags); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return 0.0; } } OpenCVResult Fisheye_DistortPoints(Mat undistorted, Mat distorted, Mat k, Mat d) { try { cv::fisheye::distortPoints(*undistorted, *distorted, *k, *d); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Fisheye_UndistortImage(Mat distorted, Mat undistorted, Mat k, Mat d) { try { cv::fisheye::undistortImage(*distorted, *undistorted, *k, *d); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Fisheye_UndistortImageWithParams(Mat distorted, Mat undistorted, Mat k, Mat d, Mat knew, Size size) { try { cv::Size sz(size.width, size.height); cv::fisheye::undistortImage(*distorted, *undistorted, *k, *d, *knew, sz); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Fisheye_UndistortPoints(Mat distorted, Mat undistorted, Mat k, Mat d, Mat r, Mat p) { try { cv::fisheye::undistortPoints(*distorted, *undistorted, *k, *d, *r, *p); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Fisheye_EstimateNewCameraMatrixForUndistortRectify(Mat k, Mat d, Size imgSize, Mat r, Mat p, double balance, Size newSize, double fovScale) { try { cv::Size newSz(newSize.width, newSize.height); cv::Size imgSz(imgSize.width, imgSize.height); cv::fisheye::estimateNewCameraMatrixForUndistortRectify(*k, *d, imgSz, *r, *p, balance, newSz, fovScale); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult InitUndistortRectifyMap(Mat cameraMatrix,Mat distCoeffs,Mat r,Mat newCameraMatrix,Size size,int m1type,Mat map1,Mat map2) { try { cv::Size sz(size.width, size.height); cv::initUndistortRectifyMap(*cameraMatrix,*distCoeffs,*r,*newCameraMatrix,sz,m1type,*map1,*map2); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } Mat GetOptimalNewCameraMatrixWithParams(Mat cameraMatrix,Mat distCoeffs,Size size,double alpha,Size newImgSize,Rect* validPixROI,bool centerPrincipalPoint) { try { cv::Size sz(size.width, size.height); cv::Size newSize(newImgSize.width, newImgSize.height); cv::Rect rect(validPixROI->x,validPixROI->y,validPixROI->width,validPixROI->height); cv::Mat* mat = new cv::Mat(cv::getOptimalNewCameraMatrix(*cameraMatrix,*distCoeffs,sz,alpha,newSize,&rect,centerPrincipalPoint)); validPixROI->x = rect.x; validPixROI->y = rect.y; validPixROI->width = rect.width; validPixROI->height = rect.height; return mat; } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return new cv::Mat(); } } double CalibrateCamera(Points3fVector objectPoints, Points2fVector imagePoints, Size imageSize, Mat cameraMatrix, Mat distCoeffs, Mat rvecs, Mat tvecs, int flag) { try { return cv::calibrateCamera(*objectPoints, *imagePoints, cv::Size(imageSize.width, imageSize.height), *cameraMatrix, *distCoeffs, *rvecs, *tvecs, flag); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return 0.0; } } OpenCVResult Undistort(Mat src, Mat dst, Mat cameraMatrix, Mat distCoeffs, Mat newCameraMatrix) { try { cv::undistort(*src, *dst, *cameraMatrix, *distCoeffs, *newCameraMatrix); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult UndistortPoints(Mat distorted, Mat undistorted, Mat k, Mat d, Mat r, Mat p) { try { cv::undistortPoints(*distorted, *undistorted, *k, *d, *r, *p); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } bool CheckChessboard(Mat image, Size size) { try { cv::Size sz(size.width, size.height); return cv::checkChessboard(*image, sz); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return false; } } bool FindChessboardCorners(Mat image, Size patternSize, Mat corners, int flags) { try { cv::Size sz(patternSize.width, patternSize.height); return cv::findChessboardCorners(*image, sz, *corners, flags); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return false; } } bool FindChessboardCornersSB(Mat image, Size patternSize, Mat corners, int flags) { try { cv::Size sz(patternSize.width, patternSize.height); return cv::findChessboardCornersSB(*image, sz, *corners, flags); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return false; } } bool FindChessboardCornersSBWithMeta(Mat image, Size patternSize, Mat corners, int flags, Mat meta) { try { cv::Size sz(patternSize.width, patternSize.height); return cv::findChessboardCornersSB(*image, sz, *corners, flags, *meta); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return false; } } OpenCVResult DrawChessboardCorners(Mat image, Size patternSize, Mat corners, bool patternWasFound) { try { cv::Size sz(patternSize.width, patternSize.height); cv::drawChessboardCorners(*image, sz, *corners, patternWasFound); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } Mat EstimateAffinePartial2D(Point2fVector from, Point2fVector to) { try { return new cv::Mat(cv::estimateAffinePartial2D(*from, *to)); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return new cv::Mat(); } } Mat EstimateAffinePartial2DWithParams(Point2fVector from, Point2fVector to, Mat inliers, int method, double ransacReprojThreshold, size_t maxIters, double confidence, size_t refineIters) { try { return new cv::Mat(cv::estimateAffinePartial2D(*from, *to, *inliers, method, ransacReprojThreshold, maxIters, confidence, refineIters)); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return new cv::Mat(); } } Mat EstimateAffine2D(Point2fVector from, Point2fVector to) { try { return new cv::Mat(cv::estimateAffine2D(*from, *to)); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return new cv::Mat(); } } Mat EstimateAffine2DWithParams(Point2fVector from, Point2fVector to, Mat inliers, int method, double ransacReprojThreshold, size_t maxIters, double confidence, size_t refineIters) { try { return new cv::Mat(cv::estimateAffine2D(*from, *to, *inliers, method, ransacReprojThreshold, maxIters, confidence, refineIters)); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return new cv::Mat(); } } OpenCVResult TriangulatePoints(Mat projMatr1, Mat projMatr2, Point2fVector projPoints1, Point2fVector projPoints2, Mat points4D) { try { cv::triangulatePoints(*projMatr1, *projMatr2, *projPoints1, *projPoints2, *points4D); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult ConvertPointsFromHomogeneous(Mat src, Mat dst) { try { cv::convertPointsFromHomogeneous(*src, *dst); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Rodrigues(Mat src, Mat dst) { try { cv::Rodrigues(*src, *dst); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } bool SolvePnP(Point3fVector objectPoints, Point2fVector imagePoints, Mat cameraMatrix, Mat distCoeffs, Mat rvec, Mat tvec, bool useExtrinsicGuess, int flags) { try { return cv::solvePnP(*objectPoints, *imagePoints, *cameraMatrix, *distCoeffs, *rvec, *tvec, useExtrinsicGuess, flags); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return false; } } OpenCVResult StereoRectify(Mat cameraMatrix1, Mat distCoeffs1, Mat cameraMatrix2, Mat distCoeffs2, Size imageSize, Mat r, Mat t, Mat R1, Mat R2, Mat P1, Mat P2, Mat Q, int flags) { try { cv::stereoRectify(*cameraMatrix1, *distCoeffs1, *cameraMatrix2, *distCoeffs2, cv::Size(imageSize.width, imageSize.height), *r, *t, *R1, *R2, *P1, *P2, *Q, flags); return successResult(); } catch(const cv::Exception& e){ return errorResult(e.code, e.what()); } } Mat FindHomography(Mat src, Mat dst, int method, double ransacReprojThreshold, Mat mask, const int maxIters, const double confidence) { try { return new cv::Mat(cv::findHomography(*src, *dst, method, ransacReprojThreshold, *mask, maxIters, confidence)); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return new cv::Mat(); } } ================================================ FILE: calib3d.go ================================================ //go:build !gocv_specific_modules || (gocv_specific_modules && gocv_calib3d) package gocv /* #include #include "calib3d.h" */ import "C" import ( "image" ) // Calib is a wrapper around OpenCV's "Camera Calibration and 3D Reconstruction" of // Fisheye Camera model // // For more details, please see: // https://docs.opencv.org/trunk/db/d58/group__calib3d__fisheye.html // CalibFlag value for calibration type CalibFlag int32 const ( // CalibUseIntrinsicGuess indicates that cameraMatrix contains valid initial values // of fx, fy, cx, cy that are optimized further. Otherwise, (cx, cy) is initially // set to the image center ( imageSize is used), and focal distances are computed // in a least-squares fashion. CalibUseIntrinsicGuess CalibFlag = 1 << iota // CalibRecomputeExtrinsic indicates that extrinsic will be recomputed after each // iteration of intrinsic optimization. CalibRecomputeExtrinsic // CalibCheckCond indicates that the functions will check validity of condition number CalibCheckCond // CalibFixSkew indicates that skew coefficient (alpha) is set to zero and stay zero CalibFixSkew // CalibFixK1 indicates that selected distortion coefficients are set to zeros and stay zero CalibFixK1 // CalibFixK2 indicates that selected distortion coefficients are set to zeros and stay zero CalibFixK2 // CalibFixK3 indicates that selected distortion coefficients are set to zeros and stay zero CalibFixK3 // CalibFixK4 indicates that selected distortion coefficients are set to zeros and stay zero CalibFixK4 // CalibFixIntrinsic indicates that fix K1, K2? and D1, D2? so that only R, T matrices are estimated CalibFixIntrinsic // CalibFixPrincipalPoint indicates that the principal point is not changed during the global optimization. // It stays at the center or at a different location specified when CalibUseIntrinsicGuess is set too. CalibFixPrincipalPoint ) // CalibFlagPinhole defines the enumeration values for calibration flags when using the so-called pinhole camera model. // // For further details, please see: // https://docs.opencv.org/4.x/d9/d0c/group__calib3d.html#enum-members type CalibFlagPinhole int const ( CalibFlagPinholeNIntrinsic CalibFlagPinhole = 18 CalibFlagPinholeUseIntrinsicGuess CalibFlagPinhole = 0x00001 CalibFlagPinholeFixAspectRatio CalibFlagPinhole = 0x00002 CalibFlagPinholeFixPrincipalPoint CalibFlagPinhole = 0x00004 CalibFlagPinholeZeroTangentDist CalibFlagPinhole = 0x00008 CalibFlagPinholeFixFocalLength CalibFlagPinhole = 0x00010 CalibFlagPinholeFixK1 CalibFlagPinhole = 0x00020 CalibFlagPinholeFixK2 CalibFlagPinhole = 0x00040 CalibFlagPinholeFixK3 CalibFlagPinhole = 0x00080 CalibFlagPinholeFixK4 CalibFlagPinhole = 0x00800 CalibFlagPinholeFixK5 CalibFlagPinhole = 0x01000 CalibFlagPinholeFixK6 CalibFlagPinhole = 0x02000 CalibFlagPinholeRationalModel CalibFlagPinhole = 0x04000 CalibFlagPinholeThinPrismModel CalibFlagPinhole = 0x08000 CalibFlagPinholeFixS1S2S3S4 CalibFlagPinhole = 0x10000 CalibFlagPinholeTiltedModel CalibFlagPinhole = 0x40000 CalibFlagPinholeFixTauxTauy CalibFlagPinhole = 0x80000 CalibFlagPinholeUseQR CalibFlagPinhole = 0x100000 CalibFlagPinholeFixTangentDist CalibFlagPinhole = 0x200000 CalibFlagPinholeFixIntrinsic CalibFlagPinhole = 0x00100 CalibFlagPinholeSameFocalLength CalibFlagPinhole = 0x00200 CalibFlagPinholeZeroDisparity CalibFlagPinhole = 0x00400 CalibFlagPinholeUseLU CalibFlagPinhole = (1 << 17) CalibFlagPinholeUseExtrinsicGuess CalibFlagPinhole = (1 << 22) ) // FisheyeCalibrate performs camera calibration. // // For further details, please see: // https://docs.opencv.org/4.x/db/d58/group__calib3d__fisheye.html#gad626a78de2b1dae7489e152a5a5a89e1 func FisheyeCalibrate(objectPoints Points3fVector, imagePoints Points2fVector, size image.Point, k, d, rvecs, tvecs *Mat, flags CalibFlag) float64 { sz := C.struct_Size{ width: C.int(size.X), height: C.int(size.Y), } return float64(C.Fisheye_Calibrate(objectPoints.p, imagePoints.p, sz, k.p, d.p, rvecs.p, tvecs.p, C.int(flags))) } // FisheyeDistortPoints distorts 2D points using fisheye model. // // For further details, please see: // https://docs.opencv.org/master/db/d58/group__calib3d__fisheye.html#gab738cdf90ceee97b2b52b0d0e7511541 func FisheyeDistortPoints(undistorted Mat, distorted *Mat, k, d Mat) error { return OpenCVResult(C.Fisheye_DistortPoints(undistorted.Ptr(), distorted.Ptr(), k.Ptr(), d.Ptr())) } // FisheyeUndistortImage transforms an image to compensate for fisheye lens distortion func FisheyeUndistortImage(distorted Mat, undistorted *Mat, k, d Mat) error { return OpenCVResult(C.Fisheye_UndistortImage(distorted.Ptr(), undistorted.Ptr(), k.Ptr(), d.Ptr())) } // FisheyeUndistortImageWithParams transforms an image to compensate for fisheye lens distortion with Knew matrix func FisheyeUndistortImageWithParams(distorted Mat, undistorted *Mat, k, d, knew Mat, size image.Point) error { sz := C.struct_Size{ width: C.int(size.X), height: C.int(size.Y), } return OpenCVResult(C.Fisheye_UndistortImageWithParams(distorted.Ptr(), undistorted.Ptr(), k.Ptr(), d.Ptr(), knew.Ptr(), sz)) } // FisheyeUndistortPoints transforms points to compensate for fisheye lens distortion // // For further details, please see: // https://docs.opencv.org/master/db/d58/group__calib3d__fisheye.html#gab738cdf90ceee97b2b52b0d0e7511541 func FisheyeUndistortPoints(distorted Mat, undistorted *Mat, k, d, r, p Mat) error { return OpenCVResult(C.Fisheye_UndistortPoints(distorted.Ptr(), undistorted.Ptr(), k.Ptr(), d.Ptr(), r.Ptr(), p.Ptr())) } // EstimateNewCameraMatrixForUndistortRectify estimates new camera matrix for undistortion or rectification. // // For further details, please see: // https://docs.opencv.org/master/db/d58/group__calib3d__fisheye.html#ga384940fdf04c03e362e94b6eb9b673c9 func EstimateNewCameraMatrixForUndistortRectify(k, d Mat, imgSize image.Point, r Mat, p *Mat, balance float64, newSize image.Point, fovScale float64) error { imgSz := C.struct_Size{ width: C.int(imgSize.X), height: C.int(imgSize.Y), } newSz := C.struct_Size{ width: C.int(newSize.X), height: C.int(newSize.Y), } return OpenCVResult(C.Fisheye_EstimateNewCameraMatrixForUndistortRectify(k.Ptr(), d.Ptr(), imgSz, r.Ptr(), p.Ptr(), C.double(balance), newSz, C.double(fovScale))) } // InitUndistortRectifyMap computes the joint undistortion and rectification transformation and represents the result in the form of maps for remap // // For further details, please see: // https://docs.opencv.org/master/d9/d0c/group__calib3d.html#ga7dfb72c9cf9780a347fbe3d1c47e5d5a func InitUndistortRectifyMap(cameraMatrix Mat, distCoeffs Mat, r Mat, newCameraMatrix Mat, size image.Point, m1type int, map1 Mat, map2 Mat) error { sz := C.struct_Size{ width: C.int(size.X), height: C.int(size.Y), } return OpenCVResult(C.InitUndistortRectifyMap(cameraMatrix.Ptr(), distCoeffs.Ptr(), r.Ptr(), newCameraMatrix.Ptr(), sz, C.int(m1type), map1.Ptr(), map2.Ptr())) } // GetOptimalNewCameraMatrixWithParams computes and returns the optimal new camera matrix based on the free scaling parameter. // // For further details, please see: // https://docs.opencv.org/master/d9/d0c/group__calib3d.html#ga7a6c4e032c97f03ba747966e6ad862b1 func GetOptimalNewCameraMatrixWithParams(cameraMatrix Mat, distCoeffs Mat, imageSize image.Point, alpha float64, newImgSize image.Point, centerPrincipalPoint bool) (Mat, image.Rectangle) { sz := C.struct_Size{ width: C.int(imageSize.X), height: C.int(imageSize.Y), } newSize := C.struct_Size{ width: C.int(newImgSize.X), height: C.int(newImgSize.Y), } rt := C.struct_Rect{} return newMat(C.GetOptimalNewCameraMatrixWithParams(cameraMatrix.Ptr(), distCoeffs.Ptr(), sz, C.double(alpha), newSize, &rt, C.bool(centerPrincipalPoint))), toRect(rt) } // CalibrateCamera finds the camera intrinsic and extrinsic parameters from several views of a calibration pattern. // // For further details, please see: // https://docs.opencv.org/master/d9/d0c/group__calib3d.html#ga3207604e4b1a1758aa66acb6ed5aa65d func CalibrateCamera(objectPoints Points3fVector, imagePoints Points2fVector, imageSize image.Point, cameraMatrix *Mat, distCoeffs *Mat, rvecs *Mat, tvecs *Mat, calibFlag CalibFlag) float64 { sz := C.struct_Size{ width: C.int(imageSize.X), height: C.int(imageSize.Y), } res := C.CalibrateCamera(objectPoints.p, imagePoints.p, sz, cameraMatrix.p, distCoeffs.p, rvecs.p, tvecs.p, C.int(calibFlag)) return float64(res) } // Undistort transforms an image to compensate for lens distortion. // // For further details, please see: // https://docs.opencv.org/4.x/d9/d0c/group__calib3d.html#ga69f2545a8b62a6b0fc2ee060dc30559d func Undistort(src Mat, dst *Mat, cameraMatrix Mat, distCoeffs Mat, newCameraMatrix Mat) error { return OpenCVResult(C.Undistort(src.Ptr(), dst.Ptr(), cameraMatrix.Ptr(), distCoeffs.Ptr(), newCameraMatrix.Ptr())) } // UndistortPoints transforms points to compensate for lens distortion // // For further details, please see: // https://docs.opencv.org/master/d9/d0c/group__calib3d.html#ga55c716492470bfe86b0ee9bf3a1f0f7e func UndistortPoints(src Mat, dst *Mat, cameraMatrix, distCoeffs, rectificationTransform, newCameraMatrix Mat) error { return OpenCVResult(C.UndistortPoints(src.Ptr(), dst.Ptr(), cameraMatrix.Ptr(), distCoeffs.Ptr(), rectificationTransform.Ptr(), newCameraMatrix.Ptr())) } // CheckChessboard renders the detected chessboard corners. // // For further details, please see: // https://docs.opencv.org/master/d9/d0c/group__calib3d.html#ga6a10b0bb120c4907e5eabbcd22319022 func CheckChessboard(image Mat, size image.Point) bool { sz := C.struct_Size{ width: C.int(size.X), height: C.int(size.Y), } return bool(C.CheckChessboard(image.Ptr(), sz)) } // CalibCBFlag value for chessboard calibration // For more details, please see: // https://docs.opencv.org/master/d9/d0c/group__calib3d.html#ga93efa9b0aa890de240ca32b11253dd4a type CalibCBFlag int const ( // Various operation flags that can be zero or a combination of the following values: // Use adaptive thresholding to convert the image to black and white, rather than a fixed threshold level (computed from the average image brightness). CalibCBAdaptiveThresh CalibCBFlag = 1 << iota // Normalize the image gamma with equalizeHist before applying fixed or adaptive thresholding. CalibCBNormalizeImage // Use additional criteria (like contour area, perimeter, square-like shape) to filter out false quads extracted at the contour retrieval stage. CalibCBFilterQuads // Run a fast check on the image that looks for chessboard corners, and shortcut the call if none is found. This can drastically speed up the call in the degenerate condition when no chessboard is observed. CalibCBFastCheck // Run an exhaustive search to improve detection rate. CalibCBExhaustive // Up sample input image to improve sub-pixel accuracy due to aliasing effects. CalibCBAccuracy // The detected pattern is allowed to be larger than patternSize (see description). CalibCBLarger // The detected pattern must have a marker (see description). This should be used if an accurate camera calibration is required. CalibCBMarker ) // FindChessboardCorners finds the positions of internal corners of the chessboard. // // For further details, please see: // https://docs.opencv.org/master/d9/d0c/group__calib3d.html#ga93efa9b0aa890de240ca32b11253dd4a func FindChessboardCorners(image Mat, patternSize image.Point, corners *Mat, flags CalibCBFlag) bool { sz := C.struct_Size{ width: C.int(patternSize.X), height: C.int(patternSize.Y), } return bool(C.FindChessboardCorners(image.Ptr(), sz, corners.Ptr(), C.int(flags))) } // FindChessboardCorners finds the positions of internal corners of the chessboard using a sector based approach. // // For further details, please see: // https://docs.opencv.org/master/d9/d0c/group__calib3d.html#gadc5bcb05cb21cf1e50963df26986d7c9 func FindChessboardCornersSB(image Mat, patternSize image.Point, corners *Mat, flags CalibCBFlag) bool { sz := C.struct_Size{ width: C.int(patternSize.X), height: C.int(patternSize.Y), } return bool(C.FindChessboardCornersSB(image.Ptr(), sz, corners.Ptr(), C.int(flags))) } // FindChessboardCornersSBWithMeta finds the positions of internal corners of the chessboard using a sector based approach. // // For further details, please see: // https://docs.opencv.org/master/d9/d0c/group__calib3d.html#ga93efa9b0aa890de240ca32b11253dd4a func FindChessboardCornersSBWithMeta(image Mat, patternSize image.Point, corners *Mat, flags CalibCBFlag, meta *Mat) bool { sz := C.struct_Size{ width: C.int(patternSize.X), height: C.int(patternSize.Y), } return bool(C.FindChessboardCornersSBWithMeta(image.Ptr(), sz, corners.Ptr(), C.int(flags), meta.Ptr())) } // DrawChessboardCorners renders the detected chessboard corners. // // For further details, please see: // https://docs.opencv.org/master/d9/d0c/group__calib3d.html#ga6a10b0bb120c4907e5eabbcd22319022 func DrawChessboardCorners(image *Mat, patternSize image.Point, corners Mat, patternWasFound bool) error { sz := C.struct_Size{ width: C.int(patternSize.X), height: C.int(patternSize.Y), } return OpenCVResult(C.DrawChessboardCorners(image.Ptr(), sz, corners.Ptr(), C.bool(patternWasFound))) } // EstimateAffinePartial2D computes an optimal limited affine transformation // with 4 degrees of freedom between two 2D point sets. // // For further details, please see: // https://docs.opencv.org/master/d9/d0c/group__calib3d.html#gad767faff73e9cbd8b9d92b955b50062d func EstimateAffinePartial2D(from, to Point2fVector) Mat { return newMat(C.EstimateAffinePartial2D(from.p, to.p)) } // EstimateAffinePartial2DWithParams computes an optimal limited affine transformation // with 4 degrees of freedom between two 2D point sets // with additional optional parameters. // // For further details, please see: // https://docs.opencv.org/master/d9/d0c/group__calib3d.html#gad767faff73e9cbd8b9d92b955b50062d func EstimateAffinePartial2DWithParams(from Point2fVector, to Point2fVector, inliers Mat, method int, ransacReprojThreshold float64, maxIters uint, confidence float64, refineIters uint) Mat { return newMat(C.EstimateAffinePartial2DWithParams(from.p, to.p, inliers.p, C.int(method), C.double(ransacReprojThreshold), C.size_t(maxIters), C.double(confidence), C.size_t(refineIters))) } // EstimateAffine2D Computes an optimal affine transformation between two 2D point sets. // // For further details, please see: // https://docs.opencv.org/4.0.0/d9/d0c/group__calib3d.html#ga27865b1d26bac9ce91efaee83e94d4dd func EstimateAffine2D(from, to Point2fVector) Mat { return newMat(C.EstimateAffine2D(from.p, to.p)) } // EstimateAffine2DWithParams Computes an optimal affine transformation between two 2D point sets // with additional optional parameters. // // For further details, please see: // https://docs.opencv.org/4.0.0/d9/d0c/group__calib3d.html#ga27865b1d26bac9ce91efaee83e94d4dd func EstimateAffine2DWithParams(from Point2fVector, to Point2fVector, inliers Mat, method int, ransacReprojThreshold float64, maxIters uint, confidence float64, refineIters uint) Mat { return newMat(C.EstimateAffine2DWithParams(from.p, to.p, inliers.p, C.int(method), C.double(ransacReprojThreshold), C.size_t(maxIters), C.double(confidence), C.size_t(refineIters))) } // TriangulatePoints reconstructs 3-dimensional points (in homogeneous coordinates) // by using their observations with a stereo camera. // // For further details, please see: // https://docs.opencv.org/4.x/d9/d0c/group__calib3d.html#gad3fc9a0c82b08df034234979960b778c func TriangulatePoints(projMatr1, projMatr2 Mat, projPoints1, projPoints2 Point2fVector, points4D *Mat) error { return OpenCVResult(C.TriangulatePoints(projMatr1.Ptr(), projMatr2.Ptr(), projPoints1.p, projPoints2.p, points4D.Ptr())) } // ConvertPointsFromHomogeneous converts points from homogeneous to Euclidean space. // // For further details, please see: // https://docs.opencv.org/4.x/d9/d0c/group__calib3d.html#gac42edda3a3a0f717979589fcd6ac0035 func ConvertPointsFromHomogeneous(src Mat, dst *Mat) error { return OpenCVResult(C.ConvertPointsFromHomogeneous(src.Ptr(), dst.Ptr())) } // Rodrigues converts a rotation matrix to a rotation vector or vice versa. // // For further details, please see: // https://docs.opencv.org/4.0.0/d9/d0c/group__calib3d.html#ga61585db663d9da06b68e70cfbf6a1eac func Rodrigues(src Mat, dst *Mat) error { return OpenCVResult(C.Rodrigues(src.p, dst.p)) } // SolvePnP finds an object pose from 3D-2D point correspondences. // // For further details, please see: // https://docs.opencv.org/4.0.0/d9/d0c/group__calib3d.html#ga549c2075fac14829ff4a58bc931c033d func SolvePnP(objectPoints Point3fVector, imagePoints Point2fVector, cameraMatrix, distCoeffs Mat, rvec, tvec *Mat, useExtrinsicGuess bool, flags int) bool { return bool(C.SolvePnP(objectPoints.p, imagePoints.p, cameraMatrix.p, distCoeffs.p, rvec.p, tvec.p, C.bool(useExtrinsicGuess), C.int(flags))) } // StereoRectify computes rectification transforms for each head of a calibrated stereo camera. // // For further details, please see: // https://docs.opencv.org/4.x/d9/d0c/group__calib3d.html#ga617b1685d4059c6040827800e72ad2b6 func StereoRectify(cameraMatrix1, distCoeffs1, cameraMatrix2, distCoeffs2 Mat, imageSize image.Point, r Mat, t Mat, R1, R2, P1, P2, Q *Mat, flags CalibFlagPinhole) error { sz := C.struct_Size{ width: C.int(imageSize.X), height: C.int(imageSize.Y), } return OpenCVResult(C.StereoRectify(cameraMatrix1.Ptr(), distCoeffs1.Ptr(), cameraMatrix2.Ptr(), distCoeffs2.Ptr(), sz, r.Ptr(), t.Ptr(), R1.Ptr(), R2.Ptr(), P1.Ptr(), P2.Ptr(), Q.Ptr(), C.int(flags))) } type HomographyMethod int const ( HomographyMethodAllPoints HomographyMethod = 0 HomographyMethodLMEDS HomographyMethod = 4 HomographyMethodRANSAC HomographyMethod = 8 HomographyMethodRHO HomographyMethod = 16 ) // FindHomography finds an optimal homography matrix using 4 or more point pairs (as opposed to GetPerspectiveTransform, which uses exactly 4) // // For further details, please see: // https://docs.opencv.org/master/d9/d0c/group__calib3d.html#ga4abc2ece9fab9398f2e560d53c8c9780 func FindHomography(srcPoints Mat, targetPoints Mat, method HomographyMethod, ransacReprojThreshold float64, mask *Mat, maxIters int, confidence float64) Mat { return newMat(C.FindHomography(srcPoints.Ptr(), targetPoints.Ptr(), C.int(method), C.double(ransacReprojThreshold), mask.Ptr(), C.int(maxIters), C.double(confidence))) } ================================================ FILE: calib3d.h ================================================ #ifndef _OPENCV3_CALIB_H_ #define _OPENCV3_CALIB_H_ #ifdef __cplusplus #include #include extern "C" { #endif #include "core.h" //Calib double Fisheye_Calibrate(Points3fVector objectPoints, Points2fVector imagePoints, Size size, Mat k, Mat d, Mat rvecs, Mat tvecs, int flags); OpenCVResult Fisheye_DistortPoints(Mat undistorted, Mat distorted, Mat k, Mat d); OpenCVResult Fisheye_UndistortImage(Mat distorted, Mat undistorted, Mat k, Mat d); OpenCVResult Fisheye_UndistortImageWithParams(Mat distorted, Mat undistorted, Mat k, Mat d, Mat knew, Size size); OpenCVResult Fisheye_UndistortPoints(Mat distorted, Mat undistorted, Mat k, Mat d, Mat R, Mat P); OpenCVResult Fisheye_EstimateNewCameraMatrixForUndistortRectify(Mat k, Mat d, Size imgSize, Mat r, Mat p, double balance, Size newSize, double fovScale); OpenCVResult InitUndistortRectifyMap(Mat cameraMatrix,Mat distCoeffs,Mat r,Mat newCameraMatrix,Size size,int m1type,Mat map1,Mat map2); Mat GetOptimalNewCameraMatrixWithParams(Mat cameraMatrix,Mat distCoeffs,Size size,double alpha,Size newImgSize,Rect* validPixROI,bool centerPrincipalPoint); double CalibrateCamera(Points3fVector objectPoints, Points2fVector imagePoints, Size imageSize, Mat cameraMatrix, Mat distCoeffs, Mat rvecs, Mat tvecs, int flag); OpenCVResult Undistort(Mat src, Mat dst, Mat cameraMatrix, Mat distCoeffs, Mat newCameraMatrix); OpenCVResult UndistortPoints(Mat distorted, Mat undistorted, Mat k, Mat d, Mat r, Mat p); bool CheckChessboard(Mat image, Size sz); bool FindChessboardCorners(Mat image, Size patternSize, Mat corners, int flags); bool FindChessboardCornersSB(Mat image, Size patternSize, Mat corners, int flags); bool FindChessboardCornersSBWithMeta(Mat image, Size patternSize, Mat corners, int flags, Mat meta); OpenCVResult DrawChessboardCorners(Mat image, Size patternSize, Mat corners, bool patternWasFound); Mat EstimateAffinePartial2D(Point2fVector from, Point2fVector to); Mat EstimateAffinePartial2DWithParams(Point2fVector from, Point2fVector to, Mat inliers, int method, double ransacReprojThreshold, size_t maxIters, double confidence, size_t refineIters); Mat EstimateAffine2D(Point2fVector from, Point2fVector to); Mat EstimateAffine2DWithParams(Point2fVector from, Point2fVector to, Mat inliers, int method, double ransacReprojThreshold, size_t maxIters, double confidence, size_t refineIters); OpenCVResult TriangulatePoints(Mat projMatr1, Mat projMatr2, Point2fVector projPoints1, Point2fVector projPoints2, Mat points4D); OpenCVResult ConvertPointsFromHomogeneous(Mat src, Mat dst); OpenCVResult Rodrigues(Mat src, Mat dst); bool SolvePnP(Point3fVector objectPoints, Point2fVector imagePoints, Mat cameraMatrix, Mat distCoeffs, Mat rvec, Mat tvec, bool useExtrinsicGuess, int flags); OpenCVResult StereoRectify(Mat cameraMatrix1, Mat distCoeffs1, Mat cameraMatrix2, Mat distCoeffs2, Size imageSize, Mat r, Mat t, Mat R1, Mat R2, Mat P1, Mat P2, Mat Q, int flags); Mat FindHomography(Mat src, Mat dst, int method, double ransacReprojThreshold, Mat mask, const int maxIters, const double confidence); #ifdef __cplusplus } #endif #endif //_OPENCV3_CALIB_H ================================================ FILE: calib3d_string.go ================================================ //go:build !gocv_specific_modules || (gocv_specific_modules && gocv_calib3d) package gocv func (c CalibFlag) String() string { switch c { case CalibUseIntrinsicGuess: return "calib-use-intrinsec-guess" case CalibRecomputeExtrinsic: return "calib-recompute-extrinsic" case CalibCheckCond: return "calib-check-cond" case CalibFixSkew: return "calib-fix-skew" case CalibFixK1: return "calib-fix-k1" case CalibFixK2: return "calib-fix-k2" case CalibFixK3: return "calib-fix-k3" case CalibFixK4: return "calib-fix-k4" case CalibFixIntrinsic: return "calib-fix-intrinsic" case CalibFixPrincipalPoint: return "calib-fix-principal-point" } return "" } func (c CalibCBFlag) String() string { switch c { case CalibCBAdaptiveThresh: return "calib-cb-adaptive-thresh" case CalibCBNormalizeImage: return "calib-cb-normalize-image" case CalibCBFilterQuads: return "calib-cb-filter-quads" case CalibCBFastCheck: return "calib-cb-fast-check" case CalibCBExhaustive: return "calib-cb-exhaustive" case CalibCBAccuracy: return "calib-cb-accuracy" case CalibCBLarger: return "calib-cb-larger" case CalibCBMarker: return "calib-cb-marker" } return "" } ================================================ FILE: calib3d_test.go ================================================ //go:build !gocv_specific_modules || (gocv_specific_modules && gocv_calib3d) package gocv import ( "fmt" "image" "image/color" "math" "testing" ) func TestFisheyeCalibrate(t *testing.T) { img := IMRead("images/chessboard_4x6_distort.png", IMReadGrayScale) if img.Empty() { t.Error("Invalid read of chessboard image") return } defer img.Close() corners := NewMat() defer corners.Close() size := image.Pt(4, 6) found := FindChessboardCorners(img, size, &corners, 0) if !found { t.Error("chessboard pattern not found") return } if corners.Empty() { t.Error("chessboard pattern not found") return } imagePoints := NewPoint2fVectorFromMat(corners) defer imagePoints.Close() objectPoints := NewPoint3fVector() defer objectPoints.Close() for j := 0; j < size.Y; j++ { for i := 0; i < size.X; i++ { objectPoints.Append(Point3f{ X: float32(100 * i), Y: float32(100 * j), Z: 0, }) } } k := NewMat() defer k.Close() d := NewMat() defer d.Close() rvecs := NewMat() defer rvecs.Close() tvecs := NewMat() defer tvecs.Close() objectPointsVector := NewPoints3fVector() objectPointsVector.Append(objectPoints) defer objectPointsVector.Close() imagePointsVector := NewPoints2fVector() imagePointsVector.Append(imagePoints) defer imagePointsVector.Close() FisheyeCalibrate( objectPointsVector, imagePointsVector, image.Pt(img.Cols(), img.Rows()), &k, &d, &rvecs, &tvecs, 0, ) if rvecs.Empty() { t.Error("rvecs result is empty") return } if tvecs.Empty() { t.Error("tvecs result is empty") return } } func TestFisheyeDistortPoints(t *testing.T) { k := NewMatWithSize(3, 3, MatTypeCV64F) defer k.Close() k.SetDoubleAt(0, 0, 1094.7249578198823) k.SetDoubleAt(0, 1, 0) k.SetDoubleAt(0, 2, 959.4907612030962) k.SetDoubleAt(1, 0, 0) k.SetDoubleAt(1, 1, 1094.9945708128778) k.SetDoubleAt(1, 2, 536.4566143451868) k.SetDoubleAt(2, 0, 0) k.SetDoubleAt(2, 1, 0) k.SetDoubleAt(2, 2, 1) d := NewMatWithSize(1, 4, MatTypeCV64F) defer d.Close() d.SetDoubleAt(0, 0, -0.05207412392075069) d.SetDoubleAt(0, 1, -0.089168300192224) d.SetDoubleAt(0, 2, 0.10465607695792184) d.SetDoubleAt(0, 3, -0.045693446831115585) // transform 3 points in one go (X and Y values of points go in each channel) src := NewMatWithSize(3, 1, MatTypeCV64FC2) defer src.Close() dst := NewMat() defer dst.Close() // This camera matrix is 1920x1080. Points where x < 960 and y < 540 should move toward the top left (x and y get smaller) // The centre point should be mostly unchanged // Points where x > 960 and y > 540 should move toward the bottom right (x and y get bigger) // The index being used for col here is actually the channel (i.e. the point's x/y dimensions) // (since there's only 1 column so the formula: (colNumber * numChannels + channelNumber) reduces to // (0 * 2) + channelNumber // so col = 0 is the x coordinate and col = 1 is the y coordinate src.SetDoubleAt(0, 0, 480) src.SetDoubleAt(0, 1, 270) src.SetDoubleAt(1, 0, 960) src.SetDoubleAt(1, 1, 540) src.SetDoubleAt(2, 0, 1440) src.SetDoubleAt(2, 1, 810) FisheyeDistortPoints(src, &dst, k, d) if dst.Empty() { t.Error("final image is empty") return } } func TestFisheyeUndistorImage(t *testing.T) { img := IMRead("images/fisheye_sample.jpg", IMReadUnchanged) if img.Empty() { t.Error("Invalid read of Mat test") return } defer img.Close() dest := NewMat() defer dest.Close() k := NewMatWithSize(3, 3, MatTypeCV64F) defer k.Close() k.SetDoubleAt(0, 0, 689.21) k.SetDoubleAt(0, 1, 0) k.SetDoubleAt(0, 2, 1295.56) k.SetDoubleAt(1, 0, 0) k.SetDoubleAt(1, 1, 690.48) k.SetDoubleAt(1, 2, 942.17) k.SetDoubleAt(2, 0, 0) k.SetDoubleAt(2, 1, 0) k.SetDoubleAt(2, 2, 1) d := NewMatWithSize(1, 4, MatTypeCV64F) defer d.Close() d.SetDoubleAt(0, 0, 0) d.SetDoubleAt(0, 1, 0) d.SetDoubleAt(0, 2, 0) d.SetDoubleAt(0, 3, 0) FisheyeUndistortImage(img, &dest, k, d) if dest.Empty() { t.Error("final image is empty") return } } func TestFisheyeUndistorImageWithParams(t *testing.T) { img := IMRead("images/fisheye_sample.jpg", IMReadUnchanged) if img.Empty() { t.Error("Invalid read of Mat test") return } defer img.Close() dest := NewMat() defer dest.Close() k := NewMatWithSize(3, 3, MatTypeCV64F) defer k.Close() k.SetDoubleAt(0, 0, 689.21) k.SetDoubleAt(0, 1, 0) k.SetDoubleAt(0, 2, 1295.56) k.SetDoubleAt(1, 0, 0) k.SetDoubleAt(1, 1, 690.48) k.SetDoubleAt(1, 2, 942.17) k.SetDoubleAt(2, 0, 0) k.SetDoubleAt(2, 1, 0) k.SetDoubleAt(2, 2, 1) d := NewMatWithSize(1, 4, MatTypeCV64F) defer d.Close() d.SetDoubleAt(0, 0, 0) d.SetDoubleAt(0, 1, 0) d.SetDoubleAt(0, 2, 0) d.SetDoubleAt(0, 3, 0) knew := NewMat() defer knew.Close() k.CopyTo(&knew) knew.SetDoubleAt(0, 0, 0.4*k.GetDoubleAt(0, 0)) knew.SetDoubleAt(1, 1, 0.4*k.GetDoubleAt(1, 1)) size := image.Point{dest.Rows(), dest.Cols()} FisheyeUndistortImageWithParams(img, &dest, k, d, knew, size) if dest.Empty() { t.Error("final image is empty") return } } func TestInitUndistortRectifyMap(t *testing.T) { img := IMRead("images/distortion.jpg", IMReadUnchanged) if img.Empty() { t.Error("Invalid read of Mat test") return } defer img.Close() dest := NewMat() defer dest.Close() k := NewMatWithSize(3, 3, MatTypeCV64F) defer k.Close() k.SetDoubleAt(0, 0, 842.0261028) k.SetDoubleAt(0, 1, 0) k.SetDoubleAt(0, 2, 667.7569792) k.SetDoubleAt(1, 0, 0) k.SetDoubleAt(1, 1, 707.3668897) k.SetDoubleAt(1, 2, 385.56476464) k.SetDoubleAt(2, 0, 0) k.SetDoubleAt(2, 1, 0) k.SetDoubleAt(2, 2, 1) d := NewMatWithSize(1, 5, MatTypeCV64F) defer d.Close() d.SetDoubleAt(0, 0, -3.65584802e-01) d.SetDoubleAt(0, 1, 1.41555815e-01) d.SetDoubleAt(0, 2, -2.62985819e-03) d.SetDoubleAt(0, 3, 2.05841873e-04) d.SetDoubleAt(0, 4, -2.35021914e-02) newC, roi := GetOptimalNewCameraMatrixWithParams(k, d, image.Point{X: img.Cols(), Y: img.Rows()}, (float64)(1), image.Point{X: img.Cols(), Y: img.Rows()}, false) if newC.Empty() { t.Error("final image is empty") return } fmt.Printf("roi:%+v\n", roi) defer newC.Close() r := NewMat() defer r.Close() mapx := NewMat() defer mapx.Close() mapy := NewMat() defer mapy.Close() InitUndistortRectifyMap(k, d, r, newC, image.Point{X: img.Cols(), Y: img.Rows()}, 5, mapx, mapy) Remap(img, &dest, &mapx, &mapy, InterpolationDefault, BorderConstant, color.RGBA{0, 0, 0, 0}) flg := IMWrite("images/distortion-correct.jpg", dest) if !flg { t.Error("IMWrite failed") } } func TestUndistort(t *testing.T) { img := IMRead("images/distortion.jpg", IMReadUnchanged) if img.Empty() { t.Error("Invalid read of Mat test") return } defer img.Close() dest := img.Clone() defer dest.Close() k := NewMatWithSize(3, 3, MatTypeCV64F) defer k.Close() k.SetDoubleAt(0, 0, 689.21) k.SetDoubleAt(0, 1, 0) k.SetDoubleAt(0, 2, 1295.56) k.SetDoubleAt(1, 0, 0) k.SetDoubleAt(1, 1, 690.48) k.SetDoubleAt(1, 2, 942.17) k.SetDoubleAt(2, 0, 0) k.SetDoubleAt(2, 1, 0) k.SetDoubleAt(2, 2, 1) d := NewMatWithSize(1, 4, MatTypeCV64F) defer d.Close() d.SetDoubleAt(0, 0, 0) d.SetDoubleAt(0, 1, 0) d.SetDoubleAt(0, 2, 0) d.SetDoubleAt(0, 3, 0) knew := NewMat() defer knew.Close() k.CopyTo(&knew) knew.SetDoubleAt(0, 0, 0.5*k.GetDoubleAt(0, 0)) knew.SetDoubleAt(1, 1, 0.5*k.GetDoubleAt(1, 1)) Undistort(img, &dest, k, d, knew) if dest.Empty() { t.Error("final image is empty") return } } func TestUndistortPoint(t *testing.T) { k := NewMatWithSize(3, 3, MatTypeCV64F) defer k.Close() k.SetDoubleAt(0, 0, 1094.7249578198823) k.SetDoubleAt(0, 1, 0) k.SetDoubleAt(0, 2, 959.4907612030962) k.SetDoubleAt(1, 0, 0) k.SetDoubleAt(1, 1, 1094.9945708128778) k.SetDoubleAt(1, 2, 536.4566143451868) k.SetDoubleAt(2, 0, 0) k.SetDoubleAt(2, 1, 0) k.SetDoubleAt(2, 2, 1) d := NewMatWithSize(1, 4, MatTypeCV64F) defer d.Close() d.SetDoubleAt(0, 0, -0.05207412392075069) d.SetDoubleAt(0, 1, -0.089168300192224) d.SetDoubleAt(0, 2, 0.10465607695792184) d.SetDoubleAt(0, 3, -0.045693446831115585) r := NewMat() defer r.Close() // transform 3 points in one go src := NewMatWithSize(3, 1, MatTypeCV64FC2) defer src.Close() dst := NewMatWithSize(3, 1, MatTypeCV64FC2) defer dst.Close() // This camera matrix is 1920x1080. Points where x < 960 and y < 540 should move toward the top left (x and y get smaller) // The centre point should be mostly unchanged // Points where x > 960 and y > 540 should move toward the bottom right (x and y get bigger) // The index being used for col here is actually the channel (i.e. the point's x/y dimensions) // (since there's only 1 column so the formula: (colNumber * numChannels + channelNumber) reduces to // (0 * 2) + channelNumber // so col = 0 is the x coordinate and col = 1 is the y coordinate src.SetDoubleAt(0, 0, 480) src.SetDoubleAt(0, 1, 270) src.SetDoubleAt(1, 0, 960) src.SetDoubleAt(1, 1, 540) src.SetDoubleAt(2, 0, 1920) src.SetDoubleAt(2, 1, 1080) UndistortPoints(src, &dst, k, d, r, k) if dst.GetDoubleAt(0, 0) >= 480 || dst.GetDoubleAt(0, 1) >= 270 { t.Error("undistortion expected top left point to move further up and left") return } if math.Round(dst.GetDoubleAt(1, 0)) != 960 || math.Round(dst.GetDoubleAt(1, 1)) != 540 { t.Error("undistortion expected centre point to be nearly unchanged") return } if dst.GetDoubleAt(2, 0) != 1920 || dst.GetDoubleAt(2, 1) != 1080 { t.Error("undistortion expected bottom right corner to be unchanged") return } } func TestFisheyeUndistortPoint(t *testing.T) { k := NewMatWithSize(3, 3, MatTypeCV64F) defer k.Close() k.SetDoubleAt(0, 0, 1094.7249578198823) k.SetDoubleAt(0, 1, 0) k.SetDoubleAt(0, 2, 959.4907612030962) k.SetDoubleAt(1, 0, 0) k.SetDoubleAt(1, 1, 1094.9945708128778) k.SetDoubleAt(1, 2, 536.4566143451868) k.SetDoubleAt(2, 0, 0) k.SetDoubleAt(2, 1, 0) k.SetDoubleAt(2, 2, 1) d := NewMatWithSize(1, 4, MatTypeCV64F) defer d.Close() d.SetDoubleAt(0, 0, -0.05207412392075069) d.SetDoubleAt(0, 1, -0.089168300192224) d.SetDoubleAt(0, 2, 0.10465607695792184) d.SetDoubleAt(0, 3, -0.045693446831115585) r := NewMat() defer r.Close() // transform 3 points in one go (X and Y values of points go in each channel) src := NewMatWithSize(3, 1, MatTypeCV64FC2) defer src.Close() dst := NewMatWithSize(3, 1, MatTypeCV64FC2) defer dst.Close() // This camera matrix is 1920x1080. Points where x < 960 and y < 540 should move toward the top left (x and y get smaller) // The centre point should be mostly unchanged // Points where x > 960 and y > 540 should move toward the bottom right (x and y get bigger) // The index being used for col here is actually the channel (i.e. the point's x/y dimensions) // (since there's only 1 column so the formula: (colNumber * numChannels + channelNumber) reduces to // (0 * 2) + channelNumber // so col = 0 is the x coordinate and col = 1 is the y coordinate src.SetDoubleAt(0, 0, 480) src.SetDoubleAt(0, 1, 270) src.SetDoubleAt(1, 0, 960) src.SetDoubleAt(1, 1, 540) src.SetDoubleAt(2, 0, 1440) src.SetDoubleAt(2, 1, 810) kNew := NewMat() defer kNew.Close() k.CopyTo(&kNew) kNew.SetDoubleAt(0, 0, 0.4*k.GetDoubleAt(0, 0)) kNew.SetDoubleAt(1, 1, 0.4*k.GetDoubleAt(1, 1)) imgSize := image.Point{X: 1920, Y: 1080} EstimateNewCameraMatrixForUndistortRectify(k, d, imgSize, r, &kNew, 1, imgSize, 1) FisheyeUndistortPoints(src, &dst, k, d, r, kNew) if dst.GetDoubleAt(0, 0) == 0 { t.Error("expected destination Mat to be populated") } } func TestCheckChessboard(t *testing.T) { img := IMRead("images/chessboard_4x6.png", IMReadGrayScale) if img.Empty() { t.Error("Invalid read of chessboard image") return } defer img.Close() if !CheckChessboard(img, image.Point{X: 4, Y: 6}) { t.Error("chessboard pattern not found") return } } func TestFindAndDrawChessboard(t *testing.T) { img := IMRead("images/chessboard_4x6.png", IMReadUnchanged) if img.Empty() { t.Error("Invalid read of chessboard image") return } defer img.Close() corners := NewMat() defer corners.Close() found := FindChessboardCorners(img, image.Point{X: 4, Y: 6}, &corners, 0) if found == false { t.Error("chessboard pattern not found") return } if corners.Empty() { t.Error("chessboard pattern not found") return } img2 := NewMatWithSize(150, 150, MatTypeCV8U) defer img2.Close() DrawChessboardCorners(&img2, image.Pt(4, 6), corners, true) if img2.Empty() { t.Error("Error in DrawChessboardCorners test") } } func TestFindAndDrawChessboardSB(t *testing.T) { img := IMRead("images/chessboard_4x6.png", IMReadUnchanged) if img.Empty() { t.Error("Invalid read of chessboard image") return } defer img.Close() corners := NewMat() defer corners.Close() found := FindChessboardCornersSB(img, image.Point{X: 4, Y: 6}, &corners, 0) if found == false { t.Error("chessboard pattern not found") return } if corners.Empty() { t.Error("chessboard pattern not found") return } img2 := NewMatWithSize(150, 150, MatTypeCV8U) defer img2.Close() DrawChessboardCorners(&img2, image.Pt(4, 6), corners, true) if img2.Empty() { t.Error("Error in DrawChessboardCorners test") } } func TestFindChessboardCornersSBWithMeta(t *testing.T) { img := IMRead("images/chessboard_4x6.png", IMReadUnchanged) if img.Empty() { t.Error("Invalid read of chessboard image") return } defer img.Close() corners := NewMat() defer corners.Close() meta := NewMat() defer meta.Close() found := FindChessboardCornersSBWithMeta(img, image.Point{X: 4, Y: 6}, &corners, 0, &meta) if found == false { t.Error("chessboard pattern not found") return } if corners.Empty() { t.Error("chessboard pattern not found") return } img2 := NewMatWithSize(150, 150, MatTypeCV8U) defer img2.Close() DrawChessboardCorners(&img2, image.Pt(4, 6), corners, true) if img2.Empty() { t.Error("Error in DrawChessboardCorners test") } } func TestCalibrateCamera(t *testing.T) { img := IMRead("images/chessboard_4x6_distort.png", IMReadGrayScale) if img.Empty() { t.Error("Invalid read of chessboard image") return } defer img.Close() corners := NewMat() defer corners.Close() size := image.Pt(4, 6) found := FindChessboardCorners(img, size, &corners, 0) if !found { t.Error("chessboard pattern not found") return } if corners.Empty() { t.Error("chessboard pattern not found") return } imagePoints := NewPoint2fVectorFromMat(corners) defer imagePoints.Close() objectPoints := NewPoint3fVector() defer objectPoints.Close() for j := 0; j < size.Y; j++ { for i := 0; i < size.X; i++ { objectPoints.Append(Point3f{ X: float32(100 * i), Y: float32(100 * j), Z: 0, }) } } cameraMatrix := NewMat() defer cameraMatrix.Close() distCoeffs := NewMat() defer distCoeffs.Close() rvecs := NewMat() defer rvecs.Close() tvecs := NewMat() defer tvecs.Close() objectPointsVector := NewPoints3fVector() objectPointsVector.Append(objectPoints) defer objectPointsVector.Close() imagePointsVector := NewPoints2fVector() imagePointsVector.Append(imagePoints) defer imagePointsVector.Close() CalibrateCamera( objectPointsVector, imagePointsVector, image.Pt(img.Cols(), img.Rows()), &cameraMatrix, &distCoeffs, &rvecs, &tvecs, 0, ) dest := NewMat() defer dest.Close() Undistort(img, &dest, cameraMatrix, distCoeffs, cameraMatrix) target := IMRead("images/chessboard_4x6_distort_correct.png", IMReadGrayScale) defer target.Close() xor := NewMat() defer xor.Close() // The method for compare is ugly : different pix number < 0.5% BitwiseXor(dest, target, &xor) differentPixelsNumber := xor.Sum().Val1 maxDifferentPixelsNumber := float64(img.Cols()*img.Rows()) * 0.005 if differentPixelsNumber > maxDifferentPixelsNumber { t.Error("the undisorted image not equal the target one:", differentPixelsNumber, "bigger than", maxDifferentPixelsNumber) } } func TestEstimateAffinePartial2D(t *testing.T) { src := []Point2f{ {0, 0}, {10, 5}, {10, 10}, {5, 10}, } dst := []Point2f{ {0, 0}, {10, 0}, {10, 10}, {0, 10}, } pvsrc := NewPoint2fVectorFromPoints(src) defer pvsrc.Close() pvdst := NewPoint2fVectorFromPoints(dst) defer pvdst.Close() m := EstimateAffinePartial2D(pvsrc, pvdst) defer m.Close() if m.Cols() != 3 { t.Errorf("TestEstimateAffinePartial2D(): unexpected cols = %v, want = %v", m.Cols(), 3) } if m.Rows() != 2 { t.Errorf("TestEstimateAffinePartial2D(): unexpected rows = %v, want = %v", m.Rows(), 2) } } func TestEstimateAffinePartial2DWithParams(t *testing.T) { src := []Point2f{ {0, 0}, {10, 5}, {10, 10}, {5, 10}, } dst := []Point2f{ {0, 0}, {10, 0}, {10, 10}, {0, 10}, } pvsrc := NewPoint2fVectorFromPoints(src) defer pvsrc.Close() pvdst := NewPoint2fVectorFromPoints(dst) defer pvdst.Close() inliers := NewMat() defer inliers.Close() method := 8 ransacProjThreshold := 3.0 maxiters := uint(2000) confidence := 0.99 refineIters := uint(10) m := EstimateAffinePartial2DWithParams(pvsrc, pvdst, inliers, method, ransacProjThreshold, maxiters, confidence, refineIters) defer m.Close() if m.Cols() != 3 { t.Errorf("TestEstimateAffinePartial2D(): unexpected cols = %v, want = %v", m.Cols(), 3) } if m.Rows() != 2 { t.Errorf("TestEstimateAffinePartial2D(): unexpected rows = %v, want = %v", m.Rows(), 2) } } func TestEstimateAffine2D(t *testing.T) { src := []Point2f{ {0, 0}, {10, 5}, {10, 10}, {5, 10}, } dst := []Point2f{ {0, 0}, {10, 0}, {10, 10}, {0, 10}, } pvsrc := NewPoint2fVectorFromPoints(src) defer pvsrc.Close() pvdst := NewPoint2fVectorFromPoints(dst) defer pvdst.Close() m := EstimateAffine2D(pvsrc, pvdst) defer m.Close() if m.Cols() != 3 { t.Errorf("TestEstimateAffine2D(): unexpected cols = %v, want = %v", m.Cols(), 3) } if m.Rows() != 2 { t.Errorf("TestEstimateAffine2D(): unexpected rows = %v, want = %v", m.Rows(), 2) } } func TestEstimateAffine2DWithParams(t *testing.T) { src := []Point2f{ {0, 0}, {10, 5}, {10, 10}, {5, 10}, } dst := []Point2f{ {0, 0}, {10, 0}, {10, 10}, {0, 10}, } pvsrc := NewPoint2fVectorFromPoints(src) defer pvsrc.Close() pvdst := NewPoint2fVectorFromPoints(dst) defer pvdst.Close() inliers := NewMat() defer inliers.Close() method := 8 ransacProjThreshold := 3.0 maxiters := uint(2000) confidence := 0.99 refineIters := uint(10) m := EstimateAffine2DWithParams(pvsrc, pvdst, inliers, method, ransacProjThreshold, maxiters, confidence, refineIters) defer m.Close() if m.Cols() != 3 { t.Errorf("TestEstimateAffine2DWithParams(): unexpected cols = %v, want = %v", m.Cols(), 3) } if m.Rows() != 2 { t.Errorf("TestEstimateAffine2DWithParams(): unexpected rows = %v, want = %v", m.Rows(), 2) } } func TestTriangulatePoints(t *testing.T) { projMat1, projMat2 := NewMatWithSize(3, 4, MatTypeCV64F), NewMatWithSize(3, 4, MatTypeCV64F) defer projMat1.Close() defer projMat2.Close() projPoints1, projPoints2 := NewPoint2fVectorFromPoints([]Point2f{{Y: 1.0, X: 2.0}}), NewPoint2fVectorFromPoints([]Point2f{{Y: 3.0, X: 4.0}}) defer projPoints1.Close() defer projPoints2.Close() homogeneous := NewMat() defer homogeneous.Close() TriangulatePoints(projMat1, projMat2, projPoints1, projPoints2, &homogeneous) if homogeneous.Empty() { t.Errorf("TriangulatePoints(): output homogeneous mat is empty") } } func TestConvertPointsFromHomogeneous(t *testing.T) { homogeneous := NewMatWithSize(1, 4, MatTypeCV32F) defer homogeneous.Close() homogeneous.SetFloatAt(0, 0, 1) homogeneous.SetFloatAt(0, 1, 2) homogeneous.SetFloatAt(0, 2, 4) homogeneous.SetFloatAt(0, 3, 2) euclidean := NewMat() defer euclidean.Close() ConvertPointsFromHomogeneous(homogeneous, &euclidean) if euclidean.Empty() { t.Fatalf("ConvertPointsFromHomogeneous(): output euclidean mat is empty") } ptsVector := NewPoint3fVectorFromMat(euclidean) defer ptsVector.Close() pts := ptsVector.ToPoints() if len(pts) != 1 { t.Fatalf("ConvertPointsFromHomogeneous(): euclidean mat converted to points is empty") } if pts[0].X != 0.5 { t.Errorf("ConvertPointsFromHomogeneous(): euclidean X - got %v, want %v", pts[0].X, 0.5) } if pts[0].Y != 1 { t.Errorf("ConvertPointsFromHomogeneous(): euclidean Y - got %v, want %v", pts[0].Y, 1) } if pts[0].Z != 2 { t.Errorf("ConvertPointsFromHomogeneous(): euclidean Z - got %v, want %v", pts[0].Z, 2) } } func TestRodrigues(t *testing.T) { k := NewMatWithSize(3, 3, MatTypeCV64F) defer k.Close() k.SetDoubleAt(0, 0, 689.21) k.SetDoubleAt(0, 1, 0) k.SetDoubleAt(0, 2, 1295.56) k.SetDoubleAt(1, 0, 0) k.SetDoubleAt(1, 1, 690.48) k.SetDoubleAt(1, 2, 942.17) k.SetDoubleAt(2, 0, 0) k.SetDoubleAt(2, 1, 0) k.SetDoubleAt(2, 2, 1) dest := NewMat() defer dest.Close() Rodrigues(k, &dest) if dest.Empty() { t.Error("final result is empty") return } } func TestSolvePnP(t *testing.T) { pts := []Point3f{ {10.0, 10.0, 0.1}, {10.0, 20.0, 1.0}, {20.5, 21.5, 2.0}, {10.0, 20.0, 1.0}, } objectPointsVector := NewPoint3fVectorFromPoints(pts) defer objectPointsVector.Close() pts2 := []Point2f{ {10.0, 10.0}, {10.0, 20.0}, {20.5, 21.5}, {25.5, 30.5}, } imagePointsVector := NewPoint2fVectorFromPoints(pts2) defer imagePointsVector.Close() cameraMatrix := Eye(3, 3, MatTypeCV64F) defer cameraMatrix.Close() distCoeffs := NewMat() defer distCoeffs.Close() rvecs := NewMat() defer rvecs.Close() tvecs := NewMat() defer tvecs.Close() SolvePnP(objectPointsVector, imagePointsVector, cameraMatrix, distCoeffs, &rvecs, &tvecs, false, 0) if rvecs.Empty() { t.Error("rvecs result is empty") return } if tvecs.Empty() { t.Error("tvecs result is empty") return } } func TestStereoRectify(t *testing.T) { cameraMatrix1 := NewMatWithSize(3, 3, MatTypeCV64F) defer cameraMatrix1.Close() cameraMatrix1.SetDoubleAt(0, 0, 1679.861998224759) cameraMatrix1.SetDoubleAt(0, 1, 0) cameraMatrix1.SetDoubleAt(0, 2, 1231.158426771668) cameraMatrix1.SetDoubleAt(1, 0, 0) cameraMatrix1.SetDoubleAt(1, 1, 1679.6751024982132) cameraMatrix1.SetDoubleAt(1, 2, 998.4768157307255) cameraMatrix1.SetDoubleAt(2, 0, 0) cameraMatrix1.SetDoubleAt(2, 1, 0) cameraMatrix1.SetDoubleAt(2, 2, 1) distCoeffs1 := NewMatWithSize(1, 5, MatTypeCV64F) defer distCoeffs1.Close() distCoeffs1.SetDoubleAt(0, 0, -0.13657891044008158) distCoeffs1.SetDoubleAt(0, 1, 0.08861314898314139) distCoeffs1.SetDoubleAt(0, 2, -0.0006100429198910993) distCoeffs1.SetDoubleAt(0, 3, -0.000146035714553745) distCoeffs1.SetDoubleAt(0, 4, -0.0223854079208295) cameraMatrix2 := NewMatWithSize(3, 3, MatTypeCV64F) defer cameraMatrix2.Close() cameraMatrix2.SetDoubleAt(0, 0, 1678.7797594660801) cameraMatrix2.SetDoubleAt(0, 1, 0) cameraMatrix2.SetDoubleAt(0, 2, 1233.9647439048256) cameraMatrix2.SetDoubleAt(1, 0, 0) cameraMatrix2.SetDoubleAt(1, 1, 1679.0176277206788) cameraMatrix2.SetDoubleAt(1, 2, 964.4565768594671) cameraMatrix2.SetDoubleAt(2, 0, 0) cameraMatrix2.SetDoubleAt(2, 1, 0) cameraMatrix2.SetDoubleAt(2, 2, 1) distCoeffs2 := NewMatWithSize(1, 5, MatTypeCV64F) defer distCoeffs2.Close() distCoeffs2.SetDoubleAt(0, 0, -0.13690489442431938) distCoeffs2.SetDoubleAt(0, 1, 0.08705821688253863) distCoeffs2.SetDoubleAt(0, 2, 0.001288895752441417) distCoeffs2.SetDoubleAt(0, 3, -5.508164903909865e-05) distCoeffs2.SetDoubleAt(0, 4, -0.02092107478701842) R := NewMatWithSize(3, 3, MatTypeCV64F) defer R.Close() R.SetDoubleAt(0, 0, 0.9978384271270464) R.SetDoubleAt(0, 1, 0.06567174227009016) R.SetDoubleAt(0, 2, -0.0023865489378896566) R.SetDoubleAt(1, 0, -0.06567842187628788) R.SetDoubleAt(1, 1, 0.9978368073955511) R.SetDoubleAt(1, 2, -0.002837376692327134) R.SetDoubleAt(2, 0, 0.0021950509020153912) R.SetDoubleAt(2, 1, 0.0029879882638097722) R.SetDoubleAt(2, 2, 0.9999931268152161) T := NewMatWithSize(3, 1, MatTypeCV64F) defer T.Close() T.SetDoubleAt(0, 0, -0.1600062730246643) T.SetDoubleAt(1, 0, 0.007804854680409705) T.SetDoubleAt(2, 0, 9.242933249524358e-05) R1 := NewMat() defer R1.Close() R2 := NewMat() defer R2.Close() P1 := NewMat() defer P1.Close() P2 := NewMat() defer P2.Close() Q := NewMat() defer Q.Close() imageSize := image.Point{X: 2448, Y: 2048} err := StereoRectify(cameraMatrix1, distCoeffs1, cameraMatrix2, distCoeffs2, imageSize, R, T, &R1, &R2, &P1, &P2, &Q, CalibFlagPinholeZeroDisparity) if err != nil { t.Errorf("StereoRectify failed: %v", err) } if R1.Empty() { t.Error("R1 result is empty") } if R2.Empty() { t.Error("R2 result is empty") } if P1.Empty() { t.Error("P1 result is empty") } if P2.Empty() { t.Error("P2 result is empty") } if Q.Empty() { t.Error("Q result is empty") } } func TestFindHomography(t *testing.T) { src := NewMatWithSize(4, 1, MatTypeCV64FC2) defer src.Close() target := NewMatWithSize(4, 1, MatTypeCV64FC2) defer target.Close() srcPoints := []Point2f{ {193, 932}, {191, 378}, {1497, 183}, {1889, 681}, } targetPoints := []Point2f{ {51.51206544281359, -0.10425475260813055}, {51.51211051314331, -0.10437947532732306}, {51.512222354139325, -0.10437679311830816}, {51.51214828037607, -0.1042212249954444}, } for i, point := range srcPoints { src.SetDoubleAt(i, 0, float64(point.X)) src.SetDoubleAt(i, 1, float64(point.Y)) } for i, point := range targetPoints { target.SetDoubleAt(i, 0, float64(point.X)) target.SetDoubleAt(i, 1, float64(point.Y)) } mask := NewMat() defer mask.Close() m := FindHomography(src, target, HomographyMethodAllPoints, 3, &mask, 2000, 0.995) defer m.Close() pvsrc := NewPoint2fVectorFromPoints(srcPoints) defer pvsrc.Close() pvdst := NewPoint2fVectorFromPoints(targetPoints) defer pvdst.Close() m2 := GetPerspectiveTransform2f(pvsrc, pvdst) defer m2.Close() for row := 0; row < 3; row++ { for col := 0; col < 3; col++ { if math.Abs(m.GetDoubleAt(row, col)-m2.GetDoubleAt(row, col)) > 0.002 { t.Errorf("expected little difference between GetPerspectiveTransform2f and FindHomography results, got %f for row %d col %d", math.Abs(m.GetDoubleAt(row, col)-m2.GetDoubleAt(row, col)), row, col) } } } } ================================================ FILE: cgo.go ================================================ //go:build !customenv && !opencvstatic package gocv // Changes here should be mirrored in contrib/cgo.go and cuda/cgo.go. /* #cgo !windows pkg-config: opencv4 #cgo CXXFLAGS: --std=c++11 -DNDEBUG #cgo windows CPPFLAGS: -IC:/opencv/build/install/include #cgo windows LDFLAGS: -LC:/opencv/build/install/x64/mingw/lib -lopencv_core4130 -lopencv_face4130 -lopencv_videoio4130 -lopencv_imgproc4130 -lopencv_highgui4130 -lopencv_imgcodecs4130 -lopencv_objdetect4130 -lopencv_features2d4130 -lopencv_video4130 -lopencv_dnn4130 -lopencv_xfeatures2d4130 -lopencv_plot4130 -lopencv_tracking4130 -lopencv_img_hash4130 -lopencv_calib3d4130 -lopencv_bgsegm4130 -lopencv_photo4130 -lopencv_aruco4130 -lopencv_wechat_qrcode4130 -lopencv_ximgproc4130 -lopencv_mcc4130 */ import "C" ================================================ FILE: cgo_static.go ================================================ //go:build !customenv && opencvstatic && linux package gocv // Changes here should be mirrored in contrib/cgo_static.go and cuda/cgo_static.go. /* #cgo CXXFLAGS: --std=c++11 -DNDEBUG #cgo CPPFLAGS: -I/usr/local/include -I/usr/local/include/opencv4 #cgo amd64 LDFLAGS: -O2 -g -static -L/usr/local/lib -L/usr/local/lib/opencv4/3rdparty -lopencv_gapi -lopencv_stitching -lopencv_aruco -lopencv_bgsegm -lopencv_bioinspired -lopencv_ccalib -lopencv_dnn_objdetect -lopencv_dnn_superres -lopencv_dpm -lopencv_face -lopencv_freetype -lopencv_fuzzy -lopencv_hfs -lopencv_img_hash -lopencv_intensity_transform -lopencv_line_descriptor -lopencv_mcc -lopencv_quality -lopencv_rapid -lopencv_reg -lopencv_rgbd -lopencv_saliency -lopencv_signal -lopencv_stereo -lopencv_structured_light -lopencv_phase_unwrapping -lopencv_superres -lopencv_optflow -lopencv_surface_matching -lopencv_tracking -lopencv_highgui -lopencv_datasets -lopencv_text -lopencv_plot -lopencv_videostab -lopencv_videoio -lopencv_wechat_qrcode -lopencv_xfeatures2d -lopencv_shape -lopencv_ml -lopencv_ximgproc -lopencv_video -lopencv_xobjdetect -lopencv_objdetect -lopencv_calib3d -lopencv_imgcodecs -lopencv_features2d -lopencv_dnn -lopencv_flann -lopencv_xphoto -lopencv_photo -lopencv_imgproc -lopencv_core -llibprotobuf -lade -ltbb -littnotify -llibjpeg-turbo -llibwebp -llibtiff -llibopenjp2 -lIlmImf -lquirc -lippiw -lippicv -lpng -lz -lgcc -lstdc++ -lfreetype -lharfbuzz -ldl -lm -lpthread -lrt -lavdevice -lm -latomic -lavfilter -pthread -lm -latomic -lswscale -lm -latomic -lpostproc -lm -latomic -lavformat -lm -latomic -lz -lavcodec -lvpx -lm -lvpx -lm -lvpx -lm -lvpx -lm -pthread -lm -latomic -lz -lx264 -lswresample -lm -latomic -lavutil -pthread -lm -latomic #cgo arm64 LDFLAGS: -O2 -g -static -L/usr/local/lib -L/usr/local/lib/opencv4/3rdparty -lopencv_gapi -lopencv_stitching -lopencv_aruco -lopencv_bgsegm -lopencv_bioinspired -lopencv_ccalib -lopencv_dnn_objdetect -lopencv_dnn_superres -lopencv_dpm -lopencv_face -lopencv_freetype -lopencv_fuzzy -lopencv_hfs -lopencv_img_hash -lopencv_intensity_transform -lopencv_line_descriptor -lopencv_mcc -lopencv_quality -lopencv_rapid -lopencv_reg -lopencv_rgbd -lopencv_saliency -lopencv_signal -lopencv_stereo -lopencv_structured_light -lopencv_phase_unwrapping -lopencv_superres -lopencv_optflow -lopencv_surface_matching -lopencv_tracking -lopencv_highgui -lopencv_datasets -lopencv_text -lopencv_plot -lopencv_videostab -lopencv_videoio -lopencv_wechat_qrcode -lopencv_xfeatures2d -lopencv_shape -lopencv_ml -lopencv_ximgproc -lopencv_video -lopencv_xobjdetect -lopencv_objdetect -lopencv_calib3d -lopencv_imgcodecs -lopencv_features2d -lopencv_dnn -lopencv_flann -lopencv_xphoto -lopencv_photo -lopencv_imgproc -lopencv_core -llibprotobuf -lade -ltbb -littnotify -llibjpeg-turbo -llibwebp -llibtiff -llibopenjp2 -lIlmImf -lquirc -ltegra_hal -lpng -lz -lgcc -lstdc++ -lfreetype -lharfbuzz -ldl -lm -lpthread -lrt -lavdevice -lm -latomic -lavfilter -pthread -lm -latomic -lswscale -lm -latomic -lpostproc -lm -latomic -lavformat -lm -latomic -lz -lavcodec -lvpx -lm -lvpx -lm -lvpx -lm -lvpx -lm -pthread -lm -latomic -lz -lx264 -lswresample -lm -latomic -lavutil -pthread -lm -latomic */ import "C" // # cgo amd64 LDFLAGS: -O2 -g -static -L/usr/local/lib -L/usr/local/lib/opencv4/3rdparty -lopencv_gapi -lopencv_stitching -lopencv_aruco -lopencv_bgsegm -lopencv_bioinspired -lopencv_ccalib -lopencv_dnn_objdetect -lopencv_dnn_superres -lopencv_dpm -lopencv_face -lopencv_freetype -lopencv_fuzzy -lopencv_hfs -lopencv_img_hash -lopencv_intensity_transform -lopencv_line_descriptor -lopencv_mcc -lopencv_quality -lopencv_rapid -lopencv_reg -lopencv_rgbd -lopencv_saliency -lopencv_signal -lopencv_stereo -lopencv_structured_light -lopencv_phase_unwrapping -lopencv_superres -lopencv_optflow -lopencv_surface_matching -lopencv_tracking -lopencv_highgui -lopencv_datasets -lopencv_text -lopencv_plot -lopencv_videostab -lopencv_videoio -lopencv_wechat_qrcode -lopencv_xfeatures2d -lopencv_shape -lopencv_ml -lopencv_ximgproc -lopencv_video -lopencv_xobjdetect -lopencv_objdetect -lopencv_calib3d -lopencv_imgcodecs -lopencv_features2d -lopencv_dnn -lopencv_flann -lopencv_xphoto -lopencv_photo -lopencv_imgproc -lopencv_core -llibprotobuf -lade -ltbb -littnotify -llibjpeg-turbo -llibwebp -llibtiff -llibopenjp2 -lIlmImf -lquirc -lippiw -lippicv -lpng -lz -lgcc -lstdc++ -lfreetype -lharfbuzz -ldl -lm -lpthread -lrt -lavdevice -lm -latomic -lavfilter -pthread -lm -latomic -lswscale -lm -latomic -lpostproc -lm -latomic -lavformat -lm -latomic -lz -lavcodec -lvpx -lm -lvpx -lm -lvpx -lm -lvpx -lm -pthread -lm -latomic -lz -lx264 -lx265 -lswresample -lm -latomic -lavutil -pthread -lm -latomic -lnuma // # cgo arm64 LDFLAGS: -O2 -g -static -L/usr/local/lib -L/usr/local/lib/opencv4/3rdparty -lopencv_gapi -lopencv_stitching -lopencv_aruco -lopencv_bgsegm -lopencv_bioinspired -lopencv_ccalib -lopencv_dnn_objdetect -lopencv_dnn_superres -lopencv_dpm -lopencv_face -lopencv_freetype -lopencv_fuzzy -lopencv_hfs -lopencv_img_hash -lopencv_intensity_transform -lopencv_line_descriptor -lopencv_mcc -lopencv_quality -lopencv_rapid -lopencv_reg -lopencv_rgbd -lopencv_saliency -lopencv_signal -lopencv_stereo -lopencv_structured_light -lopencv_phase_unwrapping -lopencv_superres -lopencv_optflow -lopencv_surface_matching -lopencv_tracking -lopencv_highgui -lopencv_datasets -lopencv_text -lopencv_plot -lopencv_videostab -lopencv_videoio -lopencv_wechat_qrcode -lopencv_xfeatures2d -lopencv_shape -lopencv_ml -lopencv_ximgproc -lopencv_video -lopencv_xobjdetect -lopencv_objdetect -lopencv_calib3d -lopencv_imgcodecs -lopencv_features2d -lopencv_dnn -lopencv_flann -lopencv_xphoto -lopencv_photo -lopencv_imgproc -lopencv_core -llibprotobuf -lade -ltbb -littnotify -llibjpeg-turbo -llibwebp -llibtiff -llibopenjp2 -lIlmImf -lquirc -ltegra_hal -lpng -lz -lfreetype -lgcc -lstdc++ -lharfbuzz -ldl -lm -lpthread -lrt -lavdevice -lm -latomic -lavfilter -pthread -lm -latomic -lswscale -lm -latomic -lpostproc -lm -latomic -lavformat -lm -latomic -lz -lavcodec -lvpx -lm -lvpx -lm -lvpx -lm -lvpx -lm -pthread -lm -latomic -lz -lx264 -lx265 -lswresample -lm -latomic -lavutil -pthread -lm -latomic -lnuma ================================================ FILE: cgo_static_darwin.go ================================================ //go:build !customenv && opencvstatic && darwin package gocv // Changes here should be mirrored in contrib/cgo_static_darwin.go and cuda/cgo_static_darwin.go. /* #cgo CXXFLAGS: --std=c++11 -DNDEBUG #cgo pkg-config: --static opencv4 */ import "C" ================================================ FILE: cgo_static_windows.go ================================================ //go:build !customenv && opencvstatic && windows package gocv // Changes here should be mirrored in contrib/cgo_static_windows.go and cuda/cgo_static_windows.go. /* #cgo CXXFLAGS: --std=c++11 -DNDEBUG #cgo CPPFLAGS: -IC:/opencv/build/install/include #cgo LDFLAGS: -LC:/opencv/build/install/x64/mingw/staticlib -lopencv_stereo4130 -lopencv_tracking4130 -lopencv_superres4130 -lopencv_stitching4130 -lopencv_optflow4130 -lopencv_gapi4130 -lopencv_face4130 -lopencv_dpm4130 -lopencv_dnn_objdetect4130 -lopencv_ccalib4130 -lopencv_bioinspired4130 -lopencv_bgsegm4130 -lopencv_aruco4130 -lopencv_xobjdetect4130 -lopencv_ximgproc4130 -lopencv_xfeatures2d4130 -lopencv_videostab4130 -lopencv_video4130 -lopencv_structured_light4130 -lopencv_shape4130 -lopencv_rgbd4130 -lopencv_rapid4130 -lopencv_objdetect4130 -lopencv_mcc4130 -lopencv_highgui4130 -lopencv_datasets4130 -lopencv_calib3d4130 -lopencv_videoio4130 -lopencv_text4130 -lopencv_line_descriptor4130 -lopencv_imgcodecs4130 -lopencv_img_hash4130 -lopencv_hfs4130 -lopencv_fuzzy4130 -lopencv_features2d4130 -lopencv_dnn_superres4130 -lopencv_dnn4130 -lopencv_xphoto4130 -lopencv_wechat_qrcode4130 -lopencv_surface_matching4130 -lopencv_reg4130 -lopencv_quality4130 -lopencv_plot4130 -lopencv_photo4130 -lopencv_phase_unwrapping4130 -lopencv_ml4130 -lopencv_intensity_transform4130 -lopencv_imgproc4130 -lopencv_flann4130 -lopencv_core4130 -lade -lquirc -llibprotobuf -lIlmImf -llibpng -llibopenjp2 -llibwebp -llibtiff -llibjpeg-turbo -lzlib -lkernel32 -lgdi32 -lwinspool -lshell32 -lole32 -loleaut32 -luuid -lcomdlg32 -ladvapi32 -luser32 */ import "C" ================================================ FILE: cmd/README.md ================================================ # GoCV Commands GoCV comes with various useful command line utilities, that are also examples of how to use the package. ## ASCIIcam Capture video from a connected webcam, and display it in the current terminal window in ASCII format. https://github.com/hybridgroup/gocv/blob/release/cmd/asciicam/main.go ## Basic Drawing Demonstrates the basic drawing primitives available for drawing on images. https://github.com/hybridgroup/gocv/blob/release/cmd/basic-drawing/main.go ## Caffe Classifier Capture video from a connected webcam, then use the Caffe deep learning framework to classify whatever is in front of the camera. https://github.com/hybridgroup/gocv/blob/release/cmd/caffe-classifier/main.go ## Capture test Tests to verify you can capture video from a connected webcam. https://github.com/hybridgroup/gocv/blob/release/cmd/captest/main.go ## Capture window Capture video from a connected webcam and display the video in a Window. https://github.com/hybridgroup/gocv/blob/release/cmd/capwindow/main.go ## Counter Capture video from a pre-recorded file, and then count the number of detected objects that cross a user-definable vertical or horizontal line. https://github.com/hybridgroup/gocv/blob/release/cmd/counter/main.go ## DNN Detection Use a Deep Neural Network to detect and track objects or faces. https://github.com/hybridgroup/gocv/blob/release/cmd/dnn-detection/main.go ## DNN Pose Detection Use a Deep Neural Network trained using OpenPose to detect and track human body poses. https://github.com/hybridgroup/gocv/blob/release/cmd/dnn-pose-detection/main.go ## DNN Style Transfer Use a Deep Neural Network to perform real-time style transfer. https://github.com/hybridgroup/gocv/blob/release/cmd/dnn-style-transfer/main.go ## Faceblur Captures video from a connected camera, then uses the CascadeClassifier to detect faces, blurs them using a Gaussian blur, then displays the blurred video in a window. https://github.com/hybridgroup/gocv/blob/release/cmd/faceblur/main.go ## Facedetect Captures video from a connected camera, then uses the CascadeClassifier to detect faces, and draw a rectangle around each of them, before displaying them within a Window. https://github.com/hybridgroup/gocv/blob/release/cmd/facedetect/main.go ## Facedetect from URL Using a single image downloaded from a URL, it then uses the CascadeClassifier to detect faces, and draw a rectangle around each of them, before displaying them within a Window. https://github.com/hybridgroup/gocv/blob/release/cmd/facedetect-from-url/main.go ## Feature Matching Match features in an image using the SIFT algorithm. https://github.com/hybridgroup/gocv/blob/release/cmd/feature-matching/main.go ## Find Chessboard Find chessboard in an image using FindChessboardCorners. https://github.com/hybridgroup/gocv/blob/release/cmd/find-chessboard/main.go ## Find Circles Find circles in an image using the Hough transform. https://github.com/hybridgroup/gocv/blob/release/cmd/find-circles/main.go ## Find Lines Find lines in an image using the Hough transform. https://github.com/hybridgroup/gocv/blob/release/cmd/find-lines/main.go ## Hand Gestures Count the number of fingers being held up in front of the camera by looking for convexity defects. https://github.com/hybridgroup/gocv/blob/release/cmd/hand-gestures/main.go ## Hello The "hello world" of computer vision. https://github.com/hybridgroup/gocv/blob/release/cmd/hello/main.go ## Image Similarity Compute and compare perceptual hashes for a pair of images, with a variety of algorithms. https://github.com/hybridgroup/gocv/blob/release/cmd/img-similarity/main.go ## MJPEG Streamer Opens a video capture device, then streams MJPEG from it that you can view in any browser. https://github.com/hybridgroup/gocv/blob/release/cmd/mjpeg-streamer/main.go ## Motion Detection Opens a video capture device, then processes it looking for motion, human or otherwise. https://github.com/hybridgroup/gocv/blob/release/cmd/motion-detect/main.go ## Save Image Capture a single frame from a connected webcam, then save it to an image file on disk. https://github.com/hybridgroup/gocv/blob/release/cmd/saveimage/main.go ## Save Video Capture video from a connected camera, and save 100 frames worth to a video file on disk. https://github.com/hybridgroup/gocv/blob/release/cmd/savevideo/main.go ## Show Image Open an image file from disk, then display it in a window. https://github.com/hybridgroup/gocv/blob/release/cmd/showimage/main.go ## SSD Face Detection Advanced Deep Neural Network example that uses SSD classifier to detect faces from a connected camera. https://github.com/hybridgroup/gocv/blob/release/cmd/ssd-facedetect/main.go ## Tensorflow Classifier Capture video from a connected webcam, then use the Tensorflow machine learning framework to classify whatever is in front of the camera. https://github.com/hybridgroup/gocv/blob/release/cmd/tf-classifier/main.go ## Tracking Example of using Tracker from OpenCV Contrib to track any region of interest selected by the user using the TrackerMOSSE algorithm using the connected camera. https://github.com/hybridgroup/gocv/blob/release/cmd/tracking/main.go ## Version Displays the current version of OpenCV that is being used by GoCV. https://github.com/hybridgroup/gocv/blob/release/cmd/version/main.go ## XPhoto This example demonstrates a couple different uses of the XPhoto module. It can use the GrayworldWB class with BalanceWhite image to save an image file on disk. It can also use the Inpaint functions with inpaint algorithms type to save an image file on disk. https://github.com/hybridgroup/gocv/blob/release/cmd/xphoto/main.go ## YOLO DNN Detection Use the YOLOv8 Deep Neural Network to detect and track objects or faces. https://github.com/hybridgroup/gocv/blob/release/cmd/yolo-detection/main.go ================================================ FILE: cmd/asciicam/main.go ================================================ // What it does: // // This example uses the VideoCapture class to capture video // then displays the ASCII representation of the video frames. // // How to run: // // go run ./cmd/asciicam/main.go // package main import ( "fmt" "os" "github.com/subeshb1/wasm-go-image-to-ascii/convert" "gocv.io/x/gocv" ) const ( // FixedWidth is the fixed width of the ASCII image FixedWidth = 80 // FixedHeight is the fixed height of the ASCII image FixedHeight = 40 ) var buf gocv.Mat func main() { if len(os.Args) < 2 { fmt.Println("How to run:\n\tcaptest [camera ID]") return } // parse args deviceID := os.Args[1] webcam, err := gocv.OpenVideoCapture(deviceID) if err != nil { fmt.Printf("Error opening video capture device: %v\n", deviceID) return } defer webcam.Close() // streaming, capture from webcam buf = gocv.NewMat() defer buf.Close() asciiConverter := convert.NewImageConverter() opts := &convert.Options{FixedWidth: FixedWidth, FixedHeight: FixedHeight, Colored: true} fmt.Printf("Start reading device: %v\n", deviceID) for { if ok := webcam.Read(&buf); !ok { fmt.Printf("Device error: %v\n", deviceID) continue } if buf.Empty() { continue } img, err := buf.ToImage() if err != nil { fmt.Printf("Error converting mat to image: %v\n", err) continue } // clear screen fmt.Print("\033[H\033[2J") // print the ASCII representation of the frame fmt.Println(asciiConverter.Image2ASCIIString(img, opts)) } } ================================================ FILE: cmd/basic-drawing/main.go ================================================ // What it does: // // This example draws two examples, an atom and a rook, based on: // https://docs.opencv.org/2.4/doc/tutorials/core/basic_geometric_drawing/basic_geometric_drawing.html. // // How to run: // // go run ./cmd/basic-drawing/main.go // package main import ( "image" "image/color" "gocv.io/x/gocv" ) var w = 400 func main() { windowA := gocv.NewWindow("basic drawing: atom") windowR := gocv.NewWindow("basic drawing: rook") defer windowA.Close() defer windowR.Close() atom := gocv.NewMatWithSize(w, w, gocv.MatTypeCV8UC3) defer atom.Close() rook := gocv.NewMatWithSize(w, w, gocv.MatTypeCV8UC3) defer rook.Close() black := color.RGBA{0, 0, 0, 0} blue := color.RGBA{0, 0, 255, 0} red := color.RGBA{255, 0, 0, 0} white := color.RGBA{255, 255, 255, 0} yellow := color.RGBA{255, 255, 0, 0} // draw the atom gocv.Ellipse(&atom, image.Pt(w/2., w/2.), image.Pt(w/4.0, w/16.0), 90., 0, 360, blue, 2) gocv.Ellipse(&atom, image.Pt(w/2., w/2.), image.Pt(w/4.0, w/16.0), 0., 0, 360, blue, 2) gocv.Ellipse(&atom, image.Pt(w/2., w/2.), image.Pt(w/4.0, w/16.0), 45., 0, 360, blue, 2) gocv.Ellipse(&atom, image.Pt(w/2., w/2.), image.Pt(w/4.0, w/16.0), -45., 0, 360, blue, 2) gocv.Circle(&atom, image.Pt(w/2., w/2.), w/32., red, -1) // draw the rook points := [][]image.Point{ { image.Pt(w/4., 7*w/8.), image.Pt(3*w/4., 7*w/8.), image.Pt(3*w/4., 13*w/16.), image.Pt(11*w/16., 13*w/16.), image.Pt(19*w/32., 3*w/8.), image.Pt(3*w/4., 3*w/8.), image.Pt(3*w/4., w/8.), image.Pt(26*w/40., w/8.), image.Pt(26*w/40., w/4.), image.Pt(22*w/40., w/4.), image.Pt(22*w/40., w/8.), image.Pt(18*w/40., w/8.), image.Pt(18*w/40., w/4.), image.Pt(14*w/40., w/4.), image.Pt(14*w/40., w/8.), image.Pt(w/4., w/8.), image.Pt(w/4., 3*w/8.), image.Pt(13*w/32., 3*w/8.), image.Pt(5*w/16., 13*w/16.), image.Pt(w/4., 13*w/16.), }, } pv := gocv.NewPointsVectorFromPoints(points) defer pv.Close() gocv.FillPoly(&rook, pv, white) gocv.Rectangle(&rook, image.Rect(0, 7*w/8.0, w, w), yellow, -1) gocv.Line(&rook, image.Pt(0, 15*w/16), image.Pt(w, 15*w/16), black, 2) gocv.Line(&rook, image.Pt(w/4, 7*w/8), image.Pt(w/4, w), black, 2) gocv.Line(&rook, image.Pt(w/2, 7*w/8), image.Pt(w/2, w), black, 2) gocv.Line(&rook, image.Pt(3*w/4, 7*w/8), image.Pt(3*w/4, w), black, 2) for { windowA.IMShow(atom) windowR.IMShow(rook) if windowA.WaitKey(10) >= 0 || windowR.WaitKey(10) >= 0 { break } } } ================================================ FILE: cmd/caffe-classifier/main.go ================================================ // What it does: // // This example uses the Caffe (http://caffe.berkeleyvision.org/) deep learning framework // to classify whatever is in front of the camera. // // Download the Caffe model file from: // http://dl.caffe.berkeleyvision.org/bvlc_googlenet.caffemodel // // Also, you will need the prototxt file: // https://raw.githubusercontent.com/opencv/opencv_extra/master/testdata/dnn/bvlc_googlenet.prototxt // // And the words text file with the descriptions: // https://raw.githubusercontent.com/opencv/opencv/master/samples/data/dnn/classification_classes_ILSVRC2012.txt // // How to run: // // go run ./cmd/caffe-classifier/main.go 0 ~/Downloads/bvlc_googlenet.caffemodel ~/Downloads/bvlc_googlenet.prototxt ~/Downloads/classification_classes_ILSVRC2012.txt // // You can also use this sample with the Intel OpenVINO Inference Engine, if you have it installed. // // go run ./cmd/caffe-classifier/main.go 0 ~/Downloads/bvlc_googlenet.caffemodel ~/Downloads/bvlc_googlenet.prototxt ~/Downloads/classification_classes_ILSVRC2012.txt openvino fp16 // package main import ( "bufio" "fmt" "image" "image/color" "os" "path/filepath" "gocv.io/x/gocv" ) func main() { if len(os.Args) < 5 { fmt.Println("How to run:\ncaffe-classifier [camera ID] [modelfile] [configfile] [descriptionsfile] ([backend] [device])") return } // parse args deviceID := os.Args[1] model := os.Args[2] config := os.Args[3] descr := os.Args[4] descriptions, err := readDescriptions(descr) if err != nil { fmt.Printf("Error reading descriptions file: %v\n", descr) return } backend := gocv.NetBackendDefault if len(os.Args) > 5 { backend = gocv.ParseNetBackend(os.Args[5]) } target := gocv.NetTargetCPU if len(os.Args) > 6 { target = gocv.ParseNetTarget(os.Args[6]) } // open capture device webcam, err := gocv.OpenVideoCapture(deviceID) if err != nil { fmt.Printf("Error opening video capture device: %v\n", deviceID) return } defer webcam.Close() window := gocv.NewWindow("Caffe Classifier") defer window.Close() img := gocv.NewMat() defer img.Close() // open DNN classifier net := gocv.ReadNet(model, config) if net.Empty() { fmt.Printf("Error reading network model from : %v %v\n", model, config) return } defer net.Close() net.SetPreferableBackend(gocv.NetBackendType(backend)) net.SetPreferableTarget(gocv.NetTargetType(target)) status := "Ready" statusColor := color.RGBA{0, 255, 0, 0} fmt.Printf("Start reading device: %v\n", deviceID) for { if ok := webcam.Read(&img); !ok { fmt.Printf("Device closed: %v\n", deviceID) return } if img.Empty() { continue } // convert image Mat to 224x224 blob that the classifier can analyze blob := gocv.BlobFromImage(img, 1.0, image.Pt(224, 224), gocv.NewScalar(104, 117, 123, 0), false, false) // feed the blob into the classifier net.SetInput(blob, "") // run a forward pass thru the network prob := net.Forward("") // reshape the results into a 1x1000 matrix probMat := prob.Reshape(1, 1) // determine the most probable classification _, maxVal, _, maxLoc := gocv.MinMaxLoc(probMat) // display classification status = fmt.Sprintf("description: %v, maxVal: %v\n", descriptions[maxLoc.X], maxVal) gocv.PutText(&img, status, image.Pt(10, 20), gocv.FontHersheyPlain, 1.2, statusColor, 2) blob.Close() prob.Close() probMat.Close() window.IMShow(img) if window.WaitKey(1) >= 0 { break } } } // readDescriptions reads the descriptions from a file // and returns a slice of its lines. func readDescriptions(path string) ([]string, error) { file, err := os.Open(filepath.Clean(path)) if err != nil { return nil, err } defer func() { _ = file.Close() }() var lines []string scanner := bufio.NewScanner(file) for scanner.Scan() { lines = append(lines, scanner.Text()) } return lines, scanner.Err() } ================================================ FILE: cmd/captest/main.go ================================================ // What it does: // // This example uses the VideoCapture class to test if you can capture video // from a connected webcam, by trying to read 100 frames. // // How to run: // // go run ./cmd/captest/main.go // package main import ( "fmt" "os" "gocv.io/x/gocv" ) func main() { if len(os.Args) < 2 { fmt.Println("How to run:\n\tcaptest [camera ID]") return } // parse args deviceID := os.Args[1] webcam, err := gocv.OpenVideoCapture(deviceID) if err != nil { fmt.Printf("Error opening video capture device: %v\n", deviceID) return } defer webcam.Close() // streaming, capture from webcam buf := gocv.NewMat() defer buf.Close() fmt.Printf("Start reading device: %v\n", deviceID) for i := 0; i < 100; i++ { if ok := webcam.Read(&buf); !ok { fmt.Printf("Device closed: %v\n", deviceID) return } if buf.Empty() { continue } fmt.Printf("Read frame %d\n", i+1) } fmt.Println("Done.") } ================================================ FILE: cmd/capwindow/main.go ================================================ // What it does: // // This example uses the VideoCapture class to capture frames from a connected webcam, // and displays the video in a Window class. // // How to run: // // go run ./cmd/capwindow/main.go // package main import ( "fmt" "os" "gocv.io/x/gocv" ) func main() { if len(os.Args) < 2 { fmt.Println("How to run:\n\tcapwindow [camera ID]") return } // parse args deviceID := os.Args[1] webcam, err := gocv.OpenVideoCapture(deviceID) if err != nil { fmt.Printf("Error opening video capture device: %v\n", deviceID) return } defer webcam.Close() window := gocv.NewWindow("Capture Window") defer window.Close() img := gocv.NewMat() defer img.Close() fmt.Printf("Start reading device: %v\n", deviceID) for { if ok := webcam.Read(&img); !ok { fmt.Printf("Device closed: %v\n", deviceID) return } if img.Empty() { continue } window.IMShow(img) if window.WaitKey(1) == 27 { break } } } ================================================ FILE: cmd/counter/main.go ================================================ // What it does: // // This example tracks objects such as cars or people passing across // a horizontal or vertical line by using the Moments method. // The Moments algorithm is not that accurate for counting multiple objects, // however it is execution efficient. // // How to run: // // go run ./counter/main.go /path/to/video.avi 400 y 10 // package main import ( "fmt" "image" "image/color" "os" "strconv" "gocv.io/x/gocv" ) func main() { if len(os.Args) < 2 { fmt.Println("How to run:\n\tcounter [filename] [line] [axis (x/y)] [width]") return } // parse args file := os.Args[1] line, _ := strconv.Atoi(os.Args[2]) axis := os.Args[3] width, _ := strconv.Atoi(os.Args[4]) video, err := gocv.VideoCaptureFile(file) if err != nil { fmt.Printf("Error opening video capture file: %s\n", file) return } defer video.Close() window := gocv.NewWindow("Track Window") defer window.Close() img := gocv.NewMat() defer img.Close() imgFG := gocv.NewMat() defer imgFG.Close() imgCleaned := gocv.NewMat() defer imgCleaned.Close() mog2 := gocv.NewBackgroundSubtractorMOG2() defer mog2.Close() count := 0 for { if ok := video.Read(&img); !ok { fmt.Printf("Device closed: %v\n", file) return } if img.Empty() { continue } // clean frame by removing background & eroding to eliminate artifacts mog2.Apply(img, &imgFG) kernel := gocv.GetStructuringElement(gocv.MorphRect, image.Pt(3, 3)) gocv.Erode(imgFG, &imgCleaned, kernel) kernel.Close() // calculate the image moment based on the cleaned frame moments := gocv.Moments(imgCleaned, true) area := moments["m00"] if area >= 1 { x := int(moments["m10"] / area) y := int(moments["m01"] / area) if axis == "y" { if x > 0 && x < img.Cols() && y > line && y < line+width { count++ } gocv.Line(&img, image.Pt(0, line), image.Pt(img.Cols(), line), color.RGBA{255, 0, 0, 0}, 2) } if axis == "x" { if y > 0 && y < img.Rows() && x > line && x < line+width { count++ } gocv.Line(&img, image.Pt(line, 0), image.Pt(line, img.Rows()), color.RGBA{255, 0, 0, 0}, 2) } } gocv.PutText(&img, fmt.Sprintf("Count: %d", count), image.Pt(10, 20), gocv.FontHersheyPlain, 1.2, color.RGBA{0, 255, 0, 0}, 2) window.IMShow(img) if window.WaitKey(1) >= 0 { break } } } ================================================ FILE: cmd/cuda/main.go ================================================ // What it does: // // This program outputs the current OpenCV library version and CUDA version the console. // // How to run: // // go run --tags cuda ./cmd/cuda/main.go // // +build cuda package main import ( "fmt" "gocv.io/x/gocv" "gocv.io/x/gocv/cuda" ) func main() { fmt.Printf("gocv version: %s\n", gocv.Version()) fmt.Println("cuda information:") devices := cuda.GetCudaEnabledDeviceCount() for i := 0; i < devices; i++ { fmt.Print(" ") cuda.PrintShortCudaDeviceInfo(i) } } ================================================ FILE: cmd/dnn-detection/main.go ================================================ // What it does: // // This example uses a deep neural network to perform object detection. // It can be used with either the Caffe face tracking or Tensorflow object detection models that are // included with OpenCV 3.4 // // To perform face tracking with the Caffe model: // // Download the model file from: // https://github.com/opencv/opencv_3rdparty/raw/dnn_samples_face_detector_20170830/res10_300x300_ssd_iter_140000.caffemodel // // You will also need the prototxt config file: // https://raw.githubusercontent.com/opencv/opencv/master/samples/dnn/face_detector/deploy.prototxt // // To perform object tracking with the Tensorflow model: // // Download and extract the model file named "frozen_inference_graph.pb" from: // http://download.tensorflow.org/models/object_detection/ssd_mobilenet_v1_coco_2017_11_17.tar.gz // // You will also need the pbtxt config file: // https://gist.githubusercontent.com/dkurt/45118a9c57c38677b65d6953ae62924a/raw/b0edd9e8c992c25fe1c804e77b06d20a89064871/ssd_mobilenet_v1_coco_2017_11_17.pbtxt // // How to run: // // go run ./cmd/dnn-detection/main.go [videosource] [modelfile] [configfile] ([backend] [device]) // package main import ( "fmt" "image" "image/color" "os" "path/filepath" "gocv.io/x/gocv" ) func main() { if len(os.Args) < 4 { fmt.Println("How to run:\ndnn-detection [videosource] [modelfile] [configfile] ([backend] [device])") return } // parse args deviceID := os.Args[1] model := os.Args[2] config := os.Args[3] backend := gocv.NetBackendDefault if len(os.Args) > 4 { backend = gocv.ParseNetBackend(os.Args[4]) } target := gocv.NetTargetCPU if len(os.Args) > 5 { target = gocv.ParseNetTarget(os.Args[5]) } // open capture device webcam, err := gocv.OpenVideoCapture(deviceID) if err != nil { fmt.Printf("Error opening video capture device: %v\n", deviceID) return } defer webcam.Close() window := gocv.NewWindow("DNN Detection") defer window.Close() img := gocv.NewMat() defer img.Close() // open DNN object tracking model net := gocv.ReadNet(model, config) if net.Empty() { fmt.Printf("Error reading network model from : %v %v\n", model, config) return } defer net.Close() net.SetPreferableBackend(gocv.NetBackendType(backend)) net.SetPreferableTarget(gocv.NetTargetType(target)) var ratio float64 var mean gocv.Scalar var swapRGB bool if filepath.Ext(model) == ".caffemodel" { ratio = 1.0 mean = gocv.NewScalar(104, 177, 123, 0) swapRGB = false } else { ratio = 1.0 / 127.5 mean = gocv.NewScalar(127.5, 127.5, 127.5, 0) swapRGB = true } fmt.Printf("Start reading device: %v\n", deviceID) for { if ok := webcam.Read(&img); !ok { fmt.Printf("Device closed: %v\n", deviceID) return } if img.Empty() { continue } // convert image Mat to 300x300 blob that the object detector can analyze blob := gocv.BlobFromImage(img, ratio, image.Pt(300, 300), mean, swapRGB, false) // feed the blob into the detector net.SetInput(blob, "") // run a forward pass thru the network prob := net.Forward("") performDetection(&img, prob) prob.Close() blob.Close() window.IMShow(img) if window.WaitKey(1) >= 0 { break } } } // performDetection analyzes the results from the detector network, // which produces an output blob with a shape 1x1xNx7 // where N is the number of detections, and each detection // is a vector of float values // [batchId, classId, confidence, left, top, right, bottom] func performDetection(frame *gocv.Mat, results gocv.Mat) { for i := 0; i < results.Total(); i += 7 { confidence := results.GetFloatAt(0, i+2) if confidence > 0.5 { left := int(results.GetFloatAt(0, i+3) * float32(frame.Cols())) top := int(results.GetFloatAt(0, i+4) * float32(frame.Rows())) right := int(results.GetFloatAt(0, i+5) * float32(frame.Cols())) bottom := int(results.GetFloatAt(0, i+6) * float32(frame.Rows())) gocv.Rectangle(frame, image.Rect(left, top, right, bottom), color.RGBA{0, 255, 0, 0}, 2) } } } ================================================ FILE: cmd/dnn-pose-detection/main.go ================================================ // What it does: // // This example shows how to perform pose detection using models from OpenPose, an open source // human body, hand, and facial keypoint detector. // // For more information about OpenPose, please go to: // https://github.com/CMU-Perceptual-Computing-Lab/openpose // // Before using running this example, you'll need to download a pretrained Caffe model, // and the respective prototxt config file. // // http://posefs1.perception.cs.cmu.edu/OpenPose/models/pose/coco/pose_iter_440000.caffemodel // https://raw.githubusercontent.com/opencv/opencv_extra/master/testdata/dnn/openpose_pose_coco.prototxt // // You can also try the hand pose model: // http://posefs1.perception.cs.cmu.edu/OpenPose/models/hand/pose_iter_102000.caffemodel // https://raw.githubusercontent.com/CMU-Perceptual-Computing-Lab/openpose/master/models/hand/pose_deploy.prototxt // // // How to run: // // go run ./cmd/dnn-pose-detection/main.go 0 ~/Downloads/pose_iter_440000.caffemodel ~/Downloads/openpose_pose_coco.prototxt openvino fp16 // package main import ( "fmt" "image" "image/color" "os" "gocv.io/x/gocv" ) var net *gocv.Net var images chan *gocv.Mat var poses chan [][]image.Point var pose [][]image.Point func main() { if len(os.Args) < 4 { fmt.Println("How to run:\ndnn-pose-detection [videosource] [modelfile] [configfile] ([backend] [device])") return } // parse args deviceID := os.Args[1] model := os.Args[2] proto := os.Args[3] backend := gocv.NetBackendDefault if len(os.Args) > 4 { backend = gocv.ParseNetBackend(os.Args[4]) } target := gocv.NetTargetCPU if len(os.Args) > 5 { target = gocv.ParseNetTarget(os.Args[5]) } // open capture device webcam, err := gocv.OpenVideoCapture(deviceID) if err != nil { fmt.Printf("Error opening video capture device: %v\n", deviceID) return } defer webcam.Close() window := gocv.NewWindow("DNN Pose Detection") defer window.Close() img := gocv.NewMat() defer img.Close() // open OpenPose model n := gocv.ReadNet(model, proto) net = &n if net.Empty() { fmt.Printf("Error reading network model from : %v %v\n", model, proto) return } defer net.Close() net.SetPreferableBackend(gocv.NetBackendType(backend)) net.SetPreferableTarget(gocv.NetTargetType(target)) fmt.Printf("Start reading device: %v\n", deviceID) images = make(chan *gocv.Mat, 1) poses = make(chan [][]image.Point) if ok := webcam.Read(&img); !ok { fmt.Printf("Error cannot read device %v\n", deviceID) return } processFrame(&img) go performDetection() for { if ok := webcam.Read(&img); !ok { fmt.Printf("Device closed: %v\n", deviceID) return } if img.Empty() { continue } select { case pose = <-poses: // we've received the next pose from channel, so send next image frame for detection processFrame(&img) default: // show current frame without blocking, so do nothing here } drawPose(&img) window.IMShow(img) if window.WaitKey(1) >= 0 { break } } } func processFrame(i *gocv.Mat) { frame := gocv.NewMat() i.CopyTo(&frame) images <- &frame } // performDetection analyzes the results from the detector network. // the result is an array of "heatmaps" which are the probability // of a body part being in location x,y func performDetection() { for { // get next frame from channel frame := <-images // convert image Mat to 368x368 blob that the pose detector can analyze blob := gocv.BlobFromImage(*frame, 1.0/255.0, image.Pt(368, 368), gocv.NewScalar(0, 0, 0, 0), false, false) // feed the blob into the detector net.SetInput(blob, "") // run a forward pass thru the network prob := net.Forward("") var midx int s := prob.Size() nparts, h, w := s[1], s[2], s[3] // find out, which model we have switch nparts { case 19: // COCO body midx = 0 nparts = 18 // skip background case 16: // MPI body midx = 1 nparts = 15 // skip background case 22: // hand midx = 2 default: fmt.Println("there should be 19 parts for the COCO model, 16 for MPI, or 22 for the hand model") return } // find the most likely match for each part pts := make([]image.Point, 22) for i := 0; i < nparts; i++ { pts[i] = image.Pt(-1, -1) heatmap, _ := prob.FromPtr(h, w, gocv.MatTypeCV32F, 0, i) _, maxVal, _, maxLoc := gocv.MinMaxLoc(heatmap) if maxVal > 0.1 { pts[i] = maxLoc } heatmap.Close() } // determine scale factor sX := int(float32(frame.Cols()) / float32(w)) sY := int(float32(frame.Rows()) / float32(h)) // create the results array of pairs of points with the lines that best fit // each body part, e.g. // [[point A for body part 1, point B for body part 1], // [point A for body part 2, point B for body part 2], ...] results := [][]image.Point{} for _, p := range PosePairs[midx] { a := pts[p[0]] b := pts[p[1]] // high enough confidence in this pose? if a.X <= 0 || a.Y <= 0 || b.X <= 0 || b.Y <= 0 { continue } // scale to image size a.X *= sX a.Y *= sY b.X *= sX b.Y *= sY results = append(results, []image.Point{a, b}) } prob.Close() blob.Close() frame.Close() // send pose results in channel poses <- results } } func drawPose(frame *gocv.Mat) { for _, pts := range pose { gocv.Line(frame, pts[0], pts[1], color.RGBA{0, 255, 0, 0}, 2) gocv.Circle(frame, pts[0], 3, color.RGBA{0, 0, 200, 0}, -1) gocv.Circle(frame, pts[1], 3, color.RGBA{0, 0, 200, 0}, -1) } } // PosePairs is a table of the body part connections in the format [model_id][pair_id][from/to] // For details please see: // https://github.com/CMU-Perceptual-Computing-Lab/openpose/blob/master/doc/output.md var PosePairs = [3][20][2]int{ { // COCO body {1, 2}, {1, 5}, {2, 3}, {3, 4}, {5, 6}, {6, 7}, {1, 8}, {8, 9}, {9, 10}, {1, 11}, {11, 12}, {12, 13}, {1, 0}, {0, 14}, {14, 16}, {0, 15}, {15, 17}, }, { // MPI body {0, 1}, {1, 2}, {2, 3}, {3, 4}, {1, 5}, {5, 6}, {6, 7}, {1, 14}, {14, 8}, {8, 9}, {9, 10}, {14, 11}, {11, 12}, {12, 13}, }, { // hand {0, 1}, {1, 2}, {2, 3}, {3, 4}, // thumb {0, 5}, {5, 6}, {6, 7}, {7, 8}, // pinkie {0, 9}, {9, 10}, {10, 11}, {11, 12}, // middle {0, 13}, {13, 14}, {14, 15}, {15, 16}, // ring {0, 17}, {17, 18}, {18, 19}, {19, 20}, // small }} ================================================ FILE: cmd/dnn-style-transfer/main.go ================================================ // What it does: // // This example performs real-time style transfer using a deep neural network. // // For more information about the model used by this example, go to: // https://github.com/jcjohnson/fast-neural-style // // Download the model file from: // http://cs.stanford.edu/people/jcjohns/fast-neural-style/models/eccv16/starry_night.t7 // // How to run: // // go run ./cmd/dnn-style-transfer/main.go 0 ~/Downloads/starry_night.t7 openvino fp16 // package main import ( "fmt" "image" "os" "gocv.io/x/gocv" ) func main() { if len(os.Args) < 3 { fmt.Println("How to run:\ndnn-style-transfer [videosource] [modelfile] ([backend] [device])") return } // parse args deviceID := os.Args[1] model := os.Args[2] backend := gocv.NetBackendDefault if len(os.Args) > 3 { backend = gocv.ParseNetBackend(os.Args[3]) } target := gocv.NetTargetCPU if len(os.Args) > 4 { target = gocv.ParseNetTarget(os.Args[4]) } // open capture device webcam, err := gocv.OpenVideoCapture(deviceID) if err != nil { fmt.Printf("Error opening video capture device: %v\n", deviceID) return } defer webcam.Close() window := gocv.NewWindow("DNN Style Transfer") defer window.Close() img := gocv.NewMat() defer img.Close() // open DNN style transfer model net := gocv.ReadNet(model, "") if net.Empty() { fmt.Printf("Error reading network model from : %v\n", model) return } defer net.Close() net.SetPreferableBackend(gocv.NetBackendType(backend)) net.SetPreferableTarget(gocv.NetTargetType(target)) fmt.Printf("Start reading device: %v\n", deviceID) for { if ok := webcam.Read(&img); !ok { fmt.Printf("Device closed: %v\n", deviceID) return } if img.Empty() { continue } // convert image Mat to 640x480 blob that the style transfer can analyze blob := gocv.BlobFromImage(img, 1.0, image.Pt(640, 480), gocv.NewScalar(103.939, 116.779, 123.68, 0), false, false) // feed the blob into the detector net.SetInput(blob, "") // run a forward pass thru the network probMat := net.Forward("") sz := probMat.Size() dims := sz[2] * sz[3] out := gocv.NewMatWithSize(480, 640, gocv.MatTypeCV8UC3) // take blob and obtain displayable Mat image from it for i := 0; i < dims; i++ { r := probMat.GetFloatAt(0, i) r += 103.939 g := probMat.GetFloatAt(0, i+dims) g += 116.779 b := probMat.GetFloatAt(0, i+dims*2) b += 123.68 out.SetUCharAt(0, i*3, uint8(r)) out.SetUCharAt(0, i*3+1, uint8(g)) out.SetUCharAt(0, i*3+2, uint8(b)) } window.IMShow(out) if window.WaitKey(1) >= 0 { break } probMat.Close() blob.Close() out.Close() } } ================================================ FILE: cmd/faceblur/main.go ================================================ // What it does: // // This example captures video from a connected camera, // then uses the CascadeClassifier to detect faces, blurs them // using a Gaussian blur, then displays the blurred video in a window. // // How to run: // // faceblur [camera ID] [classifier XML file] // // go run ./cmd/faceblur/main.go 0 data/haarcascade_frontalface_default.xml // package main import ( "fmt" "image" "os" "gocv.io/x/gocv" ) func main() { if len(os.Args) < 3 { fmt.Println("How to run:\n\tfaceblur [camera ID] [classifier XML file]") return } // parse args deviceID := os.Args[1] xmlFile := os.Args[2] // open webcam webcam, err := gocv.OpenVideoCapture(deviceID) if err != nil { fmt.Printf("error opening video capture device: %v\n", deviceID) return } defer webcam.Close() // open display window window := gocv.NewWindow("Face Blur") defer window.Close() // prepare image matrix img := gocv.NewMat() defer img.Close() // load classifier to recognize faces classifier := gocv.NewCascadeClassifier() defer classifier.Close() if !classifier.Load(xmlFile) { fmt.Printf("Error reading cascade file: %v\n", xmlFile) return } fmt.Printf("Start reading device: %v\n", deviceID) for { if ok := webcam.Read(&img); !ok { fmt.Printf("Device closed: %v\n", deviceID) return } if img.Empty() { continue } // detect faces rects := classifier.DetectMultiScale(img) fmt.Printf("found %d faces\n", len(rects)) // blur each face on the original image for _, r := range rects { imgFace := img.Region(r) // blur face gocv.GaussianBlur(imgFace, &imgFace, image.Pt(75, 75), 0, 0, gocv.BorderDefault) imgFace.Close() } // show the image in the window, and wait 1 millisecond window.IMShow(img) if window.WaitKey(1) >= 0 { break } } } ================================================ FILE: cmd/facedetect/main.go ================================================ // What it does: // // This example uses the CascadeClassifier class to detect faces, // and draw a rectangle around each of them, before displaying them within a Window. // // How to run: // // facedetect [camera ID] [classifier XML file] // // go run ./cmd/facedetect/main.go 0 data/haarcascade_frontalface_default.xml // package main import ( "fmt" "image" "image/color" "os" "gocv.io/x/gocv" ) func main() { if len(os.Args) < 3 { fmt.Println("How to run:\n\tfacedetect [camera ID] [classifier XML file]") return } // parse args deviceID := os.Args[1] xmlFile := os.Args[2] // open webcam webcam, err := gocv.OpenVideoCapture(deviceID) if err != nil { fmt.Printf("error opening video capture device: %v\n", deviceID) return } defer webcam.Close() // open display window window := gocv.NewWindow("Face Detect") defer window.Close() // prepare image matrix img := gocv.NewMat() defer img.Close() // color for the rect when faces detected blue := color.RGBA{0, 0, 255, 0} // load classifier to recognize faces classifier := gocv.NewCascadeClassifier() defer classifier.Close() if !classifier.Load(xmlFile) { fmt.Printf("Error reading cascade file: %v\n", xmlFile) return } fmt.Printf("Start reading device: %v\n", deviceID) for { if ok := webcam.Read(&img); !ok { fmt.Printf("Device closed: %v\n", deviceID) return } if img.Empty() { continue } // detect faces rects := classifier.DetectMultiScale(img) fmt.Printf("found %d faces\n", len(rects)) // draw a rectangle around each face on the original image, // along with text identifing as "Human" for _, r := range rects { gocv.Rectangle(&img, r, blue, 3) size := gocv.GetTextSize("Human", gocv.FontHersheyPlain, 1.2, 2) pt := image.Pt(r.Min.X+(r.Min.X/2)-(size.X/2), r.Min.Y-2) gocv.PutText(&img, "Human", pt, gocv.FontHersheyPlain, 1.2, blue, 2) } // show the image in the window, and wait 1 millisecond window.IMShow(img) if window.WaitKey(1) >= 0 { break } } } ================================================ FILE: cmd/facedetect-from-url/main.go ================================================ // What it does: // // This example uses the CascadeClassifier class to detect faces from url, // and draw a rectangle around each of them, before displaying them within a Window. // // How to run: // // facedetect-from-url [image URL] [classifier XML file] [image file] // // go run ./cmd/facedetect-from-url/main.go https://raw.githubusercontent.com/hybridgroup/gocv/release/images/face.jpg data/haarcascade_frontalface_default.xml output.jpg // package main import ( "fmt" "image" "image/color" "io/ioutil" "log" "net/http" "os" "gocv.io/x/gocv" ) func main() { if len(os.Args) < 4 { fmt.Println("How to run:\n\tfacedetect-from-url [image URL] [classifier XML file] [image file]") return } // parse args imageURL := os.Args[1] xmlFile := os.Args[2] saveFile := os.Args[3] // color for the rect when faces detected blue := color.RGBA{0, 0, 255, 0} // load classifier to recognize faces classifier := gocv.NewCascadeClassifier() defer classifier.Close() if !classifier.Load(xmlFile) { fmt.Printf("Error reading cascade file: %v\n", xmlFile) return } // get image from URL // #nosec res, err := http.Get(imageURL) if err != nil { log.Fatal(err) } resByte, err := ioutil.ReadAll(res.Body) if err != nil { log.Fatal(err) } img, err := gocv.IMDecode(resByte, 1) if err != nil { log.Fatal(err) } rects := classifier.DetectMultiScale(img) fmt.Printf("found %d faces\n", len(rects)) // draw a rectangle around each face on the original image, // along with text identifing as "Human" for _, r := range rects { gocv.Rectangle(&img, r, blue, 3) size := gocv.GetTextSize("Human", gocv.FontHersheyPlain, 1.2, 2) pt := image.Pt(r.Min.X+(r.Min.X/2)-(size.X/2), r.Min.Y-2) gocv.PutText(&img, "Human", pt, gocv.FontHersheyPlain, 1.2, blue, 2) } gocv.IMWrite(saveFile, img) fmt.Printf("saved to %s\n", saveFile) } ================================================ FILE: cmd/facedetectYN/main.go ================================================ // What it does: // // This example uses the FaceDetectorYN class to detect faces, // and draw a rectangle around each of them, before displaying them within a Window. // // model files download link: // https://github.com/opencv/opencv_zoo/tree/main/models/face_detection_yunet // // How to run: // // facedetectYN [camera ID] [model file] // // go run ./cmd/facedetectYN/main.go 0 face_detection_yunet_2023mar.onnx // package main import ( "fmt" "image" "image/color" "os" "gocv.io/x/gocv" ) func main() { if len(os.Args) < 3 { fmt.Println("How to run:\n\tfacedetectYN [camera ID] [model file]") return } // parse args deviceID := os.Args[1] modelFile := os.Args[2] // open webcam webcam, err := gocv.OpenVideoCapture(deviceID) if err != nil { fmt.Printf("error opening video capture device: %v\n", deviceID) return } defer webcam.Close() // open display window window := gocv.NewWindow("Face Detect YN") defer window.Close() // prepare image matrix img := gocv.NewMat() defer img.Close() // prepare faces matrix faces := gocv.NewMat() defer faces.Close() // colors for the rect faces detected red := color.RGBA{255, 0, 0, 0} green := color.RGBA{0, 255, 0, 0} blue := color.RGBA{0, 0, 255, 0} yellow := color.RGBA{255, 255, 0, 1} pink := color.RGBA{255, 105, 180, 0} detector := gocv.NewFaceDetectorYN(modelFile, "", image.Pt(200, 200)) defer detector.Close() fmt.Printf("Start reading device: %v\n", deviceID) for { if ok := webcam.Read(&img); !ok { fmt.Printf("Device closed: %v\n", deviceID) return } if img.Empty() { continue } sz := img.Size() detector.SetInputSize(image.Pt(sz[1], sz[0])) detector.Detect(img, &faces) if faces.Rows() < 1 { // no faces detected // show the captured frame anyway window.IMShow(img) if window.WaitKeyEx(1) >= 0 { break } continue } for r := 0; r < faces.Rows(); r++ { x0 := int(faces.GetFloatAt(r, 0)) y0 := int(faces.GetFloatAt(r, 1)) x1 := x0 + int(faces.GetFloatAt(r, 2)) y1 := y0 + int(faces.GetFloatAt(r, 3)) faceRect := image.Rect(x0, y0, x1, y1) rightEye := image.Pt( int(faces.GetFloatAt(r, 4)), int(faces.GetFloatAt(r, 5)), ) leftEye := image.Pt( int(faces.GetFloatAt(r, 6)), int(faces.GetFloatAt(r, 7)), ) noseTip := image.Pt( int(faces.GetFloatAt(r, 8)), int(faces.GetFloatAt(r, 9)), ) rightMouthCorner := image.Pt( int(faces.GetFloatAt(r, 10)), int(faces.GetFloatAt(r, 11)), ) leftMouthCorner := image.Pt( int(faces.GetFloatAt(r, 12)), int(faces.GetFloatAt(r, 13)), ) gocv.Rectangle(&img, faceRect, green, 1) gocv.Circle(&img, rightEye, 1, blue, 1) gocv.Circle(&img, leftEye, 1, red, 1) gocv.Circle(&img, noseTip, 1, green, 1) gocv.Circle(&img, rightMouthCorner, 1, pink, 1) gocv.Circle(&img, leftMouthCorner, 1, yellow, 1) } // show the image in the window, and wait 1 millisecond window.IMShow(img) if window.WaitKeyEx(1) >= 0 { break } } } ================================================ FILE: cmd/feature-matching/main.go ================================================ // What it does: // // This example uses Brute-Force Matching // with SIFT Descriptors and Ratio Test // // How to run: // // feature-matching [query image] [training image] // // go run ./cmd/feature-matching/main.go input.jpg training.jpg // package main import ( "fmt" "image/color" "os" "gocv.io/x/gocv" ) func main() { if len(os.Args) != 3 { fmt.Println("Usage: feature-matching /path/to/query /path/to/train") panic("error: no files provided") } // opening query image query := gocv.IMRead(os.Args[1], gocv.IMReadGrayScale) defer query.Close() // opening train image train := gocv.IMRead(os.Args[2], gocv.IMReadGrayScale) defer train.Close() // creating new SIFT sift := gocv.NewSIFT() defer sift.Close() // detecting and computing keypoints using SIFT method queryMask := gocv.NewMat() defer queryMask.Close() kp1, des1 := sift.DetectAndCompute(query, queryMask) defer des1.Close() trainMask := gocv.NewMat() defer trainMask.Close() kp2, des2 := sift.DetectAndCompute(train, trainMask) defer des2.Close() // finding K best matches for each descriptor bf := gocv.NewBFMatcher() matches := bf.KnnMatch(des1, des2, 2) // application of ratio test var good []gocv.DMatch for _, m := range matches { if len(m) > 1 { if m[0].Distance < 0.75*m[1].Distance { good = append(good, m[0]) } } } // matches color c1 := color.RGBA{ R: 0, G: 255, B: 0, A: 0, } // point color c2 := color.RGBA{ R: 255, G: 0, B: 0, A: 0, } // creating empty mask mask := make([]byte, 0) // new matrix for output image out := gocv.NewMat() defer out.Close() // drawing matches gocv.DrawMatches(query, kp1, train, kp2, good, &out, c1, c2, mask, gocv.DrawDefault) // creating output window with result window := gocv.NewWindow("Output") window.IMShow(out) defer window.Close() window.WaitKey(0) } ================================================ FILE: cmd/find-chessboard/main.go ================================================ // What it does: // // This example shows how to find chessboard patterns in an image // // How to run: // // go run ./cmd/find-chessboard/main.go ./images/chessboard_4x6.png // package main import ( "fmt" "image" "os" "gocv.io/x/gocv" ) func main() { if len(os.Args) < 2 { fmt.Println("How to run:\n\tfind-chessboard [imgfile]") return } filename := os.Args[1] img := gocv.IMRead(filename, gocv.IMReadColor) if img.Empty() { fmt.Printf("Error reading chessboard image") return } defer img.Close() corners := gocv.NewMat() defer corners.Close() sz := image.Point{X: 4, Y: 6} found := gocv.FindChessboardCorners(img, sz, &corners, 0) if found == false { fmt.Printf("chessboard pattern not found") return } if corners.Empty() { fmt.Printf("corners mat is empty") return } fmt.Printf("Corners Found. Size: %+v Rows: %+v Cols: %+v\n", corners.Size(), corners.Rows(), corners.Cols()) clone := img.Clone() defer clone.Close() gocv.DrawChessboardCorners(&clone, sz, corners, found) if clone.Empty() { fmt.Printf("Error writing to chessboard image") return } window := gocv.NewWindow("Chessboards") defer window.Close() for { window.IMShow(clone) if window.WaitKey(10) >= 0 { break } } } ================================================ FILE: cmd/find-circles/main.go ================================================ // What it does: // // This example shows how to find circles in an image using Hough transform. // // How to run: // // go run ./cmd/find-circles/main.go ./images/circles.jpg // package main import ( "fmt" "image" "image/color" "os" "gocv.io/x/gocv" ) func main() { if len(os.Args) < 2 { fmt.Println("How to run:\n\tfind-circles [imgfile]") return } filename := os.Args[1] window := gocv.NewWindow("detected circles") defer window.Close() img := gocv.IMRead(filename, gocv.IMReadGrayScale) defer img.Close() gocv.MedianBlur(img, &img, 5) cimg := gocv.NewMat() defer cimg.Close() gocv.CvtColor(img, &cimg, gocv.ColorGrayToBGR) circles := gocv.NewMat() defer circles.Close() gocv.HoughCirclesWithParams( img, &circles, gocv.HoughGradient, 1, // dp float64(img.Rows()/8), // minDist 75, // param1 20, // param2 10, // minRadius 0, // maxRadius ) blue := color.RGBA{0, 0, 255, 0} red := color.RGBA{255, 0, 0, 0} for i := 0; i < circles.Cols(); i++ { v := circles.GetVecfAt(0, i) // if circles are found if len(v) > 2 { x := int(v[0]) y := int(v[1]) r := int(v[2]) gocv.Circle(&cimg, image.Pt(x, y), r, blue, 2) gocv.Circle(&cimg, image.Pt(x, y), 2, red, 3) } } for { window.IMShow(cimg) if window.WaitKey(10) >= 0 { break } } } ================================================ FILE: cmd/find-lines/main.go ================================================ // What it does: // // This example shows how to find lines in an image using Hough transform. // // How to run: // // go run ./cmd/find-lines/main.go lines.jpg // package main import ( "fmt" "image" "image/color" "math" "os" "gocv.io/x/gocv" ) func main() { filename := os.Args[1] mat := gocv.IMRead(filename, gocv.IMReadColor) matCanny := gocv.NewMat() matLines := gocv.NewMat() window := gocv.NewWindow("detected lines") gocv.Canny(mat, &matCanny, 50, 200) gocv.HoughLinesP(matCanny, &matLines, 1, math.Pi/180, 80) fmt.Println(matLines.Cols()) fmt.Println(matLines.Rows()) for i := 0; i < matLines.Rows(); i++ { pt1 := image.Pt(int(matLines.GetVeciAt(i, 0)[0]), int(matLines.GetVeciAt(i, 0)[1])) pt2 := image.Pt(int(matLines.GetVeciAt(i, 0)[2]), int(matLines.GetVeciAt(i, 0)[3])) gocv.Line(&mat, pt1, pt2, color.RGBA{0, 255, 0, 50}, 10) } for { window.IMShow(mat) if window.WaitKey(10) >= 0 { break } } } ================================================ FILE: cmd/gstreamer-writer/main.go ================================================ /* GStreamer Video Writer What it does: Captures video from webcam and outputs the frames to a gocv VideoWriter How to run: go run main.go To receive the video feed run in a terminal: gst-launch-1.0 udpsrc port=5000 ! application/x-rtp, encoding-name=MJPG ! rtpjpegdepay ! jpegdec ! videoconvert ! xvimagesink */ package main import ( "fmt" "gocv.io/x/gocv" ) const ( gstreamerPipe = "appsrc ! videoconvert ! video/x-raw,format=YUY2,width=640,height=480,framerate=30/1 ! jpegenc ! rtpjpegpay ! udpsink host=127.0.0.1 port=5000" ) func main() { cap, err := gocv.VideoCaptureDevice(0) if err != nil { panic(err) } defer cap.Close() cap.Set(gocv.VideoCaptureFrameWidth, 640.0) cap.Set(gocv.VideoCaptureFrameHeight, 480.0) wrt, err := gocv.VideoWriterFileWithAPI(gstreamerPipe, gocv.VideoCaptureGstreamer, "YUY2", 30.0, 640, 480, true) if err != nil { panic(err) } defer wrt.Close() if !wrt.IsOpened() { panic("wrt is not opened") } frame := gocv.NewMat() defer frame.Close() for { cap.Read(&frame) if frame.Empty() { fmt.Println("empty frame") continue } if err := wrt.Write(frame); err != nil { fmt.Println(err) } } } ================================================ FILE: cmd/hand-gestures/main.go ================================================ // What it does: // // This example detects how many fingers you hold up in front of the camera. // // How to run: // // go run ./cmd/hand-gestures/main.go 0 // package main import ( "fmt" "image" "image/color" "math" "os" "gocv.io/x/gocv" ) const MinimumArea = 3000 func main() { if len(os.Args) < 2 { fmt.Println("How to run:\n\thand-gestures [camera ID]") return } // parse args deviceID := os.Args[1] webcam, err := gocv.OpenVideoCapture(deviceID) if err != nil { fmt.Printf("Error opening video capture device: %v\n", deviceID) return } defer webcam.Close() window := gocv.NewWindow("Hand Gestures") defer window.Close() img := gocv.NewMat() defer img.Close() imgGrey := gocv.NewMat() defer imgGrey.Close() imgBlur := gocv.NewMat() defer imgBlur.Close() imgThresh := gocv.NewMat() defer imgThresh.Close() hull := gocv.NewMat() defer hull.Close() defects := gocv.NewMat() defer defects.Close() green := color.RGBA{0, 255, 0, 0} fmt.Printf("Start reading device: %v\n", deviceID) for { if ok := webcam.Read(&img); !ok { fmt.Printf("Device closed: %v\n", deviceID) return } if img.Empty() { continue } // cleaning up image gocv.CvtColor(img, &imgGrey, gocv.ColorBGRToGray) gocv.GaussianBlur(imgGrey, &imgBlur, image.Pt(35, 35), 0, 0, gocv.BorderDefault) gocv.Threshold(imgBlur, &imgThresh, 0, 255, gocv.ThresholdBinaryInv+gocv.ThresholdOtsu) // now find biggest contour contours := gocv.FindContours(imgThresh, gocv.RetrievalExternal, gocv.ChainApproxSimple) c := getBiggestContour(contours) gocv.ConvexHull(c, &hull, true, false) gocv.ConvexityDefects(c, hull, &defects) var angle float64 defectCount := 0 for i := 0; i < defects.Rows(); i++ { start := c.At(int(defects.GetIntAt(i, 0))) end := c.At(int(defects.GetIntAt(i, 1))) far := c.At(int(defects.GetIntAt(i, 2))) a := math.Sqrt(math.Pow(float64(end.X-start.X), 2) + math.Pow(float64(end.Y-start.Y), 2)) b := math.Sqrt(math.Pow(float64(far.X-start.X), 2) + math.Pow(float64(far.Y-start.Y), 2)) c := math.Sqrt(math.Pow(float64(end.X-far.X), 2) + math.Pow(float64(end.Y-far.Y), 2)) // apply cosine rule here angle = math.Acos((math.Pow(b, 2)+math.Pow(c, 2)-math.Pow(a, 2))/(2*b*c)) * 57 // ignore angles > 90 and highlight rest with dots if angle <= 90 { defectCount++ gocv.Circle(&img, far, 1, green, 2) } } status := fmt.Sprintf("defectCount: %d", defectCount+1) rect := gocv.BoundingRect(c) gocv.Rectangle(&img, rect, color.RGBA{255, 255, 255, 0}, 2) gocv.PutText(&img, status, image.Pt(10, 20), gocv.FontHersheyPlain, 1.2, green, 2) window.IMShow(img) if window.WaitKey(1) == 27 { break } } } func getBiggestContour(contours gocv.PointsVector) gocv.PointVector { var area float64 index := 0 for i := 0; i < contours.Size(); i++ { newArea := gocv.ContourArea(contours.At(i)) if newArea > area { area = newArea index = i } } return contours.At(index) } ================================================ FILE: cmd/hello/main.go ================================================ package main import ( "gocv.io/x/gocv" ) func main() { webcam, _ := gocv.OpenVideoCapture(0) window := gocv.NewWindow("Hello") img := gocv.NewMat() for { webcam.Read(&img) window.IMShow(img) window.WaitKey(1) } } ================================================ FILE: cmd/img-similarity/main.go ================================================ // What it does: // // This example calculates perceptual hashes for a pair of images, // and prints the hashes and calculated similarity between them. // A variety of algorithms are supported. // // How to run: // // img-similarity [-flags] [image1.jpg] [image2.jpg] // // go run ./cmd/img-similarity/main.go -all images/space_shuttle.jpg images/toy.jpg // package main import ( "flag" "fmt" "strings" "gocv.io/x/gocv" "gocv.io/x/gocv/contrib" ) var ( useAll = flag.Bool("all", false, "Compute all hashes") usePHash = flag.Bool("phash", false, "Compute PHash") useAverage = flag.Bool("average", false, "Compute AverageHash") useBlockMean0 = flag.Bool("blockmean0", false, "Compute BlockMeanHash mode 0") useBlockMean1 = flag.Bool("blockmean1", false, "Compute BlockMeanHash mode 1") useColorMoment = flag.Bool("colormoment", false, "Compute ColorMomentHash") useMarrHildreth = flag.Bool("marrhildreth", false, "Compute MarrHildrethHash") useRadialVariance = flag.Bool("radialvariance", false, "Compute RadialVarianceHash") ) func setupHashes() []contrib.ImgHashBase { var hashes []contrib.ImgHashBase if *usePHash || *useAll { hashes = append(hashes, contrib.PHash{}) } if *useAverage || *useAll { hashes = append(hashes, contrib.AverageHash{}) } if *useBlockMean0 || *useAll { hashes = append(hashes, contrib.BlockMeanHash{}) } if *useBlockMean1 || *useAll { hashes = append(hashes, contrib.BlockMeanHash{Mode: contrib.BlockMeanHashMode1}) } if *useColorMoment || *useAll { hashes = append(hashes, contrib.ColorMomentHash{}) } if *useMarrHildreth || *useAll { // MarrHildreth has default parameters for alpha/scale hashes = append(hashes, contrib.NewMarrHildrethHash()) } if *useRadialVariance || *useAll { // RadialVariance has default parameters too hashes = append(hashes, contrib.NewRadialVarianceHash()) } // If no hashes were selected, behave as if all hashes were selected if len(hashes) == 0 { *useAll = true return setupHashes() } return hashes } func main() { flag.Usage = func() { fmt.Println("How to run:\n\timg-similarity [-flags] [image1.jpg] [image2.jpg]") flag.PrintDefaults() } printHashes := flag.Bool("print", false, "print hash values") flag.Parse() if flag.NArg() < 2 { flag.Usage() return } // read images inputs := flag.Args() images := make([]gocv.Mat, len(inputs)) for i := 0; i < 2; i++ { img := gocv.IMRead(inputs[i], gocv.IMReadColor) if img.Empty() { fmt.Printf("cannot read image %s\n", inputs[i]) return } defer img.Close() images[i] = img } // construct all of the hash types in a list. normally, you'd only use one of these. hashes := setupHashes() // compute and compare the images for each hash type for _, hash := range hashes { results := make([]gocv.Mat, len(images)) for i, img := range images { results[i] = gocv.NewMat() defer results[i].Close() hash.Compute(img, &results[i]) if results[i].Empty() { fmt.Printf("error computing hash for %s\n", inputs[i]) return } } // compare for similarity; this returns a float64, but the meaning of values is // unique to each algorithm. similar := hash.Compare(results[0], results[1]) // make a pretty name for the hash name := strings.TrimPrefix(fmt.Sprintf("%T", hash), "contrib.") fmt.Printf("%s: similarity %g\n", name, similar) if *printHashes { // print hash result for each image for i, path := range inputs { fmt.Printf("\t%s = %x\n", path, results[i].ToBytes()) } } } } ================================================ FILE: cmd/kalman-filter/main.go ================================================ // What it does: // // This example implements the kalman filter example from: // // https://docs.opencv.org/4.6.0/de/d70/samples_2cpp_2kalman_8cpp-example.html#_a7 // // Tracking of rotating point. // Point moves in a circle and is characterized by a 1D state. // // state_k+1 = state_k + speed + process_noise N(0, 1e-5) // // The speed is constant. // Both state and measurements vectors are 1D (a point angle). // Measurement is the real state + gaussian noise N(0, 1e-1). // The real and the measured points are connected with red line segment. // The real and the estimated points are connected with yellow line segment. // The real and the corrected estimated points are connected with green line segment. // // If Kalman filter works correctly, the yellow segment should be shorter than // the red one andthe green segment should be shorter than the yellow one). // // Pressing any key (except ESC) will reset the tracking. // Pressing ESC will stop the program. // // How to run: // // go run ./cmd/kalman-filter/main.go package main import ( "image" "image/color" "math" "gocv.io/x/gocv" ) var ( colorCyan = color.RGBA{0, 255, 255, 1} colorYellow = color.RGBA{255, 255, 0, 1} colorGreen = color.RGBA{0, 255, 0, 1} colorRed = color.RGBA{255, 0, 0, 1} colorWhite = color.RGBA{255, 255, 255, 1} calcPoint = func(center gocv.Point2f, R, angle float32) gocv.Point2f { x := float32(math.Cos(float64(angle))) * R y := -float32(math.Sin(float64(angle))) * R return gocv.Point2f{X: center.X + x, Y: center.Y + y} } ) func main() { var code int window := gocv.NewWindow("Kalman") img := gocv.NewMatWithSize(500, 500, gocv.MatTypeCV8UC3) kf := gocv.NewKalmanFilterWithParams(2, 1, 0, gocv.MatTypeCV32F) state := gocv.NewMatWithSize(2, 1, gocv.MatTypeCV32F) processNoise := gocv.NewMatWithSize(2, 1, gocv.MatTypeCV32F) measurement := gocv.Zeros(1, 1, gocv.MatTypeCV32F) for { img = gocv.Zeros(500, 500, gocv.MatTypeCV8UC3) state.SetFloatAt(0, 0, 0) state.SetFloatAt(0, 1, 2*math.Pi/6) transitionMatrix := gocv.NewMatWithSize(2, 2, gocv.MatTypeCV32F) transitionMatrix.SetFloatAt(0, 0, 1) transitionMatrix.SetFloatAt(0, 1, 1) transitionMatrix.SetFloatAt(1, 0, 0) transitionMatrix.SetFloatAt(1, 1, 1) kf.SetTransitionMatrix(transitionMatrix) gocv.SetIdentity(kf.GetMeasurementMatrix(), 1) gocv.SetIdentity(kf.GetProcessNoiseCov(), 1e-5) gocv.SetIdentity(kf.GetMeasurementNoiseCov(), 1e-1) gocv.SetIdentity(kf.GetErrorCovPost(), 1) statePost := kf.GetStatePost() gocv.RandN(&statePost, gocv.NewScalar(0, 0, 0, 0), gocv.NewScalar(0.1, 0.1, 0.1, 0.1)) for { center := gocv.Point2f{X: float32(img.Cols()) * 0.5, Y: float32(img.Rows()) * 0.5} R := float32(img.Cols() / 3) stateAngle := state.GetFloatAt(0, 0) statePt := calcPoint(center, R, stateAngle) prediction := kf.Predict() predictAngle := prediction.GetFloatAt(0, 0) predictPt := calcPoint(center, R, predictAngle) // generate measurement measNoiseCov := kf.GetMeasurementNoiseCov() noise := float64(measNoiseCov.GetFloatAt(0, 0)) gocv.RandN(&measurement, gocv.NewScalar(0, 0, 0, 0), gocv.NewScalar(noise, noise, noise, noise)) measMatrix := kf.GetMeasurementMatrix() gocv.Add(measurement, measMatrix.MultiplyMatrix(state), &measurement) measAngle := measurement.GetFloatAt(0, 0) measPt := calcPoint(center, R, measAngle) // correct the state estimates based on measurements // updates statePost & errorCovPost statePost := kf.Correct(measurement) improvedAngle := statePost.GetFloatAt(0, 0) improvedPt := calcPoint(center, R, improvedAngle) // plot points img.MultiplyFloat(0.2) gocv.Circle(&img, image.Point{int(measPt.X), int(measPt.Y)}, 1, colorRed, 3) gocv.Circle(&img, image.Point{int(predictPt.X), int(predictPt.Y)}, 1, colorYellow, 3) gocv.Circle(&img, image.Point{int(improvedPt.X), int(improvedPt.Y)}, 1, colorGreen, 3) gocv.Circle(&img, image.Point{int(statePt.X), int(statePt.Y)}, 1, colorWhite, 4) // forecast one step test := transitionMatrix.MultiplyMatrix(kf.GetStatePost()) newPt := calcPoint(center, R, test.GetFloatAt(0, 0)) gocv.Circle(&img, image.Point{int(newPt.X), int(newPt.Y)}, 1, colorCyan, 6) gocv.Line(&img, image.Point{int(statePt.X), int(statePt.Y)}, image.Point{int(measPt.X), int(measPt.Y)}, colorRed, 1) gocv.Line(&img, image.Point{int(statePt.X), int(statePt.Y)}, image.Point{int(predictPt.X), int(predictPt.Y)}, colorYellow, 1) gocv.Line(&img, image.Point{int(statePt.X), int(statePt.Y)}, image.Point{int(improvedPt.X), int(improvedPt.Y)}, colorGreen, 1) noiseCovMat := kf.GetProcessNoiseCov() noiseCov := math.Sqrt(float64(noiseCovMat.GetFloatAt(0, 0))) gocv.RandN(&processNoise, gocv.Scalar{}, gocv.NewScalar(noiseCov, noiseCov, noiseCov, noiseCov)) txm := kf.GetTransitionMatrix() gocv.Add(txm.MultiplyMatrix(state), processNoise, &state) window.IMShow(img) code = window.WaitKey(1000) if code > 0 { break } } if code == 27 || code == 'q' || code == 'Q' { break } } } ================================================ FILE: cmd/mjpeg-streamer/main.go ================================================ // What it does: // // This example opens a video capture device, then streams MJPEG from it. // Once running point your browser to the hostname/port you passed in the // command line (for example http://localhost:8080) and you should see // the live video stream. // // How to run: // // mjpeg-streamer [camera ID] [host:port] // // go get -u github.com/hybridgroup/mjpeg // go run ./cmd/mjpeg-streamer/main.go 1 0.0.0.0:8080 // package main import ( "fmt" "log" "net/http" "os" "time" "github.com/hybridgroup/mjpeg" "gocv.io/x/gocv" ) var ( deviceID int err error webcam *gocv.VideoCapture stream *mjpeg.Stream ) func main() { if len(os.Args) < 3 { fmt.Println("How to run:\n\tmjpeg-streamer [camera ID] [host:port]") return } // parse args deviceID := os.Args[1] host := os.Args[2] // open webcam webcam, err = gocv.OpenVideoCapture(deviceID) if err != nil { fmt.Printf("Error opening capture device: %v\n", deviceID) return } defer webcam.Close() // create the mjpeg stream stream = mjpeg.NewStream() // start capturing go mjpegCapture() fmt.Println("Capturing. Point your browser to " + host) // start http server http.Handle("/", stream) server := &http.Server{ Addr: host, ReadTimeout: 60 * time.Second, WriteTimeout: 60 * time.Second, } log.Fatal(server.ListenAndServe()) } func mjpegCapture() { img := gocv.NewMat() defer img.Close() for { if ok := webcam.Read(&img); !ok { fmt.Printf("Device closed: %v\n", deviceID) return } if img.Empty() { continue } buf, _ := gocv.IMEncode(".jpg", img) stream.UpdateJPEG(buf.GetBytes()) buf.Close() } } ================================================ FILE: cmd/motion-detect/main.go ================================================ // What it does: // // This example detects motion using a delta threshold from the first frame, // and then finds contours to determine where the object is located. // // Very loosely based on Adrian Rosebrock code located at: // http://www.pyimagesearch.com/2015/06/01/home-surveillance-and-motion-detection-with-the-raspberry-pi-python-and-opencv/ // // How to run: // // go run ./cmd/motion-detect/main.go 0 // package main import ( "fmt" "image" "image/color" "os" "gocv.io/x/gocv" ) const MinimumArea = 3000 func main() { if len(os.Args) < 2 { fmt.Println("How to run:\n\tmotion-detect [camera ID]") return } // parse args deviceID := os.Args[1] webcam, err := gocv.OpenVideoCapture(deviceID) if err != nil { fmt.Printf("Error opening video capture device: %v\n", deviceID) return } defer webcam.Close() window := gocv.NewWindow("Motion Window") defer window.Close() img := gocv.NewMat() defer img.Close() imgDelta := gocv.NewMat() defer imgDelta.Close() imgThresh := gocv.NewMat() defer imgThresh.Close() mog2 := gocv.NewBackgroundSubtractorMOG2() defer mog2.Close() status := "Ready" fmt.Printf("Start reading device: %v\n", deviceID) for { if ok := webcam.Read(&img); !ok { fmt.Printf("Device closed: %v\n", deviceID) return } if img.Empty() { continue } status = "Ready" statusColor := color.RGBA{0, 255, 0, 0} // first phase of cleaning up image, obtain foreground only mog2.Apply(img, &imgDelta) // remaining cleanup of the image to use for finding contours. // first use threshold gocv.Threshold(imgDelta, &imgThresh, 25, 255, gocv.ThresholdBinary) // then dilate kernel := gocv.GetStructuringElement(gocv.MorphRect, image.Pt(3, 3)) gocv.Dilate(imgThresh, &imgThresh, kernel) kernel.Close() // now find contours contours := gocv.FindContours(imgThresh, gocv.RetrievalExternal, gocv.ChainApproxSimple) for i := 0; i < contours.Size(); i++ { area := gocv.ContourArea(contours.At(i)) if area < MinimumArea { continue } status = "Motion detected" statusColor = color.RGBA{255, 0, 0, 0} gocv.DrawContours(&img, contours, i, statusColor, 2) rect := gocv.BoundingRect(contours.At(i)) gocv.Rectangle(&img, rect, color.RGBA{0, 0, 255, 0}, 2) } contours.Close() gocv.PutText(&img, status, image.Pt(10, 20), gocv.FontHersheyPlain, 1.2, statusColor, 2) window.IMShow(img) if window.WaitKey(1) == 27 { break } } } ================================================ FILE: cmd/openvino/ie/version/main.go ================================================ // What it does: // // This program outputs the current OpenVINO IE library version to the console. // // How to run: // // go run ./cmd/openvino/ie/version/main.go // package main import ( "fmt" "gocv.io/x/gocv" "gocv.io/x/gocv/openvino/ie" ) func main() { fmt.Printf("gocv version: %s\n", gocv.Version()) fmt.Printf("OpenVINO Inference Engine version: %s\n", ie.Version()) } ================================================ FILE: cmd/saveimage/main.go ================================================ // What it does: // // This example uses the VideoCapture class to capture a frame from a connected webcam, // then save it to an image file on disk. // // How to run: // // saveimage [camera ID] [image file] // // go run ./cmd/saveimage/main.go 0 filename.jpg // package main import ( "fmt" "os" "gocv.io/x/gocv" ) func main() { if len(os.Args) < 3 { fmt.Println("How to run:\n\tsaveimage [camera ID] [image file]") return } deviceID := os.Args[1] saveFile := os.Args[2] webcam, err := gocv.OpenVideoCapture(deviceID) if err != nil { fmt.Printf("Error opening video capture device: %v\n", deviceID) return } defer webcam.Close() img := gocv.NewMat() defer img.Close() if ok := webcam.Read(&img); !ok { fmt.Printf("cannot read device %v\n", deviceID) return } if img.Empty() { fmt.Printf("no image on device %v\n", deviceID) return } gocv.IMWrite(saveFile, img) } ================================================ FILE: cmd/savevideo/main.go ================================================ // What it does: // // This example uses the VideoCapture class to capture AVI video from a connected webcam, // then saves 100 frames to a video file on disk. // // How to run: // // savevideo [camera ID] [video file] // // go run ./cmd/savevideo/main.go 0 testvideo.avi // package main import ( "fmt" "os" "gocv.io/x/gocv" ) func main() { if len(os.Args) < 3 { fmt.Println("How to run:\n\tsavevideo [camera ID] [video file]") return } deviceID := os.Args[1] saveFile := os.Args[2] webcam, err := gocv.OpenVideoCapture(deviceID) if err != nil { fmt.Printf("Error opening video capture device: %v\n", deviceID) return } defer webcam.Close() img := gocv.NewMat() defer img.Close() if ok := webcam.Read(&img); !ok { fmt.Printf("Cannot read device %v\n", deviceID) return } writer, err := gocv.VideoWriterFile(saveFile, "MJPG", 25, img.Cols(), img.Rows(), true) if err != nil { fmt.Printf("error opening video writer device: %v\n", saveFile) return } defer writer.Close() for i := 0; i < 100; i++ { if ok := webcam.Read(&img); !ok { fmt.Printf("Device closed: %v\n", deviceID) return } if img.Empty() { continue } writer.Write(img) } } ================================================ FILE: cmd/showimage/main.go ================================================ // What it does: // // This example uses the Window class to open an image file, and then display // the image in a Window class. // // How to run: // // go run ./cmd/showimage/main.go /home/ron/Pictures/mcp23017.jpg // package main import ( "fmt" "os" "gocv.io/x/gocv" ) func main() { if len(os.Args) < 2 { fmt.Println("How to run:\n\tshowimage [imgfile]") return } filename := os.Args[1] window := gocv.NewWindow("Hello") img := gocv.IMRead(filename, gocv.IMReadColor) if img.Empty() { fmt.Printf("Error reading image from: %v\n", filename) return } for { window.IMShow(img) if window.WaitKey(1) >= 0 { break } } } ================================================ FILE: cmd/ssd-facedetect/main.go ================================================ // What it does: // // This example shows, how to use pretrained SSD (Single Shot Detection) detection networks in gocv. // Here, we detect human faces from the camera, but the setup is similar for any other kind of object detection. // // Download the (small, 5.1mb) Caffe model file from: // https://raw.githubusercontent.com/opencv/opencv_3rdparty/dnn_samples_face_detector_20180205_fp16/res10_300x300_ssd_iter_140000_fp16.caffemodel // // Also, you will need the prototxt file: // https://raw.githubusercontent.com/opencv/opencv/master/samples/dnn/face_detector/deploy.prototxt // // How to run: // // go run ./cmd/ssd-facedetect/main.go 0 [protofile] [modelfile] // package main import ( "fmt" "image" "image/color" "os" "gocv.io/x/gocv" ) func min(a, b float32) float32 { if a < b { return a } return b } func max(a, b float32) float32 { if a > b { return a } return b } func main() { if len(os.Args) < 4 { fmt.Println("How to run:\nssd-facedetect [camera ID] [protofile] [modelfile]") return } // parse args deviceID := os.Args[1] proto := os.Args[2] model := os.Args[3] // open capture device webcam, err := gocv.OpenVideoCapture(deviceID) if err != nil { fmt.Printf("Error opening video capture device: %v\n", deviceID) return } defer webcam.Close() window := gocv.NewWindow("SSD Face Detection") defer window.Close() img := gocv.NewMat() defer img.Close() // open DNN classifier net := gocv.ReadNetFromCaffe(proto, model) if net.Empty() { fmt.Printf("Error reading network model from : %v %v\n", proto, model) return } defer net.Close() green := color.RGBA{0, 255, 0, 0} fmt.Printf("Start reading device: %v\n", deviceID) for { if ok := webcam.Read(&img); !ok { fmt.Printf("Device closed: %v\n", deviceID) return } if img.Empty() { continue } W := float32(img.Cols()) H := float32(img.Rows()) // convert image Mat to 300x300 blob that the detector can analyze blob := gocv.BlobFromImage(img, 1.0, image.Pt(300, 300), gocv.NewScalar(104.0, 177.0, 123.0, 0), false, false) defer blob.Close() // feed the blob into the classifier net.SetInput(blob, "data") // run a forward pass through the network detBlob := net.Forward("detection_out") defer detBlob.Close() // extract the detections. // for each object detected, there will be 7 float features: // objid, classid, confidence, left, top, right, bottom. detections := gocv.GetBlobChannel(detBlob, 0, 0) defer detections.Close() for r := 0; r < detections.Rows(); r++ { // you would want the classid for general object detection, // but we do not need it here. // classid := detections.GetFloatAt(r, 1) confidence := detections.GetFloatAt(r, 2) if confidence < 0.5 { continue } left := detections.GetFloatAt(r, 3) * W top := detections.GetFloatAt(r, 4) * H right := detections.GetFloatAt(r, 5) * W bottom := detections.GetFloatAt(r, 6) * H // scale to video size: left = min(max(0, left), W-1) right = min(max(0, right), W-1) bottom = min(max(0, bottom), H-1) top = min(max(0, top), H-1) // draw it rect := image.Rect(int(left), int(top), int(right), int(bottom)) gocv.Rectangle(&img, rect, green, 3) } window.IMShow(img) if window.WaitKey(1) >= 0 { break } } } ================================================ FILE: cmd/tf-classifier/main.go ================================================ // What it does: // // This example uses the Tensorflow (https://www.tensorflow.org/) deep learning framework // to classify whatever is in front of the camera. // // Download the Tensorflow "Inception" model and descriptions file from: // https://storage.googleapis.com/download.tensorflow.org/models/inception5h.zip // // Extract the tensorflow_inception_graph.pb model file from the .zip file. // // Also extract the imagenet_comp_graph_label_strings.txt file with the descriptions. // // How to run: // // go run ./cmd/tf-classifier/main.go 0 ~/Downloads/tensorflow_inception_graph.pb ~/Downloads/imagenet_comp_graph_label_strings.txt opencv cpu // package main import ( "bufio" "fmt" "image" "image/color" "os" "path/filepath" "gocv.io/x/gocv" ) func main() { if len(os.Args) < 4 { fmt.Println("How to run:\ntf-classifier [camera ID] [modelfile] [descriptionsfile]") return } // parse args deviceID := os.Args[1] model := os.Args[2] descr := os.Args[3] descriptions, err := readDescriptions(descr) if err != nil { fmt.Printf("Error reading descriptions file: %v\n", descr) return } backend := gocv.NetBackendDefault if len(os.Args) > 4 { backend = gocv.ParseNetBackend(os.Args[4]) } target := gocv.NetTargetCPU if len(os.Args) > 5 { target = gocv.ParseNetTarget(os.Args[5]) } // open capture device webcam, err := gocv.OpenVideoCapture(deviceID) if err != nil { fmt.Printf("Error opening video capture device: %v\n", deviceID) return } defer webcam.Close() window := gocv.NewWindow("Tensorflow Classifier") defer window.Close() img := gocv.NewMat() defer img.Close() // open DNN classifier net := gocv.ReadNet(model, "") if net.Empty() { fmt.Printf("Error reading network model : %v\n", model) return } defer net.Close() net.SetPreferableBackend(gocv.NetBackendType(backend)) net.SetPreferableTarget(gocv.NetTargetType(target)) status := "Ready" statusColor := color.RGBA{0, 255, 0, 0} fmt.Printf("Start reading device: %v\n", deviceID) for { if ok := webcam.Read(&img); !ok { fmt.Printf("Device closed: %v\n", deviceID) return } if img.Empty() { continue } // convert image Mat to 224x224 blob that the classifier can analyze blob := gocv.BlobFromImage(img, 1.0, image.Pt(224, 224), gocv.NewScalar(0, 0, 0, 0), true, false) // feed the blob into the classifier net.SetInput(blob, "input") // run a forward pass thru the network prob := net.Forward("softmax2") // reshape the results into a 1x1000 matrix probMat := prob.Reshape(1, 1) // determine the most probable classification _, maxVal, _, maxLoc := gocv.MinMaxLoc(probMat) // display classification desc := "Unknown" if maxLoc.X < 1000 { desc = descriptions[maxLoc.X] } status = fmt.Sprintf("description: %v, maxVal: %v\n", desc, maxVal) gocv.PutText(&img, status, image.Pt(10, 20), gocv.FontHersheyPlain, 1.2, statusColor, 2) blob.Close() prob.Close() probMat.Close() window.IMShow(img) if window.WaitKey(1) >= 0 { break } } } // readDescriptions reads the descriptions from a file // and returns a slice of its lines. func readDescriptions(path string) ([]string, error) { file, err := os.Open(filepath.Clean(path)) if err != nil { return nil, err } defer func() { _ = file.Close() }() var lines []string scanner := bufio.NewScanner(file) for scanner.Scan() { lines = append(lines, scanner.Text()) } return lines, scanner.Err() } ================================================ FILE: cmd/tracking/main.go ================================================ // What it does: // // This example uses one of the Tracker classes from opencv_contrib to track a region of interest (e.g. a face) // and draws a rectangle around it, before displaying it within a Window. // // in this example, users have to select an initial roi with the mouse, and press enter, to start the tracking // (but the roi could also come from e.g. a previous cascade based detection) // // also see https://docs.opencv.org/master/d2/d0a/tutorial_introduction_to_tracker.html for a tutorial // // How to run: // // tracking [camera ID] // // go run ./cmd/tracking/main.go 0 // package main import ( "fmt" "image/color" "os" "gocv.io/x/gocv" "gocv.io/x/gocv/contrib" ) func main() { if len(os.Args) < 2 { fmt.Println("How to run:\n\ttracking [camera ID]") return } // parse args deviceID := os.Args[1] // open webcam webcam, err := gocv.OpenVideoCapture(deviceID) if err != nil { fmt.Printf("Error opening video capture device: %v\n", deviceID) return } defer webcam.Close() // open display window window := gocv.NewWindow("Tracking") defer window.Close() // create a tracker instance // (one of MIL, KCF, TLD, MedianFlow, Boosting, MOSSE or CSRT) tracker := contrib.NewTrackerKCF() defer tracker.Close() // prepare image matrix img := gocv.NewMat() defer img.Close() // read an initial image if ok := webcam.Read(&img); !ok { fmt.Printf("cannot read device %v\n", deviceID) return } // let the user mark a ROI to track rect := gocv.SelectROI("Tracking", img) if rect.Max.X == 0 { fmt.Printf("user cancelled roi selection\n") return } // initialize the tracker with the image & the selected roi init := tracker.Init(img, rect) if !init { fmt.Printf("Could not initialize the Tracker") return } // color for the rect to draw blue := color.RGBA{0, 0, 255, 0} fmt.Printf("Start reading device: %v\n", deviceID) for { if ok := webcam.Read(&img); !ok { fmt.Printf("Device closed: %v\n", deviceID) return } if img.Empty() { continue } // update the roi rect, _ := tracker.Update(img) // draw it. gocv.Rectangle(&img, rect, blue, 3) // show the image in the window, and wait 10 millisecond window.IMShow(img) if window.WaitKey(10) >= 0 { break } } } ================================================ FILE: cmd/version/main.go ================================================ // What it does: // // This program outputs the current OpenCV library version to the console. // // How to run: // // go run ./cmd/version/main.go // package main import ( "fmt" "gocv.io/x/gocv" ) func main() { fmt.Printf("gocv version: %s\n", gocv.Version()) fmt.Printf("opencv lib version: %s\n", gocv.OpenCVVersion()) } ================================================ FILE: cmd/xphoto/main.go ================================================ // What it does: // // This example demonstrates a couple of uses of the XPhoto module. // It can use the GrayworldWB class with BalanceWhite image // to save an image file on disk. // // This example can also use the Inpaint functions with inpaint algorithms type // to save an image file on disk. // // How to run: // // go run ./cmd/xphoto/main.go -i -g // package main import ( "flag" "fmt" "os" "gocv.io/x/gocv" "gocv.io/x/gocv/contrib" ) func Inpaint() { jpgImage := gocv.IMRead("./images/space_shuttle.jpg", gocv.IMReadColor) if jpgImage.Empty() { fmt.Printf("Invalid read of Source Mat in TestInpaint test\n") return } src := gocv.NewMat() defer src.Close() sizeImage := jpgImage.Size() jpgImage.ConvertTo(&src, gocv.MatTypeCV8UC3) maskFsrFast := gocv.NewMatWithSizes(sizeImage, gocv.MatTypeCV8UC1) defer maskFsrFast.Close() dstShitMap := gocv.NewMat() defer dstShitMap.Close() contrib.Inpaint(&src, &maskFsrFast, &dstShitMap, contrib.FsrFast) dstFsrFast := gocv.NewMat() defer dstFsrFast.Close() contrib.Inpaint(&src, &maskFsrFast, &dstFsrFast, contrib.FsrFast) dstFsrBest := gocv.NewMat() defer dstFsrBest.Close() contrib.Inpaint(&src, &maskFsrFast, &dstFsrBest, contrib.FsrFast) if dstShitMap.Empty() || dstShitMap.Rows() != src.Rows() || dstShitMap.Cols() != src.Cols() || dstShitMap.Type() != src.Type() { fmt.Printf("Invlalid TestInpaint ShitMap test\n") return } fmt.Printf("ShitMap : MAT %d <> %d : %d\n", dstShitMap.Rows(), src.Rows(), dstShitMap.Type()) gocv.IMWrite("ShitMap_inpaint.png", dstShitMap) if dstFsrFast.Empty() || dstFsrFast.Rows() != src.Rows() || dstFsrFast.Cols() != src.Cols() || dstFsrFast.Type() != src.Type() { fmt.Printf("Invlalid TestInpaint FsrFast test\n") return } fmt.Printf("FsrFast : MAT %d <> %d : %d\n", dstFsrFast.Rows(), src.Rows(), dstFsrFast.Type()) gocv.IMWrite("FsrFast_inpaint.png", dstFsrFast) if dstFsrBest.Empty() || dstFsrBest.Rows() != src.Rows() || dstFsrBest.Cols() != src.Cols() || dstFsrBest.Type() != src.Type() { fmt.Printf("Invlalid TestInpaint FsrBest test\n") return } fmt.Printf("FsrBest : MAT %d <> %d : %d\n", dstFsrBest.Rows(), src.Rows(), dstFsrBest.Type()) gocv.IMWrite("FsrBest_inpaint.png", dstFsrBest) } func BalanceWhite() { fileGrayWorld := "grayworld_space_shuttle.png" src := gocv.IMRead("./images/space_shuttle.jpg", gocv.IMReadColor) if src.Empty() { fmt.Printf("Invalid read of Source Mat in TestInpaint test\n") return } defer src.Close() fmt.Println("using GrayworldWB with white balance function") dst := gocv.NewMat() defer dst.Close() grayworldwb := contrib.NewGrayworldWB() defer grayworldwb.Close() grayworldwb.SetSaturationThreshold(0.7) grayworldwb.BalanceWhite(src, &dst) gocv.IMWrite(fileGrayWorld, dst) } func main() { if len(os.Args) < 2 { fmt.Println("How to run:\n\tmain [-i] [-b]") return } balanceWhitePtr := flag.Bool("b", false, "GrayworldWB functions") inpaintPtr := flag.Bool("i", false, "Inpaint functions") flag.Parse() if *balanceWhitePtr { BalanceWhite() } if *inpaintPtr { Inpaint() } } ================================================ FILE: cmd/yolo-detection/main.go ================================================ // What it does: // // This example uses the YOLOv8 deep neural network to perform object detection. // // Download the ONNX model file from the following notebook: // // https://colab.research.google.com/github/ultralytics/ultralytics/blob/main/examples/tutorial.ipynb // // How to run: // // go run ./cmd/yolo-detection/ [videosource] [modelfile] ([backend] [device]) package main import ( "fmt" "image" "image/color" "os" "gocv.io/x/gocv" ) // COCONet class names var classes = []string{ "person", "bicycle", "car", "motorcycle", "airplane", "bus", "train", "truck", "boat", "traffic light", "fire hydrant", "stop sign", "parking meter", "bench", "bird", "cat", "dog", "horse", "sheep", "cow", "elephant", "bear", "zebra", "giraffe", "backpack", "umbrella", "handbag", "tie", "suitcase", "frisbee", "skis", "snowboard", "sports ball", "kite", "baseball bat", "baseball glove", "skateboard", "surfboard", "tennis racket", "bottle", "wine glass", "cup", "fork", "knife", "spoon", "bowl", "banana", "apple", "sandwich", "orange", "broccoli", "carrot", "hot dog", "pizza", "donut", "cake", "chair", "couch", "potted plant", "bed", "dining table", "toilet", "tv", "laptop", "mouse", "remote", "keyboard", "cell phone", "microwave", "oven", "toaster", "sink", "refrigerator", "book", "clock", "vase", "scissors", "teddy bear", "hair drier", "toothbrush", } func main() { if len(os.Args) < 3 { fmt.Println("How to run:\nyolo-detection [videosource] [modelfile] ([backend] [device])") return } // parse args deviceID := os.Args[1] model := os.Args[2] backend := gocv.NetBackendDefault if len(os.Args) > 3 { backend = gocv.ParseNetBackend(os.Args[3]) } target := gocv.NetTargetCPU if len(os.Args) > 4 { target = gocv.ParseNetTarget(os.Args[4]) } // open capture device webcam, err := gocv.OpenVideoCapture(deviceID) if err != nil { fmt.Printf("Error opening video capture device: %v\n", deviceID) return } defer webcam.Close() window := gocv.NewWindow("YOLO Detection") defer window.Close() img := gocv.NewMat() defer img.Close() // open DNN object tracking model net := gocv.ReadNetFromONNX(model) if net.Empty() { fmt.Printf("Error reading network model from : %v\n", model) return } defer net.Close() net.SetPreferableBackend(gocv.NetBackendType(backend)) net.SetPreferableTarget(gocv.NetTargetType(target)) outputNames := getOutputNames(&net) if len(outputNames) == 0 { fmt.Println("Error reading output layer names") return } fmt.Printf("Start reading device: %v\n", deviceID) for { if ok := webcam.Read(&img); !ok { fmt.Printf("Device closed: %v\n", deviceID) return } if img.Empty() { continue } detect(&net, &img, outputNames) window.IMShow(img) if window.WaitKey(1) >= 0 { break } } } var ( ratio = 0.003921568627 mean = gocv.NewScalar(0, 0, 0, 0) swapRGB = false padValue = gocv.NewScalar(144.0, 0, 0, 0) scoreThreshold float32 = 0.5 nmsThreshold float32 = 0.4 ) func detect(net *gocv.Net, src *gocv.Mat, outputNames []string) { params := gocv.NewImageToBlobParams(ratio, image.Pt(640, 640), mean, swapRGB, gocv.MatTypeCV32F, gocv.DataLayoutNCHW, gocv.PaddingModeLetterbox, padValue) blob := gocv.BlobFromImageWithParams(*src, params) defer blob.Close() // feed the blob into the detector net.SetInput(blob, "") // run a forward pass thru the network probs := net.ForwardLayers(outputNames) defer func() { for _, prob := range probs { prob.Close() } }() boxes, confidences, classIds := performDetection(probs) if len(boxes) == 0 { fmt.Println("No classes detected") return } iboxes := params.BlobRectsToImageRects(boxes, image.Pt(src.Cols(), src.Rows())) indices := gocv.NMSBoxes(iboxes, confidences, scoreThreshold, nmsThreshold) drawRects(src, iboxes, classes, classIds, indices) } func getOutputNames(net *gocv.Net) []string { var outputLayers []string for _, i := range net.GetUnconnectedOutLayers() { layer := net.GetLayer(i) layerName := layer.GetName() if layerName != "_input" { outputLayers = append(outputLayers, layerName) } } return outputLayers } func performDetection(outs []gocv.Mat) ([]image.Rectangle, []float32, []int) { var classIds []int var confidences []float32 var boxes []image.Rectangle if len(outs) == 0 || outs[0].Empty() { return boxes, confidences, classIds } // transpose outs[0] safely, don't overwrite it in-place without closing the old one to avoid memory leak tmp := gocv.NewMat() // needed for yolov8: transpose (1, 84, N) -> (1, N, 84) gocv.TransposeND(outs[0], []int{0, 2, 1}, &tmp) outs[0].Close() // free the old underlying cv::Mat outs[0] = tmp // take ownership of the new transposed Mat for _, out := range outs { if out.Empty() { continue } out = out.Reshape(1, out.Size()[1]) for i := 0; i < out.Rows(); i++ { cols := out.Cols() scoresCol := out.RowRange(i, i+1) scores := scoresCol.ColRange(4, cols) _, confidence, _, classIDPoint := gocv.MinMaxLoc(scores) scores.Close() scoresCol.Close() if confidence > 0.5 { // get cx,cy,w,h at columns 0..3 centerX := out.GetFloatAt(i, 0) centerY := out.GetFloatAt(i, 1) width := out.GetFloatAt(i, 2) height := out.GetFloatAt(i, 3) left := centerX - width/2 top := centerY - height/2 right := centerX + width/2 bottom := centerY + height/2 classIds = append(classIds, classIDPoint.X) confidences = append(confidences, float32(confidence)) boxes = append(boxes, image.Rect(int(left), int(top), int(right), int(bottom))) } } out.Close() } return boxes, confidences, classIds } func drawRects(img *gocv.Mat, boxes []image.Rectangle, classes []string, classIds []int, indices []int) []string { var detectClass []string for _, idx := range indices { // Don't skip idx==0; it's a valid index from NMSBoxes if idx < 0 || idx >= len(boxes) || idx >= len(classIds) { continue } gocv.Rectangle(img, image.Rect(boxes[idx].Min.X, boxes[idx].Min.Y, boxes[idx].Max.X, boxes[idx].Max.Y), color.RGBA{0, 255, 0, 0}, 2) gocv.PutText(img, classes[classIds[idx]], image.Point{boxes[idx].Min.X, boxes[idx].Min.Y - 10}, gocv.FontHersheyPlain, 0.6, color.RGBA{0, 255, 0, 0}, 1) detectClass = append(detectClass, classes[classIds[idx]]) } return detectClass } ================================================ FILE: codecov.yml ================================================ ignore: - "*_string.go" - "*/*_string.go" ================================================ FILE: contrib/README.md ================================================ # Using OpenCV Contrib The OpenCV Contrib library contains experimental or non-free (aka patented) algorithms. GoCV support for OpenCV Contrib can be found here in the "gocv.io/x/gocv/contrib" package. For more information about OpenCV Contrib, please go to: https://github.com/opencv/opencv_contrib ## How to use If you have followed the installation instructions from the main README, then the OpenCV contrib modules have already been compiled and installed. First, you must include the `contrib` subpackage: ```go import ( "gocv.io/x/gocv" "gocv.io/x/gocv/contrib" ) ``` Then you will be able to use the functions within the `contrib` subpackage. For example, this uses the `SIFT` feature identitification algorithm that is within the `xfeatures2d` module of OpenCV: ```go si := contrib.NewSIFT() kp := si.Detect(img) ``` Note that some of the features in this package require building OpenCV with the `OPENCV_ENABLE_NONFREE=ON` option. You can run `make build_nonfree` to build with this option. ================================================ FILE: contrib/att_faces/README ================================================ The ORL face database --------------------- This directory contains a set of faces taken between April 1992 and April 1994 at the Olivetti Research Laboratory in Cambridge, UK. There are 10 different images of 40 distinct subjects. For some of the subjects, the images were taken at different times, varying lighting slightly, facial expressions (open/closed eyes, smiling/non-smiling) and facial details (glasses/no-glasses). All the images are taken against a dark homogeneous background and the subjects are in up-right, frontal position (with tolerance for some side movement). The files are in PGM format and can be conveniently viewed using the 'xv' program. The size of each image is 92x112, 8-bit grey levels. The images are organised in 40 directories (one for each subject) named as: sX where X indicates the subject number (between 1 and 40). In each directory there are 10 different images of the selected subject named as: Y.pgm where Y indicates which image for the specific subject (between 1 and 10). When using these images, please give credit to Olivetti Research Laboratory. A convenient reference is the face recognition work which uses some of these images: F. Samaria and A. Harter "Parameterisation of a stochastic model for human face identification" 2nd IEEE Workshop on Applications of Computer Vision December 1994, Sarasota (Florida). The paper is available via anonymous ftp from quince.cam-orl.co.uk and is stored in pub/users/fs/IEEE_workshop.ps.Z If you have any question, please email Ferdinando Samaria: fs@cam-orl.co.uk ================================================ FILE: contrib/att_faces/s1/1.pgm ================================================ P5 92 112 255 01-/19'*515T4JGC@XDGKB9=>4/2:<@B9.6BPPDGW@MBSM:.)+873886-4'.8-'/0('2,EFCH;343045@KQUbnkmeP]^L:QNSNHM/,@KN:BRQVIFD9/&''35423-2*33-(0,%$%,14+83/,.=HMOUdkozv{qoUPPSE>IdSVPILCEPWOUDH87/+-1+49@G;7/->PLPP[X^RF?64/)!130521.//2/*-(,==1A>=6CM=579@D>GapYqqgQ^JIKK@K_`][POIDSRVVCK:5178557:A9:502>ZWY_\XZ[TOH9.'#++23../00,+,<62EHB?>0A96';JE@MTRXa\Z{_SDMEGHGM_ei\OXORVR\TNI:8=DLQU]S<.1/08=`VUZWRSFQQH@+."&)50/-03,#)18>8GDAC2$7+,6CGGGVZ]FCPRTtKQEQDOMSbpsXQfbTeXc^VL:ELSHE9EUNZ^VEIPO\Xqyj`_sd\fYo[TF>J_ce]_a\aUGDG;?MWMDOH7:BDB5-.$# .50/1/7(64A.07@2)$+"%.MaTBDV[SG\MDNIkVSgVaYfbikumpvnpa_pledZXQT`eehc[\\VPOG?DTFBC?>8>1<4<4@,$'-15.27)9.;G4<,,)%#(9U\GLNTOONRl_`agc][h[_efkprsvvnq||wrh_VNR\ecc]SX[XIC?AQOH=8-85/2@<33=0'234017'.8Y17-3$#),66FH?FBOVbcbiqzzrnnbfmkpy}~}|ykj`\Xd`m[UU`YTNRLQSLI@=6,-68:0/.1'-2216.$29((<26+))*3M\QLN^dgny|{yx{}{xxmja`dQPY]_RSMUVOK>DA.%+16=/(0$4,5/:%-01463>88+35=W`UU`nt}~xtjdTRRabPSKONMDJ;8=+/9&4C1.#.041;'1/,G63:8<>:GOe[Zkr|{vZW]_d]OJHTJC<=4<9@=1*<63")27/@*10259=;9>FLVhf]tw~qZgd_]THXJD>>15>8N@5*:*3,0.53/;-3(@OB7=MYeqjq}{ii_\QXNYBDI6201BR;:)4( +*/188JII-'+850GOS_rz}ükYT^_bNQUEHE3DEBAG(%'--/3EA@+Q9+1264:NWk}~}_QXea]PQA8DE>?=7@&&"-102>25.N??3:6BUhr÷wfmlmn^WK=DD:D*8C+!',236.40*O:A@@4Mhw~{{xjYXGJ^3'-*H;/&.00643.(=4BGBIGf{}yi\QMEN*&%1;1,210>51'**59EBJKgzi]LDFB6'(#-722/0<6(#&%9;MHNXluZVDDH<+0)!7/231D1/"#038GFYXk|yaYCLO>362$,#,5-1<-)*6>8@RT[mylZHIHA2;5*"'-4,2;) &:2A9M[]bpyafJH@:9/0'9(*,/0=*$',-CAF^Zcqte[QCVA;.*$A1$3-.12/)$/3BPQTcp{c^GHMVO5''(/-,0/32@#)-FBJR]fo~gZD>IPF08&%!./2/.22#85JLJSX_m}h\INBE3-01,/-/&3&*=6CCUX`bsymaSMM<*,*)$"/1-/*8!+22;DV^clmXRJB5)*&(&#*20076053??RXgj}zl_QVJ7).$)Ü.<;0+);ICY^jnj_VLBH3&**"%2//2C7*)%38J_hmvv^ZN555%8(*'22/-E/&%-*BLXkn}_^UM;1'*'*#620.=2"+F)5@Pjt¿w`XFj9C)&&$.01-9?>R%2FXktžÿeQRM663($&"/1.,.?-J 9MJeqÿſgF_@1,+-,'.-1../7&!=*6TJ`mNW92%.'2-,5-2124))43LD\nTZ73),-/0-4+0/57%2E4@8\laG/44%5-/11*1117.CNA6@SxO>-%2,45/1714034+!0_C)GKxxzyy\0&&2D,06235.1525+_='LL~}ulkpwqw}d0$#>C:2@412044/7!*X9-LP~yuty|~u|bH#-?676.M-11362:&%D@,ITmV415828.D8,/1641<#H=TSPR:(,.,13$&rüǴ{>)0.+,,5,/-'mĎwz^vT<-,--++//10++'?zyH;9/-))/+-*+/0(.+0(+=H_s(,*-)+*-++--*+-+++-(-, U +,*,-+,--*.--)-*.,+.+ÿÿ<$(+,,,(*,+,/0*,,+,-+/(L½z&'-*&*/'.*,*,.,++,(,+(/-&X#'+*-'-'.&*.+1++.-+)+)-.:$+**).%(,)++&./-+,&+++*0j})",+(-+%))/'.)/.-,)+'.,*,#H` &)'()+*%*-,,)2,++,*,.+*0,¾B#($*%%+(((%+0(/,0/+(,+--).z}, &#,''(($()),)11/,0(--(*,. Dh'(*%$'*#**'(,*/1/,+.*0&,*--]$&&,$+(*$')&,(120./,,+(--+-aÿ{ysk_bqponu~wxrrsqw}X (%*$-%%,$'&',*1.20)/+-,++-/+ĸtnuupihg`geb^UU]VTUQX^\[glr{T(''&*((''&')*,-251.0,).-)+.(eózx|vtrjpmmcg`cjddlrwU!&'%((($+')&'++.3/3(3),*/()0,'ĵy{{xvu|w{}V!%%((($'&*$)()(212./0+0-,-+.))[\!()&.('(-'((',15/0300//+*,)-(,\$(''0%.+)-#-(,24//52-/0)-.)*-*Ƽ`#)"*%(+)+)),*-23.1-6-0//-,0+*.¼c '&&)%'*)%)'2&/00/8+8.20021+-&/þk&$)')&((*)),).212225012,022-./qü}h###$&'$*+&-',1*042040342-13//1-rŻj"'"&&'&.',)-3+14411514..5/13.,m{i#&%'((-'(.(.1(040433/2./2/+01.ize&('+'(*&+(*..01414.6-1131//3/3d~i&$)(-(-&',+//-02127,52304/05.5he%%%&+))*,)(0.-150332700630904*lh%!*%('&.**-+0/34105/4.0024505 rd$&'$%.#+'.+0+,014/21322005/7({{c&%$&&()'++/0-/-1/2215-1/4010 {^'&%#'&+)..0/)4.62/30341062., {b'"('&&**/-.,01/1/4203/133'&zd!)$%%*&--*2)01-4+40134./3+&%}c*&$#'++/*0-0-202.2/320.4#'óY#)#()')..,-..-61.22/.2/-"'`üJ.%%)'*+2-.//333-42/0.4"#'/'¾9*"',()1*,/.. ================================================ FILE: contrib/att_faces/s1/2.pgm ================================================ P5 92 112 255 <<>503=E==EEGUY[TVPLQanzqphon^HIKXN-@@=JPT\afnefjs~ȽwrnojYG_X67Z?06N'-31ED?OQRIKMgkpmmv}ŽvppijMQQ0?P>$/[0.1+AYODPWWX[forz}ĿzqoiX:V.LND'-V21+4>CGRYadmzy}{sniED:LQ;48@80147HNT]iitz~|poXG'05.0IECR\c_pywXAU/06/.DAIPYVgtyfGVF2//.CQS[[glnz{fWLG>01,KW^fe_lkn|vRQL/23/GMOZca`hs~~XT]934/QOVSYW^hnr|cKTR+:/DTGIQZWgmzpzuTIH35.PCDNU]^iinwy~]TD56-LJVM\^^\djyeM_5-1WMNQ]\`fpnhRP7(6@MMSU_ikoy}qQa6'1SWN\Z_hnov~}Q]B++]YX\g`dkoz}{^SJ(5\Yaknifnt{YTB0,Ragpfryz~XWF/-S\jkly}]UB0/RZ`kvu}|aY:2-USYj|{t¾TT31/VU[qowWC4-1OSalgje412.VS``lwf7-.0LSR^na+112LRP]}{+-4+SKJe}zxxxzvD*..VJNj{y{||zupipuvnv|yk'.1VONzuuoqw|{xwujruz||w~{l4+0bO]z}{|zl3*/OK^X4(-QRjwrifomzN&/.TVoqmdX[`[qx|zzq]Qu3`1]gRci_hvrrö|x|APoR&\2md4L,'1/cjjeoQBV 17\8jbgcpntveRHb_B?>qbHs5!02uyyeRiSTUDUUM}uxpaywX`^xTaS:yxkps0&1/¥}zzpߑL^dN[wownmimwŮtgjs}wib`{zho9"1/~{vuspqsupvziq{{~ww{y}wcv>',,x{zystrz{z|°vps{~|}}tvyM$-)vwuzz}|jnsyb%,,~~~prtx},1qu~&&1vx5!1|~.%+1&1*,*~'(3%(*+/y%*-g'(1]&).K&*.<',)/$,.u''+/ʫj &--ƳI!(),Ƴɚ7"&,(qxµuwz,!(-.jue!((.+rv~kzM&,,+~ej@%*&.sgn- ',).yuvn*!))(&^$,-*'B!$&*-'5$%'))! %)')$ýv%''*&þ[&&)(&&B&(')&(/&)'&&#ÿk#$&&'")~W"&*!&%'{zvrqlu{wnmoorqrptrru>($(#)$(ľsld]XSVTXXY]VMRVRSOPY`acgxz)&*('$)&ne_ffkfeb^dcnkuonjccXf^^ZSUSVTU_ix]")"(+$'(zĿ|vuoqnxvxyx}{~yvwqxxiigmcogelpw5#("&%#&+`ƿ{xpx|x{{y{s!( &$%$#'H}~~J"!$#$&%%%2v)' #$&%$(7ϼM$#&""'&):n+""!#"&"(&&(ľ=" # % '%$%&'q`% &&$%$'&''`{1%#$!&'&(&%#VM!!#"##"$%&&%Ic*# $'#!#' $#Cw5$%!!"!!'"#$2g$# '"!"$$&%%""-r!!""# """ ""$$%%)$$#" " &#"%%.{"!&%!!!!%$$( 8¾|$#&&!!! "!$#$ L}1'##! $$"" a~z= '##! # "#!%!|v@%("%#% $%w: #'&! ! $' #$v2 )! ("!!|{{.'&! ""$$ o»}{~a "+#!% "" ================================================ FILE: contrib/att_faces/s1/3.pgm ================================================ P5 92 112 255 ',5%=0=-#(('7Tn`IHVgVXRMKXZ{[^gieamlox}}xppjdkolmSLTb\^[RRPROA;(,779H=<&#"././0/,,=3<2A+((,59LiWRRT^b_gjmqrypchihhllq{~u}nkcSLWcb__WPPIK@2-2H?I@<*%$000/-.;'981>=9.*2>C`\MPYalrptwvlmrmkx~mR[Yfea]bLOAMEHHEK>5G;1.$*.0..,6,E,/B6>?;=CLhdW[lrvuu|}cWihXVXaSLEE69DA:80*>63/)0,-+*>4%89;8LMGHVZqbfv{]je\[bb[OHF>:3(4--)(&.0.,.,B>A?8:DDWdw~|x~wdWP>E<5,/29#)+10/+./0@E<::[nu}t]\KGJC@)>73,9-+/./*)3=>R>FVuiXNAPG>.77,=J,-10+/#21;FNJQrr`PEDD?49-/KL+-10,/ ,1?CUEWsogRJG<<8,-.5<,10./.,10FNOT\nĸn_bLHUFA0-))(,11-./,77@IP`[mv`XQ=VTK205&!/01//,-2>??RV_o¶pkYHDIJC(<8'$2.1...*6==JY^dpźth`G:EJ<&;6$)221/.00>;Ukikq{g`DKJJ)+*0*#/5-/.3$*7>[V`gly˶tgaVA5>3(-222.0/.2)-BOO]msv˿ƹ~f]TK<50)+740-0./.(9GEEYau¼|n]ZHT(,*-741.0.0-?35=Ubgn|¾zv\]JH#,-:3/02113.7**CUhktĿo\VR4.%0<4021/.3/(,/AZhsxŻu[OV,6,18-G/1/1//!-$DMapzž~[SM%1,8<7;G-11/2 %/5M\vzǿĿö`L<%*:B=8-F91//046:K\o{ļžŻcH2$2MB?/8DF11/.(*KCCO^zlE.*0JA9Hu@/02/\Q7IbyL(/DH7:n500+YL*=TT<1FC/Rq&/0#;A+9A[S7K8Fv,-5*3@41JzhR6KF`|i"oC-O:'Q{M37Sz&n=<++R}^8;d|dZ7$.S{}vyzvvjCM|G67\pspiiqsswy|Gln~bBYp~{rts~Xzz{ _Xu{~~|uwrzy{|NzzsmpozzqZllDp9H4juRvz}yDzQ}zn^yKF|X4sIdVN^z}d|ijktybwXf`8LrfnCn~k{Ú{cwN\5gcUUqǶegf=tC~}zvsDR.KUHrx]okƹoxy}]z}^lV^}V`IDcUu|{tCpxR{[͏Y_`\g{v||0qyukwוxrz}q~t!u|zŴpȫnz|R'y||21yp_+0{}Ƕz5-1~ƾT+/-gŊǾt//1-ɳs<,,,2{|a4)--/2i2.,(*,/ip@.-0)*0-}]:13*-*,(0/&að\9210//.,+/.2."cı6',0-0,0+++01,,%Ƶ&0,-+4)/-+*1-1/+/pȨ´q!,,,..0*.-(,0./,()OX&.(-/.-.1,.*//-,,''33?#0+-/,.,+,,*+,+),,*,k0)*.).-+.*/+/,-+)+.*+*:z'(,.+)2*0*,+0/,,(---.,`#+,,,*/(+.)-+.*,,,,/-0rηG"/++,-.*,-,*--.,)++*/*$Dͳ2)-*0+).).+-*-,+.)+*++(,&,*-(-*)(/+.,,,,.*-)+)*.Үwf-+,+)-+,+--+-..,+-',,)/P{ørorsM"*+(*-'/,,.+,/-.*,*),)+*,+x6#*)+)&0+++)*.-,-*+***(,*-}#()(*)(,,*++-,/+.,*/*+,+,.f~]!*-'-(++**.+,--*.-+.,**,&&)9~B!)'))&/*)(-.+++-,-,*.+*.+&0Ľ+#('()'--%*)1()..*.,.*.),-)'bþc '%)&'$*)*)),.-)-..--,-*+,(*,&ž?+%%&+&&()'(**,-3..,,*,++-)+-|ſ)$%'#)&)$()(%++)*1.,*,-(,,-+.('=žW#%'("('&)'+&(*+.'000,+-+-.+,,(-Ŀ¹6 &&'&%&)')*&(**,(2.1--,-,-,'+0'¿ƻ¿w!"&(%(%'*()&&(&*'-.0..1(+//,*-).ûg$%%'#&('&((&)&*+.2./01,,,-+,,*+ƽyoq{yn][W\n{xsf_ZabquntY#$'$$$')%&)%(%'--012.3,,.+)0-+/ɹ|xuhd^\]^Z_VTYXOVRPURZ]nvW&# &#$&'''''''*&.102//-+.,-,.-1ƹxtnoxruumpsmfg^jfksE%!!#$&&*('-$'**(*23200*2.'/+.+.ȿ~~}tosuy<"$!$$#()(+(*(*(-321/2,3,,/,+.-}{~|y6!#!##"(%&('((*(,122020,,/,.*/-¿ž}$!#$! % $%$'$%)$(&-23/133///0-//%ƻ&!# !##!&$%'$(&&&.231104/01+,3)'"$" "$#''%(%(&)3-4-32.2./27-!""%%$&$)&'-21022-40014&*$ !!&!#&&!%&&)&10213210323, %- '!$!%%$"&#(*)210332/140,; !0!$ &#&"#$%$%))42/6320016" Do!-)!""#$%"$$""'()01.410/2.2 B~S&%+&&""#%%%&$&''//42131/// 1=##)'+!%##!$(&&%'1/3.01/-/)(}x+")(($!#&"$%"&%2/4/--30+%(nb)&&(+!$%%" !$$$ "3311.10.)%8>}|R$ "%&*$"''" "!"14202-/'*%%<3u¶_M # #(()!$( " !" .3012*&#,#)>?@nRF "# ))(#"$$""".11-'!$+" 1=D=`ÿûñ{ZQ<##'*%&##" "1.*$ +#2>AC9¿^OO5#!!(($% "  .#" &*#/BDB@Ný¿{eXOH3! $'')   %!("!)$/?BFBFeĽüyf[TMA0# !#'%,$   ================================================ FILE: contrib/att_faces/s1/4.pgm ================================================ P5 92 112 255 )//.,10:=1:AV7TXH28GOVW[]gdn{xpfVQQKB?;Rgl_MOTFA<:EM[jku|xpgdXPLLLRI37OFQ7@E6DA7;1($+13122.0-5*9:9))%&.=U=@<@[dgt{wrgMZQJKSAATIJ>H==@91+''!"02221,/3+2C::4' '4PNC?LXfksƼ{y\`T_KGKRYFKGPD@HD?3*$"!4715.0)2DC=2//#0>QJGIZfowп}u_`]TF?UHFMKAE?AE:9UH<5>G7=>-'#+2213/*9A?/>45@0QZKQkm{ǽwra\PDAJTSTENH>2N53C>2$/354/473N;628C6PeaTeq}ļ{nmcVIMPHR]>PD9V55./-.16030/138:H<7.E\mVfvxĿ¹ǽƻxmmULMYEXXGDF>?/-1&0):4-24&4GFW?&?UNcfxǿƱxlYVc`ARL@><8363-.:-8220%CRL`A=@;Oi{ľǼ{n\i_AAL?7>70211/-A-70.+=AC1C07Jk|ýþüwnok;;;?8/=7,-/1"?5//--113*99FauĺsnmV8E=492K(/12'-612093+*-:;Ofzǿüzycb@IW3D*@A)1-0(2139U9$10<0+10/0,NT9&<>ABTl½¼¿qfcSB?I3'*@00/.5-13QA=6HDBBYnüra`WLJK>.#7? *06-/5F>ABMBKBUnĻb^[LFLE7+&H(%)501@N9>?NJ>Ebp}ĽiZ[EDGK52"70".//4KD305ONAO`k{q^N??&&+8-:0.(56@7SRKUhtiTMUC/C'/$C+4./*C?7ESZZ^f}~zrx|~rQLY[=-11'B/51*.KFDHWV]gp{ops}uuqKOXSP0-;(;?400*G;B9GL]gy~~xv~oVAVZJ,7;,61=.-*6;119T[gyuustx|uU?QNG+=00-)51/-9A&=/JUMTŲxrmuxtgqvpvKP3C-+F11-&010W5K::20>846/",-.=J>@2bT-|tIV&MaCecj~ɯ~eoxjbWfHwZRoEB,9;>?7:(+/.>D=:.eW*|xZKI-`-.0-H;7A2KZ+p[yOY/L\O|}oepϱz|pl}{{~mmylJ4:8161L./-+?2)O/=Z-rLo]MSU\j|}o}Ͳv}Y2;5:8/R2,-,?01K0;a6kpqn]m˵OC2?8@0D9--,22HZ8;ZF{~sxx{ŷTE3B;=89@)0+/2>h67HTȶhM9HCE35W(1.-1,\=2EhϿ"((%'(&((')+0(,*-.+1!E,#)''(&%'%'&/+.**-).*,%-(&&*$&)&$-1+*,)+',/ '((''%%(#'#0+*&/,()*&O%'('%&'#+!'&*0+(,)',(&-$}%()%%&$'#&*/++)+)')(,)|($))&'%$(%%$.)*+*+'+**+$?{|'%(.%')&%%%$*((,)))*-)*'¿{},"'+$*'*#'%$+-%,*%(('(*&D¼~z1 *$(%('$("'.)()((&+%')'.ƿ|}:&&'#&#$$"%,()*'*&*('(')%;ý~~~:&&&#%#&##"/())&*%)+&'&)*pŽ{~<&%%%$#&##%+)*)(+%)&(($)'*!|~F%%%$(#&'!&,)')*(*(((&'')+Ax}W(&$(%#&$%$+*&+''(''$)&%)'*rz~X)")$""$#( *)-((+('''&*'*$+`|e&'&'&#$(!+/+())*(&*&,'(*)"D{~p*($%&##!$&-2,'+),&+&+))',+$0z"&$$'#"&$"0)-')(*('('',((*&%{}{#$%#$'"#$%,.*(*&*'%)%'((*+#~y!&%"#'#%##-+))''+(('&&)&'*&|zz)%&$&%%$&--'*&'(%,%%&+&*(&ɼ}|w{8'#%$$%%$%/-**+())))&(/&+((z}|u{}?#####%&%#*,,(+&('$,$)((+*(t{vy|<$&"$$&"&"+,,)')*&)+&'&))*'jzx{~<#%!%'$$%#-,-+*)-$,)*)(*()*g{{~@'#"$%#%'!.)/,,,,)((((*)*(-]}D"#"$"'#%& ================================================ FILE: contrib/att_faces/s2/1.pgm ================================================ P5 92 112 255 ~||{|{{uuruozttyqj[e^MNGI=7*4:AC<>DMUTOE>DFINMVLXW[X\WTGJVQIEGB=?Ugmsxsz{xzzzz}w{zywyyyvwypuorpuuwvsrsma]ZVF>7-,(-18=::;9DMLD=9@BEKFIFHPPVTWLHEIKFCCC=?P]kqvtwzyyx|zyywxzx~||tqmlrxwvuoqrkigd\YRQD4%$)%&58:B?>763*):<4>CH?BB;FDCAEEHNJKUMKGAAA5?QWepnus|zywwyvzyw{~~~{|wrpppwwrpojkgb_\ZYQJH=.,%$$*<8::@A<52(+57;>D>?@;;??<=9@@EFLKJIGECB5==?EKXUYdnqt|u~}z}~{{|{{|z{rupgbeUTYYXWRNEDCD?:93515<7A;=810//$0*.)---+14315<<=E=F??GLJJG@=>9@LZ^]\dkruw~}|{}|{wyy}{}zwmjaXYTRUWVTSNHFKDBBA=>87<@>9:6321-)/-+'&*.*2-2/.37<=EBC@>FMIIK>884BGUfij`gqp|~{|{|zvwv|z{zuuie_TYYXWW[UUOLIPMJJKKGCH@F?@68111-//1+0).3*-723,41/<;AHDJRWTKP;<:C:6@S[iaez{tyrurtuturog__[[RKKQS_ft|}xocxyp~vtw|kdYNFCB;6*+)43+/,4053>;9@P^amu}vq`UNQOF>D?67=5271-3,32:105;?BINKPQLNMHLHEID=67KDDprpuvwwvhkgd^XOC94NZ`nzwtiXXTWPMEEB;>;>=>22/6237(0726@EGCGFEGGLGFGAC@4>G8loxztyojc`^XSJ@:1ETZo¼yyq`^]V^WEKCB?B>GEA22/4232,9743/31-7/0.;5).8HE?HH=781*760680,$01;>?>>DIKIBFH??84./438-+&**/4;;;9<>-+,&'*+69495;:;=85/3hhaSOLB=98922-$Nlĸuju~sxioka`ZOMH;8-.7<6(*4''+/713389>>5,*)kdTPIA<942<4/*6e¾~qsom{qjmk`\VNFB@FJRSEEB@949/2?;.$31)'*/10568=@70((bVLD90../-33).Rodcmhffe]ZPMECBGRUMFCA=824+5?6*(3,'-,--196:A?10/XIA41*-%*//++Cruf^]]`^]ULKJHCDKKPI;B?:80'/<:-*(2)0,,*,39:?@:2-HC://,(.2/-+3a|mb^[[_YXTWKQHGEHJ>@@@:/0'973.&-.-,3)+.4+*37)+I>50'*(-64)+Iw|rlh]ZSUYVWWVOKJOE?CE:5223B310).,+/3)*/,!%2-0G91/&%*35/(9ZƿyyreTQOPPW[RSOUTLDID;<73?=0.0(0&*0.-00%$,64C56*((-32&,@;68=1,3-*)(/,.)81)2D;MC8.*0133.'Vxÿ{wukYRKFGILKEJIPQM?9>99>9($-0*&)*(+2/0.=?QC7203-1./0h}wnj[VKGAEAE>DEFNH>7538?2&!-'.*-.0/+!,9HHH>8;8857,,)(.$!**% !TB:6/22-$)hûý}rh`WRE@D?;;>9ICB>A@><7841)*$'KB735:6'8vùƾrn\]QD=C<;:8?<=;9<><=8==9>8DCB>50.0%#"@=477,&c~~}{¿wsd`URH?9==:>6;A=BC;@A:8:<@BA;262/A97:,-"u{oa^YTPJG@;>9CC?:=9;?>@AB;<;8A<=613+$ !@8<4/&!'}þſsjYW[UUURQOQUNQQH;6766>=GC@=:<=<551*(!)<><20& 7»~~vmihhkhonsuusqkl_W??;81:?DA>?<8B57:1$&*D?61-"$ I¿}yzuxzxvw~}y{xtmfVOC>9488B?@=>@;78:0$,I8:)-"!]~~{|wyzxxw{||{vxtspic_SJC>;97;@==B;;8=;,0A;42*$pzxý|z{y|xyssqpnrnoplqkmlhgbWMH>>=9<><@::>:B85?@0/3"rmkifvwwv}ƾyxvzxyuplffghjfg]^Z_ghgkd]VK?556785=:57590!#&,2*44/-/95)5,%ʸNC5?GmxujqǾohowvtqokubQ?423NP:8>CM``^^]LD:%#',0-417+5///,:[QLIaw~{|ƺulyskiu[>=33*LhS;-=CY_\\]VI?(***//7438,13-Uǿ}u~rrQ5;662SlgF7,:QU_[aXMF*+$(-14/4/2+3!h¶|ʾlFA@6D]lgH@5?DW^ac[WE/)'"),./231.3 vƾ}}z˺e_TRXdc[G;AEOP^`i`ZI2!#("#/0*23/33&}ɷ|}nmmjac\NDAHMWV[dkdZL7#(&./..0//3(Ƴ}zsrlnhfc[XVY]]]`ipl_N7"&')06,+7,10ĭ}zxtvrollfjhbebjnrqfT9$#''#'2&*1010̾~}yyywsvqqoljnmuxwnT='"&(%)*&(.3.2ȼ~{y~x{}z|ytvxyzu[=.%'+&'*&%/222ɷ~ub:-'((()&)*"332,%vøxdD')%*'&'',$122. hķxhH,%))&'$.)122," ZúynF-$%&& "+'1/0.& L¿|nI) *'&!(%31/.) ?ƻ}jG(&,$ ")!4/0-- 0ƾû|j=$#*%#!&0+6.%#½ÿy[9$)($ & -.21'ƿĿwS,!!() ("%)/,0)žmH,$+%")$$/,2.( n½óý~}y]C/#$&%!")"'/0,*#aľɺrelpX?0#%$&#)$ +01*)$WŨs`SLpymX@."$'"!&#"-/2+&(R̿~phZS`y}zkTA&#,#"""")4*5)'+R¼Ǻ{wpofdk{~wjN7+&(%#(#,1.2')& Hÿyzyouv~r`J5.!&!%+)'""31/(''<ƾ{n^B3)&#)+(#''32.,%%7¾ʿvkZA0$) +(%%%%=22,&&/îzshWC-'&+%")!89/-*#,ƷxpbU?1&"$&#)!!<:2+, }znbV?0"#!&$&(9@20%&ž~zk^T?-!%"$% &<<1-$'xĿ~vy{}to]P@/% '#''>>.&&%"fû~xwrrnoprrs}zsk_Q=("!+((*@8-"$#& S»yokeyvrtqwqmlkfdlmsyyrl_L:+' !+.,?7*"""$9ȿcN>Htwrlfe_bfhxzxsj`Q2##&$+3->5)$")mOF~Ǻoo`]VXX]lzoicK/%)$:.=5"" !tȮltźv|q]VG96Rt}{ii^F("!# '"4.53%% RôkpjSE?/7Nx}tmeV@% !'!/.:&&! ')Ⱦ}rpwdY_OFLVdtypl`M5""  !223$%!!!iwwtrcfebdsypgZB-#  66.%'"$$" =ý|sqopv|umbQ9$"!!"2=0$. !!$ yž}yvu}}yqg[E+'!"!!2?-/) #*Büz}z||}{yxkcH7#!'"&$!38/0'$#")$w|wwx~}|{wrhX@(#!!!! #'#!39-/$ "",%B|uussv{}}|zsl^L2 & #!!#+$ 6:.(' !$!*% sſyvvswwy}|yxleJ>##&%$#+$$,0;1'%%!&'% 0~|wqcVA+#% &"('&%"-371. "$$-#LĽ}xqfZD2")&%,)&"+ .8023"'&*& pzwsh]F3* *&".(# ,%*4,*;)$ %(/$z¿~{wphZI81&&.#!&&)&$&,++(,00'%/.# 5¼~}ytohXJ530+*,#!#%&)#$&*,(,'1(&1/%g¿}{vumdYE@031),/  !")%%$!$)*(/",/*+3  Ysý~zxqojbOH=;233,..#!# !($$#) !+()(+*!&+0%Snz¾~wwpnifXNFB>:440/2)'%&'&$"&&"&(-&* !%&),!!Oow|}wuqmif\XHGAC;9910.0+,(& %&!!!"+&$* '#+'(Hoyzzspoi`]XQKDFGD>9:51/*20%#(#"# &('.''!%!')%( Bix{~}{vnkf`[URMJKEIBC@;:43+303&&"#$" ')-*)#%#.%(%' 7hv{~|}vqjdbWZNRNLHKIGCC@=:14100-(#$(," $ +11&'!()+'(%! %2cu||}}zxqli^[YRXNQNLLJHHCB@;6830-(&%!)!&,-('# #(5/+,"+&/*%%!## ,]ry}|}|~{{z{wyuxz}{yyyuvqtmgf`\XVUSXOUNOKMIHCD@8;632-" #$+(/:((+' &./.0)((++')%&( $#Ylz|~{}}}yywurposqpmmmhlfc]^ZX[X[XWUUNLMLJEIG<8967-/!!$!()1,36'*-",-0.,+*)0,*+&&'% "Slx}}}~wxtnojlggfaf]`^_[^]__]YWVPRNMJIFE?6:;5--#"!)%%((.2,/2(1)4.0,.*1--.&)$'##Ofs{}}~}yxrojjgbdc_bfabbaa`_YXWUNQMILGF?9@76-,$"&!&!"(./..7"+30 ================================================ FILE: contrib/att_faces/s2/2.pgm ================================================ P5 92 112 255 ~~~x{xuopnputvwnrnj]Y[LLDA6)'0-8?B?AINVUHI;BEFDFLITTVWNQBHLFA>??Mcgiqvyvxywyx{y{z{tzw|vzwwolqpvtstqtsnjff[UPSG=7-"!.&-2;;<:=DEGC?:?A=AA>BGHJMNIHBEED><=BV^gnvvvx{xyxzxzyvyw|xuw~}|xqlpovxysrplpdgg^WJIF?:4#')57AAB=6;<:5;<<@>?<=<:>ADEGDKFEFI<=9>FW[glsrzvzwxywzxzxyzxw|~zzyvppqwzuplkhe``ZTOGKCA=)!#(6:G<<::@<<==BEKJPJFA;<8BMVejqsx{vuvxvu{y{v{~{yyxuttuwtuliga__RQNTQJGDB4*+#%&2@6:=@;92)/)56:HUR[\eluywu{xwwv~}~zxz{|yvuvqhg]_KOGPSWUULKE>@6;5,3589;76<14/62-.+0+*0..130276<>=A=>AJNGGB@BQT]\`imvuyxwxx}}|yxzz{zz~|pheWXMNPLQUWVYPIBD?@;;65348<9<96412,),))'(2,(303236;=?<=<=HLKC=;?M\hhaenrrxwvw~~zz~zyw{y|yzkdUWLPQQSERKXYVVGHHD@C??976>?893630/-+*+& .,.,300)174?OGQ>:69H]lmeeotuxwx{}~x}xywyyxwylg\YXX\ZQSJTV^`[]WOUGNMPOJGKAB>775/-..2+.+&'/,0.44,,2*6>>?:<68Naaafopuvzwxvvurtvupnd_WWWSULNSU^fks}}xtjengkqmmhnhZQID;::/)'160*/.//:0645<@?:6;7:RPXcmppvtuqqqvwpna`^\TOE>AP^gl{q~vzti^THMCE;90-33+06)/,-48765A?GFOIKNNOLFGGJC9?779D?1./+1+,'38(35B>?@>700M\gvm{ukdccYXWCEAB5@A;D;00/&-..&9-,*77><<9;BFE=>A3/69=ojf`WUNQELC<3,/;Wjwļts}~shchbZYLBC?>@@>>B=622(,.19).'%&-74;77=86:81.23haSNIB;?7616./4WoŻvlq}rohfg`XXPC?=:BIJ>B@A=60%)5;+*/#'(0454489;49/*.0dVREF:=2.1<5/5Blźxhbm{tnocbf]WTJBBKNJ?A>;2**/7:-'*-"/-)/56:<>5+.-.L@42,($(,1.09U~qbWca`[XWNIE>8<@KQH?@<8',,,:4+$.,)-%.(88::=2+:6@551'*'/1/,5Jq|c]WTXSPRBB@A=?CHM9>::13()52.%+-'**,(322576)25=23)&&'75.1GGG:=756(,18*1&.)*-,-(4%#+2*/;65.$%#.73-6IqûrneVRLNMMSLPJGINA<;<61,*>512$*,(*,0,*(224986,)%)41,1;T|¼wxlhVFJGJPNSQJTPJCC>=853=4-1"*)((.53#//?6?@9/++0.2.4DdzsolULHDFHNQOPQJNG?<<:699#.,)(&+*,./)4<=;B810/1*3/5QtytnhZLK;F@EDACEIII9?566@. *,),(,)/(&)8=5?>372,1/3;d¼ytnfZOHDA@99:JF=33.9<.!*&*&'1/+$ +36F?81,),1,Jx{tpcXRKF=>986=:9EG:504790()&2$",&##%4DA8.513-)Vþvme^PRA?:;7699BEA8;46946/0*%""!3C>62980$(nĻÿ{sh`YPH9;863<6??=:;=?;853-+" $A74651& :zƿÿtja\VB887486697658;;>533.($  @6162+$J}zyreXVJ=6:59:88947737:=9630(,'!,=477,'Zusmruxww|mfXKAC<9666;88=664=687;??862)&'%3:79/0!!h½|vxyxuux{sk`[RMB<==>>56598<=79<5748??@54,$%*+;;70'$*xý}z}xi_VOLLFA<7<@D?<354267;;>>59:98:4/&'-1@=5-(:½}pcWSOTSSNJOLTKPN>:=.3.48<<=:2:;594,%-0B>2-& O}vwtiifhgfkjpsqlmggYLD;33/33<>878<4692/(/@=.2$a||vxvsspuqptuxxuwtqnf]UM??74073C:9;73483/.A7.2$oxvĻ~xwuttqqsroqsvwurvlki`^XMG:>;85;8<98:5::60<4//!¿z}tqyƿ{squqtpomjikhjmihhgidde`ZQB38=9:47<8836:=8;.002øygdTZ[_ltomv|·~rppprpmia`kelmkge[TWbcc^YXI;)1)02/598020897-//# K¼wr_UE6<:_apnjr{{Ÿxninmlj^eiophkgedb_TKJXa[YWND/,##*+.52//,*52,2.\žtiphJ9237cjghoqwɹuhgljhcehpgZUCHEDOLOFDBW\WUUJ>.$)).-05.**.21+!r¸~x~pF?:7Kr{pgmzǸqcglngjhcpgNB;71,:I7><=JZYTXOD6 %&&).,224(/-5,2ƾ~WLEAe|yrsDzvblqtkb^i~W643.(7\L208@RXTVUJ;  )&!-(/35/*.2.&,%)!+..3,'_żxk>$,+ '%"%.3/) Ožxe;%*"#'$#,0.& Jÿx^/!(,##(+4-(! ?¹uU(('&$ '.2,&$4ĻpF'!#%+$!00/(,ü`;'*##+$!"21/$"'ó|}pX9'!&&"(#'#-3/)!+{ó|{fe}{jO8&& #"%%(+1+)$0vɸzzjNEhufI0 $'! "((,,.,%#pƴphXO`w~|r_>+%$& $*(&,(0(%'b|rpggfwymS:'$#!/+$%!&.,/*&&!Pƿ}|usot{}}tgK5%'")-)%!)*...&%# Fõ~~|{o`I1#$ ((#%%$'--/)(&$0¾ʲ{viXG.#"#, '!&&)3.*) %(ƵzqdWB1! ''#$+*70#)!$į~zp`T>-!!"#%$&+(:*#'$!yðup[O?)#")!$(($:,%#&#j~uh_J@ !$")%,#"5,!"& Rþ}pfZL4$#%,-+$5)"%#! 3żspns{|zpdYH1 )$%8+!1! &ƿr||sjdbefdgituyyjbXD+$ &#:3-" ' jžwwywuoi`addf^b\cafgtyuiaUA)% %!42&'$ !#  FǿpiihgaYY\\Y]ZYYXURY_s|qg]P=#"!/-)'"!!!Ľwnlcc`^dce`\ZVOQT_l}zqcXG/!! "*0*'$$ #Zytogcfgv{}|ykaTA$$ 40'+'%! "'ù|wrpmqqwytf\K2$! 360&% #_Ļ}yrwuyvxy}wneR>"($ $19)*$$&$Ÿ}xuu}{}v}}xrj\J1!#$ "$"$1;$-! &Qyxxsuryxz||zqrdT: $ %)$/9 '!""")# u¼ytsurxvx}}yvph\D( "!""%''"(.9!&$"#!)" 5¿{|}~~yyrleM4%$#&()"#+1.#$' "%#( v}|yzuqgV9*' ")&($%$.5'%"* #"%")N~}{|zxtpj[D,"&)+'&(*,8!$'(##'($Fh¿|}{yywsri`G1$#!!!&')!)%*01 #'1%%)('>dryzu{ttqjbL9%#%% ($($)%),(!%&4* $'/$ ;fmy|wxvunthdM>)(&#%"""%(&$%))+%"+.  *.$1hrtv¾wvptnph`P:2**''&%"'!'$$"%,*$"%+$*/% 2cywuy~vsonpkg[M;32))(+!! %%"&&##*)' "$*#)+(-^uzxvvpnihiaXH?:24(/%('# ($% #&#**"#"%#)&*#\s}zsyqifgb[OKA;930,,%*+$$%#$#! '()#& $('&%!Xr}ytyynj__]UNF?D<:51.)').(%%!!! )'' #" %$&(&%#Lsvxvy~wmf`[UREIDCB=<6-.)*-)$%!"!(!&((%"'(#&)(&(#" %#Ily~zyu~ysi^\WTNJJIHBC>730..-* $!$# &+%#$!*,+"+'"$%')%%!&!@jyzyx}~|z~}~z|{zxwuskb]WSTLOKKFHF@;;032.((&($/1(!&$)00!/)*$'*&&)&& &;bv~~|z~yuxtpwpvsvsrormmla_[WTVUPOPILFD@@8341/'% !.*+/4+,*"&*.2*0,*''.(&)()#" 6ar|||ytsppjmkjkkdfb`^ZZXXYXWURILLDFA@7523.)!!(+&$.00,. $,(*8.0+-'*/-'.&)#  /Yly~~z|rspihhfdb`_b\_Y_\^ZZQQLMKEDH=9534/)# #&$ %//,0/0.+'7236,)(21*+'&&! (Zgr~xzsplijfgahdcccba__[TQOLKGJEC9971.+& "#$00(0,%35()//973*/02.)&'#% $Ufoz~|xvtkmjkijjihee`_[YUPOMKHKCB>7<5/)$!%%,4///&01*)+->93,0391(%$'%! &Nfsv{|wvpomllmimhhce\]UXRPQJLLDA=9?6/+#!'$.19-0).-),)'9:71/99:'(!)'  Gcsxv}~~|zwrqlnnmmjhhd_]]WVRNPMNGDA?@>82($(%#,:8/)7+1-)(# ================================================ FILE: contrib/att_faces/s2/4.pgm ================================================ P5 92 112 255 }}}pkinjkigkjja^YUPWY[\URMKKQ<;831-().9FLWSUQOPL??73::;@BCCJT^ijjqwltwvzwxwyxuuuuxuvwutqssv}|{wqhiiebaie^YPTTWQYUMFJB>A?6+*'$%'(&'-9=DGGIFIGB87/5849>>=55&$"!',/+!-98:?BBB<;455554575@>;BPV_\fijquqyvvwwxutzuvryuutws{yxpsnod_\[VMPOPORPUJJF?A=@;//+## '18>)!(49EGAA<<562,4417534;99AEQX]gbgtotuvuyqyryrutwvsuru~}xxmogmfXPKMG@KJKQPNNED@=9:900.1),*.@AA)#+)39@<=:.0.3%0721440676;?IKVZ_goiqtvssvqvutuuwussr|zwvrgjfXLHQMROQTWXRRQMF;;688;507/(3,9GTWafbjnrrtttuvxqvwtuy}stq`OD=AFIMQX^\WSOPHIBH:>?>>@::3,2D@BNZ^c_XZXPKKHE??==8;?AAA@:=FOHUUX=<86442-/908//1..-,''-,3/6235:59AIQUdpsrutvvsqurvszrneSG;<:99-1740112,.+*(#)&)-/.05:8?BHMVbkpssvuvurwssvqkXH?DOOTZ\UXZYZWVPOHGCJKLOUXYTb]b^aeng^X\MDHBKDG;455400/-.+,)'$%%,$//*16;PVgkrzoe[eglmd^\YSG;::5:*,).((*)$%0+/-447::>@@N[^innrqrUILKKPMNNR\aXUHB984>HXcoy~dcYZnsg]]X[RG8A9:83%-("1-%!%#/'-23479;9/+*++;*% !)-+2-*97A>ENVQR^dnF?EEKMRQVQKF>4479=DR\ly¿wecTXjpc^eRPFCB<;794+/*092&#'&,0.$029?6CNOXTTJGFHGPPUOPH>8983>MUfmĽ|ibZa[[\XUJHIDA977.803+43($","+/$%/471AJJLGCKJKLOEA:4.-067<>FV_mng`ZXNZTNLKHD;=5216/3.63$#$,&1(&(1338=CA=CIMLLEA5/),/166=HV]e¿wgZTLQMLOGGF?<777/515.44+%#+03-)(0/:A=@=5OHIE94*)(&/56AJT]h{ÿmaMILGCIEEB;8651+;/8012.,')243!++/58CII;EI>5-)&#()49:CR^izgUL@B@ACCA@564.439:116/#(*44'','039KE=?;8,'"%$(.17=O]k}ÿ¸nhXJ?<>BDC>6:/3085:123(#&-9/.&,&2.A?3:62&"$'*32;4)*&$/)/8DUhnĿ{k`c_KB;:562776;??E;;73.8.%+.0/1;=45+-'$&5>H]htľ~kek_OA?73.3258:=CDE<::64+//(-,2A<40-*$0:FOapzvde`PE@2.+*1/39==B;=<;43(*+&),D;85()(38GVo½qh`\RF:1(*,/).62:866;794,%('/E=9/*+.1?Icth_[QF;3.*+*),-.55.77:22(&"(F@4/,089:Qt¾xka[OK>6.*(.'%-.36-5;08.(#&FA2-310/Dfod[XK?//&+)*$-411.:773++!D:6.0-,6Suɾvf]WPB4-&*-'&+.)/.78554)D;510&->aúzumopotwtzslbSOB6)&($(&,+1),7.-13D=43-)0Hlſsgd\fajpglqxu~updTE@?1(#%*&&(/)/+0,--I9:6)%6VxúvlfbgjiilhmozukbPD6/52+'(!&)"*)0((./'@<;5&(?dżz{oowqjpln{~tgYLD?72)-002"'!&&&(*-.+/*C:;2$,Nmv~zxwwwy}zrfQI?>981)-/09+&$'!"')&,,..F?7/"1Wvľ}|~}uomg_KJFEGCFABD=C?.(&% '&+#/,/EF6/&6hýzxtpursptwx{{yqihf`]^[\[]aa]_\ZTD25#'$)+-+L?9+)Eozlh^iuw}~wjlegfeggcdafgbbb`[OB9('$+&1)G@4",QxüqogYdov|w~{pkiehaeda`]]^][^Y\XUHD,#%(,-D>/#1^|wk_[YZY]Zbmuswyrjfbehe_]UTQUNNKJITXRNI2!#$+C9,(>e¾|fA8?7KK\Vdnrsw}þmebafb_TUZVUWPJIA6>PLHH4"'?8%-Ilv}h<.3'=KP\^gqty}ĺ}i]b]_ZXW]`]REB<734.:GGI."!:6*,Mq¾x^4,(*>\QXdlrz}Ⱦzb^]\Y\[Z[gbK0*%'/*'(?CI5$72..]yd>/4/Ta\Qktè}ccba]^Ycp`3%!(7"'5@F5!%#86)<_{ÿuJ:>EbiiivƮdkmfWZex[*$#&=,0<=5')54*AeĿmedknw|ǵilpd`^hzc.*& 0:0#-:A2 %25)Ek{}phmmluxqlomnhikvm>!)*;9-16BC3&321Erýzzrmoppu{ŤzopnllmhhmpgSFIH7 !22)Lv¼~wuqwy~Ƭsupojkmhgd`ZOIC>84?EIP801$LwÿƲwz}uslkmifd^ZQQGFIFKSSA 2/&NzĿȶw}}rqipjiic^_VZVSVYQM"6/"Kz¿ȷw{uqrlmiheebbbW`[[P' "!8''G|ɻy|zvtsoklhlmijfdaT0 ! %4(%Nw{~xyswvxyvqpdZ3 !"-))Krƿ|}zxm_:0'/Ktz{~qc>!#"2&1Opyve>$%3'5Pow}zk?"$2-3Pnº¾y~l:!"!0/3Pm¾¾y{j9"!1+;Okſzxg0" #/,:Niý|xzX+ !(314Lkÿ|v{qM !!*82-IgĿxswy{iA%#;9.Egvotymnu||y\,&!"5;-;d¿yz|ug`nu{|y|nL##*33&1aÿ}tgZgry~y{vh7'!%)0 '[|½Ż|rn_cp~}|{y~zpZ% ##(',#Twx{qnhmv|z{~~~xj?&)+%Duÿ{zyutxy~~~{}ws[. #%)' 1n¾}{}~|~~~qoI" ,%]}~}}vqc0'&" F~ytnS $'" 0wÿÿ}~}wri>% &f½u{|}~}|{rq\- *%"J{wxvvytjjeikit}}}z}yyznnN #$!3s{owtqttqlbfcc^\\]\ZX^hu{|~~|z~yvnf= #!  !'_»{cWW\giagntnuy~rhdghe[`XSKPNUdow~z~}urn_-! !#EkPHCZe^h~{~sng[R?DGGLao}}|{tqjO " ##9h»ioswjq}yvpaS;+/69Wk}}{rnc?!'4S|~yynaSA2%-8GZp{~~vth_)*6Ag}xpipmecRTLGJMTeqv|}~|rmhG#-5C[sÿ¿x|ytsgjfe``fuxz{uql_5 "*6GSe|¿{umhafpx~}{}}ysliN## '.8DWbk|pfbekr~{z}{sph]4%!(,BEZcen~y{wrvvtslbaefpy{|xvtlkbI !! #' -EJVegkr}wtrtpropki``bgms|}zuxxtqhjU5""(!!$# /EOVchiit}sqnkkjfecb^bhmrwy|ttrwpjhaC "+ '%".ISUeekjiw{{rqmljgkijjjqntwyzttsrkidO' #$* !,$"1HU\bdjllju|{zvrtqnrrqrqvrwzwxtsmkhS0)#$)/$ -DY[bdjnmkjwľ{{xyyyyyxzzyzyzxqrif\6   %" -)'-CZ`bgijnmkit}zxqlh[=$$#(%'$#(ETcakiknnkifszxkf`G$# #"&'"",?Uaggmjonkjihpysf^E#  !!%& %$*$%-:U`gkmnpmniihgox¿}ug\D#$"&$& $ "-#%:P`iisoqpnljljgjt|wj[D(%%$" % ")- 7J_hoptsqrommjigknyyoZD. (#"!$#)*#8G\hnntuxtsolmjjjhpszzqZ>2'&"$ !$ )+($!6EZfmpswx{vqrqppmmklpvx}~xuoZC2+! %"$ !"/$%$9ESfnotyy|xwvstnqpnnpossv}~|xrumjVE73(!!!''$ ( ! (,'%&8FQ`opruy|zz|wwrrsqqrqtlnsuz||xzyrxsvy{vvrnoie`VB<72)!!$%(! %+  #-') %:EN]joqvv|{|~ytrvqvuvrsqmnoptvzu{qsnshpljlmokjifbaUND@89/, "# %"% )%$/'+!/4DO\cnptt}{{}{wtsuswyxwtrnknlkoljjgcfa_d``_c[][VTLKE>:6/( #  "$%  #+&/*%% (:DOVaiorvzxz}|~{wvtvxx|z{upqmmjfheda^`[[[TYTX[U[RPNED@98/'&$  "$%$"!,+0,#!)5FKW]cnrsvyy{}{{vvswv|}{ywqqqljicc_`]Z[VWXYY^\UTMMJCC;35"##+# $!%!"$!%*$$/+) )0IKX[^irpxtzx}z}{uswuz{{|yuuqnjkdec``Y_[[[]_[YYQPJJH@@72#$$,)%(!$*$('- ================================================ FILE: contrib/att_faces/s3/1.pgm ================================================ P5 92 112 255 gihligjmnkimjojmopplaZVmssiiad_[]i_[WR]qcW_w}`Zdhikfgb^ZVU``YWF8773?D^hmmomqkmqonjnmojpklokjfjkhigkkkjgnjokmmokZHHLbmrmp^j]_biccYeke^[btwaUX[chpejougaXFF9,14'%4HbipinpjqjpmmnlpnmnknjjgjhjhiilghklkkllnsbVT`dfpnpfknetwwghljo{t_[`a]RPPD2589766/- %'5OYecklgfgjmnohlmmlljokfkekhkjikkollnmj^J5>Vdeltsj{u|{pb_^nopkc][\RNE=7<4124:96-,($Kbb[himhchhhojmmonjjlhghiilhnkjpmo`a`eVG9DV`bcnsbrjO[Shb_iYUUTSLAF=B5@:?;0>2%%;^g^WVW^Y\UYailhonhpjgihghkhikkopg`ORMNLD[]`Z`guu}~ri[YZidWa_UMI:9==>:=>583F@3-0KRcQC8HNU[WajmilimklghhhkjgjikpmXKFHCJPa]cbW^n~xz{||l^QW_`YYbYJ?7:38=@HBGQMC>>2EOfZE3;8Lf`bfmjknknijclhhmgkilm`RHE=38/:HLRJE><:.842<;A<7-26,EhdVH76KD^blelgohjnjgjjmkljlikimUQBEOIIZVZe_m|snqjf_eloyyzshcWSRTUZRXD73:452=71;:\daOC;FNMSdijkllnjoifigjhlmegbj^ZSUM_LDMKOffiv~~{tqb`TXYcgnsx~vusi]TLKRU\[D3<490421IaYYQLDOTUSbgmkjnrmmmgggdejgg_f_[ZORN^TN@DIddfhoquvzqnmmgebVKLHLT_fmpomooogWQIMX\RB;<5<9:HWFJNTNCKUVfkljodrillhgg[XWVU]S^VM:XP[aMG7ATi]bZcjnrz{vjl^_X[TNHGEMR[ae`]`]`]\[XZVSLFGE;CF@5;IP>=FSW^ihlkiommldgRONHBGMIWEC+XT]XMO5??RVU\]_`Yghrqwvtdb]Y[TTMHFBBBINTPQQSTSSKLJKIIGKIDH7,5@LB@S[]`dkkmilllkkfKELLCAIFHGB3KP\UIRKB?8DKU[dbZW[QXVabW]]YRPJJFKAA@DDLCMGGPOKFIJLMOMR[UOC1,9C@4?RbbddkojllkikaE=9JPOCH@DFABDENF[YOOA@ALU`Xb[bVVPQSFKKJEEGGFKHKUMPGLLLKQUSXW^c^fbggodWI74A:42>UjhjfnolhlmiU?682GJNJNACIQC=@;ISWVWA5?BTPXS\ZWTLJFEBJ=DFAFGHJPKGQMTPSYajhnsyywzyvwxe\I<6:131=JbkfgjlglkjZ6:7$1*59:=9:KF;?E?JWKSIAE1GCRNOWW[WVQVKLNGNJUTPOHMX[Zdafiq|~|~yi`G5@(+135AZjgghgiijW93/*)-83=669A@5:ZjghljiaY3,,//.222<:6AF<9,8:?JUXZSMPMNHMMZY]Vd]hehfjnptqstqsw{ze[B/"$(5?8EUihdkh\F5&&+(!-?PMHAAGK;6683:HMMRYV]\UY^cclipqqmomqwvfY/(!%48@5KXhdfjH2)"#EdlaYTVUUQG><>97:>JMagjloiolz{qgM)%*'2=>;SYlek:"EYehfltnc_ZYUIDEIOYfpv|{pj=&-*-:8=8Qcif!8T_ihw|wsurioszt]2'&/76<7ARhf/EIdcgx~xqI/'-/6198BSi!&;.0:*(")0.-24>P[[jn}yrbL89157" -*(/1BJFUZalwĿyoaO77-&;-2-(.,76;CNT]huý~vk_T<5,,2*)#/.09?9EPWhxļ{uk`J=90(!3#)%+'+/6:9>MWis{sn_K;10,"**)%'+123.:K\auzypk[N85,1%.!'"(*(.-,*/%) &"+%! -#" /Icv|phkU@* #$$'%"$)1&*-Hh|rjjZ>$ '!")50#*(0Ki|omg^?'%"!% (-(2(7Ao~|w|vuvy|qmg[;$ $!! +*260Cs}|z|zuic]`]X\_imx~{urqostvw}w~pki\0&#' !!2-9,8{}olejqkjfcYUVULRQRYhfty}vmng^\YW[\_dnrrz}ywvlhnV0!/""!0/2%Cy}yspsprtxqtohheYVUUU_^imvxsce]YOMHHCLNP\fgmpfba`bjW( #+&).3)O{x~vrkiecb]b^]iqrh\\VSTJNNKOQPRZ\^_\Y^W_jF#!'"! &(4.)Y|v||zvlgcfdidg\bctzg_ZZ^Z^V^`chjigbc^\\`Y[U`D"%*)*'('9!+`}t|vvsg`S_ffibcequ`]Zdcgbfcgjnw}{yvkgiiYWa=!!*,7724#09%-muefm|}|tqg^XY^VVVaccaesp\[_ffb[``hijmnny~wsnmd]`? /=:BHF>6/@*7}t]Y_dhi]U=6/-7R]QO\c_`jvhY]_`W_^]dfpo{si_eowoimhebA!#4N[AJIRLN'?2C}smlkmrvfYC5#.?^cSOTbeftk`^WXOZbZI@BIVcii`Ucilmioe;/'?[aRUSUSQ64-Pt`UESWoi_ZYkyxrs]YLT`u`=,$!(8WYaSReloqqj="!&$(G=Jb_ded^YS761Qu{{}ÿ{ug[YZjyiE( *#;LNVWOdpoorl>&*8-=TTVbblspdYR792WĿ|}umkpyr^LB1PaX\dew~yhVU696c~||~vwv{}|uupntponpjgeqorm=;_P6d\\[ad~}qTI8CIjy}yzy}~z~|{vs{}zvruxrjOaqPQeiUcaalT9?gbs~¾z~}zzrtvtuuzy|y{|rxiZmtN_i`bacdx]1_|{z{ƾž{x~xulrnps|{}~{zvk_pvXfg__aael5y}vxýźvxwxxsx}{x~ztndqzahY[bdcfzOx{Ƽw||z}to`yvne[bgcgaw|~yĿ½xz~~ywjcy}md^ef_earky|y¿y}|xydcwjccbeed`{wzyyŽv~wunnyzh^dcfce`v}x{{¼ż~wz}urp}uvdZeaecd_X|{u}¿ĺ}vst|umrsoqcY\eccd^Lp{xz|wyjq{vlottu[Zdae`fc>T~{}z}snymksvtpy~vm]`ccccbbQ6j~|{zz{n`g}ee{zlsyui[adbdacbBC=qztxxx~uj`\bz{i\i~witzo`fb_ccbdbIJ,:Ynpnxwuz}ypc]ZcostzmU[k~{mnkxtk_ace^dab^MO4)7ENL\hwysswxxwoaWY`q~wn_RUgu~rlilvjTQ`t|vljeile`d^e]bb`cXN-""#4gtuqmoontx~~xsogaUW\k`L<5F\_oqxyxk`VUYgh_OTcvz{xtnmeX```db_d\e^_a_V3^otqkf`cgspwuwuokbbYPRUfyeRBBCCRbjlhdMRXekkuouqmlhmfb[[]``e`ac\c`_b\bW>) 3epmolbZ^cglia_ZUGRRR_i~saQLBCE>CDDDCRMW]]fijeXVNSX_fjihhffc]dZ^_c``a`d]`__]\^`U?.!anrnoeb`ahie^_NJFKYYr{ufYQGKGGBKNT[[[_[\ikgbTVOIUX]c`a_]^[\^_^ea``_a^^``]]__[WN9/(SjnrpjgefnkfaYKKKQ[g{ymbYOKLJRZ^]^]_^cinee\_WIGOVY\W[ZYZ^^^d_c]`b\d^a_^]^\\[`RUB@EEdkqoprgjroleYNJRUY_jtyq^UOKHV[a\^_`cdgmjidnaV?IQRUVVVY[Y^b_d\d^a^^`]_^`ZaZ]aZ\[YVUXdptrulntttjdSO]U]X[gt{xiZVOJW\b]`cfa`dbihlqkgMDRXXYYW[Zab`^b_ca]b\a]^d[][_]`\^\\eVPbkquvvnqwuup]`_`^YTUbx{oga[UX^\_bgee]]ZdahslkYOZa^XYUZ][\b^c_a_a^a]a\d\]\^[^[^_\[cLVdoqttossxy~vllhieaNEN]jpz~vplb``]cdbc_\WUUWZecgb^ch]]XaX[`\b^b^\b^^^\a[a[Y]\W]^]]]aWJI\glrxolsv}xutzvraE9NVZamqv}}{vvhfcb`Z]QSHB@@LP[edmghb[\[\Z\`]`___b]`_]`Zb[YZX]_W__[`^A?DW`jmqqmlnx\VYJO\YT]fkojj_XSIMHR74-7;LQ[`gfugjaXY][[^a_``]\b\_a]^]][T_W\Z^^^^\O&2^LTahmmrljn{~gSUe]Q^a_VX\XSI84HE.4DX^\bcggluldbW\\W]]^_b[b___^`_]]\]XX\[ZZZ\^PA%l]KVailqlfnv}xejdQ`onfjkdXG5,7BCPehibebjlnuhc\\VV^^[d]`a]_[c[a_][_^^Y[Y[\Z]VM5#moOKZ`ikihjppywtpgm`YPSLNL\[jkklifhqmof]\ZMM]`_^^`[cZ_^_`[^]]\YYY\X]XZSF/rtdFUXhbhdgnp|}wwjfd^`knonmnimpd_\[UA.Z\^^___[a[a\``]^[_XY[W[[ZUQ?%o|tROS_chehinzyrjcejqrqnpokm^\XZG,#F]^^]]aZ^[`^Y_]]\]YWYZXXPUL/& k|wdKKU_ckfeozznjfhkotrnqnlh][]N1($1[^]^[bX`][`\^_Z_ZWUU]TUPPH(! h~srSKQZcgmhryz}}{zuoqtqsnomkddhmqrqormieZaX8!%!,J]^\Z`Xb\_Z`\Z]_YUVVSUTLPA&h}{tbKL\anlkpy||}{vxpqmmkefhjbgaedjitqrnpmd]_]K)#>]W__]a\_Z^]_]\[ZQRSWTSLO7%"my~{iWHQckqjpu{{}nncdgkjgecca]affkjqmrpki_[]X.#.0AVZ[_\Z^^ZbW]]]WNQMTPQKC6&/mw|~wcQFUcmrosz|wnhdeffcgd_bYceikjropkoc_VaN!",+.1DQS\U`Z\^[]Y_YSMTQSOP<7$% Hnuz}o_HJWirpuy{xqofa^\`hf`^hkhhmoprkg^_]_\'+)/()3=NQXZ\]\^XYaQPRNWPM83&$ctsx}{kXEMahqtz{utqmjf^babd`cijmipnpqhdXZ\i^% ! %1.0%,*-=FTUY[ZZY\JMAKQTA:()!ouuw~sdR?Q\ityxzvrnmfe`bdjdnnqrstonf^ZVdle(#(.0,*),'+*9>PZY_WZL?BLQS6:.,xyswlaR8QX`ttwsrekjlrrusu{oqgeZU^mm` "%-,2+.*#0'+)+5124'g|w{t|wg_OC6:L_jtv~~xzukgVZjnklklB "(3.40'"*(++,#3*/./FBOWE?420-l}~twxzvqd]F@5>A\gt{~zppxxwneWT`nkkjib8%%+0240"'",)$0+.(./00FHUMM<8;0. r{zur{}si\SFC5:7F:99:9996?5>:8746;=/=1 "VTLTC8AMKZSVhmoopqomppmokkhmjlkmkknlnppV?,5GGJYXZ]dYnY\rvuV]NHKVcUgjOQJ?AB<>4<83,:G@.D?LR?...Dib_ngknsmonpnnnmigpikpimknlkti;-%6EKMW^]Khou`]u~czR^QO:ie][b[O5./6@>@;24N@?@:/H@]D-02ChbcnjikopoqopmohjinklmljmojmmV.#(1BBFOPUZ]peypd[ovntel^XOIK^dUY[OD?,2(5GEND?)*59[UB*.4OT`hnbnhnpqpskqmhmjkiklnhqefjjF.0*/63,<:7*-)-)9aQ<.2F^F[jniolpnoonnmpjmkkmjlkmoN9EI;2-;IK?;?Fhdbp{Y\bcgadhkvukcxr[ZSCITQNYX[406=0-6531(MZJ?-DUVWYlkkmkvmnqpopmmimjillopf=0432,8GG?IINVopenkvrtX\\gb^Uflutrvp^XHBDIEVYU=2;79(.+1MQ>I=UQT]]mkmpguknnpnnolhkljmkokJ//2,/07GJ:>MIawim}wkjqykZdcc`TVYiqpmq}str]WK>CBQZI=D4:<+?K@?JR[_WWNLQTMGGCC>AGHN9:+<@E?>?FHDH@EGFN[SfQ='%*BU;UXhgcflmnkksqmqmjimjjfcNLB@D2=7FG/)) ?VPGIHDWANV^Zcjdgada[ZPLJNHNSAIHISIGYPV[beisqsqrbD-$9^71F[inghjljktplopiiihj`Y>KE@2*;F8C72$!:>BBFPTKEEGFFORPUPPQQKKMOISYVROP]PTbjpy|}{m;,;HB'?9Lacemjlgjqoqpg_QPKAA5=H.-#C@AA65=)"$"0:EMORKWXNRVGD??;AGGJFJILMTN^_fhix|f<:8B#696=\fjfpommrpqRK9=--+<*<52!86<>92RG50)33>(4:.,%<&637*+23/.BPU`abbtnvsz{uY3.5-0AEDDdhpnnqk)-;* )$'&6(.4.*""(-.1B=AOHHNWSPQ[lnjor~zT.494:>BEPfloppm(;7%$$/0$,&,354(!"(#(.1585=MU^hnplq{xE8/<@B1GBVetkrl3/$(,,$65*/.46?9(,,,,2,-:JQjux}xu}gC?53G+9=BNoqnsE!#&$/PWR72;@B?:;;=@6CSap|¿G7>=52#>:3Rums-Ujf\WSUVMIOUPOUgºÿe;AC9>C5+-auq=`^coXvwmgnwt|ž¾½mTCC"-5lv,O\`h_szv|}s`BB4'9 Kw :MQ[T_yúºxlJ66IE""%/B q/C3UW`xmMD96I? -X%>(33?Vj{ɿmT:945O.DN407Hozrqy¾|q\6A1#6G"!E-)3-CUlZS`tzzúxrZ>@;*'81&2/)5>EJBChnqqy{scB<:=7*$'#23569@Pdfhh{Ŀwqf?=5=1..))*;4*7KWN[]duĽuvcA2;56./*&'5+/62CHDQQ]aryrj>2713210/"00#.9394FLNWbpzutkE6+/1./!8O!3%()3689?BIRgm{wpoG3/&3(.%1i#. 2/9/:85W[Å{êssyR"f5D>QckzuyT%3\jim * -;0*hlh_rrs34ob͡yzū{̎QS)5XPoTrwr~`#*1J;hkli$%# &-9*0oojvjf|ȲưfbI[^yfy|wzj45?hMgkij#,/+/''%902u|zŷ~p|tv{}p>7M~[`mfl412FF:-4#M7t´ŵɻzy}t5WIb~Wkeem7:>KPWJB'&=={üȹuUoUyXijjmDKE\b^XP+ 68qýȸts_zYjjik^_Ro|vfU3+68jɺnil^ijhlwv[tP1.@:cȾlsUbkihmgwR(3<>h|ŽkVljkhmm|O)9A89hegpl\flv{z\bQ864L_gpu{kK9KZ~n]caeffediegkBC4) XmUilnaYgpy~xer\QB?;ORXWRGKRn{shYbfagchffhhfF?0(Kx]Tfipk\`irsxvm]OA@LICJ_nx~yi^`ddeddfhffgf<84!)=c[M8Hdgoia\_ljsxgg_`bVZfr~zwl`\]eaeeegfggig399)" .Yfks]b`abbhrwuvs~~~{ozwthZX`bcehchfghhdA<<  I[gki\ddc]^fsw~~z}ms~wti\X\`c`chagdiefgH>B /T_nhe_kjca\kp~tw~huztajT^bdaefedgegggFDK#'AXkrhgkoqkbdp}|os~~~v}zp`cVaaddeddgcfeffEDG=!#%5Lbmfpnpwrnmn|rx{zje]XbbdeeegeeificEAHE6$#-3:]hjlquz}uv|}|}{dnW]`c`gcegehfhefDFDCHE4,'-680Nbfsszzx}yojhN^`c`eddhdlcddeABEEBEDDA>168@1;.9Qbqs}zxjkgRa_dfbgedfgefcd@DDEDDECEF@AE;:64B[fqu|v}ww{nmmkcjx}thlWUb_ebdeaghchgdhCCCCEEEEBDFK<7;;4H]mpz~}r]CBCFPPQV[[hraT=9?6/L\n|~njcIa`cagcfcfeeffdeDBC@FEFBFEGF#3:E67Temty~zcN<:/DXfnmtxw}}u{uy}xv|x|xv~tqtxgd`++CQ^_e`gdccbcdcebLKMMKGF;@HD'TTYWJD<1GYejvwt{|xupwsmkadadfhllprvyw[gF.1:5BJ[_hbfdfddfacRMOMKIK>EDB& SYZTNDE23OYekww~|phnphgkkfhkglgy~k^V-0484793DP`cbgcddbcVRLMJHEEGI=' PW`YSI@;,:N`mtwvwsnknkmqswppz|ba1465979468>HYafaeddRQRKHIGGLI13 5SY^^WNC88.9Ugsstvqxtx~}|v^:(344?6:59818<1/4Rdpvo}{~lU+56788;67:5:17;8KX_OPOGLCEOO99( &]NT[[aZRH?91.6Kcpk{xi? ,247>5=69569535968BIRKID8JOK6:$' ?eJXY\dZ\LC@5313M^fq}ztZ..574?6>8677;94876:5LLLKL5==:146775<56<6:8PFOH6MVDB580/2piW\baomgh^OKC=:762/-7D^mwvgUSgR=#2;:39<5057:76:75<99029yqcZcihtrjeZOKG<783945,5Tcw}wyhTX]bO=&4A31A5539;:74:985<<@AFHHAMPA;;@2/=|qmaaemmpshaYOHC=989795.6Q]ippzzuk_WU^dWP9+:823;:8479454;65=;9:POOCFQJ@<7?8-?ypjc]lpporgbXQBE=:;8:7825=LS\cln|~}~}~|~tsd_UPX_abPP-8?803?4:93549684;99<9OQMDKRH=A2C6)>ytii\dluupnm[XMEB=;>8;;65515J>RO^v^anhkofc\OOINY]`hUUD3:=2667;9287-7594888<9KOIEJTD?@9?8.9|{pkmdccpvrpmj`VIIB@<99>5845/44436M>?FJILILPGPQSY`bfMQ68990;85=;7656101;49588OLN?PT?E8@676731912.1135;@FHNORMPTYchTNA39:3/:6474955745002;98; ================================================ FILE: contrib/att_faces/s3/2.pgm ================================================ P5 92 112 255 dclclfkhflhmgnkokmmmolphmgY_gmcb_a]ViaWW_jzljg[Ze|`ahbab_]UWPQMZX_TYjnrknopnonmnlllokoonmnohdifiblemgllijkinjmlmhjfiidfcmggc^XUYYo\SSnslaWOexd_\a^YPMYZXNFHDKGRjqnoonnoojlkkmmllnjpjmdfdghhihgmekimikmlljdWWbilphhc\fl^ZTR`nsqgmtjpfS]jp{j\\\]V]ZVQ=?;BD>?Ulnqlklopnlqnlmnhnmnknegejbjijijikkkmilkm[LIJZglmpobXQTOETDZjijfboxeffj[RD<8878=1UflqimjkkjkokooinmmqigejdiihdkikjgkhkpkMD2GEWlhjmnifj_\nclse`[Zfahj`KH;;5803:78/3Ohggdhfgjgogqoiooljmfgeghcljehjmhklji^9>?9GL^_agngldoqsst~tc[PgucfhP?;6@9<29982>dk`WPdM[]^fnlllmklpahekckhhhjimladccVA?BA@H`da_dmjlyvzsypkq}{^DLSc_bdH=3@7;568MK=O`\E>XDDPV^cnjolkmlhchfghldljlkiQKRWSKLOKG[^baagkupwysmggsu|qsxykJGHW^]]QI45:7<=MF>COTCEWO9CV^fiinimmlfjfhhfjfijjjSI?GHRRU`ZR`ga_flops|vtjZZXhkhkqw{ucMQNGTOWK=85I@<411?QFV^M;@McjjjkknlmgeghifhijjjWE?=E;HKQMPGUa^cadipvqkb^NQP]bhijw~zrbSFGGJX@GA1:+410:TaYJFDP^nghhpilohffhfihjhidLILTBE@OIO@GGXYY`bgly~xypmknj^YKMEKXV_ehpzuhaSRAGMLPB>/1106YZUMJQWZeihjnnlndhffhhmnkmQMTQYKMTWLJQJHIPOUW_gqrtrmrzyi`^\^TUJLEA1:TU^QXXTbbhlknlkqdgidg`icb[WYd^ZYJJMUYXZXJL:@BFU][bb^cWZOTVYMQSQKROMQIFD><4=8>;;79?B=F9=A<=61<@B:@BETV__bdekkjjomhe^DF5BTPU_OUPQEB1BOKMPKOOYY\QO@KMGQRXRMNL@D6:3.43564;;89?>C=DFECJGLINHPMEGAB=7[Sa`hgkhkinmiigYC52:GMPIIJNIEF:986?>:@@<>@CCCLPLNT^bfikef_RBC;5JPZehkmhjgrlkkcS9106EXa\XQPNCC9HL<<420;@GPbjkfgjlolU>3+''+;DGGKD<<73=EED855>AMX]gt{}wtstr{~{Y#!,0"/b}xofhsſuB')3.9QRM`l)+D\jodelx}c0,-+%ILMIg%"EPgzz{|ü~q=91/ BHC44BESanssv}xD+36 ->O>15>CVY`cklxÿ~}rE,('*) ".$(,(7:JMJ[_impz{|pI2((+($%/&*,0DL@BCPXjfqz}wnM+(*$,-I')%&015?:=9EZb`tu¿zyqJ.!''%/Y%#((,/"4.5/BUZhr~uqK(%%#-1_"!'("($0/1->R[o{~zqE&#!%"3Z$""#!$&03$-?Q`s|{p?&"# 0F"! 07,*(?Sfv{|~p@ "%$1&752!0CSl{{rgf``\^fknz}{tuopnplrqxy}pI$*%#0#! )6'+4IZi{utxvvnj`cVPTTQPQX_hmt}}qojd_\W^R]\cmkvonT(#$%;! %*+/:RQl{pmjlmpllge`_^XUQV]_corzmf_[QSHHALKLW`gcd^K++#$3Q$ *#:>ITm{z~xoihe_c\dfepx}sfaVSQLNJMGRKTPZXZSM1,"$EZ#$#?8@Orzpnkljhfeepzxl^\WYW\\ahjkg^^XRXYJ1$#&*Oc""#:1?Rw~yjkgonimiin|qb^\fenlnz{|wrbbeK-%%3Vb#;44Z}ubedjhijiun^ejokhlmosvwx~|{pkqS+"8ag'! #46,awq{wuqsk`\fhfimwe_feeb`fovxvpdnssloO.#!:Zg12.((&$( 516fueefqswhaOI:=Ofd_[aghew¿f\\Z^]_cfqz{~tg^cjjpR%"5A\f@6@@4).-!)E8myqfmhnprZO:+'4Pr]VT`qtmn^RPT^UH9@GQeil^TgirV'%5PUbgCIQQQ?9:1 ",B?qphQ=JMgvlchkxwYQI_qb2,"!#;OW^S_nyS)>Ma\ecJQSUXQIB?(+2:Bixxt~ÿ{rhajrjL:%(-EFPSYbsoY?G`dajbZWa[V^PKF1.3G@fvxvrwvtnh^\[ach`dlh[GVa_ibbhhrgb\XQI65CCXa}ývvxxx}z~wotrvqppll[Zcdcfedn|uh[OB?7=LIap½uzu|}{styuuuuvv|wst][jdbfdhx}gXI67DAWab}þñr~||xqmlknsxzz|ztc^dfbgbh}~eYE3MTSfrs|ľxzvxpvtvz{|{xddcahfed~dP7:nnu}w¿źuwvvjbcgchee~bL.O~zt~skegcebgimN2g}tzvocdddccevWAr}ÿqyumh`geddin`vþ±xu|zwjeghbhea~ſlw}tjh`dhcddys}okzzsjaiaibbe}qzyxeo~pgdcdgbedt{}}mj{s`qytafceg_i_<~~x}tg_h~u{b`wzpbd_iaacbS~~y|znfe_hz~|zktcPhz}ymcc_h`ede.b|~{{~|o^d`m}~vp^K>F_msv}|g]i[A]l|xpncag^bccd0-rw{x}|x~|tm`^eihXA?94>NZ`adcgoi[SSd]GMbm{|wqpecdacad`d!43iqyxzyyx|{{}urg^a`eytVCGAEED@OPOORWL>V`mgTASdqz|}wxqrijbdabcbe`#,' F_t~zw|jtvz}yrusvmtquy|{trke[^UemnYUKHNDCEFJABJFK``lnTLJSglppsnmiiaad_abbae&#,"7@;C^kfqw~~ysurpgjmouxvwtnmh_X^XYh|of[KJHGDE@DFSTW]ZfkgPHMS]ckjhdd_e\ce_bd`c$(!%@g_krx|~{woqrldheomotnkf`\VZbWhvzl^ZRMJKJOV^[Z[_bifVRLHSZa`c^d_\b_h__a`a##%.YZdity}zxtoxnidgojrpigaSUU]cfu}sp[SPRPSa^\_^adh`a]VFEUW^Z]]\bba`b`dba  .I[\djuz|wusvqnhjpntqleYQPS\drzreYXTL\`^_`^`fgh_kaO=RX[XY^\`b`b__`d_7>ZQ[hnwt}t{ysppmrqxvkiSWTZ]hcsvsh_`L^\e[bdfXbcddhf\ERU`XV]bbd_`ad_a_ ,88YKW]juqzsw{sssqv|z{tl[[X]Z_^co}|rombcc_bggc^a_agel^YY^_T]Yd`b_c^b^e_"#"17==JMK\_moqyz{zuwwtyz}txb`c`^V[[ht|{zqlhch`c[ZZYUa`efZg`]\\_c`f_]c]aaa6*" +9JICADRDU[ciswy|zyxwvy{~~qkiie\]PNRVdgkntz|yrf`_SQKFHJQZ`ejij\\\^^a_d^\d^aa]HE9()%4CPOQAEA\KDM`]kqvuuxuzvzu|zwqmmlaM67V[NYX^U^b_knnkeRMOP<*,1@PV]fgpieYW]a]a`aa]e]^`[[WYLJKNRTVPEHETY@ESXdjrttwvxqvtwyxu}hVcgRYnhX_`cT^X_\MFYX4#>SZcfiimqk^ZY^_b`]d_`aab[_YZWYUVY[\P.KFSZ^CDHXYenospuusqqow~|qYSkn[iq{qnqqoQ7JS5>\caeekippdYZX^`^``[d^a^[`_X^WY]V\YQ1LU^ecU?DPQadfootttnnup{~|lkoZ`ovztqsdZCDKKYaigmhkkqkaVW[]a]`^a`[b\a_]X[ZX[]XP1Magjk\PCR\mrtyz~|zppjgbehjoqounmdT2&-4>HVVYZ][^^ZZ^_X^]TLQEG4,"u}~|~zslcYUKF8=5BR^llsz~}|sptrrxrqvql[@(%*(,,7BNVYZ_]Y\X\YZ]SQMO>8/F}|~}zwkaWRJC<:6?L]ccmy{~z~{wqtcP* (++(+*+/9IT[[\\YZ]ZXPRMP96. [zy~ysmX[OP;?937BQ_dkwx|z}zyuoa:$$1+*+'-),$8>RS^Y]Y\XPQNK59) ^~zz}wqh_TRHA:?2==KS]krtz{{~|tjR(&%*0+)((.*,,'4@JUVY[WPRMD;2' `||zxlg_TQC=?=55>7>484>F]bmuxwwyvsopxz||tqcdY:*/,*$$()**'/%1)+&1,5QOQ:50* b}|z{~}uih^[RGA@>;:933@RX]cbgorovtxnopqqnqtjhbW^N!((,3!+"-%%",**+0/+/(+MQP?/=- ]zzzmjf[UTNG "))0.'"'/'%#'(&(0,1*//JSJA:;8V}ywx{~uof__UYHLLGI=A<<48317<5;CF?EFIGPFQLIY^eW* "$&1,1-!&$#'&"-!0&10+-,ONL?9;<Wxrxwvoia]\WUJKGDDCD@?;8888-536;?@GMN[]fgfeeL #+'/+-))'&#&!((+**-,*, ================================================ FILE: contrib/att_faces/s3/3.pgm ================================================ P5 92 112 255 ejfhhfllhleknjkllnleOKYcqsnlfbc_]Tmuy|xtqnhffroi`fg`TPG8;6;.30297:Vcminiifhilmlokrimllklehfjfhhlgjgljmjoik\N=IZalvnoc^\WWKcwqfk_lnxoc^XQI@:67:066977+6afdahfjafbhkmmknkjjlichfjffkekjinhkjmlhSC3HWddmpmqkk_nvgsqgd\XeielgaZQCA>:<8<7?581*]odWWZSR][Z_llnjnkljodkbjiflhhnhnkpinl_A=9MUhionrtjk|~wh`]Xjw_egZSC=9:;@A6<@MH1<[bROQDFE\`ZlhmjlnkkmggfjihhljklmhloidT849?R_aeirrwxtpwubOL\a[^_`L7669;@B>JOCD>BAFLK__`Zegrxpge\UQO\fehltyx|qh[YIEGRWXA=8,3.5L[[QQTT^YcgjleonlnlfcjgljgkiojZKQF;AGJ>FSZ[]cdov{}z{qqvql^]PKFMNQWckomkhbbcdRQKUMOD?=66IROYRQPU[bjkijkonlofghillkjjjd^WWHHNIVGAHMLRXdhtsutu|vkki`_XTVREH>BGJXW`X\TTZVURNQLGJB?7AE@TPJFWW]gkikkiqklehjgholljja]UUYSXMNULGAIHQdfhjhinpq}}}zwpbaVNN\NSCF@>BEEHH?JGGLDI>>>>CE7:/>DKSP__deghilmomjfffhhhjkf_d_WVWNOSR[\Q?;5;Ua]e`d`eU_]^a_^^_YWXOSKLFFAA=CBEADBFFEGEBH@JJTF-,56NMX^`ejeilhmkngfhjdb`dg\_]`^SK;76>6E@@A?FCJHGLSNTWggoqttxqsl_@61?;EFUadejgkglimfbYLACIJFDGKKJ@;9NCOKMUSaUXKC?@DISUOOXTNRHMA>B@H@FDMIIDPMY\[aehxyy}|zuV>068=?DK_eggkfjjlhf\D:4DTRFA?D@CCC>>9F;CEMX[YM@>;9FFMIQKOQOSFOOLSVVX^X]P[adgoqx|sS24174A=?\delgmklghR?6-:H[UTOGKC983;879DBA4/556?IPVTZYU]WWSX[gafgimrovu|b<%%%*9DJP[elnnkcB59++,6;AE71069=CFC332448:A?AKHY`gnomnov|}Z+*-'0;>NS\mhogbI)0+.5D29@>@20=EPTH@==7?:88>SZctx~sN ,/6+5OMUdjnfZL)+%/,(&=SYS?@JYSVMSQNFECP\epo5/)35+?MNPghiSA#'  1Tl_\Qgnmbdbnjdfcp}W-,.0'0JOCWjfC(& *Nljfgn|t;3$2)(;HFB\R.Bfosij~X70+0%.;H=8F0DXhcgr|jF302/".G@00(:DOblrvĽuU519.(#5I;.19CSj{zX>075+!(FD1'82Te~½}d>:663$$5N+$-5>TgmmpxzfH22)61%B%+-6JW_ls}uj]<'*"&)$# #&$0/'50/3DW]lquk[8'##%$'#'%+(%*+*.+@N_o|~uka3$$%%%&%"$'"(/)&/9Oftvnf;'"'#%" """&.)).Sm}|ulmfdg`pt|wqoe`\b`]`fippwmof\6#+$#""#%!34((1>Zjw|tphbSUYTSRW_ipu|{pih[YMNEMJPV\hfi\_WR3 "'$)%  +4#*5>Yj{umkkrlica_X\TSMOTS`cftxzph\VVLLHICLKNNYT][VWN)')!$/!! ()*2:?Kr}}qrlmssuuorkhfb[`V^^adjvticUWYTVV]\e`_aZ^Waa_F*#'$5# +&99:Hw}|zwpmhfdgb`eeuq]]]abcdjswy}y|sohjldC(''7" "*862Hvz}{ridjfldcahrgbahkonmotv}}{}ysmnlI# #2*&940Nyyx||obbfdhfdesicfnkggkut{}vrp{qkonN$ '=(! 808Ouu}zgY\]de^grzf^hbdajiv{tgikijjP "2BV&! 50-Yz{v~quyroihYVWbddlu{gb]]Z]jinqw|ulZ`cghT$$0EYf6&)  #10)\zyqedkrr}of[B9O_ed?:66>BPlľſ}y~~zwpdff`bdcfniq|~rcXA<0BL\púv}vsifcc_fdf{ux|gOC3IJahu¼­ux}wqmma_hb`ay{}dK9=lppp|{~ijyt}wtqffcegf_m}dI/[}x~zzzķtyvxtjkcccebfVnP.n{}||{¿¿ù~tsztkcaiddfc=zY?wz|{¿¿ûtsurl`bheaae#vo]n}}~¾»yqzuqj_dagbbdd}z{}{¿ƿotsoh\ebecfa$D|u|x}{~Ľxq}}sqddb`edcc=(uxpvz~{zɾ~n|yooj`d`_h_aJ4L}~zy|}y}syk|vsicaebdbfcJ?:l}y~zx}ostlvgp}wlibdc``ccbHH;C}|}{}ww~{miu{pZ\puu~q_hlae||{qkh_g\^e_aaRFCVyv}||uylhnxsgV3/@\bahemmshVL[c\[s|~|unkccad\g_baRDA&cur{{}uxx||kbld\>99>?JUSWTYWLALama]fq}zusmi`bad^a`abVK9.2ikrtz~xvwy}|obj~pUDBIDNGGPLMLLCD_msn^`nz}{zuorhc`aab``__]TB<(3Nm}ymfpsw{sttw{y}ymba{fVMMJKNGLJLMWQUfpttg\dtz~~zxuopig^_e]f^aa_bHE2)#!+FMRAHTjsyxytpslrrpuz{|~|toa\t|dfWRLQPJQTU\baeqowta^gkzvvxnllhcba_aa_aaa[FH4&  EZmzw|nrqknighopww||}zom^_l~reZWUU[X^ec]bfqrtpf]dqlwqlgh`d^_b^c_^a_bLJ1"0Oeuxwtmlsgfgegnrrwvtkf][p{la^[X]bbk^bdkoosua[bonombh^]``c`ca`a^bRJ.%# (?`luyupntjihaglqtttod][izi_YTZabjafekjomztV^cpigc]^]b^a_a^a]b_YR6$'+2Set|uqrsoskmlrt|{xl[_ezzkbTOZdcdchdkmilu~cU]kff]^Z[``a_bb[`c]Z`G-(#25D^nuvswovsrqtx{vg\hxznb\U[cbcfkcdgnhrrsX_ii`Y]]^`cZa^^\^^^X`U@02""17?7Tisrvvvtuuwyxedxxvr~}omicbdfijge_dihmqqcbif`Y^Y`_e__^^_^\aZ^ZUK;9)$ "4JAG8E`kpuzv|v{z|yms|vjcfp~|~vmldjkfcf`diikkhijecU`^`\bba^___^_XZaU[TYLA59BIPIB>>U`lww{{|{}~qea]]h|~wqffad\]VS`dekiqcg\[\]a^``]]`[a_]\X]W\Z[[WVVW]TCG?=NWflwuy|{~{ra_XNVZahceikjpq~|u`WWJNMOACMS]igpo_a\S^[]``]]_^^_[^XZX^Z[[[Y]V^V@)B=O@QWmpquu|{{|ttnibXKF;8>B@>DEMQVTI851,05KGHMV^elmic^U[[a^c]Z^`Z`_[`UZZZY\\YVcX\G'=GJNDTcmnrytyz}~}}j[EECH=GCHD?FC7A=B@P]c]Z_egnnga[XX^_a]`]]a^]`\]XWZWYY[^Ya\K24CM]hnywz~}|}z|t{uid\M(.../)/%'-.5HVYW^VSOQEQSE=2$%+ 9:2:AR\jqyy{xmiZR$%)4.+()*%$/'-+'@GT=GEOPO?43)+"Uzmfpx}}mdVOB?:64AHXhmt{v||si]`H%'..4)('- *'.'-),0;MHPOQJ<5.//%]zniiy|wh^WME?<959GSegwv}{puz~uk_\XF')/01'&$)%$''-,(-)1JDMMTE;6.5*)^yuiiuwta_TOF>?:69DC;93:EU`ksqr||vvsypzwzyptbd\T_W+ "*-1/1*'!"#)')*+++/*@EKNJF47823&u~yohmyyog\YKHCGB@>96CNT_]bjliorqmjkopmomnbfXUTa`E !)*+305+#'"'((%+'.*00JQUNJ>8552-!"uzuhjosk`[OOAECFD>894AEJPUZQei]``abgce_]TWPTZdY/'*.)501(#",(#&".&(.0,MSTNI9B,41. $ozqodo{ymgaRPHABGAE98917?;@FDMXNLYLWVYRNHLIV[f_D&.+...0+#%,0$"*'&.2- ================================================ FILE: contrib/att_faces/s3/4.pgm ================================================ P5 92 112 255 iflifmiihlkmmikqnnlnjolhqzrsuqiqjxipnjgcc\ZZbpwjqmq\XQOAB@<82)&%1-63:.F]aimiipknjkljjgijiegchihhkgllknllnmoiknokl~rum~ukopnkkge`ibfg[XTTMHDEDD@8:3)'!"544C=F^ZljkjjlhkhlmijlhjekdhjikemhmknjlnnkjpjdW|ok{wjlkouphbhlffaWURME:9CONF?4*5++"3&6C;ES[kgjjikmilkngnkfejfhlhjgmjkmimkjolgxj]f|ujr|vg_uif]Z^b`e`\YQQGC:;OPPHB@=5+&)(1>EC3AN`hegfkkilkkijigiejhlikihjlkmnlmmqn~vgf{vo}rtjcmY[QYOOOOUYTRKK>E?SZPECA300778<9=98IGbc`^dhjkkljhjifakkflimomimkmmm{xy~rzxngeoj__eTVWMEPQSSQIJFM]_]TMCG=DaKI:<5?457EJ\^WU[gngmilidlekhliiglljikiom|~uuxw}sfb]dXbb\NNKGCR=8@JTgrqg[LHCZpq_JHB8:DBB)7=LXfjjghjjhifgjffMEKimngUPEOOY`_agkeffgrrosplqpmi`YWNCIAMNONSPQJWX^ZYVYZ_XUQLLIEII6( '7MZijljejigfhfjg\TLUengf^K@?LF_b_`bccejmjlejgic[\VPJHPNOMNZ`he`bejihcjgqnhkgaZZZNH:7' !.K`fglfifmejehhdUMFY\ggc]O>3;BLWabcgijjorsololfd[YUOVXV]X^glptsxy~}zsfee[PMfhhgijliihifiUPH[`_\ba\B71=COR[denquv{}vwxwtnd^^]biillmx~zmncWHHJ>3"#%/FBDje`fhmkhjhgfMFRNUMCI[_^KEH@LNY`bjpwxv{{t{ywvussqxv}zpjbLCUK;-"! )HI@PikdigdijheT6.DHCA3+.IOKOUSPY\^eov|~~~~qg_AQ\O8#25^P[Uedmedlhm[5+*KQO<.)61DQ``d^bivy~oiQHddK(#$=L_^MLY`ieik]:*(3PLL<998E[jotlux|qeNchT7")5MPGC;SZUdjl?,)1=CMOKX]n{usbYp`F%%!=DXI:>@QTfl\/""31:CHXkynbekO<)%$;DLXE@?DOamR))+327FO_¾vsfsaD2+'.DLRX=MDIhkM0(0.7BL^v{ryoL63))ANJUHGPEiiF1+,3FXR]z|yZ661)=HAPO>LGkbH+27;DEKn}ye=854:G?:RI=FlX?11856,5DI@WE2-+,/79h½{z^D406F6'&:ABKB3)1//47t}}fE;:1B<!0;:H74/-100Fz¿yhO=6B@C$$93?>'2,0/0Iľ~{teSF3CHF,,0B40+0(/.X}wm^O>>)-,%#%'"&m~yylmbVS@>@1JC(.*#&' x}}wvoh^TKE@=9@@+5(##!,½~~~wvrq^]`HCHC<88,0&,$!)~y|ypkk`VQN8EI85.('5&&(%B|zx{xpmgdUJG@?;<*1##/)21.$'T{vzw}wngh\WJ?=>64+$'5*4-0*&^{z|wxt{{wxzzxnedVTD5;68-- (>-"+/&7irtqo{}vof\a\]\kpzxyzyutnfYSDE39322.$B+'%25000-7) B3#-2.;wpoqpnvuvurii]ZUS[_gv~zyvrgeeglqx|u}ywrurn]D=1.*.-3)X95'#,8utp}vle`\\aduvnigdZZNQORZeity~vxzsvosobJ92))+,)+eT1!*"H{qn|yqmee_`p{nd_`[ZQPHHNLQV`jo{x{}z}y|vxquoyrndL>1#0)*#$fb=',#Otlt}vokkb\g|teb\a^`ZXVX[VXZ\]ajlikkkltv~sxvrsvwurdP77"6--! dbF83c}qs{{rjkfi[b}lf]``c^d\bdffnihgfggdbkhmlsqorrvtyuusdM5043& ]`RS8 wqbw{phgfk`_|i`]a`a`Xd_mr}{~|{wqoinrrmilgipwtyusqdM,#0-`cdb=~odq{vkf_hhjbzĿ|h[\^_^Z_gn{wswvqkehdprrynumf@+"-&dcdl=G}~rcjgkcZRSYke^Z`kztwc_[WZWYbl||ttsvpoghnvtwosqd>" $!d]i|8ji_QK:6?G]c\_dnüufbc`XU]i|~rmrtsqkjruvvrusb>"`^f}B~n^QOCO[bsľursmYVOUpy}wnlkoqrnossyuvvq`7'#ab`xSwjediqw¸{{s]RSVdjr~rpojofilrsqstwvxtxqb:(! $cdYxm|usu}Ŀ}~rroocRO_l{|wticbhinmrssryxxtwwt_<&#&)`c`n}nO@AN[^gdjc^__iprrrpzy{uwqwtbC# "(/2/e`ZlźyZLGSVWX[Z`bbgmsosrw{xx{x{xh;!"')/:;=;ba``úï{j``dchlnvx{rrnpuwy}x{yzwyl@%.67=LNLHCcbXh¾~zskrowzwz{|y{{zuxkB "#&3FEPT[YK:_eYiļyutuz}~xywlK'#.*:DK^gjgN@acYjķwyxtxmR.4::LbpkRea_]]yxvnoliZn~U4FM^d`^v^c]`ż||xusmkjdgub<:74.4258<9=56DQVbkoqxzumhfec^_aa`c]VNJ\dpa =XX[YYY^Y[Y^YWY[X\\V\W_krz}~uh[XSKPGEG@>:;=CC;AIO^insxukfccba^b`[]ZQGTiluV(M][\\ZZ\X_\YZZYYZ]V_T^anv~wrla]\_cf`WSST]hmrz|qjid`b\`b\[WWOK]oorL $7Y\Y^Y_Y[\X^[VYZW\\[S\acp~~zrqlsnrhge\hnkpzyoigdb]b_]XYUJJQkprt; %(M^Z\Z\]Z]Wa[UY[VYZ\WP]bmv~}z}|vroqxvrroijnqswwmgf`a]`\Y[UU;R]njtm:  %'9S]Y\Y\TbZ\XTUTWQWPSJWair|~w{yrcgnnmss{zyyuqrwvuwwyrlkuusohefcd[^[\ROMFbdppsj4  ",-KU`W`WV^X\UNVQTURQSLR_iot|oroibjgabhhnpnpnqsryr}vyussppjj_bc^`__XYLIKSelpotf4 $ 0)8LW[Y\X[ZUMSKTLVNQTMNWfkn~~snc`celdiihddhkmkrtt{yy|utumokdad_^c\_XREEW^foqrsg7#'.,29OYWX\ZX[UPOPMPLKQOMKcir{}}rhfacgcgff`acimmpsuuxwwutrnjie_`^]Z]\SLGN\einuqrj:).,133CVVWYXXNQQLIOKJLPOKWkt}{vqjf_``ck__bchjnnvrutywtrqijfd__^\Y[TQDTUdfmnsosk>#,+2/6'&6LRVYWOMSPHSJKJOKVNdnu~}vrcgd_`ab^edgpmqtqvswstnmmed_]_]bVTRLV]abkoosslmC#*3-5/. .:LVZQSWTPTPOVKQS@Kis~~xomcb``ffmnoqsuzwwyttojhcba]a[^TLIL`]^gmrsrspnC ),40110"$0.?JNQVLPNQLLGQQ72]pz}utmrqrusw|{}~xuvomfgabc`\XRRMSX\`fhpmvqrmpE"*/,/63-$(&$+01NLWJQPLMNSNF5+>hx{yvwmlf_cb^[VQIKQTWabhjnvooqnpI!#.0+2232($/))-.SSVPPJQKQWJC30'Ujzwrpnge_`\VROJJRXZ[edmiposmros?+..-0054'$/*.(.LEMDFHDESPH:77(9]p~skijc`aZSRDOHSWU`]gimklporrnl4*-.1./.4.*(-,/(.>9B=A@BGTFA4?72*=ht}xznjh`^ZXMKFFSJR\Z_egimpknrmtp]-"+0,/14-21-&1,,,*=<>>@KNHMQQYUZXT_\_bacadebce]<+"10,+0171-/4+$+$*.%&)DIGNTL7;7.295+#%-*sr\UUSI;;><=@9=A98?:<<@@EBGEKLXSUY[X]_`_d`dc`e`ZA+%0/10.-06/7-*0!()-+*#% ================================================ FILE: contrib/att_faces/s3/5.pgm ================================================ P5 92 112 255 ehhfgjfihkhjelgea}{{ksxrmpyrmhi]ilpjih[^PWKDG]`[TH=:DGH=;;?=59LJZa^WZekojnlonlmmnkmoleehdgiigihjgfklciut|r|nrpi__\[TQ\]b^VQRJQ[bdaaVRYpeV@F81+%+@JQdf\Mfkhplknljloillmjfgcfickghhkihmo`bz~xxjywillc\[XPUXWOFOPShrqs^XL\tqhILCB2*+*F\mcQYijiohqjmllnnlmmiedgbhhjdigehqtbcltnjnkfimiXYYKGMRB8ERTPOPIHUquhKRNRS: &! ,DccTW`jlhqkplknkljkldgdjdjjgmmnpvrzugihvro}wnfjckntseREGS\CGDHJOUXZtugTDFPSS/#%3SZNNeifkkmmjlmjklklehbhgkffhkvusu~wwnk[b{rgheqvrm_VKQLPSOTZ]Ymvj_A;OQSO'$KWNFceimjhnikmjkkil`jeegeefifsytlq~wldnw|uiommutjhVQ_]QRWca_SK/9HCEF* 2UJGcfijilipjomkmkneffichkgfhkto|~s}~~yu{{xu|wt}|xwwti^]UURYPK?856/I7>.")IIC_nfimhmjmgmjmnfcfcgggjdfedaooy|~xuphbdifjkm`^]]X\_Y[SUY]ULF=C75O=7(>AD_lgijklhmjmoinneggdhihaljc_`anu}|tsnXVJSQUOOMPFPOXV[ZU`[[TTPMGDPD6(# 0?Dcnfkjlpfoljoimljgiajg``mhddVOSYbfrs|{}}vy|~~{yvfXQMHFEELR\[\TZ`aafckpwolifd\TZK?2.'$#&Xdijfjlonkojplmmhdfga_^X`a^_\WWV\`_\__jiehmtkia`WMKOLMMPV^djilpx|z}|zrdhaZIAB6/'#=D\jchjjpljmnljljeffcgagWUTMQX[YXZVUXU]Yabirokff^WUIUWX^Ydmx}tphdTAHD<3!!%AMHTbccgeljmkolljgh`_ecaXHBbbkflkllnlkmhjUOWa\ND51+AEFJRPZX]jksrurlupngomq{x{jpUDT_L:(=PgGIVgnjjjlknjojfbLPY[SLG6-$.3EBLKSYZhiutsqrz|~trgESf]H)""1Gd[V^X]ehhjklhnhhXQOVTABFB990859BGR^aosy|w~zl]S`jQ="3=TdTJPJX^glfllklcWQMJC0(1=725kzytyxaD;?+ALRUONQUJHYYbbfF0 6A6!=[s}yrS?@;:NKCOLA[L@EURZ[/'#:91=k¿|zcDGF7BQIT(&*3.70crMCHCFG7-MU>;C=0B;F7E6#),5;BBż~qYGDMNI$*662?2F$+02/2Rľ{m\P=HOM1"90,.52?3+-)/Y½vbVH@AXQA*,$+":+/$),,k{{j_X@B2SZF,,''%,'+1)9u¿}wsnaOGB<9XR* """&-+1*:}¿¾|tqhYTG=A8NP3#' "))).<}ſ½zrmgYTJBEADL3$#! (&/?}~ysi\aTFFJHBE4$#!$&-C½zssj_TSECFI<@1& $*G¾}xsrgbVHHDFE<41'  $!(G¾}xsqi\UG?FCC>&/$ (!W}~xokh\MD?>C?50&# "" "[|}~zvpbcVM@9>8>7/"$!&l}~~zwpkVUF>67896." '$!3l{|vtrzvz|}vywm^EI8235.9,!1(=kyy{|pde]b]`hpy|zshcebern{}~~z|pw{naO@5/3/.1*.'CgkgevsicZTUVJQT^bqz}wnmd^VTROV[cjpyz|wwsxyphVA323-.-$ .-Ngi^Wcjeegbe^XWOZZ^ktujbf]X^MNRLLXQcdlvsvpqts{}twxzwtk[C40<8(&&#1Saghkky{tia]_X_j}ri_aa\`YZ_[_^`b]akgfkopruvwvx{vv}|wtm]B.,5;'" %/*Oiex{wqfg`\gutmbadef`deiixtsxqqrmklqvsoqplsxw|y|xrp\=*%14#%$,'Gihvorlk`]mzfdgclbhckv|vwy{qrljlpzyyyusnX8($,0 !'Mkfpy}rnkle_ducdeecddmw{{z{onglryyyvurpW5$!+"! $Tqjnsv|rmhjh_a»wdabadbeq|~tyzwtjory~xvvuqW3$$""%!&Puusddyrmejjhftege_abku{qtvuwqqrx{yvvutT%$($% CKr{y}{kbTH<1?B_k|mffbl[SPgox|nje^oowvsux{|xy{{yvaF'%('103/U[/xxhbU[\mv¸v\D6>RS__hd\\]dq{|xwu{{w|x|ykG)"'*1;6.:D\W?uprr{ƻrVHIVY[`degkmotrsyx||zz}~{{nH*! &+-;>H<4B[.cWK|wuxĶ{lcehlprz~~yx}z}{{{|pJ-"(/59=QRQE>@e@`Y\vutvz~y|rV+ "#+8DGN]cdQEIiHaUfſvutwv{|v[;%!"6>IP^oupYCLqK^YqƼ}{zz`F,1;7BVco}w_@VrI`Uqü}|tyygJ0AHAQfmuz]Jbp8ZWvŵ~txsuiJCMRJAbhux^Srk-X[ó}xsutiSUbQD>Wcw}Y[xb ^YżyxmsmmVhs`B9N^l{^mxIYaù~tvlqmffkn?BS_etbvh+,[\~tsqinkdc{~MBYae~lnsH(;Ufüyukmjkgef{[L\`ckug%4LX`ľ|~xslkkjffh~bU]\gssH!:^[c}xytojijfe]nlbccjxe1'P\X`uxx~tqmjhhgacwtmfit~||V&9Yc]Yyosyuxwyx~npzyrkkihdf\hsrry|{z?%JZ^[]orbpj[[iwzrgigheot|~_ms}xkimhjdc_fztmy{uui25KZ]]Whwrg\s|`ORY]hnke\USI@[\^bZbluwjZbWIANMWTUMFFH<96>Wighj|r}|{xrmgiee_c`iwo0#K`[e\^\biv}xkbR|hK<>CHEJGEJJDH=>Qckmx~{}wtvpkikc`_`]qpyvI$Kaa_\]_XVlnxzzutl_UgxRJ>;CBFHFOKQSUUcnpyt~w~wytsnkjidccZfrqnw~M"2Jd^b[^_WP]dqtuqi^VW|dWN<@BGGMTW`beiirtyzw~|wrusqnijhd_c]dy|gouvX!+GUa_bW\[_RLZholhaQOpxm\JHKMJO[^agfhimnuxttyzvrqsuqlijiab^^j|~hgjntu^*"8N]]baW[_^\QReklcUGdn[JVONS[_eigfbgjmtzqoz|vvruponqonhfhecYVZdkw__\__P,"AWZ]c_aX]ZaPWbrocRQsuhZTNIHXeffheekhor~{jnw|}rsnnohlkhljjigbaX]\TWUQHBF2(-JY\^ab^Z\[_[WesuiSdwtaVSDHWcbebeejksr{imoxvvrrqoiifkgeeihdh\Z\VF*4,)$"=S[[_^^XZ]][^^d|zt]sxu{{nZWJET]\abhgfkur~]gnrnrkrenefhghhfegdYZUL7&1OUX_^c^_[X^X_ifvuyytfesyvgfSPS[ZbcgllhkmxxZfopmnjijcdkdhdcfbaZZPF5(;KUV\^b`_WZ[[]\ils}qeZfz}{rgZ\]cbhggkggkot{g[ismnikhe`hgcai`eX`OMO7%=GXVYb^\``ZY[]W\hisxm][gnp|ylciegeidhdegjfptxapsrqimidbcgdcbd`Z^NJ]: !"5PVZZ_b^[b]]V[[[Zbjn}}pbQKCLWXfs{rk]^\__Z^]b\`\X\`r{s|ywjpjbf_dfdfcc\YQO[`; )17CBWVZ\Xbbckinqnmnlkgf9%(&2/0'%1),,+(4*KJILGJOUGFLRW\^a\cca`ahiikhnnnhkfhdH,#+01030%%(('.&2-,GBH:,6-7T]qlsnprnpoopmmooloommolpmmknnknpkolqjrlornmpkjkidhWDRQYZOKG4DQLRPPPOcechbbYVJKLJQ?E?PD:9+3).HTlmqnlopnonpkpnkqiomnlnnlknnjlllnnlmpnnrqloSRX_f`ZG@JARb>1T>OL5x\A99VW_b_TXXZPILKICK<1..(-)-6dgmmnnpnpmnmnonpmmknmnlkilokmlnmmplpmmppjR94IS\URMG\E;SM0URD7DvjUF@5>JXdnk_]jhgRH;9,%,(%"!$?eekpnolonpnpooqmmonnlnkljpimlnnonoomops_<=;JKTHRIWcS=R>VUSM??ifaYKN;:>PR\d]iYN@;:4),%%&$S[^fjllkjpoqmomonpmnloknlmmnmommmqompt[E6EDHQUSXQdydgpJOSRRL^DOV`aKGGIPNHG?A9/64=8557#$0MCRfngffemmpmpopnmpkqmlnjmonnmpmpljogB&8LXPQrzxyksynH\SC>XfHKb^NP:;:8CD>E;;>3/+9C=8##+$JG.+,HGPSRJQcgpnnpkqokpjnnmolqd?414=KPB61VqZaFcfnp}ht^~FacCLVXSSaYWN?4(368ECCH:3FF66>:*&;U@4)()*=IX]a]jhklnonnnjokpnolkK;2/5IDIENCsel|f9_fegjzkVfZRTPPWeKU`YN=>842'-BN>.>7IN@c^fdvj`lpvzg^aSVVetqqfTDLRJWZdR=(2;>1:<8?77]ZM<3N2#;MPhnoimqminnjjgci_LLNA>;PG/21ROGNUb^Roqp\``hknaZ\NT_rm}zt~scWIDAMWbX>28GB7B?AGZI88;[,!&PF\kmmlooljmqZZTFIEAFB,??DH6.,XNIJBOV[biwuicibenzjd[PGSZgpodZacmhf_[RPNYYXJFFJPJJQM2/.ES0 "3Q\dfpnqjqgno@LK06(:>1%DAM2;&&?P@DBAIBVXert|rkd`f^_b`\MSKOS]ZYZZUXX]TZSYSPSVMSTRORG71'BP?"6IVjjhglludpp4:J4,3062-;CL-K4&*-9?/14?:4A$OL.0&,6;JJDJWJKRXQWNSVRSUK\`XV\RLNPRVQLOYXY]^fflovwvvysld^E6TT+ .!'19Khpjkhnik-+4,.=931G>.5%AD;A2%%.DA?FVMGPMCKHHMMQSVWXVT_eYYSV_YW\fqqz{xf^JQQ?(&')3FLYkndlhf*24"#1'4,5+.16J578-%'*@E=GPWRTZ[YWWQ[]Y]_^\TUT^djotqth`NGC.!.#&1-BQImkfnb0(!$"3,(:-*#4.=A523/.-*3DP[cgfijihy{cfMF8,27I;N?JDT4<..(5?D?BN0;1#-06/60F\^k½|sxsY5@ICF)))-,+&6>BKXi}ý}q}kYN3:KD&!#'(*7?6>JOi}ſ~tsgUHC85W7.42+,3:ETj÷~sqfPN<1,DR'5-.209?Xe}|Ĺpme[?J;&&J3%-001-/CYixxsi[LW=F1%2?&)0,+)2EYfxz|thYIFED<,)8#$0/'&+7AVn|}|riXJFA>:3+-$+2*#BZp¾zicZE9?:86*&!(4(&'1Edqv~}o_SK0:633*%#&--" 2Mkvÿv{hbUC3008(** 04!$ 5Wsy¿zxo]T@(4-/5$)'=+'&&6Y{~{þuyux`A?2!3.+,&A@4&5"2_{|u{utfI1*"+0".('8?0--*`}~y}ttrN/ ($.&#.*@3>4 b~{w~}v~vvvvrnv|zyspqM0%*3"!$%@/;{x{~wsirqtmnc`cabedfbfhiqpeglfiiVu}pj?#*403<M~{z|ynwvmrttwwouzoeOg{ll3.$&-,03Z~|uuwhrws~zbSiuqn.""<26C&&n{wj\j}jpîpz|kYotwh1 #AA9N*3wtVi}~|nŽuz}y|{t`qxyf-' $ /+LII:1A{|~O]lZTMKPNhxpz}ǿz{rtyw|{zlwuxe)##%J-f[U5&R}ykjaTREXZ}t|tzsh_ksittxsvwxzuyh' #,(-6eLqfR<&S~z|rqyƿw}w{|5>)Ee~mkn~xyvl)*1>DD@E~\xkR?!U~ļiU>%2HSimlthdhtyzx{t$0BGNXQd~XmO?&W~Ʊ}dQKjqmde`rz|~zt)"1Mfjj_}LkK1/`v̾~|vxy$EWwqsipX~W%_dlzľ˵|r-[y~r~e\`2e_yûʳzjEtpJbuClZ{Ϲȿǵt\f~PFa_}j[tÿŷƵp]l{S_fdf]u¿ýµ`px^[gcj\_oż¿þŶ~UxWegff^oƾĿĽño[`[baecadǿþ¹ɾ}[lAZcecf^mǽvTzF_bdch_fƾlVmSddbezjdaz¿ø~\tQdbdbhIziZeszǻsTlVedddf7A[pu]Ybmz´^huWb`abbe@=*/1]dcswet}UuQ\`abbbbIL% VeYfmxnqE(il|zx{uWhU^b`cbdcFK=FdY^`ft~x[M,(Uco~u_ZJEdt}{gey{wkS\]_abcdcMDL. ,a^[`U^n|yRE7<@NV`nn`KF<!HMIQWW_[`_b_e^cGGEJGE7N\dkqkmuttuorwqmwpvc9?QKNXU[[__bb`badHEEHIE?B_ahtok|~o{~tlolRIFOPOUS][ab^_cdbeFCHHIGF:Ydiuuj}}s{}~~vljlcJHRLTPSZZ]b^a__e`eEGDIEHI=J`ht|fx||u~}ihjw}ylcmlXHKMOWQZV]_`^e^bdccDEFGGFGI=Telvknqjeljxo}t|~em{xy|za~~tegshJNLSPVVZ[]_``baccbeGFGCGHHD*C^hojcxlc^Y^enrv{{}zy|qoztvw~}r}nwzpamk`FMQSSSX^[^]`babc_eeDCGCICG=0V_hmTmrmjgcUUU\fkpxyzvpwu}rvwlut}~}}efwhJKLTQTVY]]^]b`cac`beCDIFGI@6JSalZZvxum]__dkusjlejckeikip}svbpsSHJPQUU[X^^b]`b_cbdbaEEDFGD;,7GZk_Te{{|wwy}tge^[dd_UILms~lhhrk>)PUMRZV[\`]`]caacfacDCCHF?7"2BPbeMRk{~whcev}xjeonQ,'DVQWWX\\b]\ebd`ebccECDG@>,?OF[hW@Wn}|{{jecmW<$-3SQVU_Z]`^b_adb`c`cCADBD7&1q@P`h[E\q~lgdehB!,3+FPS[Z]_]b_a`d`d`d_EDCAD4$-qd9ZbhRMep_cgfV/1376BJU]`_]h^addbdcbEAE?F03jrGFcmnT_xv}}z}}y}r^`Zf^8 #+636:39=BSX``_ccaedecGBGA@($Fhgg:Urxi\w{zuxuxux~wywti[cc^Q.0664:4;55;9NR]ba_dab`>FKD8(# d`dhX9_uvekzwyzvqmw{t~ukafj]TZ?2784>596:3849DJZ]ccb_@JQE-- 8i__aaO8a{ln~xzwtuyx~y~y}wre_piKV_K0463?4:575;35587DR[__XsywvleZQLbainXN*$5:767:637635724485875STE55+$xcWY\ic`[OM<<[pwz|uj^[GN\^hnoRQ.%5<5;8?3354567<6467059SR=:42(vfZ^^_j_^UMM8;Zr}ssVIFRV^innhQR*-3;6:8;/49:59;096;=<=:WJE?;335ufe_]``aeZYSJI18\xrk]CFRTahoonodNE,9;95=990;:8:5;69:5@==@WFA;A37B|igeZ[aa`^\VLIC1:`os}{pZGDMZafqqrnoXS76::549:>74767:3:58;=:<=QGA6A71@~lhebU`]c][\RKH<72IXlkuwstQEIRWbjntwpocTN07>551:8=95324=775:;8=88O@C8:<2?{og`i][]c_[ZWTIG>587QS_Zw{xw~wv|sd^KCEU\_ltuzsqkYV;:;@047:8<288216682;59;73DG==7?7"Btwi`g`\Za`_X[TNIC=683?='8q{nge_\Y_\aXYUUKI=;:@55158=EAJ[PXXRZNNF=G:FPS_^jrwwxxtmUZ:6<6557:6626588454//5796589263104660:>58=9??@FLU[biv{{|yys^ZD7?92136MAmU9HA;BT[ccZXX\aUVD:O:=57138%.<JXbqomlmnnklnnkqmnlljnlmojnmolomoqopproqorprkfBGKODbGJANMKE8ubI>DJ54DXfrmgcligXHE>/4*'"1,*2%Q]fpmnknnmnklmnomllnkkmololnmpmqnprqoopqqonfYEBFCV^IICJLYO3uP[NEHLA6:VdkevpdMI@5.,-$$!*0-.UTkpkpklmnlplommmlmnmokmpmompoopoqoqpppoo\MOOLQUjjfOMK[JWAUUOXPIPIDMHKL=GF:9B>75=('%!0#70ONljinnmoononlonknlompmnnonpnnrpomrnsh`WXGJD?Zp~y[T`R=_PVHaWLSLHGKD@BD;1*0363H53#$ 7*5CRdicjlonmnplnokqlnmnlnolnqnonoooprgQ@BPQ=D6vLqWWDo]JL\SaUNGRLOGLGH?9.*1MM;DrIK[qkerv^YULRZh@AcNHJH9;06BB@L=9?38B9><3%$+:3(*86/PY\LFTbplnomopkplqnokqlnmoltopkP@TBTGglv\L`ls|q\tdVYHZT]P?^QSKL897;?AAFEADSB==A?(6TA04)&.!4M^B_Fijkmlonnlomnplonnnonmon]JLSTB\Zp]lu_\T_fyrei\UTZF^aJcZTK?C8;2(2AHN`_QG?778aW@=4/!#GUFWSbmflnpnkmlnnpkmonmomiicEBLQEFfa|g]vu`NQX\m{ybjcYITfYT`REBB:94%.;AA9>5.+#[iN46?$"6LCeWchifnomkoknnnmnpnojhWN]>RGBFGb_bw`WowyYRVH\{tzscVVd_ScZNH@6=<-26.6@848Uk_49:F-GEa]imiekrolmlmnmpmpdceUYFGAQM2ZNO`b`n`e[lxpi\R^lpz~jVRR\[`g]I=73??)ACKBAPnaH.7@B!&;LVhgrqjeqlojlplnnslNYH;L;@EAG?]LLE[WZilgZUemkaUY]gs~xwbUTNSoheN12?P@8LJSdgR<*IP:!4S`ijprofllpmonoomrfFHO@;;BL?/:_FGAIPZbmwktik{ej\U]\xzoignxwqfXRPdhcRGGTROPW\L@89IGC =iihgtofkmnnmmlopt\G5@-9;DQ\irwsdgkiignhY[[dgehadimkjmjmeYa_XOZ\ZRY>L@D8GI++ClnepkgjnknlmlnmqO6#Ccglgiiogmlknnlq`6-3<2991EBB3'2>7EBOTNXRTQ]]WZWcjiebVP^\ZTWOTRZ[Y]edptnyxvxvslf_RTAM2' %%D'@[lacllmlmmnnomd4 %01316H=2B+%1=4F?HCEDHJP[UX]`acbg`[TXZVWX[dnsyzop_[FRJ/%#""&STTg`jokv[$,8HJC800''7HKHLELSaW^mqww~qY8plM$/7DD?1P[Labllv6 /53:KD@395--BLXaa_c^anmMcu[9'??JD9=AXGa[mm%+3.1:Q]MGMGH^isqqokwtk[wlD9,3GHL3F*JNJ[_i" "//./CNhaizxz}lrL=8+-GA\;E:*D5TX]*"++(7J830X\,#$-0GdR_urƿqwH?8@9C"aVGF*$=^*##):=O@Ab}zuQ)C:I56%=H-J-K&&-/*)(7Ik~ĿyhF95V=175:%:6))-!$,19Do|wsLF4DZ!(1/$$.10#'%+15/HqýwQ>?CV9.$-#<%))0+*-2Kr½n\H:IGF&#$&/ $(-*'04Vu˸}yoVX7F8HX#!#5&"'*(,$9^o|ɽ|~x`LU815U65"&"-$+&7]tĿzsqd\DN<-AB!!'#&",&!9fx¿~oiW\TG@-3@%&!!&#"#$@>68'1!,,5/%(\tznlXY=0=1-)--25..) cwj_\N8447),"( +7)6dzýtTRH=)4-0)#'399azruz{wvx~~}zcAD7*,,,/))-?;_~pnekixx{pknhdgdy|}s=;1/#38@('!76mtgtfXgwlibSQ\VYWcuyy~oN00$..!*G-';@{tmr~zwlZPVQbhvzlsw}}u~rP4.-/.&P.3+9.#rrx~~zwyulka]eez}vfn^[Ycmrx~y|uQ1*#B-MAA!*.%.yp}r_][g]FZ[wn{ysfi{||xqh_ZPQVV_fq{~ztrh~|zytM*#%8-I_X'8.JxzsWWL{nVDhPVlhqvyvyxrusptrlinitzmspngohrsmJ$!3$K\_)H/bzpZRbpq!kaLjmyj|}}vttsgaxyrtA, JWd/E6r~qb|qP-^_ttmvĶ~{wrvrko{njckvzpE' PMl;B:/zzzvgxxuwuò|wp{p@8?2Djtp}kd}z~nC!""OHvZC5=|}~vwwqU-,6hydy|uu}i?%')7*#$R>tmV6Mǿz}gX$9/BHbsXp~yi9$!"'*0L9O@kui$,>A9GI;mc8NZODot}b^óv~~t406@ONSZSR9XcIFls}piĻȽ~{u8*31?`wjjj7?\\U?pwm{Žij}{1,D;Pguq;XY[KGdYv¾ʽ}|y~44HKbps=`aeNGTeLĿÿĸʵýx||3JLjy~45V_aMIGe¹Ʒ}y{uGhnqw-7GY_INDs|ƾŵýxxj`}OOYTbcMNDb±}tu\|nL^```gPIC_ÿñ~wonWOW^caebMMD\}ù¿ǿojc\K]abdbaJKENpǻ÷kkXmh9^`bdcbMJNJak~ügaSEFW__eedKLKIF`t|½|d^V@S][bcdfLILLESoyyƿþrcVaNJa^cc_eaJJLLMJ]n{}ƻc_Xm},Za`c^bbaILILHJSVm~~x~{xv¶~{{cW[CN[daa^bb`JJKIMJRDYs~rsl:Kn}l¿u`T_T=^Z]c`bbaaGLJKIJUFFbvtes}D"Jd~ln^T{APX^^^cc^bcJGLIMKKUDVnxxxua_w~zU:-F^|}lf_R>BYhwiulW[|wsSFL]_[^`cb`eJEKHJIE_FPqtor`YkxkK@1;J[ovfUIHBKNK]ohl}qnCg{ob]>GSO\\]]_`abaHHIFKICU[Lkwuybeokz~cN:61:DL?=BVdkwcmtxkjHLGMH9:>@NWR\_]_\c_a`IEKFILEMeLklonmn~eHC9<;DCZjoy||cd{zsnkie7[\S}xyj__z{}idshho~pOcntpqlonhcaejH#4:GLLNPYY^_\a_a_`aEHKEGGGFHcLo~^Pru{tcz~{B[jghkln[h_gf(-GFJKNNPQ]^[^__]`abaHIHGGFKIB\TXxKJgw~v{~iWlrjlq`]kciR7:CGMHNSNNXZ_\_a]]d`c]IIFIIIHL@KY@rlBM^wx|vkntywzz|ytvjZlggh38BJGLJNLQSX^\^\_`aaac_GHFFJHFJJ;VK\w|fVP]u}uupqh`[VU\bfuwz{sx^ivfj\! GKHMMLPPT[[`\_^___cb_JDFGJFJEJDINBh~qkmr{vzltphg[_ckin|~||ypgasrcVS$avufhts_H6z-18,KJPQPS[[Z[]a__a_``_GBCBDB?@;=@3:;=B0NWJfyw}kicmxjR7Cht.526KNRWYY[_[^a_ca_^_aC>;:;A9-4`VX{|mz{~w~}tjejqo];;Znp056/D9QTZ\[_[`a]`ca`a_@<@>><=;??0$ Nd[n~vuqnvy~{}z|{wnlltnaK2Sdwm(4644@1:>E;&) #cbpxyxxswnw}u{olowrdU7JaqsgF,784A1458>Q^_\_`^b_``b@=B7@97D;1#& Mel{zuywvy}}~tokt}lV:FZnxobR0::4:;05526=O^`]dZa_]`A<@A=7@B9$' GQpz}x}}}}xyrvuqdBBPjyyk^V3:668<1437516:R`a__c^a>;A<8;FA*) KHVu}}vuxo{t^F>Qax}wo[N;1=45@/36963075BR^`c__=?;8*@H8*%O[Edu~vurrugD@Ndq|~svXI)2;:08>03664816068=R`_`7@9:5HG0+$$[[RFl{~zqmmiG@Obs{zvt^;.8643872965827534527=OZEE<:>P?0#+# bRaFVt}xyrmiXI@ObuyzuwY10<7548747=0;2747471724:B=9-LR:8'&%$,bS[[85-RN=54&('HaPUbT;l|zwt[WQ;@KZl}wyrB-<;45:79706823/84373661;IB9?00, jcUVPY\YQEGV_o}vxjNF@DIR\fxzzt^D6?862:9584,8877893697=489HFOTIA>?:2.!keU[JWYZYMC=ANtfoyyz|s}xigYI<=FKSWnx~yvkQ;==545>57:11>:8658767=<;<3IFOOCA>>:-/"ig\YKST[[UJ=63FJQ\`iqnlpgicfdQH?;?@KN^g|ywlb><<5325<78>53:968287785=984GGTJ@D9@?2+!#iiaXJKS[VWOD9761>78Q>SOMVKLAB:A7@J@QbRNAGTRUIOfK`XPLPHIMIKB:F958@7;=?3' /=.AF`hjcihslonnnolnnipmmlkjlljklmmmnkonmnaZNHHJJgjhUX=cPLYI^H_\VQTMMLKFHHK@:32+99C@<;$ .+6K=2FJa`hcdZdqlpmolnolonnmiloipjkomnonopekTBJM=PjzqQjZRHtR[RZ\Y_XNSUOUNLLIA?;43AF,@C+0/AH2-6BDZYaQH[jopmrnlqmpmmpilklmllnkomnqfRPUO>C,kmfbl[TNebILU\VSKMKJLOMUKKF8E:19>>B87 ,7F5+(96'MZ\OSOnkknnnnomomlokmlklkmmmlnpfH:EKDDL=g|qtth\_OOWiU9Y\MKLG7=.>D?CKF@6:Q?=AC@'<^G86,(*!SZ@^ZdoeoqjmpomolmljolnkmknmnqH=CQ@.dLLAutddsyjVbNR[\_FN]XNRT5:@;698?KQfjYSG;5:hYF@>4"(:MGaYbglfnppmknnnmjlkjpmklnjq^;@GT:Llq^MTapwxqZ~vWbK[TRkXMe\SLCD:B2&*4'5=06@:56Yjb0;5<<<7.6BLHCJpcO1;FF!#6OZkmi{mjisnnqnomjlminhljaK>HKCIMgZtlUhvtqWMUKUrx{j^UT_WagnZK@18FFC@HKMcfUA+FQD%$$HghgispijomnpoopmikmlgeNV@AU8BVB_]]okZh\mspm\^^enwxxl[YNRTangTDAIRGLSU[OCC.H>J#"'0Pnljkojjjqkponlkkjal\\IG@=T0CUJGOcQgkojXXajre]_[[ekzuijot}{urld`jgedcURU\\XULCT>ABI4""$F-GcjjniikpkpmpmjmYUU?DC;;FC1NYHD;O]\jvunrifwybfhed`\dhmjgebgkhebdc\UVYa^Z`fdb^a_VKJGF*$"$ )D&5_nkcdnlomknnknIIL9;4;AI8+8Q?DLahfijnjmknnlK?5<0:8D@L5,/;<>B=@CDO\aaakjda_gojmf^VYd_VVXUY^dgls~{sjcRHW@1 "#/-IPF8PUldhinmnnmbH59B.3:>4PI4#.7>?@FMVRUOQJV^]W\cfggi`aVWaV\\Zhqql_FN`D/&!*7EG.OTPledpmookgB(5;:.<9/I9D3"&5;5IDHDGBEHLYTU[_beff_Y[afonrrlkS9adC*"!!3AB1P\Nfdmlpm`H$*22=)43J>:," 7;@9HKMYZ`]agouy~}wZ>onL*%*A=PE8AKVGhZomjF,2295-'*GM>/)%+1:ELSY`Zkot{v^S{[F.)9GIO8J+NSD_`p]#,;A4,&'7FGCA>:RWg-&0@A80+/+$),ACSW\^\\fyrvd7854;GDjFM9%25RY*2/4D?0556/7IZ]jjbnrzſqxL>:=7@'B[/!$)-,)-.Poz¿{xtdPLN70K=!#!&)+$)*0Tn~ƿǽnmTcQK=49B( %+-%',1Rmwľ}ta]MQJJ727-'$&&*'#8Qgvþ|seXVIBMD-.%!%#'%$(2QlsývriWFKA@F./ ## $'###+Vpxûomeb=F@==,2!#""($.Xpw¼so^_C67>2..%!# %" +Xp{þnnaTE/969)$"#+ ".^qydWOI-4405# ..#!)et|pOL;8%5'8' 51&"#$ho¿Žz{W=81&.+%2*84*( noƼ½yd=6,)0+#+ ,0-+)psw~}~gI7(13*'$5,40 opjmqms~ylqpikgu}xy}uD3*1C("52H-iufhe_[vvmjaV[Z`\X^sz{jolhbrty~~{tB**&@''**:/n|khia[esvy|yupdYVT]im{~yrhbXRXZ`]nx|xnrhv|wt@"!%5%$%#%;6 r}olfvmdedixztphekfhkmgmoksypprporkn{vr=2 2-(95|llm~rgn~x{x~uxyoneqwzv@"(@%2-4%*xqo~z{~{jyunht{nI ")*"BH4 2-8|wx^Voxsh«xoy~~t?'" +/;*>j@'?.M}vUT{{t}{yy}eª}wt{|r@*"$).5V+DaPA:V}}fTZ^FS2')Jc|vzyyqzvw~z~|xB% )/>>@z>C?\Z)8=$bvqnpZ^J%8^qhmsz|Ôzh]weMQcqntx~{N/=E?GSE`3UJIn:=;'jwzdjÚvisJ-"!>Zo~{zm{}xI&d|wqiq1_O?ffTB2}Ĺ}wspR'aq^K7tɿ~Z+LDcy~EVeN>Yvh^;}Ƹ~{c3ORvwL^MBWwknD{ű|{]MhyzK3GOHCRdwVǿ»z~^v@\\`IHI\npľì|tz[Y[ceeKK@rLaÿ¾~zqsZEaedgLLU{mû¿oa_b;U`ecfcIEGHHiwh~yĽh]]tVN^eaddhEIIJHG]fux|ɺ~~e_VyB\_abefaEIJEGDEZi|~y{ǻuvhYgTM\aabdfdEHFGHIGN[k}wsvew|xpsdVvpLQ\b``ecgDGGFGGEQHUly{p||lE1^snq~mhIso\B[V[cb`deeHEGBMGFLL@Rmwriy{}J/+Sm{nkYI:J^xgl{ym\OlrmZJD>S\Y^`bfbfaHEHGIIFJL@?Zlyz~|uggzw{{]:74F^iwhWMEHTU`t`muxon[9!""GKS\Y^bcbfacDFEHGIHCLM:14DMWVACI_j|zefvwrlknY >ROY^]]`aabacIEFGHGHJAQL>_rpse\gnyhP?6616@?Gakxu}~n\qv~~}wzzpkgikE +9OSTZ\^_abccaeHFFHHHHEBPYAVrr}riilrr|lQCGAEQXky}~w]\mrsropspbifjk' !I_H[eI>P\p~~|vtskba[c^ns}tmc{pf^>4OJRNTU[[\^`b]bbcbeCDBGDGEEDKG8UQDkj[MOTd{yvrlf_Wefjs}~tbt}r\S7*@PMTVYW`]a^a_adacgCEDAFHDFFGGA@WEXuxpothlglkszzunf}sfE\* /+ORSXX[\^`a_acaed`CBD@EFEEECJF=HO;aw{pho{hY6s 4/9SXUV]Z^`_b`cad_hEAG@EEBCFFHDG5M9Efyºusllyt^=Tz27+PVW\X`__a`a`bdbeBCDFAGEBFBE>A87O6JiwokgyweG>8>>2@VFYwznl}twt}tu{{w{xzuluxtgW>_wyk; 55;0@78?S^_eaaeabab@B=:C=>9>;;>;-"SXOkz}{rmlopsxw~}wu|zrlyo^?Qo|yd^63<3;?::8=::C=6!) ;[\av~uvutroo~}rsrw{jJCe{veg07=39B0/7588OY`dae_<@;@:;<;<9B>(%  %Hd\wy}uy|z}|yyw}pnRD[xrcf.:>58A7/46:35;H^ca`B;>=9?A:9B>4## )HW`sz{}|{xuv|tUAYk|vbX77=3;:445786167:HZa9<==7=;6$+ YFPoxzzuqtsd=Vi|zwhO$6;8:5>8378677624;9ED?B?:<55@B5&! VRAWp{}~rpnbCPfy~yxiF-4;:3887637857860:55HC::4536F@+$&TVQ?er~xvkkXDMdwy|c;*;=7677<58;793856863BH@9E;A65LK/9$$!$-WPY[@Lnz~}xiUT@GYl{}z}R16<8697;;54=92465975;CIB79,6PE8-1$"">[HY\X4Ul}zxoZCFDTj|||rM38B76<789745604735269><@@:/DW@:.5,"&SXHO]XM5[t}qmQCCKYhw}{~k=1?<74=4::924353:66341MINGB8LN>=1,/& [^MJX]VD>hsw|kUFFKVdw~z~y_8;@;488?8=7.3878:;7874OKLICBTJ==23-&_ZUFT[US?>Xhnzz~fOCGOV`p}}{|mT:=<5797=87.759<7795<6>LKKFGHUDB<:+4&dYYKOZZVN<:TThmzrm\LBEPVbr}zqg?>?837=98=50>::797>3:9?GIHH?SPCE=@.6-i]URG[UXTF@9?LImqmx~{~zwwtgslZR@?HFX]q~wvhT8@:7/6:<8>847;5<66;69::@4703?6<;<7476<6766:<8JNKFJPI@=;=<.,! hecTLIUWTPJ?937027;;@IALICHAC8=8?>DLct~{obI;?94627=8?=86:1/78248:89 ================================================ FILE: contrib/att_faces/s3/9.pgm ================================================ P5 92 112 255 hmhmjilljmlmmllimpi`]ab`LQOJAWNML>BXLDIHsofM@ABOV[f__QA<;92/-!+#!&WSfcnoghfjporopooopqplnomhljlkmjmklkpjnnmplS<8M_YYR]IO\NK\C`^PNQ[QfXmfJGUWNMLHG4578<0A-1!)!9;RY`mnl`angiqonqooopokpnjgjkjllkllionknpmT85;KPSMO[XZfvV{o^Xn_P\V]claPWPSOGMD@>A26/AD64.#*#@XNSKKU_U`JT_roqqonnqmopkiikkmlljokmknpqj@3>BEOYWYagWuqbnf[FQMcYYhbMPSPJHLEE8=573.=F6$%4HQU.4,ANXS[`nkpopooonmokijhimklhnlmjqnqN.)DCCPXL_c|n_utw_Z^DMGk[Sj_VO:=/A>@@@C4-<@D?;)1@VS1+9$G>1$E[L8,5(:OpgandmkmrslpooeikkkkjlkmmmbfdU;,@>=:EIc^UXlhfbk~{ikf\VTSMWY[Q\SEC57(+58,812,D\V793,&USNhnlglplnqnopmjkhmhjmmlmpJ910,6CGL@OLqchovlbW_`ahhopqw|tiZSKNQVQ``R959>1/>62:.QUP5B@4_QOjnmmkoqiqmqlphhlimjklmq]932-,=D@;JNagqnnlltjWXYb^UR^oxwp{~lZDLHHP[b[;-?B:087>QK;>JD;VTYlinolgrnnnqnnlhlkkmgknqP=3(619FB>H9gi_jypnklzqvdih``S^kotuwqt{yuiaKEEIW[OGCEH@9FN138P=74RXakolrjronqpnqijimjkklneZ=50C4-@>8WCGe[f`a~ra[adjfng\ZQL>MY^dik[^UYcb]`XXTUPLMPLDII#5DJ*5U^]cmloqlqnornorljlkkflkd`X<97G?.-2B;0 >K?ICGLFFNNNZ]\a]aaVZQPZSZYUPNMSXIKZ]_fmuw{~~~|wjZ64MK&*,8TjmkgkomfsmsmmdfOVIE;>A7 6B@E-C("#'2=BMMOFSLGSUTLIHLINOTYUOVa]STZ[[[lw~pSI4X% 8&7>gklelnigrqpoTKE8-(5+88'/<@E+IQ.%$".9BJLJa\OOPGMLIRQVSPTPUQOR^dop{snUDH0&)%0>.\khklmmlrjmL7;A.$41//?3099,9),$+/8CHKJLTU\hc^ffityz}{eRD)"$23<8ILlkaqnomgF+3!*)495-6--!"622ED>4*.#%0:EIPWU[dejtqvuy[[?!4'-.KG<<8>J?EEQcdeiuwv}vgb,09+4@H7LTkimlrsE+<"#'#$6'02-#(!*'3<94==U\nmr]F""AWPB83:?32244*8JZcquy}yx^;?85G'I0=NflsK&>[bUVLCFB:IG@D[q}½vw8=:=>(8@%>Qjo,5PY[fZhg]^`cks~¼zwZ:BBE6G1&4Uq-AKNaYrtktssmLG>>R2A#$-j#8D@PK]}}|~v|¸isX=7HI.<*$#4.75BL\wls^H-FN;!&+ !' 2/7Ja{v~ſʻqsYN=:FS+!#! (,2:ixigix|ÿɹsn^K@46PD $ "))AM\GLZmsoĿ{ncCD:-&Q/"($7<<=8D_fiož~ym`NE@9%4B%'(53,46HTY_p~ż{xs`IE?B3)=$#&%02,,3HHITXn{¾{zq`GFA><(7%()0(,/6;7?FNYl~wxo]M;@5?22&#1)",61.4@GG\gv~szqWK92;453%/&$'54/48AAXfv}xſ¿uxs_K<,58-.*"+#-.5034/:EYgp{¿uvv[K63,7,(- )%,$*8$./9LRdzþwqv`J3(6.-/%#$'$*0/+%,=BSduruj>5+*4++3&% '+30')&>?Xi|yvrkO)+#1,(4$"' -;,*$&6Cau|ľ¿ywqpV($$-,%&&#-./0.'&1Kk{{ž¿s}kqW(% 32#!"!,(.6((!2Xkxzxxy{t}wvmtW"'(43$  . :9)'+0To|}{wzqtw{ojjj`hnmr~zzund_gtptX$%>7):?1-+/Ro{|w||mec`a`e`drpcbVPPVW[flrwhcf[[htwR"+4:% 7E7307Ip}zuuszemi}}tkheY_WUUY_dow|xrlc[\^_gpjpksulotp`SwuH,(7) 8C6?6?s~}yuyppv~sfeglquwrtwvty||dSlrA#0) %)AAF18r}}vtzwzwy~tPiv=!%"5AH+6uw}}xslgfmq~zy{uÿx|~}tkigpy}v~Znx;"!#*^fg}ar{apyA&!(+9&"6>4G|}ibTm~iNpa`rs}|z|GM@\S{XtVz{psxD+$ *#6[!+37&KytbdNwtD+j_\Ťq|¤yztw]m2GI__clyysxG-&H9j0"("&'63$U~~v]tr{tCawu˹}ţ}ЈWL+7*$#2Waipo{usy}{}ckoTX[a]c``cbcgedgeCCBHAGBEDHDBA8J&D\koz~|z{|ptgqdRY^[]daadgeeicgdDBBBGBEFEKAGBK2;Mjkvz}w{}{mlp}{wkjr\N]_^]c`cddcehcfhAECCG@FBFEFDJ@7A^ioz{}|xrcZ\Ykhmkuy}lkjc]^^]]mos|tjomOVZ_^_b_dcdfdffdgCCAH@FDDGBIGG, ;2Raltzw|zdHB;6BEOSY^kZUF?CBHS_pvpim^JYZa^_c]ebddhfeeb>DBDDECHBEFG=! :AASenu}vu~xl`TQFDHBKRV^eqxtx{sqjjUF\\__c`bbgdfbgedf?DBACCBBCEFF18T,6XK=F`lsrwt}}noblc5Xa_a^bbcdaddfcdfB@BBCBEB@?=<,6[Y;7XdjtmpypichN*&E`^_abc`haceffbgB>CECFEE@=?<&4[^P3MYgbpkw{~}tyyyyy~}|nflb+*02V__a`bccf`chbdcIJIIMJCDB;F<%.^cNE4P_fpnlu~wovonuwxvx|}ufmkG236;BO[b_fbfdfdbfcMOJQLELF@G@;0\`RK:,&PY\`XTA:-I_moq|~ugbYK;"2576<7677471;6FQ\`RQOMHHFEMO07 '^UW_\YHC53BaqmxnaRVJL$3545?58847454094>FSLPHK??IPH5. !>bSZ_^aOH<60C^hs{|wnPRc8Z$4947;:;9685:660:5;RNNHJH@NS=;'%'UdR[]aZ\QC<63BPi|vzoWSXe@R'593:;5=74358877687JJKFLQ,5<0;9785164956878:HDEHKEISI8:0+!pkX]hfh`[QIA76.3HcqvwhQUbegAQ-7877=52632;6563685FHHWK@KRF::4-'to[^gildcWLI=6103C]h|}xlPTachfCO24<66A25/84:6<47:47QNGQE>QSE?934&yv]eehqdg[RJG=7;.1:SlxznWN_fglbGG";9:5;<7167;:4:27><=JG@G8=PRE9<90*.~vgbhkjvec\OFL89:107I`tto`N^gkljZP9,;:479BDBMDETHC:B29#Fwleimlqqf\VMHA;:963,Pantr~uwp[K^copmkVO62:6167>194=749898=6@IMNPCGWFC8<:6"S{nnhmnrln_[QJC=;:78.2@SWehqw~~rqm`NQ\emwvncOM18<7/77;>2384:7868;8?HTRMDIUD?<9>9!Jxrrjimnlkd`VJGCA7=:;3569RH]Wv{lqyt|wwrkdaPRIO\dlw{voYP=7;=2477:875209859:89;6:624:@8QbRTa``bXWVDDAETVbjwwziZI6<;73788=856:/3366:4;8 ================================================ FILE: contrib/bgsegm.cpp ================================================ //go:build !gocv_specific_modules || (gocv_specific_modules && gocv_contrib_bgsegm) #include "bgsegm.h" BackgroundSubtractorCNT BackgroundSubtractorCNT_Create() { try { return new cv::Ptr(cv::bgsegm::createBackgroundSubtractorCNT()); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } void BackgroundSubtractorCNT_Close(BackgroundSubtractorCNT b) { delete b; } OpenCVResult BackgroundSubtractorCNT_Apply(BackgroundSubtractorCNT b, Mat src, Mat dst) { try { (*b)->apply(*src, *dst); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } ================================================ FILE: contrib/bgsegm.go ================================================ //go:build !gocv_specific_modules || (gocv_specific_modules && gocv_contrib_bgsegm) package contrib /* #include #include "bgsegm.h" */ import "C" import ( "unsafe" "gocv.io/x/gocv" ) // BackgroundSubtractorCNT is a wrapper around the cv::BackgroundSubtractorCNT. type BackgroundSubtractorCNT struct { // C.BackgroundSubtractorCNT p unsafe.Pointer } // NewBackgroundSubtractorCNT returns a new BackgroundSubtractor algorithm // of type CNT. CNT is Background subtraction algorithm based on counting. // About as fast as MOG2 on a high end system. More than twice faster than MOG2 on cheap hardware (benchmarked on Raspberry Pi3). // Algorithm by Sagi Zeevi // // For further details, please see: // https://docs.opencv.org/3.4/de/dca/classcv_1_1bgsegm_1_1BackgroundSubtractorCNT.html func NewBackgroundSubtractorCNT() BackgroundSubtractorCNT { return BackgroundSubtractorCNT{p: unsafe.Pointer(C.BackgroundSubtractorCNT_Create())} } // Close BackgroundSubtractorCNT. func (b *BackgroundSubtractorCNT) Close() error { C.BackgroundSubtractorCNT_Close((C.BackgroundSubtractorCNT)(b.p)) b.p = nil return nil } // Apply computes a foreground mask using the current BackgroundSubtractorCNT. // // For further details, please see: // https://docs.opencv.org/3.4/de/dca/classcv_1_1bgsegm_1_1BackgroundSubtractorCNT.html func (b *BackgroundSubtractorCNT) Apply(src gocv.Mat, dst *gocv.Mat) error { return OpenCVResult(C.BackgroundSubtractorCNT_Apply((C.BackgroundSubtractorCNT)(b.p), (C.Mat)(src.Ptr()), (C.Mat)(dst.Ptr()))) } ================================================ FILE: contrib/bgsegm.h ================================================ #ifndef _OPENCV3_BGSEGM_H_ #define _OPENCV3_BGSEGM_H_ #ifdef __cplusplus #include #include extern "C" { #endif #include "../core.h" #ifdef __cplusplus typedef cv::Ptr* BackgroundSubtractorCNT; #else typedef void* BackgroundSubtractorCNT; #endif BackgroundSubtractorCNT BackgroundSubtractorCNT_Create(); void BackgroundSubtractorCNT_Close(BackgroundSubtractorCNT b); OpenCVResult BackgroundSubtractorCNT_Apply(BackgroundSubtractorCNT b, Mat src, Mat dst); #ifdef __cplusplus } #endif #endif //_OPENCV3_BGSEGM_H_ ================================================ FILE: contrib/bgsegm_test.go ================================================ //go:build !gocv_specific_modules || (gocv_specific_modules && gocv_contrib_bgsegm) package contrib import ( "testing" "gocv.io/x/gocv" ) func TestCNT(t *testing.T) { img := gocv.IMRead("../images/face.jpg", gocv.IMReadColor) if img.Empty() { t.Error("Invalid Mat in CNT test") } defer img.Close() dst := gocv.NewMat() defer dst.Close() cnt := NewBackgroundSubtractorCNT() defer cnt.Close() cnt.Apply(img, &dst) if dst.Empty() { t.Error("Error in TestCNT test") } } ================================================ FILE: contrib/cgo.go ================================================ //go:build !customenv && !opencvstatic package contrib // Changes here should be mirrored in gocv/cgo.go and cuda/cgo.go /* #cgo !windows pkg-config: opencv4 #cgo CXXFLAGS: --std=c++11 -DNDEBUG #cgo windows CPPFLAGS: -IC:/opencv/build/install/include #cgo windows LDFLAGS: -LC:/opencv/build/install/x64/mingw/lib -lopencv_core4120 -lopencv_face4120 -lopencv_videoio4120 -lopencv_imgproc4120 -lopencv_highgui4120 -lopencv_imgcodecs4120 -lopencv_objdetect4120 -lopencv_features2d4120 -lopencv_video4120 -lopencv_dnn4120 -lopencv_xfeatures2d4120 -lopencv_plot4120 -lopencv_tracking4120 -lopencv_img_hash4120 -lopencv_calib3d4120 -lopencv_bgsegm4120 -lopencv_xphoto4120 -lopencv_aruco4120 -lopencv_wechat_qrcode4120 -lopencv_ximgproc4120 -lopencv_xobjdetect4120 -lopencv_mcc4120 */ import "C" ================================================ FILE: contrib/cgo_static.go ================================================ //go:build !customenv && opencvstatic && linux package contrib // Changes here should be mirrored in contrib/cgo_static.go and cuda/cgo_static.go. /* #cgo CXXFLAGS: --std=c++11 -DNDEBUG #cgo CPPFLAGS: -I/usr/local/include -I/usr/local/include/opencv4 #cgo amd64 LDFLAGS: -O2 -g -static -L/usr/local/lib -L/usr/local/lib/opencv4/3rdparty -lopencv_gapi -lopencv_stitching -lopencv_aruco -lopencv_bgsegm -lopencv_bioinspired -lopencv_ccalib -lopencv_dnn_objdetect -lopencv_dnn_superres -lopencv_dpm -lopencv_face -lopencv_freetype -lopencv_fuzzy -lopencv_hfs -lopencv_img_hash -lopencv_intensity_transform -lopencv_line_descriptor -lopencv_mcc -lopencv_quality -lopencv_rapid -lopencv_reg -lopencv_rgbd -lopencv_saliency -lopencv_signal -lopencv_stereo -lopencv_structured_light -lopencv_phase_unwrapping -lopencv_superres -lopencv_optflow -lopencv_surface_matching -lopencv_tracking -lopencv_highgui -lopencv_datasets -lopencv_text -lopencv_plot -lopencv_videostab -lopencv_videoio -lopencv_wechat_qrcode -lopencv_xfeatures2d -lopencv_shape -lopencv_ml -lopencv_ximgproc -lopencv_video -lopencv_xobjdetect -lopencv_objdetect -lopencv_calib3d -lopencv_imgcodecs -lopencv_features2d -lopencv_dnn -lopencv_flann -lopencv_xphoto -lopencv_photo -lopencv_imgproc -lopencv_core -llibprotobuf -lade -ltbb -littnotify -llibjpeg-turbo -llibwebp -llibtiff -llibopenjp2 -lIlmImf -lquirc -lippiw -lippicv -lpng -lz -lgcc -lstdc++ -lfreetype -lharfbuzz -ldl -lm -lpthread -lrt -lavdevice -lm -latomic -lavfilter -pthread -lm -latomic -lswscale -lm -latomic -lpostproc -lm -latomic -lavformat -lm -latomic -lz -lavcodec -lvpx -lm -lvpx -lm -lvpx -lm -lvpx -lm -pthread -lm -latomic -lz -lx264 -lswresample -lm -latomic -lavutil -pthread -lm -latomic #cgo arm64 LDFLAGS: -O2 -g -static -L/usr/local/lib -L/usr/local/lib/opencv4/3rdparty -lopencv_gapi -lopencv_stitching -lopencv_aruco -lopencv_bgsegm -lopencv_bioinspired -lopencv_ccalib -lopencv_dnn_objdetect -lopencv_dnn_superres -lopencv_dpm -lopencv_face -lopencv_freetype -lopencv_fuzzy -lopencv_hfs -lopencv_img_hash -lopencv_intensity_transform -lopencv_line_descriptor -lopencv_mcc -lopencv_quality -lopencv_rapid -lopencv_reg -lopencv_rgbd -lopencv_saliency -lopencv_signal -lopencv_stereo -lopencv_structured_light -lopencv_phase_unwrapping -lopencv_superres -lopencv_optflow -lopencv_surface_matching -lopencv_tracking -lopencv_highgui -lopencv_datasets -lopencv_text -lopencv_plot -lopencv_videostab -lopencv_videoio -lopencv_wechat_qrcode -lopencv_xfeatures2d -lopencv_shape -lopencv_ml -lopencv_ximgproc -lopencv_video -lopencv_xobjdetect -lopencv_objdetect -lopencv_calib3d -lopencv_imgcodecs -lopencv_features2d -lopencv_dnn -lopencv_flann -lopencv_xphoto -lopencv_photo -lopencv_imgproc -lopencv_core -llibprotobuf -lade -ltbb -littnotify -llibjpeg-turbo -llibwebp -llibtiff -llibopenjp2 -lIlmImf -lquirc -ltegra_hal -lpng -lz -lgcc -lstdc++ -lfreetype -lharfbuzz -ldl -lm -lpthread -lrt -lavdevice -lm -latomic -lavfilter -pthread -lm -latomic -lswscale -lm -latomic -lpostproc -lm -latomic -lavformat -lm -latomic -lz -lavcodec -lvpx -lm -lvpx -lm -lvpx -lm -lvpx -lm -pthread -lm -latomic -lz -lx264 -lswresample -lm -latomic -lavutil -pthread -lm -latomic */ import "C" ================================================ FILE: contrib/cgo_static_darwin.go ================================================ //go:build !customenv && opencvstatic && darwin package contrib // Changes here should be mirrored in contrib/cgo_static_darwin.go and cuda/cgo_static_darwin.go. /* #cgo CXXFLAGS: --std=c++11 -DNDEBUG #cgo pkg-config: --static opencv4 */ import "C" ================================================ FILE: contrib/cgo_static_windows.go ================================================ //go:build !customenv && opencvstatic && windows package contrib // Changes here should be mirrored in contrib/cgo_static_windows.go and cuda/cgo_static_windows.go. /* #cgo CXXFLAGS: --std=c++11 -DNDEBUG #cgo CPPFLAGS: -IC:/opencv/build/install/include #cgo LDFLAGS: -LC:/opencv/build/install/x64/mingw/staticlib -lopencv_stereo4120 -lopencv_tracking4120 -lopencv_superres4120 -lopencv_stitching4120 -lopencv_optflow4120 -lopencv_gapi4120 -lopencv_face4120 -lopencv_dpm4120 -lopencv_dnn_objdetect4120 -lopencv_ccalib4120 -lopencv_bioinspired4120 -lopencv_bgsegm4120 -lopencv_aruco4120 -lopencv_xobjdetect4120 -lopencv_ximgproc4120 -lopencv_xfeatures2d4120 -lopencv_videostab4120 -lopencv_video4120 -lopencv_structured_light4120 -lopencv_shape4120 -lopencv_rgbd4120 -lopencv_rapid4120 -lopencv_objdetect4120 -lopencv_mcc4120 -lopencv_highgui4120 -lopencv_datasets4120 -lopencv_calib3d4120 -lopencv_videoio4120 -lopencv_text4120 -lopencv_line_descriptor4120 -lopencv_imgcodecs4120 -lopencv_img_hash4120 -lopencv_hfs4120 -lopencv_fuzzy4120 -lopencv_features2d4120 -lopencv_dnn_superres4120 -lopencv_dnn4120 -lopencv_xphoto4120 -lopencv_wechat_qrcode4120 -lopencv_surface_matching4120 -lopencv_reg4120 -lopencv_quality4120 -lopencv_plot4120 -lopencv_photo4120 -lopencv_phase_unwrapping4120 -lopencv_ml4120 -lopencv_intensity_transform4120 -lopencv_imgproc4120 -lopencv_flann4120 -lopencv_core4120 -lade -lquirc -llibprotobuf -lIlmImf -llibpng -llibopenjp2 -llibwebp -llibtiff -llibjpeg-turbo -lzlib -lkernel32 -lgdi32 -lwinspool -lshell32 -lole32 -loleaut32 -luuid -lcomdlg32 -ladvapi32 -luser32 */ import "C" ================================================ FILE: contrib/contrib.go ================================================ // Package contrib is the GoCV wrapper around OpenCV Contrib. // // For further details, please see: // https://github.com/opencv/opencv_contrib package contrib // import "gocv.io/x/gocv/contrib" ================================================ FILE: contrib/errors.go ================================================ package contrib /* #include "../core.h" */ import "C" import "errors" // Converts a OpenCVResult struct to an error. func OpenCVResult(result C.OpenCVResult) error { if result.Code == 0 { return nil } return errors.New(C.GoString(result.Message)) } ================================================ FILE: contrib/face.cpp ================================================ //go:build !gocv_specific_modules || (gocv_specific_modules && gocv_contrib_face) #include "face.h" bool FaceRecognizer_Empty(FaceRecognizer fr) { try { return (*fr)->empty(); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return false; } } OpenCVResult FaceRecognizer_Train(FaceRecognizer fr, Mats mats, IntVector labels_in) { try { std::vector labels; for (int i = 0, *v = labels_in.val; i < labels_in.length; ++v, ++i) { labels.push_back(*v); } std::vector images; for (int i = 0; i < mats.length; ++i) { images.push_back(*mats.mats[i]); } (*fr)->train(images, labels); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult FaceRecognizer_Update(FaceRecognizer fr, Mats mats, IntVector labels_in) { try { std::vector labels; for (int i = 0, *v = labels_in.val; i < labels_in.length; ++v, ++i) { labels.push_back(*v); } std::vector images; for (int i = 0; i < mats.length; ++i) { images.push_back(*mats.mats[i]); } (*fr)->update(images, labels); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } int FaceRecognizer_Predict(FaceRecognizer fr, Mat sample) { try { int label; label = (*fr)->predict(*sample); return label; } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return 0; } } struct PredictResponse FaceRecognizer_PredictExtended(FaceRecognizer fr, Mat sample) { try { struct PredictResponse response; int label; double confidence; (*fr)->predict(*sample, label, confidence); response.label = label; response.confidence = confidence; return response; } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); struct PredictResponse response; return response; } } double FaceRecognizer_GetThreshold(FaceRecognizer fr){ try { return (*fr)->getThreshold(); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return 0.0; } } void FaceRecognizer_SetThreshold(FaceRecognizer fr, double threshold) { try { (*fr)->setThreshold(threshold); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); } } OpenCVResult FaceRecognizer_SaveFile(FaceRecognizer fr, const char* filename) { try { (*fr)->write(filename); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult FaceRecognizer_LoadFile(FaceRecognizer fr, const char* filename) { try { (*fr)->read(filename); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult BasicFaceRecognizer_Train(BasicFaceRecognizer fr, Mats mats, IntVector labels_in){ try { std::vector labels; for (int i = 0, *v = labels_in.val; i < labels_in.length; ++v, ++i) { labels.push_back(*v); } std::vector images; for (int i = 0; i < mats.length; ++i) { images.push_back(*mats.mats[i]); } (*fr)->train(images, labels); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult BasicFaceRecognizer_Update(BasicFaceRecognizer fr, Mats mats, IntVector labels_in){ try { std::vector labels; for (int i = 0, *v = labels_in.val; i < labels_in.length; ++v, ++i) { labels.push_back(*v); } std::vector images; for (int i = 0; i < mats.length; ++i) { images.push_back(*mats.mats[i]); } (*fr)->update(images, labels); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } Mat BasicFaceRecognizer_getEigenValues(BasicFaceRecognizer fr){ try { return new cv::Mat((*fr)->getEigenValues()); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return new cv::Mat(); } } Mat BasicFaceRecognizer_getEigenVectors(BasicFaceRecognizer fr){ try { return new cv::Mat((*fr)->getEigenVectors()); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return new cv::Mat(); } } Mat BasicFaceRecognizer_getLabels(BasicFaceRecognizer fr){ try { return new cv::Mat((*fr)->getLabels()); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return new cv::Mat(); } } Mat BasicFaceRecognizer_getMean(BasicFaceRecognizer fr){ try { return new cv::Mat((*fr)->getMean()); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return new cv::Mat(); } } int BasicFaceRecognizer_getNumComponents(BasicFaceRecognizer fr) { try { return (*fr)->getNumComponents(); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return 0; } } Mats BasicFaceRecognizer_getProjections(BasicFaceRecognizer fr) { try { Mats mats; std::vector vec = (*fr)->getProjections(); mats.length = (int)vec.size(); mats.mats = new Mat[vec.size()]; for(size_t i = 0; i < vec.size(); i++) { mats.mats[i] = new cv::Mat(vec[i]); } return mats; } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); Mats mats; return mats; } } void BasicFaceRecognizer_setNumComponents(BasicFaceRecognizer fr, int val){ try { (*fr)->setNumComponents(val); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); } } OpenCVResult BasicFaceRecognizer_SaveFile(BasicFaceRecognizer fr, const char* filename){ try { (*fr)->write(filename); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult BasicFaceRecognizer_LoadFile(BasicFaceRecognizer fr, const char* filename){ try { (*fr)->read(filename); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } LBPHFaceRecognizer CreateLBPHFaceRecognizer() { try { return new cv::Ptr(cv::face::LBPHFaceRecognizer::create()); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } void LBPHFaceRecognizer_SetRadius(LBPHFaceRecognizer fr, int radius) { try { (*fr)->setRadius(radius); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); } } void LBPHFaceRecognizer_SetNeighbors(LBPHFaceRecognizer fr, int neighbors) { try { (*fr)->setNeighbors(neighbors); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); } } int LBPHFaceRecognizer_GetNeighbors(LBPHFaceRecognizer fr) { try { return (*fr)->getNeighbors(); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return 0; } } void LBPHFaceRecognizer_SetGridX(LBPHFaceRecognizer fr, int x) { try { (*fr)->setGridX(x); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); } } void LBPHFaceRecognizer_SetGridY(LBPHFaceRecognizer fr, int y) { try { (*fr)->setGridY(y); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); } } int LBPHFaceRecognizer_GetGridX(LBPHFaceRecognizer fr) { try { return (*fr)->getGridX(); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return 0; } } int LBPHFaceRecognizer_GetGridY(LBPHFaceRecognizer fr) { try { return (*fr)->getGridY(); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return 0; } } void LBPHFaceRecognizer_Close(LBPHFaceRecognizer fr) { delete fr; } FisherFaceRecognizer FisherFaceRecognizer_Create(void) { try { return new cv::Ptr(cv::face::FisherFaceRecognizer::create()); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } FisherFaceRecognizer FisherFaceRecognizer_CreateWithParams(int num_components, float threshold) { try { return new cv::Ptr(cv::face::FisherFaceRecognizer::create(num_components, threshold)); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } void FisherFaceRecognizer_Close(FisherFaceRecognizer fr) { delete fr; } EigenFaceRecognizer EigenFaceRecognizer_Create(void) { try { return new cv::Ptr(cv::face::EigenFaceRecognizer::create()); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } EigenFaceRecognizer EigenFaceRecognizer_CreateWithParams(int num_components, float threshold) { try { return new cv::Ptr(cv::face::EigenFaceRecognizer::create(num_components, threshold)); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } void EigenFaceRecognizer_Close(EigenFaceRecognizer fr) { delete fr; } ================================================ FILE: contrib/face.go ================================================ //go:build !gocv_specific_modules || (gocv_specific_modules && gocv_contrib_face) package contrib /* #include #include "face.h" */ import "C" import ( "image" "gocv.io/x/gocv" ) // PredictResponse represents a predicted label and associated confidence. type PredictResponse struct { Label int32 `json:"label"` Confidence float32 `json:"confidence"` } var _ FaceRecognizer = (*LBPHFaceRecognizer)(nil) var _ FaceRecognizer = (*FisherFaceRecognizer)(nil) var _ BasicFaceRecognizer = (*FisherFaceRecognizer)(nil) var _ FaceRecognizer = (*EigenFaceRecognizer)(nil) var _ BasicFaceRecognizer = (*EigenFaceRecognizer)(nil) // LBPHFaceRecognizer is a wrapper for the OpenCV Local Binary Patterns // Histograms face recognizer. type LBPHFaceRecognizer struct { p C.LBPHFaceRecognizer } // Empty returns true if the model is empty. func (fr *LBPHFaceRecognizer) Empty() bool { return faceRecognizer_Empty(C.FaceRecognizer(fr.p)) } // NewLBPHFaceRecognizer creates a new LBPH Recognizer model. // // For further information, see: // https://docs.opencv.org/master/df/d25/classcv_1_1face_1_1LBPHFaceRecognizer.html func NewLBPHFaceRecognizer() *LBPHFaceRecognizer { return &LBPHFaceRecognizer{p: C.CreateLBPHFaceRecognizer()} } // Train loaded model with images and their labels // // see https://docs.opencv.org/master/dd/d65/classcv_1_1face_1_1FaceRecognizer.html#ac8680c2aa9649ad3f55e27761165c0d6 func (fr *LBPHFaceRecognizer) Train(images []gocv.Mat, labels []int) error { return faceRecognizer_Train(C.FaceRecognizer(fr.p), images, labels) } // Update updates the existing trained model with new images and labels. // // For further information, see: // https://docs.opencv.org/master/dd/d65/classcv_1_1face_1_1FaceRecognizer.html#a8a4e73ea878dcd0c235d0487189d25f3 func (fr *LBPHFaceRecognizer) Update(newImages []gocv.Mat, newLabels []int) error { return faceRecognizer_Update(C.FaceRecognizer(fr.p), newImages, newLabels) } // Predict predicts a label for a given input image. It returns the label for // correctly predicted image or -1 if not found. // // For further information, see: // https://docs.opencv.org/master/dd/d65/classcv_1_1face_1_1FaceRecognizer.html#aa2d2f02faffab1bf01317ae6502fb631 func (fr *LBPHFaceRecognizer) Predict(sample gocv.Mat) int { label := faceRecognizer_Predict(C.FaceRecognizer(fr.p), sample) return int(label) } // PredictExtendedResponse returns a label and associated confidence (e.g. // distance) for a given input image. It is the extended version of // `Predict()`. // // For further information, see: // https://docs.opencv.org/master/dd/d65/classcv_1_1face_1_1FaceRecognizer.html#ab0d593e53ebd9a0f350c989fcac7f251 func (fr *LBPHFaceRecognizer) PredictExtendedResponse(sample gocv.Mat) PredictResponse { resp := faceRecognizer_PredictExtendedResponse(C.FaceRecognizer(fr.p), sample) return resp } // GetThreshold gets the threshold value of the model, i.e. the threshold // applied in the prediction. // // For further information, see: // https://docs.opencv.org/4.x/df/d25/classcv_1_1face_1_1LBPHFaceRecognizer.html#acf2a6993eb4347b3f89009da693a3f70 func (fr *LBPHFaceRecognizer) GetThreshold() float32 { t := faceRecognizer_GetThreshold(C.FaceRecognizer(fr.p)) return float32(t) } // SetThreshold sets the threshold value of the model, i.e. the threshold // applied in the prediction. // // For further information, see: // https://docs.opencv.org/master/dd/d65/classcv_1_1face_1_1FaceRecognizer.html#a3182081e5f8023e658ad8ab96656dd63 func (fr *LBPHFaceRecognizer) SetThreshold(threshold float32) { faceRecognizer_SetThreshold(C.FaceRecognizer(fr.p), threshold) } // SetNeighbors sets the neighbors value of the model, i.e. the number of // sample points to build a Circular Local Binary Pattern from. Note that wrong // neighbors can raise OpenCV exception! // // For further information, see: // https://docs.opencv.org/master/df/d25/classcv_1_1face_1_1LBPHFaceRecognizer.html#ab225f7bf353ce8697a506eda10124a92 func (fr *LBPHFaceRecognizer) SetNeighbors(neighbors int) { C.LBPHFaceRecognizer_SetNeighbors(fr.p, C.int(neighbors)) } // GetNeighbors returns the neighbors value of the model. // // For further information, see: // https://docs.opencv.org/master/df/d25/classcv_1_1face_1_1LBPHFaceRecognizer.html#a50a3e2ca6e8464166e153c9df84b0a77 func (fr *LBPHFaceRecognizer) GetNeighbors() int { n := C.LBPHFaceRecognizer_GetNeighbors(fr.p) return int(n) } // SetRadius sets the radius used for building the Circular Local Binary // Pattern. // // For further information, see: // https://docs.opencv.org/master/df/d25/classcv_1_1face_1_1LBPHFaceRecognizer.html#a62d94c75cade902fd3b487b1ef9883fc func (fr *LBPHFaceRecognizer) SetRadius(radius int) { C.LBPHFaceRecognizer_SetRadius(fr.p, C.int(radius)) } // SaveFile saves the trained model data to file. // // For further information, see: // https://docs.opencv.org/master/dd/d65/classcv_1_1face_1_1FaceRecognizer.html#a2adf2d555550194244b05c91fefcb4d6 func (fr *LBPHFaceRecognizer) SaveFile(fname string) error { return faceRecognizer_SaveFile(C.FaceRecognizer(fr.p), fname) } // LoadFile loads a trained model data from file. // // For further information, see: // https://docs.opencv.org/master/dd/d65/classcv_1_1face_1_1FaceRecognizer.html#acc42e5b04595dba71f0777c7179af8c3 func (fr *LBPHFaceRecognizer) LoadFile(fname string) error { return faceRecognizer_LoadFile(C.FaceRecognizer(fr.p), fname) } // SetGridX sets grid's X value // // For further information, see: // https://docs.opencv.org/4.x/df/d25/classcv_1_1face_1_1LBPHFaceRecognizer.html#ad65975baee31dbf3bd2a750feef74831 func (fr *LBPHFaceRecognizer) SetGridX(x int) { C.LBPHFaceRecognizer_SetGridX(fr.p, C.int(x)) } // SetGridY sets grid's Y value // // For further information, see: // https://docs.opencv.org/4.x/df/d25/classcv_1_1face_1_1LBPHFaceRecognizer.html#a9cebb0138dbb3553b27beb2df3924ae6 func (fr *LBPHFaceRecognizer) SetGridY(y int) { C.LBPHFaceRecognizer_SetGridY(fr.p, C.int(y)) } // GetGridX gets grid's X value // // For further information, see: // https://docs.opencv.org/4.x/df/d25/classcv_1_1face_1_1LBPHFaceRecognizer.html#ada6839bed931a8f68c5127e1af7a8b83 func (fr *LBPHFaceRecognizer) GetGridX() int { x := C.LBPHFaceRecognizer_GetGridX(fr.p) return int(x) } // GetGridY gets grid's Y value // // For further information, see: // https://docs.opencv.org/4.x/df/d25/classcv_1_1face_1_1LBPHFaceRecognizer.html#a22c68c0baf3eb9e852f47ae9241dbf15 func (fr *LBPHFaceRecognizer) GetGridY() int { y := C.LBPHFaceRecognizer_GetGridY(fr.p) return int(y) } // SetGrid helper for SetGrid* functions func (fr *LBPHFaceRecognizer) SetGrid(p image.Point) { fr.SetGridX(p.X) fr.SetGridY(p.Y) } // GetGrid helper for GetGrid* functions func (fr *LBPHFaceRecognizer) GetGrid() image.Point { return image.Pt(fr.GetGridX(), fr.GetGridY()) } func (fr *LBPHFaceRecognizer) Close() error { C.LBPHFaceRecognizer_Close(fr.p) fr.p = nil return nil } type FisherFaceRecognizer struct { p C.FisherFaceRecognizer } // NewFisherFaceRecognizer creates a new Fisher Recognizer model. // // For further information, see: // https://docs.opencv.org/4.x/d2/de9/classcv_1_1face_1_1FisherFaceRecognizer.html#ac6e204df6d7e526f4c77d3e0389dfbaa func NewFisherFaceRecognizer() *FisherFaceRecognizer { return &FisherFaceRecognizer{p: C.FisherFaceRecognizer_Create()} } // NewFisherFaceRecognizerWithParams creates a new Fisher Recognizer model. // // [num_components] The number of components (read: Fisherfaces) kept for this Linear Discriminant Analysis with the Fisherfaces criterion. It's useful to keep all components, that means the number of your classes c (read: subjects, persons you want to recognize). If you leave this at the default (0) or set it to a value less-equal 0 or greater (c-1), it will be set to the correct number (c-1) automatically. // // [threshold] The threshold applied in the prediction. If the distance to the nearest neighbor is larger than the threshold, this method returns -1. // // For further information, see: // https://docs.opencv.org/4.x/d2/de9/classcv_1_1face_1_1FisherFaceRecognizer.html#ac6e204df6d7e526f4c77d3e0389dfbaa func NewFisherFaceRecognizerWithParams(numComponents int, threshold float32) *FisherFaceRecognizer { return &FisherFaceRecognizer{p: C.FisherFaceRecognizer_CreateWithParams(C.int(numComponents), C.float(threshold))} } // Empty returns true if the model is empty. func (fr *FisherFaceRecognizer) Empty() bool { b := faceRecognizer_Empty(C.FaceRecognizer(fr.p)) return bool(b) } func (fr *FisherFaceRecognizer) GetEigenValues() gocv.Mat { return basicFaceRecognizer_GetEigenValues(C.BasicFaceRecognizer(fr.p)) } func (fr *FisherFaceRecognizer) GetEigenVectors() gocv.Mat { return basicFaceRecognizer_GetEigenVectors(C.BasicFaceRecognizer(fr.p)) } func (fr *FisherFaceRecognizer) GetLabels() gocv.Mat { return basicFaceRecognizer_GetLabels(C.BasicFaceRecognizer(fr.p)) } func (fr *FisherFaceRecognizer) GetMean() gocv.Mat { return basicFaceRecognizer_GetMean(C.BasicFaceRecognizer(fr.p)) } func (fr *FisherFaceRecognizer) GetNumComponents() int { return basicFaceRecognizer_GetNumComponents(C.BasicFaceRecognizer(fr.p)) } func (fr *FisherFaceRecognizer) SetNumComponents(val int) { basicFaceRecognizer_SetNumComponents(C.BasicFaceRecognizer(fr.p), val) } func (fr *FisherFaceRecognizer) GetProjections() []gocv.Mat { return basicFaceRecognizer_GetProjections(C.BasicFaceRecognizer(fr.p)) } // GetThreshold gets the threshold value of the model, i.e. the threshold // applied in the prediction. // // For further information, see: // https://docs.opencv.org/4.x/df/d25/classcv_1_1face_1_1LBPHFaceRecognizer.html#acf2a6993eb4347b3f89009da693a3f70 func (fr *FisherFaceRecognizer) GetThreshold() float32 { return faceRecognizer_GetThreshold(C.FaceRecognizer(fr.p)) } // SetThreshold sets the threshold value of the model, i.e. the threshold // applied in the prediction. // // For further information, see: // https://docs.opencv.org/master/dd/d65/classcv_1_1face_1_1FaceRecognizer.html#a3182081e5f8023e658ad8ab96656dd63 func (fr *FisherFaceRecognizer) SetThreshold(threshold float32) { faceRecognizer_SetThreshold(C.FaceRecognizer(fr.p), threshold) } // LoadFile loads a trained model data from file. // // For further information, see: // https://docs.opencv.org/master/dd/d65/classcv_1_1face_1_1FaceRecognizer.html#acc42e5b04595dba71f0777c7179af8c3 func (fr *FisherFaceRecognizer) LoadFile(filename string) error { return basicFaceRecognizer_LoadFile(C.BasicFaceRecognizer(fr.p), filename) } // SaveFile saves the trained model data to file. // // For further information, see: // https://docs.opencv.org/master/dd/d65/classcv_1_1face_1_1FaceRecognizer.html#a2adf2d555550194244b05c91fefcb4d6 func (fr *FisherFaceRecognizer) SaveFile(filename string) error { return basicFaceRecognizer_SaveFile(C.BasicFaceRecognizer(fr.p), filename) } // Predict predicts a label for a given input image. It returns the label for // correctly predicted image or -1 if not found. // // For further information, see: // https://docs.opencv.org/master/dd/d65/classcv_1_1face_1_1FaceRecognizer.html#aa2d2f02faffab1bf01317ae6502fb631 func (fr *FisherFaceRecognizer) Predict(sample gocv.Mat) int { return faceRecognizer_Predict(C.FaceRecognizer(fr.p), sample) } // PredictExtendedResponse returns a label and associated confidence (e.g. // distance) for a given input image. It is the extended version of // `Predict()`. // // For further information, see: // https://docs.opencv.org/master/dd/d65/classcv_1_1face_1_1FaceRecognizer.html#ab0d593e53ebd9a0f350c989fcac7f251 func (fr *FisherFaceRecognizer) PredictExtendedResponse(sample gocv.Mat) PredictResponse { return faceRecognizer_PredictExtendedResponse(C.FaceRecognizer(fr.p), sample) } // Train loaded model with images and their labels // // see https://docs.opencv.org/master/dd/d65/classcv_1_1face_1_1FaceRecognizer.html#ac8680c2aa9649ad3f55e27761165c0d6 func (fr *FisherFaceRecognizer) Train(images []gocv.Mat, labels []int) error { return basicFaceRecognizer_Train(C.BasicFaceRecognizer(fr.p), images, labels) } // Update This model does not support updating. // // For further information, see: // https://docs.opencv.org/4.x/d2/de9/classcv_1_1face_1_1FisherFaceRecognizer.html#ac6e204df6d7e526f4c77d3e0389dfbaa func (fr *FisherFaceRecognizer) Update(newImages []gocv.Mat, newLabels []int) error { return faceRecognizer_Train(C.FaceRecognizer(fr.p), newImages, newLabels) } func (fr *FisherFaceRecognizer) Close() error { C.FisherFaceRecognizer_Close(fr.p) fr.p = nil return nil } type EigenFaceRecognizer struct { p C.EigenFaceRecognizer } // NewEigenFaceRecognizer creates a new Eigen Recognizer model. // // For further information, see: // https://docs.opencv.org/4.x/dd/d7c/classcv_1_1face_1_1EigenFaceRecognizer.html#a22c8392f27a20b24d04351b675e7b6db func NewEigenFaceRecognizer() *EigenFaceRecognizer { return &EigenFaceRecognizer{p: C.EigenFaceRecognizer_Create()} } // NewEigenFaceRecognizerWithParams creates a new Eigen Recognizer model. // // [num_components] The number of components (read: Eigenfaces) kept for this Principal Component Analysis. // [threshold] The threshold applied in the prediction. // // For further information, see: // https://docs.opencv.org/4.x/dd/d7c/classcv_1_1face_1_1EigenFaceRecognizer.html#a22c8392f27a20b24d04351b675e7b6db func NewEigenFaceRecognizerWithParams(numComponents int, threshold float32) *EigenFaceRecognizer { return &EigenFaceRecognizer{p: C.EigenFaceRecognizer_CreateWithParams(C.int(numComponents), C.float(threshold))} } // Empty returns true if the model is empty. func (fr *EigenFaceRecognizer) Empty() bool { b := faceRecognizer_Empty(C.FaceRecognizer(fr.p)) return bool(b) } func (fr *EigenFaceRecognizer) GetEigenValues() gocv.Mat { return basicFaceRecognizer_GetEigenValues(C.BasicFaceRecognizer(fr.p)) } func (fr *EigenFaceRecognizer) GetEigenVectors() gocv.Mat { return basicFaceRecognizer_GetEigenVectors(C.BasicFaceRecognizer(fr.p)) } func (fr *EigenFaceRecognizer) GetLabels() gocv.Mat { return basicFaceRecognizer_GetLabels(C.BasicFaceRecognizer(fr.p)) } func (fr *EigenFaceRecognizer) GetMean() gocv.Mat { return basicFaceRecognizer_GetMean(C.BasicFaceRecognizer(fr.p)) } func (fr *EigenFaceRecognizer) GetNumComponents() int { return basicFaceRecognizer_GetNumComponents(C.BasicFaceRecognizer(fr.p)) } func (fr *EigenFaceRecognizer) SetNumComponents(val int) { basicFaceRecognizer_SetNumComponents(C.BasicFaceRecognizer(fr.p), val) } func (fr *EigenFaceRecognizer) GetProjections() []gocv.Mat { return basicFaceRecognizer_GetProjections(C.BasicFaceRecognizer(fr.p)) } // GetThreshold gets the threshold value of the model, i.e. the threshold // applied in the prediction. // // For further information, see: // https://docs.opencv.org/4.x/df/d25/classcv_1_1face_1_1LBPHFaceRecognizer.html#acf2a6993eb4347b3f89009da693a3f70 func (fr *EigenFaceRecognizer) GetThreshold() float32 { return faceRecognizer_GetThreshold(C.FaceRecognizer(fr.p)) } // SetThreshold sets the threshold value of the model, i.e. the threshold // applied in the prediction. // // For further information, see: // https://docs.opencv.org/master/dd/d65/classcv_1_1face_1_1FaceRecognizer.html#a3182081e5f8023e658ad8ab96656dd63 func (fr *EigenFaceRecognizer) SetThreshold(threshold float32) { faceRecognizer_SetThreshold(C.FaceRecognizer(fr.p), threshold) } // LoadFile loads a trained model data from file. // // For further information, see: // https://docs.opencv.org/master/dd/d65/classcv_1_1face_1_1FaceRecognizer.html#acc42e5b04595dba71f0777c7179af8c3 func (fr *EigenFaceRecognizer) LoadFile(filename string) error { return basicFaceRecognizer_LoadFile(C.BasicFaceRecognizer(fr.p), filename) } // SaveFile saves the trained model data to file. // // For further information, see: // https://docs.opencv.org/master/dd/d65/classcv_1_1face_1_1FaceRecognizer.html#a2adf2d555550194244b05c91fefcb4d6 func (fr *EigenFaceRecognizer) SaveFile(filename string) error { return basicFaceRecognizer_SaveFile(C.BasicFaceRecognizer(fr.p), filename) } // Predict predicts a label for a given input image. It returns the label for // correctly predicted image or -1 if not found. // // For further information, see: // https://docs.opencv.org/master/dd/d65/classcv_1_1face_1_1FaceRecognizer.html#aa2d2f02faffab1bf01317ae6502fb631 func (fr *EigenFaceRecognizer) Predict(sample gocv.Mat) int { return faceRecognizer_Predict(C.FaceRecognizer(fr.p), sample) } // PredictExtendedResponse returns a label and associated confidence (e.g. // distance) for a given input image. It is the extended version of // `Predict()`. // // For further information, see: // https://docs.opencv.org/master/dd/d65/classcv_1_1face_1_1FaceRecognizer.html#ab0d593e53ebd9a0f350c989fcac7f251 func (fr *EigenFaceRecognizer) PredictExtendedResponse(sample gocv.Mat) PredictResponse { return faceRecognizer_PredictExtendedResponse(C.FaceRecognizer(fr.p), sample) } // Train loaded model with images and their labels // // see https://docs.opencv.org/master/dd/d65/classcv_1_1face_1_1FaceRecognizer.html#ac8680c2aa9649ad3f55e27761165c0d6 func (fr *EigenFaceRecognizer) Train(images []gocv.Mat, labels []int) error { return basicFaceRecognizer_Train(C.BasicFaceRecognizer(fr.p), images, labels) } // Update This model does not support updating. // // For further information, see: // https://docs.opencv.org/4.x/dd/d7c/classcv_1_1face_1_1EigenFaceRecognizer.html#a22c8392f27a20b24d04351b675e7b6db func (fr *EigenFaceRecognizer) Update(newImages []gocv.Mat, newLabels []int) error { return basicFaceRecognizer_Train(C.BasicFaceRecognizer(fr.p), newImages, newLabels) } func (fr *EigenFaceRecognizer) Close() error { C.EigenFaceRecognizer_Close(fr.p) fr.p = nil return nil } ================================================ FILE: contrib/face.h ================================================ #ifndef _OPENCV3_FACE_H_ #define _OPENCV3_FACE_H_ #ifdef __cplusplus #include #include extern "C" { #endif #include "../core.h" #ifdef __cplusplus typedef cv::Ptr* FaceRecognizer; typedef cv::Ptr* BasicFaceRecognizer; typedef cv::Ptr* LBPHFaceRecognizer; typedef cv::Ptr* EigenFaceRecognizer; typedef cv::Ptr* FisherFaceRecognizer; #else typedef void* FaceRecognizer; typedef void* BasicFaceRecognizer; typedef void* LBPHFaceRecognizer; typedef void* EigenFaceRecognizer; typedef void* FisherFaceRecognizer; #endif struct PredictResponse { int label; double confidence; }; bool FaceRecognizer_Empty(FaceRecognizer fr); OpenCVResult FaceRecognizer_Train(FaceRecognizer fr, Mats images, IntVector labels); OpenCVResult FaceRecognizer_Update(FaceRecognizer fr, Mats images, IntVector labels); int FaceRecognizer_Predict(FaceRecognizer fr, Mat sample); struct PredictResponse FaceRecognizer_PredictExtended(FaceRecognizer fr, Mat sample); double FaceRecognizer_GetThreshold(FaceRecognizer fr); void FaceRecognizer_SetThreshold(FaceRecognizer fr, double threshold); OpenCVResult FaceRecognizer_SaveFile(FaceRecognizer fr, const char* filename); OpenCVResult FaceRecognizer_LoadFile(FaceRecognizer fr, const char* filename); OpenCVResult BasicFaceRecognizer_Train(BasicFaceRecognizer fr, Mats images, IntVector labels); OpenCVResult BasicFaceRecognizer_Update(BasicFaceRecognizer fr, Mats images, IntVector labels); Mat BasicFaceRecognizer_getEigenValues(BasicFaceRecognizer fr); Mat BasicFaceRecognizer_getEigenVectors(BasicFaceRecognizer fr); Mat BasicFaceRecognizer_getLabels(BasicFaceRecognizer fr); Mat BasicFaceRecognizer_getMean(BasicFaceRecognizer fr); int BasicFaceRecognizer_getNumComponents(BasicFaceRecognizer fr); Mats BasicFaceRecognizer_getProjections(BasicFaceRecognizer fr); void BasicFaceRecognizer_setNumComponents(BasicFaceRecognizer fr, int val); OpenCVResult BasicFaceRecognizer_SaveFile(BasicFaceRecognizer fr, const char* filename); OpenCVResult BasicFaceRecognizer_LoadFile(BasicFaceRecognizer fr, const char* filename); LBPHFaceRecognizer CreateLBPHFaceRecognizer(void); void LBPHFaceRecognizer_SetRadius(LBPHFaceRecognizer fr, int radius); void LBPHFaceRecognizer_SetNeighbors(LBPHFaceRecognizer fr, int neighbors); int LBPHFaceRecognizer_GetNeighbors(LBPHFaceRecognizer fr); void LBPHFaceRecognizer_SetGridX(LBPHFaceRecognizer fr, int x); void LBPHFaceRecognizer_SetGridY(LBPHFaceRecognizer fr, int y); int LBPHFaceRecognizer_GetGridX(LBPHFaceRecognizer fr); int LBPHFaceRecognizer_GetGridY(LBPHFaceRecognizer fr); void LBPHFaceRecognizer_Close(LBPHFaceRecognizer fr); FisherFaceRecognizer FisherFaceRecognizer_Create(void); FisherFaceRecognizer FisherFaceRecognizer_CreateWithParams(int num_components, float threshold); void FisherFaceRecognizer_Close(FisherFaceRecognizer fr); EigenFaceRecognizer EigenFaceRecognizer_Create(void); EigenFaceRecognizer EigenFaceRecognizer_CreateWithParams(int num_components, float threshold); void EigenFaceRecognizer_Close(EigenFaceRecognizer fr); #ifdef __cplusplus } #endif #endif //_OPENCV3_FACE_H_ ================================================ FILE: contrib/face_recognizer.go ================================================ //go:build !gocv_specific_modules || (gocv_specific_modules && gocv_contrib_face) package contrib /* #include #include "face.h" */ import "C" import ( "unsafe" "gocv.io/x/gocv" ) type FaceRecognizer interface { Empty() bool Train(images []gocv.Mat, labels []int) error Update(newImages []gocv.Mat, newLabels []int) error Predict(sample gocv.Mat) int PredictExtendedResponse(sample gocv.Mat) PredictResponse GetThreshold() float32 SetThreshold(threshold float32) SaveFile(fname string) error LoadFile(fname string) error Close() error } type BasicFaceRecognizer interface { GetEigenValues() gocv.Mat GetEigenVectors() gocv.Mat GetLabels() gocv.Mat GetMean() gocv.Mat GetNumComponents() int SetNumComponents(val int) GetProjections() []gocv.Mat SaveFile(fname string) error LoadFile(fname string) error } func faceRecognizer_Empty(fr C.FaceRecognizer) bool { b := C.FaceRecognizer_Empty(fr) return bool(b) } func faceRecognizer_Train(fr C.FaceRecognizer, images []gocv.Mat, labels []int) error { cparams := []C.int{} for _, v := range labels { cparams = append(cparams, C.int(v)) } labelsVector := C.struct_IntVector{} labelsVector.val = (*C.int)(&cparams[0]) labelsVector.length = (C.int)(len(cparams)) cMatArray := make([]C.Mat, len(images)) for i, r := range images { cMatArray[i] = (C.Mat)(r.Ptr()) } matsVector := C.struct_Mats{ mats: (*C.Mat)(&cMatArray[0]), length: C.int(len(images)), } return OpenCVResult(C.FaceRecognizer_Train(fr, matsVector, labelsVector)) } func faceRecognizer_Update(fr C.FaceRecognizer, newImages []gocv.Mat, newLabels []int) error { cparams := []C.int{} for _, v := range newLabels { cparams = append(cparams, C.int(v)) } labelsVector := C.struct_IntVector{} labelsVector.val = (*C.int)(&cparams[0]) labelsVector.length = (C.int)(len(cparams)) cMatArray := make([]C.Mat, len(newImages)) for i, r := range newImages { cMatArray[i] = (C.Mat)(r.Ptr()) } matsVector := C.struct_Mats{ mats: (*C.Mat)(&cMatArray[0]), length: C.int(len(newImages)), } return OpenCVResult(C.FaceRecognizer_Update(fr, matsVector, labelsVector)) } func faceRecognizer_Predict(fr C.FaceRecognizer, sample gocv.Mat) int { label := C.FaceRecognizer_Predict(fr, (C.Mat)(sample.Ptr())) return int(label) } func faceRecognizer_PredictExtendedResponse(fr C.FaceRecognizer, sample gocv.Mat) PredictResponse { respp := C.FaceRecognizer_PredictExtended(fr, (C.Mat)(sample.Ptr())) resp := PredictResponse{ Label: int32(respp.label), Confidence: float32(respp.confidence), } return resp } func faceRecognizer_GetThreshold(fr C.FaceRecognizer) float32 { t := C.FaceRecognizer_GetThreshold(fr) return float32(t) } func faceRecognizer_SetThreshold(fr C.FaceRecognizer, threshold float32) { C.FaceRecognizer_SetThreshold(fr, (C.double)(threshold)) } func faceRecognizer_SaveFile(fr C.FaceRecognizer, fname string) error { cName := C.CString(fname) defer C.free(unsafe.Pointer(cName)) return OpenCVResult(C.FaceRecognizer_SaveFile(fr, cName)) } func faceRecognizer_LoadFile(fr C.FaceRecognizer, fname string) error { cName := C.CString(fname) defer C.free(unsafe.Pointer(cName)) return OpenCVResult(C.FaceRecognizer_LoadFile(fr, cName)) } func basicFaceRecognizer_Train(fr C.BasicFaceRecognizer, images []gocv.Mat, labels []int) error { cparams := []C.int{} for _, v := range labels { cparams = append(cparams, C.int(v)) } labelsVector := C.struct_IntVector{} labelsVector.val = (*C.int)(&cparams[0]) labelsVector.length = (C.int)(len(cparams)) cMatArray := make([]C.Mat, len(images)) for i, r := range images { cMatArray[i] = (C.Mat)(r.Ptr()) } matsVector := C.struct_Mats{ mats: (*C.Mat)(&cMatArray[0]), length: C.int(len(images)), } return OpenCVResult(C.BasicFaceRecognizer_Train(fr, matsVector, labelsVector)) } func basicFaceRecognizer_Update(fr C.BasicFaceRecognizer, newImages []gocv.Mat, newLabels []int) error { cparams := []C.int{} for _, v := range newLabels { cparams = append(cparams, C.int(v)) } labelsVector := C.struct_IntVector{} labelsVector.val = (*C.int)(&cparams[0]) labelsVector.length = (C.int)(len(cparams)) cMatArray := make([]C.Mat, len(newImages)) for i, r := range newImages { cMatArray[i] = (C.Mat)(r.Ptr()) } matsVector := C.struct_Mats{ mats: (*C.Mat)(&cMatArray[0]), length: C.int(len(newImages)), } return OpenCVResult(C.BasicFaceRecognizer_Update(fr, matsVector, labelsVector)) } func basicFaceRecognizer_GetEigenValues(fr C.BasicFaceRecognizer) gocv.Mat { c_mat := C.BasicFaceRecognizer_getEigenValues(fr) return gocv.NewMatFromCMat(unsafe.Pointer(c_mat)) } func basicFaceRecognizer_GetEigenVectors(fr C.BasicFaceRecognizer) gocv.Mat { c_mat := C.BasicFaceRecognizer_getEigenVectors(fr) return gocv.NewMatFromCMat(unsafe.Pointer(c_mat)) } func basicFaceRecognizer_GetLabels(fr C.BasicFaceRecognizer) gocv.Mat { c_mat := C.BasicFaceRecognizer_getLabels(fr) return gocv.NewMatFromCMat(unsafe.Pointer(c_mat)) } func basicFaceRecognizer_GetMean(fr C.BasicFaceRecognizer) gocv.Mat { c_mat := C.BasicFaceRecognizer_getMean(fr) return gocv.NewMatFromCMat(unsafe.Pointer(c_mat)) } func basicFaceRecognizer_GetNumComponents(fr C.BasicFaceRecognizer) int { i := C.BasicFaceRecognizer_getNumComponents(fr) return int(i) } func basicFaceRecognizer_SetNumComponents(fr C.BasicFaceRecognizer, val int) { C.BasicFaceRecognizer_setNumComponents(fr, C.int(val)) } func basicFaceRecognizer_GetProjections(fr C.BasicFaceRecognizer) []gocv.Mat { c_mats := C.BasicFaceRecognizer_getProjections(fr) defer C.Mats_Close(c_mats) mats := make([]gocv.Mat, 0, c_mats.length) for i := 0; i < int(c_mats.length); i++ { c_mat := C.Mats_get(c_mats, C.int(i)) mat := gocv.NewMatFromCMat(unsafe.Pointer(c_mat)) mats = append(mats, mat) } return mats } func basicFaceRecognizer_SaveFile(fr C.BasicFaceRecognizer, fname string) error { cName := C.CString(fname) defer C.free(unsafe.Pointer(cName)) return OpenCVResult(C.BasicFaceRecognizer_SaveFile(fr, cName)) } func basicFaceRecognizer_LoadFile(fr C.BasicFaceRecognizer, fname string) error { cName := C.CString(fname) defer C.free(unsafe.Pointer(cName)) return OpenCVResult(C.BasicFaceRecognizer_LoadFile(fr, cName)) } ================================================ FILE: contrib/face_test.go ================================================ //go:build !gocv_specific_modules || (gocv_specific_modules && gocv_contrib_face) package contrib import ( "image" "math" "testing" "gocv.io/x/gocv" ) func TestLBPHFaceRecognizer_Methods(t *testing.T) { model := NewLBPHFaceRecognizer() if model == nil { t.Errorf("Invalid NewLBPHFaceRecognizer call %v", model) } model.Empty() labels := []int{1, 1, 1, 1, 2, 2, 2, 2} images := []gocv.Mat{ gocv.IMRead("./att_faces/s1/1.pgm", gocv.IMReadGrayScale), gocv.IMRead("./att_faces/s1/2.pgm", gocv.IMReadGrayScale), gocv.IMRead("./att_faces/s1/3.pgm", gocv.IMReadGrayScale), gocv.IMRead("./att_faces/s1/4.pgm", gocv.IMReadGrayScale), gocv.IMRead("./att_faces/s2/1.pgm", gocv.IMReadGrayScale), gocv.IMRead("./att_faces/s2/2.pgm", gocv.IMReadGrayScale), gocv.IMRead("./att_faces/s2/3.pgm", gocv.IMReadGrayScale), gocv.IMRead("./att_faces/s2/4.pgm", gocv.IMReadGrayScale), } model.Train(images, labels) sample := gocv.IMRead("./att_faces/s2/5.pgm", gocv.IMReadGrayScale) label := model.Predict(sample) if label != 2 { t.Errorf("Invalid simple predict! label: %d", label) } resp := model.PredictExtendedResponse(sample) if resp.Label != 2 { t.Errorf("Invalid extended result predict! label: %d", resp.Label) } // set wrong threshold model.SetThreshold(0.0) label = model.Predict(sample) if label != -1 { t.Errorf("Invalid set wrong threshold! label: %d", label) } //// set good threshold model.SetThreshold(math.MaxFloat32) // set wrong radius model.SetRadius(0) label = model.Predict(sample) if label == 2 { t.Errorf("Invalid set wrong radius! label: %d", label) } neighbors := model.GetNeighbors() if neighbors == 0 { t.Errorf("Invalid get neighbors! n: %d", neighbors) } model.SetRadius(1) model.SetNeighbors(8) label = model.Predict(sample) if label != 2 { t.Errorf("Invalid set neighbors! label: %d", label) } // add new data sample = gocv.IMRead("./att_faces/s3/10.pgm", gocv.IMReadGrayScale) newLabels := []int{3, 3, 3, 3, 3, 3} newImages := []gocv.Mat{ gocv.IMRead("./att_faces/s3/1.pgm", gocv.IMReadGrayScale), gocv.IMRead("./att_faces/s3/2.pgm", gocv.IMReadGrayScale), gocv.IMRead("./att_faces/s3/3.pgm", gocv.IMReadGrayScale), gocv.IMRead("./att_faces/s3/4.pgm", gocv.IMReadGrayScale), gocv.IMRead("./att_faces/s3/5.pgm", gocv.IMReadGrayScale), gocv.IMRead("./att_faces/s3/6.pgm", gocv.IMReadGrayScale), } model.Update(newImages, newLabels) label = model.Predict(sample) if label != 3 { t.Errorf("Invalid new data update: %d", label) } // test save and load fName := "data.yaml" model.SaveFile(fName) modelNew := NewLBPHFaceRecognizer() modelNew.LoadFile(fName) label = modelNew.Predict(sample) if label != 3 { t.Errorf("Invalid loaded data: %d", label) } } func TestLBPHFaceRecognizer_SetGridY_GetGridY(t *testing.T) { facer := NewLBPHFaceRecognizer() facer.SetGridY(5) if v := facer.GetGridY(); v != 5 { t.Errorf("got %d want 5", v) } } func TestLBPHFaceRecognizer_SetGrid_GetGrid(t *testing.T) { facer := NewLBPHFaceRecognizer() defer facer.Close() facer.SetGrid(image.Point{7, 5}) if p := facer.GetGrid(); p.X != 7 || p.Y != 5 { t.Errorf("got %+v want {7, 5}", p) } } func TestEigenFaceRecognizer_Methods(t *testing.T) { model := NewEigenFaceRecognizer() if model == nil { t.Errorf("Invalid NewEigenFaceRecognizer call %v", model) } model.Empty() m := model.GetEigenValues() defer m.Close() m2 := model.GetEigenVectors() defer m2.Close() m3 := model.GetMean() defer m3.Close() nc := model.GetNumComponents() t.Logf("numComponents %d\n", nc) labels := []int{1, 1, 1, 1, 2, 2, 2, 2} images := []gocv.Mat{ gocv.IMRead("./att_faces/s1/1.pgm", gocv.IMReadGrayScale), gocv.IMRead("./att_faces/s1/2.pgm", gocv.IMReadGrayScale), gocv.IMRead("./att_faces/s1/3.pgm", gocv.IMReadGrayScale), gocv.IMRead("./att_faces/s1/4.pgm", gocv.IMReadGrayScale), gocv.IMRead("./att_faces/s2/1.pgm", gocv.IMReadGrayScale), gocv.IMRead("./att_faces/s2/2.pgm", gocv.IMReadGrayScale), gocv.IMRead("./att_faces/s2/3.pgm", gocv.IMReadGrayScale), gocv.IMRead("./att_faces/s2/4.pgm", gocv.IMReadGrayScale), } model.Train(images, labels) sample := gocv.IMRead("./att_faces/s2/5.pgm", gocv.IMReadGrayScale) label := model.Predict(sample) if label != 2 { t.Errorf("Invalid simple predict! label: %d", label) } resp := model.PredictExtendedResponse(sample) if resp.Label != 2 { t.Errorf("Invalid extended result predict! label: %d", resp.Label) } // set wrong threshold model.SetThreshold(0.0) label = model.Predict(sample) if label != -1 { t.Errorf("Invalid set wrong threshold! label: %d", label) } // test save and load fName := "data.yaml" model.SaveFile(fName) modelNew := NewEigenFaceRecognizer() modelNew.LoadFile(fName) label = modelNew.Predict(sample) if label != 2 { t.Errorf("Invalid loaded data: %d", label) } } func TestFisherFaceRecognizer_Methods(t *testing.T) { model := NewFisherFaceRecognizer() if model == nil { t.Errorf("Invalid NewFisherFaceRecognizer call %v", model) } model.Empty() m := model.GetEigenValues() defer m.Close() m2 := model.GetEigenVectors() defer m2.Close() m3 := model.GetMean() defer m3.Close() nc := model.GetNumComponents() t.Logf("numComponents %d\n", nc) labels := []int{1, 1, 1, 1, 2, 2, 2, 2} images := []gocv.Mat{ gocv.IMRead("./att_faces/s1/1.pgm", gocv.IMReadGrayScale), gocv.IMRead("./att_faces/s1/2.pgm", gocv.IMReadGrayScale), gocv.IMRead("./att_faces/s1/3.pgm", gocv.IMReadGrayScale), gocv.IMRead("./att_faces/s1/4.pgm", gocv.IMReadGrayScale), gocv.IMRead("./att_faces/s2/1.pgm", gocv.IMReadGrayScale), gocv.IMRead("./att_faces/s2/2.pgm", gocv.IMReadGrayScale), gocv.IMRead("./att_faces/s2/3.pgm", gocv.IMReadGrayScale), gocv.IMRead("./att_faces/s2/4.pgm", gocv.IMReadGrayScale), } model.Train(images, labels) sample := gocv.IMRead("./att_faces/s2/5.pgm", gocv.IMReadGrayScale) label := model.Predict(sample) if label != 2 { t.Errorf("Invalid simple predict! label: %d", label) } resp := model.PredictExtendedResponse(sample) if resp.Label != 2 { t.Errorf("Invalid extended result predict! label: %d", resp.Label) } // add new data sample = gocv.IMRead("./att_faces/s3/10.pgm", gocv.IMReadGrayScale) newLabels := []int{1, 3, 3, 3, 3, 3, 3} newImages := []gocv.Mat{ gocv.IMRead("./att_faces/s1/1.pgm", gocv.IMReadGrayScale), gocv.IMRead("./att_faces/s3/1.pgm", gocv.IMReadGrayScale), gocv.IMRead("./att_faces/s3/2.pgm", gocv.IMReadGrayScale), gocv.IMRead("./att_faces/s3/3.pgm", gocv.IMReadGrayScale), gocv.IMRead("./att_faces/s3/4.pgm", gocv.IMReadGrayScale), gocv.IMRead("./att_faces/s3/5.pgm", gocv.IMReadGrayScale), gocv.IMRead("./att_faces/s3/6.pgm", gocv.IMReadGrayScale), } model.Update(newImages, newLabels) label = model.Predict(sample) if label != 3 { t.Errorf("Invalid new data update: %d", label) } // test save and load fName := "data.yaml" model.SaveFile(fName) modelNew := NewFisherFaceRecognizer() modelNew.LoadFile(fName) label = modelNew.Predict(sample) if label != 3 { t.Errorf("Invalid loaded data: %d", label) } } ================================================ FILE: contrib/freetype.cpp ================================================ //go:build linux && (!gocv_specific_modules || (gocv_specific_modules && gocv_contrib_freetype)) #ifndef _WIN32 // Exclude compiling on Windows platforms #include "freetype.h" FreeType2 FreeType2_CreateFreeType2() { try { return new cv::Ptr(cv::freetype::createFreeType2()); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } void FreeType2_Close(FreeType2 f) { delete f; } OpenCVResult FreeType2_LoadFontData(FreeType2 f, const char *fontFileName, int id) { try { (*f)->loadFontData(fontFileName, id); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } void FreeType2_SetSplitNumber(FreeType2 f, int num) { try { (*f)->setSplitNumber(num); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); } } OpenCVResult FreeType2_PutText(FreeType2 f, Mat img, const char *text, Point org, int fontHeight, Scalar color, int thickness, int line_type, bool bottomLeftOrigin) { try { cv::Point pt(org.x, org.y); cv::Scalar c = cv::Scalar(color.val1, color.val2, color.val3, color.val4); (*f)->putText(*img, text, pt, fontHeight, c, thickness, line_type, bottomLeftOrigin); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } Size FreeType2_GetTextSize(FreeType2 f, const char *text, int fontHeight, int thickness, int *baseLine) { try { cv::Size sz = (*f)->getTextSize(text, fontHeight, thickness, baseLine); return Size{sz.width, sz.height}; } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); Size sz = {0, 0}; return sz; } } #endif // _WIN32 ================================================ FILE: contrib/freetype.go ================================================ //go:build linux && (!gocv_specific_modules || (gocv_specific_modules && gocv_contrib_freetype)) package contrib /* #include #include "freetype.h" */ import "C" import ( "image" "image/color" "unsafe" "gocv.io/x/gocv" ) type FreeType2 struct { // C.FreeType2 p unsafe.Pointer } // NewFreeType2 create instance to draw UTF-8 strings. // // For further details, please see: // https://docs.opencv.org/master/d4/dfc/group__freetype.html#ga0fd8f9c0ae69bb4d95c41af79473a756 func NewFreeType2() FreeType2 { return FreeType2{p: unsafe.Pointer(C.FreeType2_CreateFreeType2())} } // Close FreeType2. func (f *FreeType2) Close() error { C.FreeType2_Close((C.FreeType2)(f.p)) f.p = nil return nil } // LoadFontData loads font data. // // For further details, please see: // https://docs.opencv.org/master/d9/dfa/classcv_1_1freetype_1_1FreeType2.html#af059d49b806b916ffdd6380b9eb2f59a func (f *FreeType2) LoadFontData(fontFileName string, id int) error { cFontFileName := C.CString(fontFileName) defer C.free(unsafe.Pointer(cFontFileName)) return OpenCVResult(C.FreeType2_LoadFontData((C.FreeType2)(f.p), cFontFileName, C.int(id))) } // SetSplitNumber set the number of split points from bezier-curve to line. // If you want to draw large glyph, large is better. // If you want to draw small glyph, small is better. // // For further details, please see: // https://docs.opencv.org/master/d9/dfa/classcv_1_1freetype_1_1FreeType2.html#a572143e6c68eab181387d9f4b3366f8b func (f *FreeType2) SetSplitNumber(num int) { C.FreeType2_SetSplitNumber((C.FreeType2)(f.p), C.int(num)) } // PutText draws a text string. // It renders the specified text string in the image. // Symbols that cannot be rendered using the specified font are replaced by "Tofu" or non-drawn. // // For further details, please see: // https://docs.opencv.org/master/d9/dfa/classcv_1_1freetype_1_1FreeType2.html#aba641f774c47a70eaeb76bf7aa865915 func (f *FreeType2) PutText(img *gocv.Mat, text string, org image.Point, fontHeight int, c color.RGBA, thickness int, lineType gocv.LineType, bottomLeftOrigin bool) error { cText := C.CString(text) defer C.free(unsafe.Pointer(cText)) sOrg := C.struct_Point{ x: C.int(org.X), y: C.int(org.Y), } sColor := C.struct_Scalar{ val1: C.double(c.B), val2: C.double(c.G), val3: C.double(c.R), val4: C.double(c.A), } return OpenCVResult(C.FreeType2_PutText((C.FreeType2)(f.p), (C.Mat)(img.Ptr()), cText, sOrg, C.int(fontHeight), sColor, C.int(thickness), C.int(lineType), C.bool(bottomLeftOrigin))) } // GetTextSize calculates the width and height of a text string. // The function getTextSize calculates and returns the approximate size of a box that contains the specified text. // That is, the following code renders some text, the tight box surrounding it, and the baseline. // // For further details, please see: // https://docs.opencv.org/master/d9/dfa/classcv_1_1freetype_1_1FreeType2.html#af135a132505125bdea74b378dda3bb5d func (f *FreeType2) GetTextSize(text string, fontHeight int, thickness int) (image.Point, int) { cText := C.CString(text) defer C.free(unsafe.Pointer(cText)) cBaseLine := C.int(0) sz := C.FreeType2_GetTextSize((C.FreeType2)(f.p), cText, C.int(fontHeight), C.int(thickness), &cBaseLine) return image.Point{ X: int(sz.width), Y: int(sz.height), }, int(cBaseLine) } ================================================ FILE: contrib/freetype.h ================================================ #ifndef _OPENCV3_FREETYPE2_H_ #define _OPENCV3_FREETYPE2_H_ #ifdef __cplusplus #include #include extern "C" { #endif #include "../core.h" #ifdef __cplusplus typedef cv::Ptr* FreeType2; #else typedef void* FreeType2; #endif FreeType2 FreeType2_CreateFreeType2(); void FreeType2_Close(FreeType2 f); OpenCVResult FreeType2_LoadFontData(FreeType2 f, const char* fontFileName, int id); void FreeType2_SetSplitNumber(FreeType2 f, int num); OpenCVResult FreeType2_PutText(FreeType2 f, Mat img, const char* text, Point org, int fontHeight, Scalar color, int thickness, int line_type, bool bottomLeftOrigin ); Size FreeType2_GetTextSize(FreeType2 f, const char* text, int fontHeight, int thickness, int* baseLine); #ifdef __cplusplus } #endif #endif //_OPENCV3_FREETYPE2_H_ ================================================ FILE: contrib/freetype_test.go ================================================ //go:build linux && (!gocv_specific_modules || (gocv_specific_modules && gocv_contrib_freetype)) package contrib import ( "image" "image/color" "testing" "gocv.io/x/gocv" ) func TestFreeTypeLoadFontData(t *testing.T) { ft := NewFreeType2() defer ft.Close() ft.LoadFontData("../data/JetBrainsMono-Regular.ttf", 0) } func TestFreeTypeGetTextSize(t *testing.T) { ft := NewFreeType2() defer ft.Close() ft.LoadFontData("../data/JetBrainsMono-Regular.ttf", 0) size, baseLine := ft.GetTextSize("test", 60, 2) if size.X != 140 { t.Error("Invalid text size width") } if size.Y != 46 { t.Error("Invalid text size height") } if baseLine != 1 { t.Errorf("invalid base. expected %d, actual %d", 1, baseLine) } } func TestFreeTypePutText(t *testing.T) { ft := NewFreeType2() defer ft.Close() ft.LoadFontData("../data/JetBrainsMono-Regular.ttf", 0) img := gocv.NewMatWithSize(150, 500, gocv.MatTypeCV8UC3) if img.Empty() { t.Error("Invalid Mat") } defer img.Close() pt := image.Pt(80, 80) ft.PutText(&img, "Testing", pt, 60, color.RGBA{R: 255, G: 255, B: 255}, -1, gocv.LineAA, true) if img.Empty() { t.Error("Error in PutText test") } } func TestFreeTypeSetSplitNumber(t *testing.T) { ft := NewFreeType2() defer ft.Close() ft.LoadFontData("../data/JetBrainsMono-Regular.ttf", 0) ft.SetSplitNumber(10) } ================================================ FILE: contrib/img_hash.cpp ================================================ //go:build !gocv_specific_modules || (gocv_specific_modules && gocv_contrib_img_hash) #include "img_hash.h" void pHashCompute(Mat inputArr, Mat outputArr) { try { cv::img_hash::pHash(*inputArr, *outputArr); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); } } double pHashCompare(Mat a, Mat b) { try { return cv::img_hash::PHash::create()->compare(*a, *b); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return 0.0; } } void averageHashCompute(Mat inputArr, Mat outputArr) { try { cv::img_hash::averageHash(*inputArr, *outputArr); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); } } double averageHashCompare(Mat a, Mat b) { try { return cv::img_hash::AverageHash::create()->compare(*a, *b); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return 0.0; } } void blockMeanHashCompute(Mat inputArr, Mat outputArr, int mode) { try { cv::img_hash::blockMeanHash(*inputArr, *outputArr, mode); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); } } double blockMeanHashCompare(Mat a, Mat b, int mode) { try { return cv::img_hash::BlockMeanHash::create(mode)->compare(*a, *b); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return 0.0; } } void colorMomentHashCompute(Mat inputArr, Mat outputArr) { try { cv::img_hash::colorMomentHash(*inputArr, *outputArr); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); } } double colorMomentHashCompare(Mat a, Mat b) { try { return cv::img_hash::ColorMomentHash::create()->compare(*a, *b); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return 0.0; } } void marrHildrethHashCompute(Mat inputArr, Mat outputArr, float alpha, float scale) { try { cv::img_hash::marrHildrethHash(*inputArr, *outputArr, alpha, scale); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); } } double marrHildrethHashCompare(Mat a, Mat b, float alpha, float scale) { try { return cv::img_hash::MarrHildrethHash::create(alpha, scale)->compare(*a, *b); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return 0.0; } } void radialVarianceHashCompute(Mat inputArr, Mat outputArr, double sigma, int numOfAngleLine) { try { cv::img_hash::radialVarianceHash(*inputArr, *outputArr, sigma, numOfAngleLine); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); } } double radialVarianceHashCompare(Mat a, Mat b, double sigma, int numOfAngleLine) { try { return cv::img_hash::RadialVarianceHash::create(sigma, numOfAngleLine)->compare(*a, *b); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return 0.0; } } ================================================ FILE: contrib/img_hash.go ================================================ //go:build !gocv_specific_modules || (gocv_specific_modules && gocv_contrib_img_hash) package contrib //#include //#include "img_hash.h" import "C" import ( "gocv.io/x/gocv" ) // ImgHashBase defines the interface used for all of the img_hash algorithms. type ImgHashBase interface { Compare(a, b gocv.Mat) float64 Compute(inputArr gocv.Mat, outputArr *gocv.Mat) } // PHash is implementation of the PHash algorithm. type PHash struct{} // Compute computes hash of the input image using PHash. // // For further information, see: // https://docs.opencv.org/master/de/d29/classcv_1_1img__hash_1_1ImgHashBase.html#ae2d9288db370089dfd8aab85d5e0b0f3 func (hash PHash) Compute(input gocv.Mat, output *gocv.Mat) { C.pHashCompute(C.Mat(input.Ptr()), C.Mat(output.Ptr())) } // Compare compares the hash value between a and b using PHash. // // For further information, see: // https://docs.opencv.org/master/de/d29/classcv_1_1img__hash_1_1ImgHashBase.html#a444a3e9ec792cf029385809393f84ad5 func (hash PHash) Compare(a, b gocv.Mat) float64 { return float64(C.pHashCompare(C.Mat(a.Ptr()), C.Mat(b.Ptr()))) } // AverageHash is implementation of the AverageHash algorithm. type AverageHash struct{} // Compute computes hash of the input image using AverageHash. // // For further information, see: // https://docs.opencv.org/master/de/d29/classcv_1_1img__hash_1_1ImgHashBase.html#ae2d9288db370089dfd8aab85d5e0b0f3 func (hash AverageHash) Compute(input gocv.Mat, output *gocv.Mat) { C.averageHashCompute(C.Mat(input.Ptr()), C.Mat(output.Ptr())) } // Compare compares the hash value between a and b using AverageHash. // // For further information, see: // https://docs.opencv.org/master/de/d29/classcv_1_1img__hash_1_1ImgHashBase.html#a444a3e9ec792cf029385809393f84ad5 func (hash AverageHash) Compare(a, b gocv.Mat) float64 { return float64(C.averageHashCompare(C.Mat(a.Ptr()), C.Mat(b.Ptr()))) } // BlockMeanHash is implementation of the BlockMeanHash algorithm. type BlockMeanHash struct { Mode BlockMeanHashMode } type BlockMeanHashMode int const ( BlockMeanHashMode0 BlockMeanHashMode = iota BlockMeanHashMode1 BlockMeanHashModeDefault = BlockMeanHashMode0 ) // Compute computes hash of the input image using BlockMeanHash. // // For further information, see: // https://docs.opencv.org/master/de/d29/classcv_1_1img__hash_1_1ImgHashBase.html#ae2d9288db370089dfd8aab85d5e0b0f3 func (hash BlockMeanHash) Compute(input gocv.Mat, output *gocv.Mat) { C.blockMeanHashCompute(C.Mat(input.Ptr()), C.Mat(output.Ptr()), C.int(hash.Mode)) } // Compare compares the hash value between a and b using BlockMeanHash. // // For further information, see: // https://docs.opencv.org/master/de/d29/classcv_1_1img__hash_1_1ImgHashBase.html#a444a3e9ec792cf029385809393f84ad5 func (hash BlockMeanHash) Compare(a, b gocv.Mat) float64 { return float64(C.blockMeanHashCompare(C.Mat(a.Ptr()), C.Mat(b.Ptr()), C.int(hash.Mode))) } // TODO: BlockMeanHash.GetMean isn't implemented, because it requires state from the last // call to Compute, and there's no easy way to keep it. // ColorMomentHash is implementation of the ColorMomentHash algorithm. type ColorMomentHash struct{} // Compute computes hash of the input image using ColorMomentHash. // // For further information, see: // https://docs.opencv.org/master/de/d29/classcv_1_1img__hash_1_1ImgHashBase.html#ae2d9288db370089dfd8aab85d5e0b0f3 func (hash ColorMomentHash) Compute(input gocv.Mat, output *gocv.Mat) { C.colorMomentHashCompute(C.Mat(input.Ptr()), C.Mat(output.Ptr())) } // Compare compares the hash value between a and b using ColorMomentHash. // // For further information, see: // https://docs.opencv.org/master/de/d29/classcv_1_1img__hash_1_1ImgHashBase.html#a444a3e9ec792cf029385809393f84ad5 func (hash ColorMomentHash) Compare(a, b gocv.Mat) float64 { return float64(C.colorMomentHashCompare(C.Mat(a.Ptr()), C.Mat(b.Ptr()))) } // MarrHildrethHash is implementation of the MarrHildrethHash algorithm. type MarrHildrethHash struct { Alpha float32 Scale float32 } func NewMarrHildrethHash() MarrHildrethHash { return MarrHildrethHash{2.0, 1.0} } // Compute computes hash of the input image using MarrHildrethHash. // // For further information, see: // https://docs.opencv.org/master/de/d29/classcv_1_1img__hash_1_1ImgHashBase.html#ae2d9288db370089dfd8aab85d5e0b0f3 func (hash MarrHildrethHash) Compute(input gocv.Mat, output *gocv.Mat) { C.marrHildrethHashCompute(C.Mat(input.Ptr()), C.Mat(output.Ptr()), C.float(hash.Alpha), C.float(hash.Scale)) } // Compare compares the hash value between a and b using MarrHildrethHash. // // For further information, see: // https://docs.opencv.org/master/de/d29/classcv_1_1img__hash_1_1ImgHashBase.html#a444a3e9ec792cf029385809393f84ad5 func (hash MarrHildrethHash) Compare(a, b gocv.Mat) float64 { return float64(C.marrHildrethHashCompare(C.Mat(a.Ptr()), C.Mat(b.Ptr()), C.float(hash.Alpha), C.float(hash.Scale))) } // RadialVarianceHash is implementation of the RadialVarianceHash algorithm. type RadialVarianceHash struct { Sigma float64 NumOfAngleLine int } func NewRadialVarianceHash() RadialVarianceHash { return RadialVarianceHash{1, 180} } // Compute computes hash of the input image using RadialVarianceHash. // // For further information, see: // https://docs.opencv.org/master/de/d29/classcv_1_1img__hash_1_1ImgHashBase.html#ae2d9288db370089dfd8aab85d5e0b0f3 func (hash RadialVarianceHash) Compute(input gocv.Mat, output *gocv.Mat) { C.radialVarianceHashCompute(C.Mat(input.Ptr()), C.Mat(output.Ptr()), C.double(hash.Sigma), C.int(hash.NumOfAngleLine)) } // Compare compares the hash value between a and b using RadialVarianceHash. // // For further information, see: // https://docs.opencv.org/master/de/d29/classcv_1_1img__hash_1_1ImgHashBase.html#a444a3e9ec792cf029385809393f84ad5 func (hash RadialVarianceHash) Compare(a, b gocv.Mat) float64 { return float64(C.radialVarianceHashCompare(C.Mat(a.Ptr()), C.Mat(b.Ptr()), C.double(hash.Sigma), C.int(hash.NumOfAngleLine))) } // TODO: RadialVariance getFeatures, getHash, getPixPerLine, getProjection are not // implemented here, because they're stateful. ================================================ FILE: contrib/img_hash.h ================================================ #ifndef _OPENCV3_IMG_HASH_H_ #define _OPENCV3_IMG_HASH_H_ #ifdef __cplusplus #include #include extern "C" { #endif #include "../core.h" void pHashCompute(Mat inputArr, Mat outputArr); double pHashCompare(Mat a, Mat b); void averageHashCompute(Mat inputArr, Mat outputArr); double averageHashCompare(Mat a, Mat b); void blockMeanHashCompute(Mat inputArr, Mat outputArr, int mode); double blockMeanHashCompare(Mat a, Mat b, int mode); void colorMomentHashCompute(Mat inputArr, Mat outputArr); double colorMomentHashCompare(Mat a, Mat b); void marrHildrethHashCompute(Mat inputArr, Mat outputArr, float alpha, float scale); double marrHildrethHashCompare(Mat a, Mat b, float alpha, float scale); void radialVarianceHashCompute(Mat inputArr, Mat outputArr, double sigma, int numOfAngleLine); double radialVarianceHashCompare(Mat a, Mat b, double sigma, int numOfAngleLine); #ifdef __cplusplus } #endif #endif //_OPENCV3_IMG_HASH_H_ ================================================ FILE: contrib/img_hash_string.go ================================================ //go:build !gocv_specific_modules || (gocv_specific_modules && gocv_contrib_img_hash) package contrib func (c BlockMeanHashMode) String() string { switch c { case BlockMeanHashMode0: return "block-mean-hash-mode0" case BlockMeanHashMode1: return "block-mean-hash-mode1" } return "" } ================================================ FILE: contrib/img_hash_test.go ================================================ //go:build !gocv_specific_modules || (gocv_specific_modules && gocv_contrib_img_hash) package contrib import ( "errors" "testing" "gocv.io/x/gocv" ) const ( testImage = "../images/space_shuttle.jpg" testImage2 = "../images/toy.jpg" ) func compute(path string, hash ImgHashBase) (*gocv.Mat, error) { img := gocv.IMRead(path, gocv.IMReadColor) if img.Empty() { return nil, errors.New("Invalid input") } defer img.Close() dst := gocv.NewMat() hash.Compute(img, &dst) if dst.Empty() { dst.Close() return nil, errors.New("Empty output") } return &dst, nil } func testHash(t *testing.T, hash ImgHashBase) { result, err := compute(testImage, hash) if err != nil { t.Error(err) } defer result.Close() t.Logf("%T: %x", hash, result.ToBytes()) // Load second image and make sure it doesn't compare as identical result2, err := compute(testImage2, hash) if err != nil { t.Error(err) } defer result2.Close() similar := hash.Compare(*result, *result2) t.Logf("%T: similarity %g", hash, similar) // The range and meaning of this value varies between algorithms, and // there doesn't seem to be a well defined set of default thresholds, so // "anything but zero" is the minimum smoke test. if similar == 0 { t.Error("Image similarity is zero?") } } func TestHashes(t *testing.T) { t.Run("PHash", func(t *testing.T) { testHash(t, PHash{}) }) t.Run("AverageHash", func(t *testing.T) { testHash(t, AverageHash{}) }) t.Run("BlockMeanHash", func(t *testing.T) { testHash(t, BlockMeanHash{}) }) t.Run("ColorMomentHash", func(t *testing.T) { testHash(t, ColorMomentHash{}) }) t.Run("MarrHidlrethHash", func(t *testing.T) { testHash(t, NewMarrHildrethHash()) }) t.Run("RadialVarianceHash", func(t *testing.T) { testHash(t, NewRadialVarianceHash()) }) } func BenchmarkCompute(b *testing.B) { img := gocv.IMRead(testImage, gocv.IMReadColor) if img.Empty() { b.Error("Invalid input") } defer img.Close() b.ResetTimer() compute := func(b *testing.B, hash ImgHashBase) { for i := 0; i < b.N; i++ { dst := gocv.NewMat() hash.Compute(img, &dst) if dst.Empty() { b.Error("Empty output") dst.Close() return } dst.Close() } } b.Run("PHash", func(b *testing.B) { compute(b, PHash{}) }) b.Run("AverageHash", func(b *testing.B) { compute(b, AverageHash{}) }) b.Run("BlockMeanHash", func(b *testing.B) { compute(b, BlockMeanHash{}) }) b.Run("ColorMomentHash", func(b *testing.B) { compute(b, ColorMomentHash{}) }) b.Run("MarrHidlrethHash", func(b *testing.B) { compute(b, NewMarrHildrethHash()) }) b.Run("RadialVarianceHash", func(b *testing.B) { compute(b, NewRadialVarianceHash()) }) } func BenchmarkCompare(b *testing.B) { compare := func(b *testing.B, hash ImgHashBase) { result1, err := compute(testImage, hash) if err != nil { b.Error(err) } defer result1.Close() result2, err := compute(testImage2, hash) if err != nil { b.Error(err) } defer result2.Close() b.ResetTimer() for i := 0; i < b.N; i++ { hash.Compare(*result1, *result2) } } b.Run("PHash", func(b *testing.B) { compare(b, PHash{}) }) b.Run("AverageHash", func(b *testing.B) { compare(b, AverageHash{}) }) b.Run("BlockMeanHash", func(b *testing.B) { compare(b, BlockMeanHash{}) }) b.Run("ColorMomentHash", func(b *testing.B) { compare(b, ColorMomentHash{}) }) b.Run("MarrHidlrethHash", func(b *testing.B) { compare(b, NewMarrHildrethHash()) }) b.Run("RadialVarianceHash", func(b *testing.B) { compare(b, NewRadialVarianceHash()) }) } ================================================ FILE: contrib/mcc.cpp ================================================ // go:build !gocv_specific_modules || (gocv_specific_modules && gocv_mcc) #include "mcc.h" MccCCheckerDetector MccCCheckerDetector_New() { try { return new cv::Ptr(cv::mcc::CCheckerDetector::create()); } catch (const cv::Exception &e) { setExceptionInfo(e.code, e.what()); return NULL; } } void MccCCheckerDetector_Close(MccCCheckerDetector md) { delete md; } MccCCheckerVector MccCCheckerDetector_GetListColorChecker(MccCCheckerDetector md) { try { std::vector> *result = new std::vector>((*md)->getListColorChecker()); return result; } catch (const cv::Exception &e) { setExceptionInfo(e.code, e.what()); return NULL; } } void MccCCheckerVector_Close(MccCCheckerVector mv) { delete mv; } int MccCCheckerVector_Size(MccCCheckerVector mv) { return mv->size(); } MccCChecker MccCCheckerVector_At(MccCCheckerVector mv, int idx) { if (!mv || idx < 0 || idx >= mv->size()) { return NULL; } return mv->at(idx); } MccCChecker MccCCheckerDetector_GetBestColorChecker(MccCCheckerDetector md) { try { return (*md)->getBestColorChecker(); } catch (const cv::Exception &e) { setExceptionInfo(e.code, e.what()); return NULL; } } bool MccCCheckerDetector_Process(MccCCheckerDetector md, Mat inputArr, int chartType, int nc, bool useNet) { try { return (*md)->process(*inputArr, cv::mcc::TYPECHART(chartType), nc); } catch (const cv::Exception &e) { setExceptionInfo(e.code, e.what()); return false; } } bool MccCCheckerDetector_ProcessWithRegionsOfInterest(MccCCheckerDetector md, Mat inputArr, int chartType, const MccRectVector regionsOfInterest, int nc, bool useNet) { try { return (*md)->process(*inputArr, cv::mcc::TYPECHART(chartType), *regionsOfInterest, nc, useNet); } catch (const cv::Exception &e) { setExceptionInfo(e.code, e.what()); return false; } } bool MccCCheckerDetector_SetNet(MccCCheckerDetector md, MccDnnNet net) { try { return (*md)->setNet(*static_cast(net)); } catch (const cv::Exception &e) { setExceptionInfo(e.code, e.what()); return false; } } Points2f MccCChecker_GetBox(MccCChecker mc) { Points2f out = {nullptr, 0}; try { std::vector box = mc->getBox(); out.length = static_cast(box.size()); if (out.length > 0) { out.points = new Point2f[out.length]; for (int i = 0; i < out.length; ++i) { out.points[i].x = box[i].x; out.points[i].y = box[i].y; } } } catch (const cv::Exception &e) { setExceptionInfo(e.code, e.what()); } return out; } Point2f MccCChecker_GetCenter(MccCChecker mc) { try { cv::Point2f pt = mc->getCenter(); Point2f out; out.x = pt.x; out.y = pt.y; return out; } catch (const cv::Exception &e) { setExceptionInfo(e.code, e.what()); Point2f out = {0, 0}; return out; } } void MccCChecker_SetTarget(MccCChecker mc, int target) { mc->setTarget(cv::mcc::TYPECHART(target)); } void MccCChecker_SetBox(MccCChecker mc, Point2f *pts, int length) { std::vector box(length); for (int i = 0; i < length; ++i) { box[i] = cv::Point2f(pts[i].x, pts[i].y); } mc->setBox(box); } void MccCChecker_SetChartsRGB(MccCChecker mc, Mat mat) { mc->setChartsRGB(*mat); } void MccCChecker_SetChartsYCbCr(MccCChecker mc, Mat mat) { mc->setChartsYCbCr(*mat); } void MccCChecker_SetCost(MccCChecker mc, float cost) { mc->setCost(cost); } void MccCChecker_SetCenter(MccCChecker mc, Point2f pt) { mc->setCenter(cv::Point2f(pt.x, pt.y)); } int MccCChecker_GetTarget(MccCChecker mc) { return int(mc->getTarget()); } Points2f MccCChecker_GetColorCharts(MccCChecker mc) { Points2f out = {nullptr, 0}; try { std::vector charts = mc->getColorCharts(); out.length = static_cast(charts.size()); if (out.length > 0) { out.points = new Point2f[out.length]; for (int i = 0; i < out.length; ++i) { out.points[i].x = charts[i].x; out.points[i].y = charts[i].y; } } } catch (const cv::Exception &e) { setExceptionInfo(e.code, e.what()); } return out; } Mat MccCChecker_GetChartsRGB(MccCChecker mc) { return new cv::Mat(mc->getChartsRGB()); } Mat MccCChecker_GetChartsYCbCr(MccCChecker mc) { return new cv::Mat(mc->getChartsYCbCr()); } float MccCChecker_GetCost(MccCChecker mc) { return mc->getCost(); } MccCCheckerDraw MccCCheckerDraw_Create(MccCChecker mc, double b, double g, double r, double a, int thickness) { try { cv::Scalar color(b, g, r, a); return new cv::Ptr(cv::mcc::CCheckerDraw::create(cv::Ptr(mc), color, thickness)); } catch (const cv::Exception &e) { setExceptionInfo(e.code, e.what()); return nullptr; } } void MccCCheckerDraw_Draw(MccCCheckerDraw md, Mat img) { try { (*md)->draw(*img); } catch (const cv::Exception &e) { setExceptionInfo(e.code, e.what()); } } void MccCCheckerDraw_Close(MccCCheckerDraw md) { delete md; } MccRectVector MccRectVector_New() { return new std::vector(); } void MccRectVector_PushBack(MccRectVector mv, int x, int y, int width, int height) { mv->emplace_back(x, y, width, height); } void MccRectVector_Close(MccRectVector mv) { delete mv; } MccDetectorParameters MccDetectorParameters_Create() { try { return new cv::mcc::DetectorParameters(); } catch (const cv::Exception &e) { setExceptionInfo(e.code, e.what()); return NULL; } } void MccDetectorParameters_Close(MccDetectorParameters mp) { delete mp; } void MccDetectorParameters_SetAdaptiveThreshWinSizeMin(MccDetectorParameters mp, int adaptiveThreshWinSizeMin) { mp->adaptiveThreshWinSizeMin = adaptiveThreshWinSizeMin; } int MccDetectorParameters_GetAdaptiveThreshWinSizeMin(MccDetectorParameters mp) { return mp->adaptiveThreshWinSizeMin; } void MccDetectorParameters_SetAdaptiveThreshWinSizeMax(MccDetectorParameters mp, int adaptiveThreshWinSizeMax) { mp->adaptiveThreshWinSizeMax = adaptiveThreshWinSizeMax; } int MccDetectorParameters_GetAdaptiveThreshWinSizeMax(MccDetectorParameters mp) { return mp->adaptiveThreshWinSizeMax; } void MccDetectorParameters_SetAdaptiveThreshWinSizeStep(MccDetectorParameters mp, int adaptiveThreshWinSizeStep) { mp->adaptiveThreshWinSizeStep = adaptiveThreshWinSizeStep; } int MccDetectorParameters_GetAdaptiveThreshWinSizeStep(MccDetectorParameters mp) { return mp->adaptiveThreshWinSizeStep; } void MccDetectorParameters_SetBorderWidth(MccDetectorParameters mp, int borderWidth) { mp->borderWidth = borderWidth; } int MccDetectorParameters_GetBorderWidth(MccDetectorParameters mp) { return mp->borderWidth; } void MccDetectorParameters_SetMinContourLengthAllowed(MccDetectorParameters mp, int minContourLengthAllowed) { mp->minContourLengthAllowed = minContourLengthAllowed; } int MccDetectorParameters_GetMinContourLengthAllowed(MccDetectorParameters mp) { return mp->minContourLengthAllowed; } void MccDetectorParameters_SetMinContourPointsAllowed(MccDetectorParameters mp, int minContourPointsAllowed) { mp->minContourPointsAllowed = minContourPointsAllowed; } int MccDetectorParameters_GetMinContourPointsAllowed(MccDetectorParameters mp) { return mp->minContourPointsAllowed; } void MccDetectorParameters_SetMinImageSize(MccDetectorParameters mp, int minImageSize) { mp->minImageSize = minImageSize; } int MccDetectorParameters_GetMinImageSize(MccDetectorParameters mp) { return mp->minImageSize; } void MccDetectorParameters_SetMinInterCheckerDistance(MccDetectorParameters mp, int minInterCheckerDistance) { mp->minInterCheckerDistance = minInterCheckerDistance; } int MccDetectorParameters_GetMinInterCheckerDistance(MccDetectorParameters mp) { return mp->minInterCheckerDistance; } void MccDetectorParameters_SetMinInterContourDistance(MccDetectorParameters mp, int minInterContourDistance) { mp->minInterContourDistance = minInterContourDistance; } int MccDetectorParameters_GetMinInterContourDistance(MccDetectorParameters mp) { return mp->minInterContourDistance; } void MccDetectorParameters_SetAdaptiveThreshConstant(MccDetectorParameters mp, double adaptiveThreshConstant) { mp->adaptiveThreshConstant = adaptiveThreshConstant; } double MccDetectorParameters_GetAdaptiveThreshConstant(MccDetectorParameters mp) { return mp->adaptiveThreshConstant; } void MccDetectorParameters_SetConfidenceThreshold(MccDetectorParameters mp, double confidenceThreshold) { mp->confidenceThreshold = confidenceThreshold; } double MccDetectorParameters_GetConfidenceThreshold(MccDetectorParameters mp) { return mp->confidenceThreshold; } void MccDetectorParameters_SetFindCandidatesApproxPolyDPEpsMultiplier(MccDetectorParameters mp, double findCandidatesApproxPolyDPEpsMultiplier) { mp->findCandidatesApproxPolyDPEpsMultiplier = findCandidatesApproxPolyDPEpsMultiplier; } double MccDetectorParameters_GetFindCandidatesApproxPolyDPEpsMultiplier(MccDetectorParameters mp) { return mp->findCandidatesApproxPolyDPEpsMultiplier; } void MccDetectorParameters_SetMinContourSolidity(MccDetectorParameters mp, double minContourSolidity) { mp->minContourSolidity = minContourSolidity; } double MccDetectorParameters_GetMinContourSolidity(MccDetectorParameters mp) { return mp->minContourSolidity; } void MccDetectorParameters_SetMinContoursArea(MccDetectorParameters mp, double minContoursArea) { mp->minContoursArea = minContoursArea; } double MccDetectorParameters_GetMinContoursArea(MccDetectorParameters mp) { return mp->minContoursArea; } void MccDetectorParameters_SetMinContoursAreaRate(MccDetectorParameters mp, double minContoursAreaRate) { mp->minContoursAreaRate = minContoursAreaRate; } double MccDetectorParameters_GetMinContoursAreaRate(MccDetectorParameters mp) { return mp->minContoursAreaRate; } void MccDetectorParameters_SetB0factor(MccDetectorParameters mp, float B0factor) { mp->B0factor = B0factor; } float MccDetectorParameters_GetB0factor(MccDetectorParameters mp) { return mp->B0factor; } void MccDetectorParameters_SetMaxError(MccDetectorParameters mp, float maxError) { mp->maxError = maxError; } float MccDetectorParameters_GetMaxError(MccDetectorParameters mp) { return mp->maxError; } void MccDetectorParameters_SetMinGroupSize(MccDetectorParameters mp, unsigned minGroupSize) { mp->minGroupSize = minGroupSize; } unsigned MccDetectorParameters_GetMinGroupSize(MccDetectorParameters mp) { return mp->minGroupSize; } ================================================ FILE: contrib/mcc.go ================================================ //go:build !gocv_specific_modules || (gocv_specific_modules && gocv_mcc) package contrib /* #include #include "mcc.h" #include "../core.h" */ import "C" import ( "image" "unsafe" "gocv.io/x/gocv" ) type TYPECHART int const ( MCC24 TYPECHART = iota SG140 VINYL18 ) type MccCCheckerDetector struct { p C.MccCCheckerDetector } type MccDnnNet struct { p C.MccDnnNet } // NewMccCCheckerDetector returns a new MccCCheckerDetector. func NewMccCCheckerDetector() MccCCheckerDetector { return MccCCheckerDetector{p: C.MccCCheckerDetector_New()} } // Close deletes the MccCCheckerDetector's pointer. func (md *MccCCheckerDetector) Close() error { C.MccCCheckerDetector_Close(md.p) md.p = nil return nil } // Get the best color checker. By the best it means the one detected with the highest confidence. // // For further details, please see: // https://docs.opencv.org/4.x/d9/d53/classcv_1_1mcc_1_1CCheckerDetector.html#a4bb27724447e01b613f5bc8fb9bb3bfc func (md *MccCCheckerDetector) GetBestColorChecker() MccCChecker { res := C.MccCCheckerDetector_GetBestColorChecker(md.p) return MccCChecker{p: res} } // Get the list of all detected colorcheckers. // // For further details, please see: // https://docs.opencv.org/4.x/d9/d53/classcv_1_1mcc_1_1CCheckerDetector.html#a67bd0b2271e93b550c0d4d058d438cb6 func (md *MccCCheckerDetector) GetListColorChecker() []MccCChecker { list := C.MccCCheckerDetector_GetListColorChecker(md.p) defer C.MccCCheckerVector_Close(list) size := int(C.MccCCheckerVector_Size(list)) res := make([]MccCChecker, size) for i := 0; i < size; i++ { res[i] = MccCChecker{p: C.MccCCheckerVector_At(list, C.int(i))} } return res } // Process does basic macbeth chart detection. // // For further details, please see: // https://docs.opencv.org/4.x/d9/d53/classcv_1_1mcc_1_1CCheckerDetector.html#aa07092a6bc9f0a2b75738bc76f9b2d8b func (md *MccCCheckerDetector) Process(input gocv.Mat, chartType TYPECHART) bool { res := C.MccCCheckerDetector_Process(md.p, C.Mat(input.Ptr()), C.int(chartType), C.int(1), C.bool(false)) return bool(res) } // Process does basic macbeth chart detection. // // For further details, please see: // https://docs.opencv.org/4.x/d9/d53/classcv_1_1mcc_1_1CCheckerDetector.html#aa07092a6bc9f0a2b75738bc76f9b2d8b func (md *MccCCheckerDetector) ProcessWithRegionsOfInterest(input gocv.Mat, chartType TYPECHART, regionsOfInterest []image.Rectangle) bool { vec := NewMccRectVector(regionsOfInterest) defer vec.Close() res := C.MccCCheckerDetector_ProcessWithRegionsOfInterest(md.p, C.Mat(input.Ptr()), C.int(chartType), vec.p, C.int(1), C.bool(false)) return bool(res) } // Process does basic macbeth chart detection. // // For further details, please see: // https://docs.opencv.org/4.x/d9/d53/classcv_1_1mcc_1_1CCheckerDetector.html#aa07092a6bc9f0a2b75738bc76f9b2d8b func (md *MccCCheckerDetector) ProcessWithParams(input gocv.Mat, chartType TYPECHART, nc int, useNet bool) bool { res := C.MccCCheckerDetector_Process(md.p, C.Mat(input.Ptr()), C.int(chartType), C.int(nc), C.bool(useNet)) return bool(res) } // Process does basic macbeth chart detection. // // For further details, please see: // https://docs.opencv.org/4.x/d9/d53/classcv_1_1mcc_1_1CCheckerDetector.html#aa07092a6bc9f0a2b75738bc76f9b2d8b func (md *MccCCheckerDetector) ProcessWithRegionsOfInterestWithParams(input gocv.Mat, chartType TYPECHART, regionsOfInterest []image.Rectangle, nc int, useNet bool) bool { vec := NewMccRectVector(regionsOfInterest) defer vec.Close() res := C.MccCCheckerDetector_ProcessWithRegionsOfInterest(md.p, C.Mat(input.Ptr()), C.int(chartType), vec.p, C.int(nc), C.bool(useNet)) return bool(res) } // Set the net which will be used to find the approximate bounding boxes for the color charts. // // For further details, please see: // https://docs.opencv.org/4.x/d9/d53/classcv_1_1mcc_1_1CCheckerDetector.html#a1ad73dda58c3a8c6cb822397e8ef76a1 func (md *MccCCheckerDetector) SetNet(net MccDnnNet) bool { res := C.MccCCheckerDetector_SetNet(md.p, net.p) return bool(res) } type MccCChecker struct { p C.MccCChecker } func (mc *MccCChecker) SetTarget(target TYPECHART) { C.MccCChecker_SetTarget(mc.p, C.int(target)) } func (mc *MccCChecker) GetTarget() TYPECHART { return TYPECHART(C.MccCChecker_GetTarget(mc.p)) } func (mc *MccCChecker) SetBox(box []gocv.Point2f) { n := len(box) if n == 0 { return } cBox := make([]C.Point2f, n) for i := range box { cBox[i] = C.Point2f{x: C.float(box[i].X), y: C.float(box[i].Y)} } C.MccCChecker_SetBox(mc.p, (*C.Point2f)(unsafe.Pointer(&cBox[0])), C.int(n)) } func (mc *MccCChecker) GetBox() []gocv.Point2f { res := C.MccCChecker_GetBox(mc.p) defer C.Points2f_Close(res) n := int(res.length) if n == 0 || res.points == nil { return nil } pts := (*[1 << 28]C.Point2f)(unsafe.Pointer(res.points))[:n:n] out := make([]gocv.Point2f, n) for i := 0; i < n; i++ { out[i] = gocv.Point2f{X: float32(pts[i].x), Y: float32(pts[i].y)} } return out } func (mc *MccCChecker) SetChartsRGB(mat gocv.Mat) { C.MccCChecker_SetChartsRGB(mc.p, C.Mat(mat.Ptr())) } func (mc *MccCChecker) GetChartsRGB() gocv.Mat { cmat := C.MccCChecker_GetChartsRGB(mc.p) defer C.Mat_Close(cmat) return gocv.NewMatFromCMat(unsafe.Pointer(cmat)) } func (mc *MccCChecker) SetChartsYCbCr(mat gocv.Mat) { C.MccCChecker_SetChartsYCbCr(mc.p, C.Mat(mat.Ptr())) } func (mc *MccCChecker) GetChartsYCbCr() gocv.Mat { cmat := C.MccCChecker_GetChartsYCbCr(mc.p) defer C.Mat_Close(cmat) return gocv.NewMatFromCMat(unsafe.Pointer(cmat)) } func (mc *MccCChecker) SetCost(cost float32) { C.MccCChecker_SetCost(mc.p, C.float(cost)) } func (mc *MccCChecker) GetCost() float32 { return float32(C.MccCChecker_GetCost(mc.p)) } func (mc *MccCChecker) SetCenter(center gocv.Point2f) { C.MccCChecker_SetCenter(mc.p, C.Point2f{x: C.float(center.X), y: C.float(center.Y)}) } func (mc *MccCChecker) GetCenter() gocv.Point2f { res := C.MccCChecker_GetCenter(mc.p) return gocv.Point2f{X: float32(res.x), Y: float32(res.y)} } // Computes and returns the coordinates of the central parts of the charts modules. // // This method computes transformation matrix from the checkers's coordinates (cv::mcc::CChecker::getBox()) and // find by this the coordinates of the central parts of the charts modules. It is used in cv::mcc::CCheckerDraw::draw() // and in ChartsRGB calculation. func (mc *MccCChecker) GetColorCharts() []gocv.Point2f { res := C.MccCChecker_GetColorCharts(mc.p) n := int(res.length) if n == 0 || res.points == nil { return nil } pts := (*[1 << 28]C.Point2f)(unsafe.Pointer(res.points))[:n:n] out := make([]gocv.Point2f, n) for i := 0; i < n; i++ { out[i] = gocv.Point2f{X: float32(pts[i].x), Y: float32(pts[i].y)} } return out } type MccDetectorParameters struct { p C.MccDetectorParameters } // NewMccDetectorParameters returns the default parameters for the MccDetector func NewMccDetectorParameters() MccDetectorParameters { return MccDetectorParameters{p: C.MccDetectorParameters_Create()} } func (mp *MccDetectorParameters) SetAdaptiveThreshWinSizeMin(adaptiveThreshWinSizeMin int) { C.MccDetectorParameters_SetAdaptiveThreshWinSizeMin(mp.p, C.int(adaptiveThreshWinSizeMin)) } func (mp *MccDetectorParameters) GetAdaptiveThreshWinSizeMin() int { return int(C.MccDetectorParameters_GetAdaptiveThreshWinSizeMin(mp.p)) } func (mp *MccDetectorParameters) SetAdaptiveThreshWinSizeMax(adaptiveThreshWinSizeMax int) { C.MccDetectorParameters_SetAdaptiveThreshWinSizeMax(mp.p, C.int(adaptiveThreshWinSizeMax)) } func (mp *MccDetectorParameters) GetAdaptiveThreshWinSizeMax() int { return int(C.MccDetectorParameters_GetAdaptiveThreshWinSizeMax(mp.p)) } func (mp *MccDetectorParameters) SetAdaptiveThreshWinSizeStep(adaptiveThreshWinSizeStep int) { C.MccDetectorParameters_SetAdaptiveThreshWinSizeStep(mp.p, C.int(adaptiveThreshWinSizeStep)) } func (mp *MccDetectorParameters) GetAdaptiveThreshWinSizeStep() int { return int(C.MccDetectorParameters_GetAdaptiveThreshWinSizeStep(mp.p)) } func (mp *MccDetectorParameters) SetBorderWidth(borderWidth int) { C.MccDetectorParameters_SetBorderWidth(mp.p, C.int(borderWidth)) } func (mp *MccDetectorParameters) GetBorderWidth() int { return int(C.MccDetectorParameters_GetBorderWidth(mp.p)) } func (mp *MccDetectorParameters) SetMinContourLengthAllowed(minContourLengthAllowed int) { C.MccDetectorParameters_SetMinContourLengthAllowed(mp.p, C.int(minContourLengthAllowed)) } func (mp *MccDetectorParameters) GetMinContourLengthAllowed() int { return int(C.MccDetectorParameters_GetMinContourLengthAllowed(mp.p)) } func (mp *MccDetectorParameters) SetMinContourPointsAllowed(minContourPointsAllowed int) { C.MccDetectorParameters_SetMinContourPointsAllowed(mp.p, C.int(minContourPointsAllowed)) } func (mp *MccDetectorParameters) GetMinContourPointsAllowed() int { return int(C.MccDetectorParameters_GetMinContourPointsAllowed(mp.p)) } func (mp *MccDetectorParameters) SetMinImageSize(minImageSize int) { C.MccDetectorParameters_SetMinImageSize(mp.p, C.int(minImageSize)) } func (mp *MccDetectorParameters) GetMinImageSize() int { return int(C.MccDetectorParameters_GetMinImageSize(mp.p)) } func (mp *MccDetectorParameters) SetMinInterCheckerDistance(minInterCheckerDistance int) { C.MccDetectorParameters_SetMinInterCheckerDistance(mp.p, C.int(minInterCheckerDistance)) } func (mp *MccDetectorParameters) GetMinInterCheckerDistance() int { return int(C.MccDetectorParameters_GetMinInterCheckerDistance(mp.p)) } func (mp *MccDetectorParameters) SetMinInterContourDistance(minInterContourDistance int) { C.MccDetectorParameters_SetMinInterContourDistance(mp.p, C.int(minInterContourDistance)) } func (mp *MccDetectorParameters) GetMinInterContourDistance() int { return int(C.MccDetectorParameters_GetMinInterContourDistance(mp.p)) } func (mp *MccDetectorParameters) SetAdaptiveThreshConstant(adaptiveThreshConstant float64) { C.MccDetectorParameters_SetAdaptiveThreshConstant(mp.p, C.double(adaptiveThreshConstant)) } func (mp *MccDetectorParameters) GetAdaptiveThreshConstant() float64 { return float64(C.MccDetectorParameters_GetAdaptiveThreshConstant(mp.p)) } func (mp *MccDetectorParameters) SetConfidenceThreshold(confidenceThreshold float64) { C.MccDetectorParameters_SetConfidenceThreshold(mp.p, C.double(confidenceThreshold)) } func (mp *MccDetectorParameters) GetConfidenceThreshold() float64 { return float64(C.MccDetectorParameters_GetConfidenceThreshold(mp.p)) } func (mp *MccDetectorParameters) SetFindCandidatesApproxPolyDPEpsMultiplier(findCandidatesApproxPolyDPEpsMultiplier float64) { C.MccDetectorParameters_SetFindCandidatesApproxPolyDPEpsMultiplier(mp.p, C.double(findCandidatesApproxPolyDPEpsMultiplier)) } func (mp *MccDetectorParameters) GetFindCandidatesApproxPolyDPEpsMultiplier() float64 { return float64(C.MccDetectorParameters_GetFindCandidatesApproxPolyDPEpsMultiplier(mp.p)) } func (mp *MccDetectorParameters) SetMinContourSolidity(minContourSolidity float64) { C.MccDetectorParameters_SetMinContourSolidity(mp.p, C.double(minContourSolidity)) } func (mp *MccDetectorParameters) GetMinContourSolidity() float64 { return float64(C.MccDetectorParameters_GetMinContourSolidity(mp.p)) } func (mp *MccDetectorParameters) SetMinContoursArea(minContoursArea float64) { C.MccDetectorParameters_SetMinContoursArea(mp.p, C.double(minContoursArea)) } func (mp *MccDetectorParameters) GetMinContoursArea() float64 { return float64(C.MccDetectorParameters_GetMinContoursArea(mp.p)) } func (mp *MccDetectorParameters) SetMinContoursAreaRate(minContoursAreaRate float64) { C.MccDetectorParameters_SetMinContoursAreaRate(mp.p, C.double(minContoursAreaRate)) } func (mp *MccDetectorParameters) GetMinContoursAreaRate() float64 { return float64(C.MccDetectorParameters_GetMinContoursAreaRate(mp.p)) } func (mp *MccDetectorParameters) SetB0factor(B0factor float32) { C.MccDetectorParameters_SetB0factor(mp.p, C.float(B0factor)) } func (mp *MccDetectorParameters) GetB0factor() float32 { return float32(C.MccDetectorParameters_GetB0factor(mp.p)) } func (mp *MccDetectorParameters) SetMaxError(maxError float32) { C.MccDetectorParameters_SetMaxError(mp.p, C.float(maxError)) } func (mp *MccDetectorParameters) GetMaxError() float32 { return float32(C.MccDetectorParameters_GetMaxError(mp.p)) } func (mp *MccDetectorParameters) SetMinGroupSize(minGroupSize uint) { C.MccDetectorParameters_SetMinGroupSize(mp.p, C.uint(minGroupSize)) } func (mp *MccDetectorParameters) GetMinGroupSize() uint { return uint(C.MccDetectorParameters_GetMinGroupSize(mp.p)) } type MccCCheckerDraw struct { p C.MccCCheckerDraw } // NewMccCCheckerDraw creates a new CCheckerDraw with the given color and thickness. func NewMccCCheckerDraw(cc MccCChecker, color gocv.Scalar, thickness int) MccCCheckerDraw { p := C.MccCCheckerDraw_Create(cc.p, C.double(color.Val1), C.double(color.Val2), C.double(color.Val3), C.double(color.Val4), C.int(thickness)) return MccCCheckerDraw{p: p} } // Draw draws the checker on the given image. func (md *MccCCheckerDraw) Draw(img gocv.Mat) { C.MccCCheckerDraw_Draw(md.p, C.Mat(img.Ptr())) } func (md *MccCCheckerDraw) Close() error { C.MccCCheckerDraw_Close(md.p) md.p = nil return nil } type MccRectVector struct { p C.MccRectVector } func NewMccRectVector(rects []image.Rectangle) MccRectVector { vec := C.MccRectVector_New() for _, r := range rects { C.MccRectVector_PushBack(vec, C.int(r.Min.X), C.int(r.Min.Y), C.int(r.Dx()), C.int(r.Dy())) } return MccRectVector{p: vec} } func (mv *MccRectVector) Close() error { C.MccRectVector_Close(mv.p) mv.p = nil return nil } ================================================ FILE: contrib/mcc.h ================================================ #ifndef _OPENCV3_MCC_H_ #define _OPENCV3_MCC_H_ #ifdef __cplusplus #include #include #include extern "C" { #endif #include "../core.h" #ifdef __cplusplus typedef cv::mcc::CChecker* MccCChecker; typedef cv::Ptr* MccCCheckerDetector; typedef cv::Ptr* MccCCheckerDraw; typedef cv::mcc::DetectorParameters* MccDetectorParameters; typedef cv::dnn::Net* MccDnnNet; typedef std::vector* MccRectVector; typedef std::vector>* MccCCheckerVector; #else typedef void *MccCChecker; typedef void *MccCCheckerDetector; typedef void *MccCCheckerDraw; typedef void *MccDetectorParameters; typedef void *MccDnnNet; typedef void *MccRectVector; typedef void *MccCCheckerVector; #endif MccDetectorParameters MccDetectorParameters_Create(); void MccDetectorParameters_Close(MccDetectorParameters mp); void MccDetectorParameters_SetAdaptiveThreshWinSizeMin(MccDetectorParameters mp, int adaptiveThreshWinSizeMin); int MccDetectorParameters_GetAdaptiveThreshWinSizeMin(MccDetectorParameters mp); void MccDetectorParameters_SetAdaptiveThreshWinSizeMax(MccDetectorParameters mp, int adaptiveThreshWinSizeMax); int MccDetectorParameters_GetAdaptiveThreshWinSizeMax(MccDetectorParameters mp); void MccDetectorParameters_SetAdaptiveThreshWinSizeStep(MccDetectorParameters mp, int adaptiveThreshWinSizeStep); int MccDetectorParameters_GetAdaptiveThreshWinSizeStep(MccDetectorParameters mp); void MccDetectorParameters_SetBorderWidth(MccDetectorParameters mp, int borderWidth); int MccDetectorParameters_GetBorderWidth(MccDetectorParameters mp); void MccDetectorParameters_SetMinContourLengthAllowed(MccDetectorParameters mp, int minContourLengthAllowed); int MccDetectorParameters_GetMinContourLengthAllowed(MccDetectorParameters mp); void MccDetectorParameters_SetMinContourPointsAllowed(MccDetectorParameters mp, int minContourPointsAllowed); int MccDetectorParameters_GetMinContourPointsAllowed(MccDetectorParameters mp); void MccDetectorParameters_SetMinImageSize(MccDetectorParameters mp, int minImageSize); int MccDetectorParameters_GetMinImageSize(MccDetectorParameters mp); void MccDetectorParameters_SetMinInterCheckerDistance(MccDetectorParameters mp, int minInterCheckerDistance); int MccDetectorParameters_GetMinInterCheckerDistance(MccDetectorParameters mp); void MccDetectorParameters_SetMinInterContourDistance(MccDetectorParameters mp, int minInterContourDistance); int MccDetectorParameters_GetMinInterContourDistance(MccDetectorParameters mp); void MccDetectorParameters_SetAdaptiveThreshConstant(MccDetectorParameters mp, double adaptiveThreshConstant); double MccDetectorParameters_GetAdaptiveThreshConstant(MccDetectorParameters mp); void MccDetectorParameters_SetConfidenceThreshold(MccDetectorParameters mp, double confidenceThreshold); double MccDetectorParameters_GetConfidenceThreshold(MccDetectorParameters mp); void MccDetectorParameters_SetFindCandidatesApproxPolyDPEpsMultiplier(MccDetectorParameters mp, double findCandidatesApproxPolyDPEpsMultiplier); double MccDetectorParameters_GetFindCandidatesApproxPolyDPEpsMultiplier(MccDetectorParameters mp); void MccDetectorParameters_SetMinContourSolidity(MccDetectorParameters mp, double minContourSolidity); double MccDetectorParameters_GetMinContourSolidity(MccDetectorParameters mp); void MccDetectorParameters_SetMinContoursArea(MccDetectorParameters mp, double minContoursArea); double MccDetectorParameters_GetMinContoursArea(MccDetectorParameters mp); void MccDetectorParameters_SetMinContoursAreaRate(MccDetectorParameters mp, double minContoursAreaRate); double MccDetectorParameters_GetMinContoursAreaRate(MccDetectorParameters mp); void MccDetectorParameters_SetB0factor(MccDetectorParameters mp, float B0factor); float MccDetectorParameters_GetB0factor(MccDetectorParameters mp); void MccDetectorParameters_SetMaxError(MccDetectorParameters mp, float maxError); float MccDetectorParameters_GetMaxError(MccDetectorParameters mp); void MccDetectorParameters_SetMinGroupSize(MccDetectorParameters mp, unsigned minGroupSize); unsigned MccDetectorParameters_GetMinGroupSize(MccDetectorParameters mp); void MccCChecker_SetTarget(MccCChecker mc, int target); int MccCChecker_GetTarget(MccCChecker mc); void MccCChecker_SetBox(MccCChecker mc, Point2f* pts, int length); Points2f MccCChecker_GetBox(MccCChecker mc); void MccCChecker_SetChartsRGB(MccCChecker mc, Mat mat); Mat MccCChecker_GetChartsRGB(MccCChecker mc); void MccCChecker_SetChartsYCbCr(MccCChecker mc, Mat mat); Mat MccCChecker_GetChartsYCbCr(MccCChecker mc); void MccCChecker_SetCost(MccCChecker mc, float cost); float MccCChecker_GetCost(MccCChecker mc); void MccCChecker_SetCenter(MccCChecker mc, Point2f pt); Point2f MccCChecker_GetCenter(MccCChecker mc); Points2f MccCChecker_GetColorCharts(MccCChecker mc); MccCCheckerDraw MccCCheckerDraw_Create(MccCChecker mc, double b, double g, double r, double a, int thickness); void MccCCheckerDraw_Draw(MccCCheckerDraw md, Mat img); void MccCCheckerDraw_Close(MccCCheckerDraw md); MccCCheckerDetector MccCCheckerDetector_New(); void MccCCheckerDetector_Close(MccCCheckerDetector md); MccCCheckerVector MccCCheckerDetector_GetListColorChecker(MccCCheckerDetector md); MccCChecker MccCCheckerDetector_GetBestColorChecker(MccCCheckerDetector md); bool MccCCheckerDetector_Process(MccCCheckerDetector md, Mat inputArr, int chartType, int nc, bool useNet); bool MccCCheckerDetector_ProcessWithRegionsOfInterest(MccCCheckerDetector md, Mat inputArr, int chartType, const MccRectVector regionsOfInterest, int nc, bool useNet); bool MccCCheckerDetector_SetNet(MccCCheckerDetector md, MccDnnNet net); int MccCCheckerVector_Size(MccCCheckerVector mv); MccCChecker MccCCheckerVector_At(MccCCheckerVector mv, int idx); void MccCCheckerVector_Close(MccCCheckerVector mv); MccRectVector MccRectVector_New(); void MccRectVector_PushBack(MccRectVector mv, int x, int y, int width, int height); void MccRectVector_Close(MccRectVector mv); #ifdef __cplusplus } #endif #endif //_OPENCV3_MCC_H_ ================================================ FILE: contrib/mcc_test.go ================================================ //go:build !gocv_specific_modules || (gocv_specific_modules && gocv_mcc) package contrib import ( "math" "testing" "gocv.io/x/gocv" ) const ( macbethImage = "../images/macbeth.png" ) func TestMccDetectorParams(t *testing.T) { adaptiveThreshWinSizeMin := 23 adaptiveThreshWinSizeMax := 153 adaptiveThreshWinSizeStep := 16 adaptiveThreshConstant := 7.0 borderWidth := 0 minContourLengthAllowed := 100 minContourPointsAllowed := 4 minImageSize := 1000 minInterCheckerDistance := 10000 minInterContourDistance := 100 confidenceThreshold := 0.1 findCandidatesApproxPolyDPEpsMultiplier := 0.05 minContourSolidity := 0.9 minContoursArea := 100.0 minContoursAreaRate := 0.003 B0factor := float32(1.25) maxError := float32(0.1) minGroupSize := uint(4) params := NewMccDetectorParameters() params.SetAdaptiveThreshWinSizeMin(adaptiveThreshWinSizeMin) params.SetAdaptiveThreshWinSizeMax(adaptiveThreshWinSizeMax) params.SetAdaptiveThreshWinSizeStep(adaptiveThreshWinSizeStep) params.SetAdaptiveThreshConstant(adaptiveThreshConstant) params.SetBorderWidth(borderWidth) params.SetMinContourLengthAllowed(minContourLengthAllowed) params.SetMinContourPointsAllowed(minContourPointsAllowed) params.SetMinImageSize(minImageSize) params.SetMinInterCheckerDistance(minInterCheckerDistance) params.SetMinInterContourDistance(minInterContourDistance) params.SetAdaptiveThreshConstant(adaptiveThreshConstant) params.SetConfidenceThreshold(confidenceThreshold) params.SetFindCandidatesApproxPolyDPEpsMultiplier(findCandidatesApproxPolyDPEpsMultiplier) params.SetMinContourSolidity(minContourSolidity) params.SetMinContoursArea(minContoursArea) params.SetMinContoursAreaRate(minContoursAreaRate) params.SetB0factor(B0factor) params.SetMaxError(maxError) params.SetMinGroupSize(minGroupSize) if params.GetAdaptiveThreshWinSizeMin() != adaptiveThreshWinSizeMin { t.Errorf("AdaptiveThreshWinSizeMin expected %v got %v", adaptiveThreshWinSizeMin, params.GetAdaptiveThreshWinSizeMin()) } if params.GetAdaptiveThreshWinSizeMax() != adaptiveThreshWinSizeMax { t.Errorf("AdaptiveThreshWinSizeMax expected %v got %v", adaptiveThreshWinSizeMax, params.GetAdaptiveThreshWinSizeMax()) } if params.GetAdaptiveThreshWinSizeStep() != adaptiveThreshWinSizeStep { t.Errorf("AdaptiveThreshWinSizeStep expected %v got %v", adaptiveThreshWinSizeStep, params.GetAdaptiveThreshWinSizeStep()) } if params.GetAdaptiveThreshConstant() != adaptiveThreshConstant { t.Errorf("AdaptiveThreshConstant expected %v got %v", adaptiveThreshConstant, params.GetAdaptiveThreshConstant()) } if params.GetBorderWidth() != borderWidth { t.Errorf("BorderWidth expected %v got %v", borderWidth, params.GetBorderWidth()) } if params.GetMinContourLengthAllowed() != minContourLengthAllowed { t.Errorf("MinContourLengthAllowed expected %v got %v", minContourLengthAllowed, params.GetMinContourLengthAllowed()) } if params.GetMinContourPointsAllowed() != minContourPointsAllowed { t.Errorf("MinContourPointsAllowed expected %v got %v", minContourPointsAllowed, params.GetMinContourPointsAllowed()) } if params.GetMinImageSize() != minImageSize { t.Errorf("MinImageSize expected %v got %v", minImageSize, params.GetMinImageSize()) } if params.GetMinInterCheckerDistance() != minInterCheckerDistance { t.Errorf("MinInterCheckerDistance expected %v got %v", minInterCheckerDistance, params.GetMinInterCheckerDistance()) } if params.GetMinInterContourDistance() != minInterContourDistance { t.Errorf("MinInterContourDistance expected %v got %v", minInterContourDistance, params.GetMinInterContourDistance()) } if params.GetAdaptiveThreshConstant() != adaptiveThreshConstant { t.Errorf("AdaptiveThreshConstant expected %v got %v", adaptiveThreshConstant, params.GetAdaptiveThreshConstant()) } if params.GetConfidenceThreshold() != confidenceThreshold { t.Errorf("ConfidenceThreshold expected %v got %v", confidenceThreshold, params.GetConfidenceThreshold()) } if params.GetFindCandidatesApproxPolyDPEpsMultiplier() != findCandidatesApproxPolyDPEpsMultiplier { t.Errorf("FindCandidatesApproxPolyDPEpsMultiplier expected %v got %v", findCandidatesApproxPolyDPEpsMultiplier, params.GetFindCandidatesApproxPolyDPEpsMultiplier()) } if params.GetMinContourSolidity() != minContourSolidity { t.Errorf("MinContourSolidity expected %v got %v", minContourSolidity, params.GetMinContourSolidity()) } if params.GetMinContoursArea() != minContoursArea { t.Errorf("MinContoursArea expected %v got %v", minContoursArea, params.GetMinContoursArea()) } if params.GetMinContoursAreaRate() != minContoursAreaRate { t.Errorf("MinContoursAreaRate expected %v got %v", minContoursAreaRate, params.GetMinContoursAreaRate()) } if params.GetB0factor() != B0factor { t.Errorf("B0factor expected %v got %v", B0factor, params.GetB0factor()) } if params.GetMaxError() != maxError { t.Errorf("MaxError expected %v got %v", maxError, params.GetMaxError()) } if params.GetMinGroupSize() != minGroupSize { t.Errorf("MinGroupSize expected %v got %v", minGroupSize, params.GetMinGroupSize()) } } func TestProcess(t *testing.T) { path := macbethImage imgCopy := gocv.NewMat() img := gocv.IMRead(path, gocv.IMReadColor) img.CopyTo(&imgCopy) defer imgCopy.Close() if img.Empty() { t.Fatal("Invalid input: image is empty or could not be loaded. Check that ./images/macbeth.jpg exists and is a valid image.") } defer img.Close() detector := NewMccCCheckerDetector() defer detector.Close() res := detector.Process(img, MCC24) if !res { t.Error("Atleast one chart is expected to be detected got 0") } checkers := detector.GetListColorChecker() var EPS = 0.001 for _, checker := range checkers { whitePatch := checker.GetColorCharts()[18*4 : 18*4+4] expected := make([]gocv.Point2f, 4) expected[0] = gocv.Point2f{X: 438.60522, Y: 465.06586} expected[1] = gocv.Point2f{X: 480.70596, Y: 461.58606} expected[2] = gocv.Point2f{X: 484.52277, Y: 502.17834} expected[3] = gocv.Point2f{X: 442.45264, Y: 505.96082} for idx, _ := range expected { if distPoint2f(whitePatch[idx], expected[idx]) > EPS { t.Errorf("White patch expected at %v got %v", expected[idx], whitePatch[idx]) } } // Outputting for visual inspection cdraw := NewMccCCheckerDraw(checker, gocv.NewScalar(0, 250, 0, 255), 2) cdraw.Draw(img) } gocv.IMWrite("../images/macbeth-correct.png", img) } func distPoint2f(a, b gocv.Point2f) float64 { return math.Sqrt(math.Pow(float64(a.X-b.X), 2) + math.Pow(float64(a.Y-b.Y), 2)) } ================================================ FILE: contrib/tracking.cpp ================================================ //go:build !gocv_specific_modules || (gocv_specific_modules && gocv_contrib_tracking) #include "tracking.h" #include bool TrackerSubclass_Init(Tracker self, Mat image, Rect boundingBox) { try { cv::Rect bb(boundingBox.x, boundingBox.y, boundingBox.width, boundingBox.height); (*self)->init(*image, bb); return true; } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return false; } } bool TrackerSubclass_Update(Tracker self, Mat image, Rect* boundingBox) { try { cv::Rect bb; bool ret = (*self)->update(*image, bb); boundingBox->x = int(bb.x); boundingBox->y = int(bb.y); boundingBox->width = int(bb.width); boundingBox->height = int(bb.height); return ret; } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return false; } } TrackerKCF TrackerKCF_Create() { try { return new cv::Ptr(cv::TrackerKCF::create()); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } void TrackerKCF_Close(TrackerKCF self) { delete self; } TrackerCSRT TrackerCSRT_Create() { try { return new cv::Ptr(cv::TrackerCSRT::create()); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } void TrackerCSRT_Close(TrackerCSRT self) { delete self; } ================================================ FILE: contrib/tracking.go ================================================ //go:build !gocv_specific_modules || (gocv_specific_modules && gocv_contrib_tracking) package contrib /* #include "tracking.h" */ import "C" import ( "image" "gocv.io/x/gocv" ) // TrackerKCF is a Tracker based on KCF, which is a novel tracking framework that // utilizes properties of circulant matrix to enhance the processing speed. // // For further details, please see: // https://docs.opencv.org/master/d2/dff/classcv_1_1TrackerKCF.html type TrackerKCF struct { p C.TrackerKCF } // NewTrackerKCF returns a new TrackerKCF. func NewTrackerKCF() gocv.Tracker { return TrackerKCF{p: C.TrackerKCF_Create()} } // Close closes this Tracker. func (trk TrackerKCF) Close() error { C.TrackerKCF_Close(trk.p) trk.p = nil return nil } // Init initializes this Tracker. func (trk TrackerKCF) Init(img gocv.Mat, boundingBox image.Rectangle) bool { return trackerInit(C.Tracker(trk.p), img, boundingBox) } // Update updates this Tracker. func (trk TrackerKCF) Update(img gocv.Mat) (image.Rectangle, bool) { return trackerUpdate(C.Tracker(trk.p), img) } // TrackerCSRT is an implementation of Discriminative Correlation Filter Tracker // with Channel and Spatial Reliability. // // For further details, please see: // https://docs.opencv.org/master/d2/da2/classcv_1_1TrackerCSRT.html type TrackerCSRT struct { p C.TrackerCSRT } // NewTrackerCSRT returns a new TrackerCSRT. func NewTrackerCSRT() gocv.Tracker { return TrackerCSRT{p: C.TrackerCSRT_Create()} } // Close closes this Tracker. func (trk TrackerCSRT) Close() error { C.TrackerCSRT_Close(trk.p) trk.p = nil return nil } // Init initializes this Tracker. func (trk TrackerCSRT) Init(img gocv.Mat, boundingBox image.Rectangle) bool { return trackerInit(C.Tracker(trk.p), img, boundingBox) } // Update updates this Tracker. func (trk TrackerCSRT) Update(img gocv.Mat) (image.Rectangle, bool) { return trackerUpdate(C.Tracker(trk.p), img) } func trackerInit(trk C.Tracker, img gocv.Mat, boundingBox image.Rectangle) bool { cBox := C.struct_Rect{ x: C.int(boundingBox.Min.X), y: C.int(boundingBox.Min.Y), width: C.int(boundingBox.Size().X), height: C.int(boundingBox.Size().Y), } ret := C.TrackerSubclass_Init(trk, C.Mat(img.Ptr()), cBox) return bool(ret) } func trackerUpdate(trk C.Tracker, img gocv.Mat) (image.Rectangle, bool) { cBox := C.struct_Rect{} ret := C.TrackerSubclass_Update(trk, C.Mat(img.Ptr()), &cBox) rect := image.Rect(int(cBox.x), int(cBox.y), int(cBox.x+cBox.width), int(cBox.y+cBox.height)) return rect, bool(ret) } ================================================ FILE: contrib/tracking.h ================================================ #ifndef _OPENCV3_TRACKING_H_ #define _OPENCV3_TRACKING_H_ #include "../core.h" #ifdef __cplusplus #include extern "C" { #endif #ifdef __cplusplus typedef cv::Ptr* Tracker; typedef cv::Ptr* TrackerKCF; typedef cv::Ptr* TrackerCSRT; #else typedef void* Tracker; typedef void* TrackerKCF; typedef void* TrackerCSRT; #endif bool TrackerSubclass_Init(Tracker self, Mat image, Rect boundingBox); bool TrackerSubclass_Update(Tracker self, Mat image, Rect* boundingBox); TrackerKCF TrackerKCF_Create(); void TrackerKCF_Close(TrackerKCF self); TrackerCSRT TrackerCSRT_Create(); void TrackerCSRT_Close(TrackerCSRT self); #ifdef __cplusplus } #endif #endif //_OPENCV3_TRACKING_H_ ================================================ FILE: contrib/tracking_test.go ================================================ //go:build !gocv_specific_modules || (gocv_specific_modules && gocv_contrib_tracking) package contrib import ( "image" "testing" "gocv.io/x/gocv" ) func BaseTestTracker(t *testing.T, tracker gocv.Tracker, name string) { if tracker == nil { t.Error("TestTracker " + name + " should not be nil") } img := gocv.IMRead("../images/face.jpg", 1) if img.Empty() { t.Error("TestTracker " + name + " input img failed to load") } defer img.Close() rect := image.Rect(250, 150, 250+200, 150+250) init := tracker.Init(img, rect) if !init { t.Error("TestTracker " + name + " failed in Init") } _, ok := tracker.Update(img) if !ok { t.Error("TestTracker " + name + " lost object in Update") } } func TestSingleTrackers(t *testing.T) { tab := []struct { name string tracker gocv.Tracker }{ {"KCF", NewTrackerKCF()}, {"CSRT", NewTrackerCSRT()}, } for _, test := range tab { func() { defer test.tracker.Close() BaseTestTracker(t, test.tracker, test.name) }() } } ================================================ FILE: contrib/wechat_qrcode.cpp ================================================ //go:build !gocv_specific_modules || (gocv_specific_modules && gocv_contrib_wechat_qrcode) #include "wechat_qrcode.h" WeChatQRCode NewWeChatQRCode(const char *detector_prototxt_path, const char *detector_caffe_model_path, const char *super_resolution_prototxt_path, const char *super_resolution_caffe_model_path) { try { return new cv::Ptr( cv::makePtr(detector_prototxt_path, detector_caffe_model_path, super_resolution_prototxt_path, super_resolution_caffe_model_path)); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } StringsVector NewStringsVector() { return new std::vector; } void WeChatQRCode_CStrings_Close(struct CStrings cstrs) { for ( int i = 0; i < cstrs.length; i++ ) { delete [] cstrs.strs[i]; } delete [] cstrs.strs; } void WeChatQRCode_Mats_to(struct Mats mats, int i, Mat dst) { try { mats.mats[i]->copyTo(*dst);; } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); } } void WeChatQRCode_Mats_Close(struct Mats mats) { delete[] mats.mats; } CStrings WeChatQRCode_DetectAndDecode(WeChatQRCode wq, Mat img, struct Mats *points, StringsVector codes) { try { std::vector Points; *codes = ((*wq)->detectAndDecode(*img, Points)); CStrings results; points->mats = new Mat[Points.size()]; for (size_t i = 0; i < Points.size(); ++i) { points->mats[i] = new cv::Mat(Points[i]); } points->length = (int) Points.size(); const char **decodes = new const char *[codes->size()]; for (size_t i = 0; i < codes->size(); ++i) { decodes[i] = (*codes)[i].c_str(); } (&results)->length = codes->size(); (&results)->strs = decodes; return results; } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); CStrings results; return results; } } ================================================ FILE: contrib/wechat_qrcode.go ================================================ //go:build !gocv_specific_modules || (gocv_specific_modules && gocv_contrib_wechat_qrcode) package contrib /* #include #include "wechat_qrcode.h" */ import "C" import ( "gocv.io/x/gocv" "unsafe" ) type WeChatQRCode struct { p C.WeChatQRCode } func NewWeChatQRCode(detectProtoTxt, detectCaffe, superProtoTxt, superCaffe string) *WeChatQRCode { dp := C.CString(detectProtoTxt) dc := C.CString(detectCaffe) sp := C.CString(superProtoTxt) sc := C.CString(superCaffe) defer C.free(unsafe.Pointer(dp)) defer C.free(unsafe.Pointer(dc)) defer C.free(unsafe.Pointer(sp)) defer C.free(unsafe.Pointer(sc)) return &WeChatQRCode{p: C.NewWeChatQRCode(dp, dc, sp, sc)} } func (wq *WeChatQRCode) DetectAndDecode(img gocv.Mat, point *[]gocv.Mat) []string { cMats := C.struct_Mats{} defer C.WeChatQRCode_Mats_Close(cMats) cDecoded := C.CStrings{} defer C.WeChatQRCode_CStrings_Close(cDecoded) cCodes := C.NewStringsVector() defer C.free(unsafe.Pointer(cCodes)) cDecoded = C.WeChatQRCode_DetectAndDecode((C.WeChatQRCode)(wq.p), (C.Mat)(img.Ptr()), &(cMats), cCodes) ps := make([]gocv.Mat, cMats.length) for i := C.int(0); i < cMats.length; i++ { ps[i] = gocv.NewMat() C.WeChatQRCode_Mats_to(cMats, i, (C.Mat)(ps[i].Ptr())) } *point = ps result := make([]string, 0) for _, v := range toGoStrings(cDecoded) { result = append(result, v) } return result } func toGoStrings(strs C.CStrings) []string { length := int(strs.length) tmpslice := (*[1 << 20]*C.char)(unsafe.Pointer(strs.strs))[:length:length] gostrings := make([]string, length) for i, s := range tmpslice { gostrings[i] = C.GoString(s) } return gostrings } ================================================ FILE: contrib/wechat_qrcode.h ================================================ #ifndef _OPENCV4_WECHAT_QRCODE_H_ #define _OPENCV4_WECHAT_QRCODE_H_ #ifdef __cplusplus #include #include extern "C" { #endif #include "../core.h" #ifdef __cplusplus typedef cv::Ptr *WeChatQRCode; typedef std::vector *StringsVector; #else typedef void* WeChatQRCode; typedef void* StringsVector; #endif WeChatQRCode NewWeChatQRCode(const char *detector_prototxt_path, const char *detector_caffe_model_path, const char *super_resolution_prototxt_path, const char *super_resolution_caffe_model_path); CStrings WeChatQRCode_DetectAndDecode(WeChatQRCode wq, Mat img, struct Mats *points, StringsVector codes); StringsVector NewStringsVector(); void WeChatQRCode_CStrings_Close(struct CStrings cstrs); void WeChatQRCode_Mats_Close(struct Mats mats); void WeChatQRCode_Mats_to(struct Mats mats, int i, Mat dst); #ifdef __cplusplus } #endif #endif //_OPENCV4_WECHAT_QRCODE_H_ ================================================ FILE: contrib/wechat_qrcode_test.go ================================================ //go:build !gocv_specific_modules || (gocv_specific_modules && gocv_contrib_wechat_qrcode) package contrib import ( "gocv.io/x/gocv" "os" "reflect" "testing" ) func TestNewWeChatQRCode(t *testing.T) { tests := []struct { name string notWant *WeChatQRCode }{ {"testNewWeChatQRCode", nil}, } path := os.Getenv("GOCV_CAFFE_TEST_FILES") if path == "" { t.Skip("Unable to locate Caffe model files for tests") } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := NewWeChatQRCode(path+"/detect.prototxt", path+"/detect.caffemodel", path+"/sr.prototxt", path+"/sr.caffemodel"); reflect.DeepEqual(got, tt.notWant) { t.Errorf("NewWeChatQRCode() = %v, want %v", got, tt.notWant) } }) } } func TestWeChatQRCode_DetectAndDecode(t *testing.T) { mat := gocv.IMRead("../images/qrcode.png", gocv.IMReadColor) mats := make([]gocv.Mat, 0) defer mat.Close() type args struct { img gocv.Mat point *[]gocv.Mat } tests := []struct { name string args args want []string qrCounts int }{ {"TestDetectAndDecode", args{point: &mats, img: mat}, []string{"Hello World!"}, 1}, } path := os.Getenv("GOCV_CAFFE_TEST_FILES") if path == "" { t.Skip("Unable to locate Caffe model files for tests") } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { wq := NewWeChatQRCode(path+"/detect.prototxt", path+"/detect.caffemodel", path+"/sr.prototxt", path+"/sr.caffemodel") if got := wq.DetectAndDecode(tt.args.img, tt.args.point); !reflect.DeepEqual(got, tt.want) { t.Errorf("DetectAndDecode() = %v, want %v", got, tt.want) } if len(mats) != tt.qrCounts { t.Errorf("DetectAndDecode() = %v, want qrcode counts %v", tt.qrCounts, len(mats)) } }) } } ================================================ FILE: contrib/xfeatures2d.cpp ================================================ //go:build !gocv_specific_modules || (gocv_specific_modules && gocv_contrib_xfeatures2d) #include "xfeatures2d.h" SURF SURF_Create() { try { return new cv::Ptr(cv::xfeatures2d::SURF::create()); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } SURF SURF_CreateWithParams(double hessianThreshold, int nOctaves, int nOctaveLayers, bool extended, bool upright) { try { return new cv::Ptr(cv::xfeatures2d::SURF::create(hessianThreshold, nOctaves, nOctaveLayers, extended, upright)); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } void SURF_Close(SURF d) { delete d; } struct KeyPoints SURF_Detect(SURF d, Mat src) { try { std::vector detected; (*d)->detect(*src, detected); KeyPoint* kps = new KeyPoint[detected.size()]; for (size_t i = 0; i < detected.size(); ++i) { KeyPoint k = {detected[i].pt.x, detected[i].pt.y, detected[i].size, detected[i].angle, detected[i].response, detected[i].octave, detected[i].class_id }; kps[i] = k; } KeyPoints ret = {kps, (int)detected.size()}; return ret; } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); KeyPoints ret = {NULL, 0}; return ret; } } struct KeyPoints SURF_Compute(SURF d, Mat src, struct KeyPoints kp, Mat desc) { try { std::vector computed; for (size_t i = 0; i < kp.length; i++) { cv::KeyPoint k = cv::KeyPoint(kp.keypoints[i].x, kp.keypoints[i].y, kp.keypoints[i].size, kp.keypoints[i].angle, kp.keypoints[i].response, kp.keypoints[i].octave, kp.keypoints[i].classID); computed.push_back(k); } (*d)->compute(*src, computed, *desc); KeyPoint* kps = new KeyPoint[computed.size()]; for (size_t i = 0; i < computed.size(); ++i) { KeyPoint k = {computed[i].pt.x, computed[i].pt.y, computed[i].size, computed[i].angle, computed[i].response, computed[i].octave, computed[i].class_id }; kps[i] = k; } KeyPoints ret = {kps, (int)computed.size()}; return ret; } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); KeyPoints ret = {NULL, 0}; return ret; } } struct KeyPoints SURF_DetectAndCompute(SURF d, Mat src, Mat mask, Mat desc) { try { std::vector detected; (*d)->detectAndCompute(*src, *mask, detected, *desc); KeyPoint* kps = new KeyPoint[detected.size()]; for (size_t i = 0; i < detected.size(); ++i) { KeyPoint k = {detected[i].pt.x, detected[i].pt.y, detected[i].size, detected[i].angle, detected[i].response, detected[i].octave, detected[i].class_id }; kps[i] = k; } KeyPoints ret = {kps, (int)detected.size()}; return ret; } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); KeyPoints ret = {NULL, 0}; return ret; } } BriefDescriptorExtractor BriefDescriptorExtractor_Create() { try { return new cv::Ptr(cv::xfeatures2d::BriefDescriptorExtractor::create()); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } BriefDescriptorExtractor BriefDescriptorExtractor_CreateWithParams(int bytes, bool useOrientation) { try { return new cv::Ptr(cv::xfeatures2d::BriefDescriptorExtractor::create(bytes, useOrientation)); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } void BriefDescriptorExtractor_Close(BriefDescriptorExtractor b) { delete b; } void BriefDescriptorExtractor_Compute(BriefDescriptorExtractor b, Mat src, struct KeyPoints kp, Mat desc) { try { std::vector keypts; keypts.reserve(kp.length); cv::KeyPoint keypt; for (int i = 0; i < kp.length; ++i) { keypt = cv::KeyPoint(kp.keypoints[i].x, kp.keypoints[i].y, kp.keypoints[i].size, kp.keypoints[i].angle, kp.keypoints[i].response, kp.keypoints[i].octave, kp.keypoints[i].classID); keypts.push_back(keypt); } (*b)->compute(*src, keypts, *desc); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); } } ================================================ FILE: contrib/xfeatures2d.go ================================================ //go:build !gocv_specific_modules || (gocv_specific_modules && gocv_contrib_xfeatures2d) package contrib /* #include #include "xfeatures2d.h" */ import "C" import ( "reflect" "unsafe" "gocv.io/x/gocv" ) // SURF is a wrapper around the cv::SURF algorithm. // Due to being a patented algorithm you must set the OpenCV contrib build flag OPENCV_ENABLE_NONFREE=1 // in order to use it. type SURF struct { // C.SURF p unsafe.Pointer } var _ gocv.Feature2D = (*SURF)(nil) // NewSURF returns a new SURF algorithm. // // For further details, please see: // https://docs.opencv.org/master/d5/df7/classcv_1_1xfeatures2d_1_1SURF.html func NewSURF() SURF { return SURF{p: unsafe.Pointer(C.SURF_Create())} } // NewSURFWithParams returns a new SURF algorithm algorithm with parameters // // For further details, please see: // https://docs.opencv.org/master/d5/df7/classcv_1_1xfeatures2d_1_1SURF.html#a436553ca44d9a2238761ddbee5b395e5 func NewSURFWithParams(hessianThreshold float64, nOctaves int, nOctaveLayers int, extended bool, upright bool) SURF { return SURF{p: unsafe.Pointer(C.SURF_CreateWithParams(C.double(hessianThreshold), C.int(nOctaves), C.int(nOctaveLayers), C.bool(extended), C.bool(upright)))} } // Close SURF. func (d *SURF) Close() error { C.SURF_Close((C.SURF)(d.p)) d.p = nil return nil } // Detect keypoints in an image using SURF. // // For further details, please see: // https://docs.opencv.org/master/d0/d13/classcv_1_1Feature2D.html#aa4e9a7082ec61ebc108806704fbd7887 func (d *SURF) Detect(src gocv.Mat) []gocv.KeyPoint { ret := C.SURF_Detect((C.SURF)(d.p), C.Mat(src.Ptr())) return getKeyPoints(ret) } // Compute keypoints in an image using SURF. // // For further details, please see: // https://docs.opencv.org/4.x/d0/d13/classcv_1_1Feature2D.html#ab3cce8d56f4fc5e1d530b5931e1e8dc0 func (d *SURF) Compute(src gocv.Mat, mask gocv.Mat, kps []gocv.KeyPoint) ([]gocv.KeyPoint, gocv.Mat) { desc := gocv.NewMat() kp2arr := make([]C.struct_KeyPoint, len(kps)) for i, kp := range kps { kp2arr[i].x = C.double(kp.X) kp2arr[i].y = C.double(kp.Y) kp2arr[i].size = C.double(kp.Size) kp2arr[i].angle = C.double(kp.Angle) kp2arr[i].response = C.double(kp.Response) kp2arr[i].octave = C.int(kp.Octave) kp2arr[i].classID = C.int(kp.ClassID) } cKeyPoints := C.struct_KeyPoints{ keypoints: (*C.struct_KeyPoint)(&kp2arr[0]), length: (C.int)(len(kps)), } ret := C.SURF_Compute((C.SURF)(d.p), C.Mat(src.Ptr()), cKeyPoints, C.Mat(desc.Ptr())) return getKeyPoints(ret), desc } // DetectAndCompute detects and computes keypoints in an image using SURF. // // For further details, please see: // https://docs.opencv.org/master/d0/d13/classcv_1_1Feature2D.html#a8be0d1c20b08eb867184b8d74c15a677 func (d *SURF) DetectAndCompute(src gocv.Mat, mask gocv.Mat) ([]gocv.KeyPoint, gocv.Mat) { desc := gocv.NewMat() ret := C.SURF_DetectAndCompute((C.SURF)(d.p), C.Mat(src.Ptr()), C.Mat(mask.Ptr()), C.Mat(desc.Ptr())) return getKeyPoints(ret), desc } func getKeyPoints(ret C.KeyPoints) []gocv.KeyPoint { cArray := ret.keypoints defer C.free(unsafe.Pointer(cArray)) length := int(ret.length) hdr := reflect.SliceHeader{ Data: uintptr(unsafe.Pointer(cArray)), Len: length, Cap: length, } s := *(*[]C.KeyPoint)(unsafe.Pointer(&hdr)) keys := make([]gocv.KeyPoint, length) for i, r := range s { keys[i] = gocv.KeyPoint{X: float64(r.x), Y: float64(r.y), Size: float64(r.size), Angle: float64(r.angle), Response: float64(r.response), Octave: int(r.octave), ClassID: int(r.classID)} } return keys } // BriefDescriptorExtractor is a wrapper around the cv::BriefDescriptorExtractor algorithm. type BriefDescriptorExtractor struct { // C.BriefDescriptorExtractor p unsafe.Pointer } // NewBriefDescriptorExtractor returns a new BriefDescriptorExtractor algorithm. // // For further details, please see: // https://docs.opencv.org/master/d1/d93/classcv_1_1xfeatures2d_1_1BriefDescriptorExtractor.html func NewBriefDescriptorExtractor() BriefDescriptorExtractor { return BriefDescriptorExtractor{p: unsafe.Pointer(C.BriefDescriptorExtractor_Create())} } // NewBriefDescriptorExtractorWithParams returns a new BriefDescriptorExtractor algorithm algorithm with parameters // // For further details, please see: // https://docs.opencv.org/master/d1/d93/classcv_1_1xfeatures2d_1_1BriefDescriptorExtractor.html#ae3bc52666010fb137ab6f0d32de51f60 func NewBriefDescriptorExtractorWithParams(bytes int, useOrientation bool) BriefDescriptorExtractor { return BriefDescriptorExtractor{p: unsafe.Pointer(C.BriefDescriptorExtractor_CreateWithParams(C.int(bytes), C.bool(useOrientation)))} } // Close BriefDescriptorExtractor. func (d *BriefDescriptorExtractor) Close() error { C.BriefDescriptorExtractor_Close((C.BriefDescriptorExtractor)(d.p)) d.p = nil return nil } // Compute descriptors with given keypoints using BriefDescriptorExtractor // // For further details, please see: // https://docs.opencv.org/master/d0/d13/classcv_1_1Feature2D.html#ab3cce8d56f4fc5e1d530b5931e1e8dc0 func (b *BriefDescriptorExtractor) Compute(keyPoints []gocv.KeyPoint, src gocv.Mat) gocv.Mat { desc := gocv.NewMat() cKeyPointArray := make([]C.struct_KeyPoint, len(keyPoints)) for i, kp := range keyPoints { cKeyPointArray[i].x = C.double(kp.X) cKeyPointArray[i].y = C.double(kp.Y) cKeyPointArray[i].size = C.double(kp.Size) cKeyPointArray[i].angle = C.double(kp.Angle) cKeyPointArray[i].response = C.double(kp.Response) cKeyPointArray[i].octave = C.int(kp.Octave) cKeyPointArray[i].classID = C.int(kp.ClassID) } cKeyPoints := C.struct_KeyPoints{ keypoints: (*C.struct_KeyPoint)(&cKeyPointArray[0]), length: (C.int)(len(keyPoints)), } C.BriefDescriptorExtractor_Compute((C.BriefDescriptorExtractor)(b.p), C.Mat(src.Ptr()), cKeyPoints, C.Mat(desc.Ptr())) return desc } ================================================ FILE: contrib/xfeatures2d.h ================================================ #ifndef _OPENCV3_XFEATURES2D_H_ #define _OPENCV3_XFEATURES2D_H_ #ifdef __cplusplus #include #include extern "C" { #endif #include "../core.h" #ifdef __cplusplus typedef cv::Ptr* SURF; typedef cv::Ptr* BriefDescriptorExtractor; #else typedef void* SURF; typedef void* BriefDescriptorExtractor; #endif SURF SURF_Create(); SURF SURF_CreateWithParams(double hessianThreshold, int nOctaves, int nOctaveLayers, bool extended, bool upright); void SURF_Close(SURF f); struct KeyPoints SURF_Detect(SURF f, Mat src); struct KeyPoints SURF_Compute(SURF f, Mat src, struct KeyPoints kp, Mat desc); struct KeyPoints SURF_DetectAndCompute(SURF f, Mat src, Mat mask, Mat desc); BriefDescriptorExtractor BriefDescriptorExtractor_Create(); BriefDescriptorExtractor BriefDescriptorExtractor_CreateWithParams(int bytes, bool useOrientation); void BriefDescriptorExtractor_Close(BriefDescriptorExtractor b); void BriefDescriptorExtractor_Compute(BriefDescriptorExtractor b, Mat src, struct KeyPoints kp, Mat desc); #ifdef __cplusplus } #endif #endif //_OPENCV3_XFEATURES2D_H_ ================================================ FILE: contrib/xfeatures2d_test.go ================================================ //go:build !gocv_specific_modules || (gocv_specific_modules && gocv_contrib_xfeatures2d) package contrib import ( "os" "testing" "gocv.io/x/gocv" ) func TestSURF(t *testing.T) { testNonFree := os.Getenv("OPENCV_ENABLE_NONFREE") if testNonFree == "" { t.Skip("Skipping SURF test since OPENCV_ENABLE_NONFREE was not set") } img := gocv.IMRead("../images/face.jpg", gocv.IMReadGrayScale) if img.Empty() { t.Error("Invalid Mat in SURF test") } defer img.Close() dst := gocv.NewMat() defer dst.Close() si := NewSURF() defer si.Close() kp := si.Detect(img) if len(kp) == 512 { t.Errorf("Invalid KeyPoint array in SURF Detect: %d", len(kp)) } mask := gocv.NewMat() defer mask.Close() kpc, desc := si.Compute(img, mask, kp) defer desc.Close() if len(kpc) < 512 { t.Errorf("Invalid KeyPoint array in SURF Compute: %d", len(kpc)) } if desc.Empty() { t.Error("Invalid Mat desc in SURF Compute") } kpdc, desc2 := si.DetectAndCompute(img, mask) defer desc2.Close() if len(kpdc) < 512 { t.Errorf("Invalid KeyPoint array in SURF DetectAndCompute: %d", len(kpdc)) } if desc2.Empty() { t.Error("Invalid Mat desc in SURF DetectAndCompute") } } func TestSURFWithParams(t *testing.T) { testNonFree := os.Getenv("OPENCV_ENABLE_NONFREE") if testNonFree == "" { t.Skip("Skipping SURFWithParams test since OPENCV_ENABLE_NONFREE was not set") } img := gocv.IMRead("../images/face.jpg", gocv.IMReadGrayScale) if img.Empty() { t.Error("Invalid Mat in SURF test") } defer img.Close() dst := gocv.NewMat() defer dst.Close() si := NewSURFWithParams(100, 4, 3, false, false) defer si.Close() kp := si.Detect(img) if len(kp) == 512 { t.Errorf("Invalid KeyPoint array in SURF Detect: %d", len(kp)) } mask := gocv.NewMat() defer mask.Close() kpc, desc := si.Compute(img, mask, kp) defer desc.Close() if len(kpc) < 512 { t.Errorf("Invalid KeyPoint array in SURF Compute: %d", len(kpc)) } if desc.Empty() { t.Error("Invalid Mat desc in SURF Compute") } kpdc, desc2 := si.DetectAndCompute(img, mask) defer desc2.Close() if len(kpdc) < 512 { t.Errorf("Invalid KeyPoint array in SURF DetectAndCompute: %d", len(kpdc)) } if desc2.Empty() { t.Error("Invalid Mat desc in SURF DetectAndCompute") } } func TestBriefDescriptorExtractor(t *testing.T) { testNonFree := os.Getenv("OPENCV_ENABLE_NONFREE") if testNonFree == "" { t.Skip("Skipping BriefDescriptorExtractor test since OPENCV_ENABLE_NONFREE was not set") } img := gocv.IMRead("../images/face.jpg", gocv.IMReadGrayScale) if img.Empty() { t.Error("Invalid Mat in BriefDescriptorExtractor test") } defer img.Close() fast := gocv.NewFastFeatureDetector() defer fast.Close() b := NewBriefDescriptorExtractor() defer b.Close() kp := fast.Detect(img) desc := b.Compute(kp, img) if desc.Empty() { t.Error("Invalid Mat desc in BriefDescriptorExtractor Compute") } } func TestBriefDescriptorExtractorWithParams(t *testing.T) { testNonFree := os.Getenv("OPENCV_ENABLE_NONFREE") if testNonFree == "" { t.Skip("Skipping BriefDescriptorExtractorWithParams test since OPENCV_ENABLE_NONFREE was not set") } img := gocv.IMRead("../images/face.jpg", gocv.IMReadGrayScale) if img.Empty() { t.Error("Invalid Mat in BriefDescriptorExtractorWithParams test") } defer img.Close() fast := gocv.NewFastFeatureDetector() defer fast.Close() b := NewBriefDescriptorExtractorWithParams(32, false) defer b.Close() kp := fast.Detect(img) desc := b.Compute(kp, img) if desc.Empty() { t.Error("Invalid Mat desc in BriefDescriptorExtractorWithParams Compute") } } ================================================ FILE: contrib/ximgproc.cpp ================================================ //go:build !gocv_specific_modules || (gocv_specific_modules && gocv_contrib_ximgproc) #include "ximgproc.h" OpenCVResult anisotropicDiffusion(Mat src, Mat dst, float alpha, float K, int niters) { try { cv::ximgproc::anisotropicDiffusion(*src, *dst, alpha, K, niters); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult edgePreservingFilter(Mat src, Mat dst, int d, float threshold) { try { cv::ximgproc::edgePreservingFilter(*src, *dst, d, threshold); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult niBlackThreshold(Mat src, Mat dst, float maxValue, int type, int blockSize, float k, int binarizationMethod, float r) { try { cv::ximgproc::niBlackThreshold(*src, *dst, maxValue, type, blockSize, k, binarizationMethod, r); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult PeiLinNormalization(Mat src, Mat dst) { try { cv::ximgproc::PeiLinNormalization(*src, *dst); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult thinning(Mat src, Mat dst, int typ) { try { cv::ximgproc::thinning(*src, *dst, typ); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } ================================================ FILE: contrib/ximgproc.go ================================================ //go:build !gocv_specific_modules || (gocv_specific_modules && gocv_contrib_ximgproc) package contrib /* #include #include "ximgproc.h" */ import "C" import ( "gocv.io/x/gocv" ) // AnisotropicDiffusion performs anisotropic diffusion on an image. // // The function applies Perona-Malik anisotropic diffusion to an image. // // For further details, please see: // https://docs.opencv.org/4.x/df/d2d/group__ximgproc.html#gaffedd976e0a8efb5938107acab185ec2 func AnisotropicDiffusion(src gocv.Mat, dst *gocv.Mat, alpha float32, k float32, niters int) error { return OpenCVResult(C.anisotropicDiffusion(C.Mat(src.Ptr()), C.Mat(dst.Ptr()), C.float(alpha), C.float(k), C.int(niters))) } // EdgePreservingFilter smoothes an image using the Edge-Preserving filter. // // For further details, please see: // https://docs.opencv.org/4.x/df/d2d/group__ximgproc.html#ga86fcda65ced0aafa2741088d82e9161c func EdgePreservingFilter(src gocv.Mat, dst *gocv.Mat, d int, threshold float32) error { return OpenCVResult(C.edgePreservingFilter(C.Mat(src.Ptr()), C.Mat(dst.Ptr()), C.int(d), C.float(threshold))) } type BinarizationMethod int const ( BinarizationNiblack BinarizationMethod = iota BinarizationSauvola BinarizationWolf BinarizationNICK ) // NiblackThreshold performs thresholding on input images using Niblack's technique // or some of the popular variations it inspired. // // For further details, please see: // https://docs.opencv.org/4.x/df/d2d/group__ximgproc.html#gab042a5032bbb85275f1fd3e04e7c7660 func NiblackThreshold(src gocv.Mat, dst *gocv.Mat, maxValue float32, typ gocv.ThresholdType, blockSize int, k float32, binarizationMethod BinarizationMethod, r float32) error { return OpenCVResult(C.niBlackThreshold(C.Mat(src.Ptr()), C.Mat(dst.Ptr()), C.float(maxValue), C.int(typ), C.int(blockSize), C.float(k), C.int(binarizationMethod), C.float(r))) } // PeiLinNormalization calculates an affine transformation that normalize // given image using Pei&Lin Normalization. // // For further details, please see: // https://docs.opencv.org/4.x/df/d2d/group__ximgproc.html#ga50d064b92f63916f4162474eea22d656 func PeiLinNormalization(src gocv.Mat, dst *gocv.Mat) error { return OpenCVResult(C.PeiLinNormalization(C.Mat(src.Ptr()), C.Mat(dst.Ptr()))) } type ThinningType int const ( ThinningZhangSuen ThinningType = iota ThinningGuoHall ) // Thinning applies a binary blob thinning operation, to achieve a skeletization // of the input image. // // The function transforms a binary blob image into a skeletized form using the // technique of Zhang-Suen. // // For further details, please see: // https://docs.opencv.org/4.x/df/d2d/group__ximgproc.html#ga37002c6ca80c978edb6ead5d6b39740c func Thinning(src gocv.Mat, dst *gocv.Mat, typ ThinningType) error { return OpenCVResult(C.thinning(C.Mat(src.Ptr()), C.Mat(dst.Ptr()), C.int(typ))) } ================================================ FILE: contrib/ximgproc.h ================================================ #ifndef _OPENCV3_XIMGPROC_H_ #define _OPENCV3_XIMGPROC_H_ #ifdef __cplusplus #include #include extern "C" { #endif #include "../core.h" OpenCVResult anisotropicDiffusion(Mat src, Mat dst, float alpha, float K, int niters); OpenCVResult edgePreservingFilter(Mat src, Mat dst, int d, float threshold); OpenCVResult niBlackThreshold(Mat src, Mat dst, float maxValue, int type, int blockSize, float k, int binarizationMethod, float r); OpenCVResult PeiLinNormalization(Mat src, Mat dst); OpenCVResult thinning(Mat src, Mat dst, int typ); #ifdef __cplusplus } #endif #endif //_OPENCV3_XIMGPROC_H ================================================ FILE: contrib/ximgproc_test.go ================================================ //go:build !gocv_specific_modules || (gocv_specific_modules && gocv_contrib_ximgproc) package contrib import ( "testing" "gocv.io/x/gocv" ) func TestAnisotropicDiffusion(t *testing.T) { src := gocv.NewMatWithSize(200, 200, gocv.MatTypeCV8UC3) defer src.Close() dst := gocv.NewMat() defer dst.Close() AnisotropicDiffusion(src, &dst, 0.5, 0.5, 100) if src.Empty() || dst.Rows() != src.Rows() { t.Error("invalid AnisotropicDiffusion test") } } func TestAnisotropicDiffusionException(t *testing.T) { src := gocv.NewMat() defer src.Close() dst := gocv.NewMat() defer dst.Close() err := AnisotropicDiffusion(src, &dst, 0.5, 0.5, 100) if err == nil { t.Error("Expected exception in test") } if len(err.Error()) == 0 { t.Error("Expected exception message in test") } } func TestEdgePreservingFilter(t *testing.T) { src := gocv.NewMatWithSize(200, 200, gocv.MatTypeCV8UC3) defer src.Close() dst := gocv.NewMat() defer dst.Close() EdgePreservingFilter(src, &dst, 3, 0.5) if src.Empty() || dst.Rows() != src.Rows() { t.Error("invalid EdgePreservingFilter test") } } func TestNiblackThreshold(t *testing.T) { src := gocv.NewMatWithSize(200, 200, gocv.MatTypeCV8UC1) defer src.Close() dst := gocv.NewMat() defer dst.Close() NiblackThreshold(src, &dst, 127.0, gocv.ThresholdBinary, 3, 0.5, BinarizationNiblack, 128) if src.Empty() || dst.Rows() != src.Rows() { t.Error("invalid NiblackThreshold test") } } func TestPeiLinNormalization(t *testing.T) { src := gocv.NewMatWithSize(200, 200, gocv.MatTypeCV8UC1) defer src.Close() dst := gocv.NewMat() defer dst.Close() PeiLinNormalization(src, &dst) if src.Empty() || dst.Rows() != 2 || dst.Cols() != 3 { t.Error("invalid PeiLinNormalization test", dst.Rows(), dst.Cols()) } } func TestThinning(t *testing.T) { src := gocv.NewMatWithSize(200, 200, gocv.MatTypeCV8UC1) defer src.Close() dst := gocv.NewMat() defer dst.Close() Thinning(src, &dst, ThinningZhangSuen) if src.Empty() || dst.Rows() != src.Rows() { t.Error("invalid Thinning test") } } ================================================ FILE: contrib/xobjdetect.cpp ================================================ //go:build !gocv_specific_modules || (gocv_specific_modules && gocv_contrib_xobjdetect) #include "xobjdetect.h" WBDetector WBDetector_Create(){ try { return new cv::Ptr(cv::xobjdetect::WBDetector::create()); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } void WBDetector_Close(WBDetector det){ delete det; } WBDetector_detect_result WBDetector_Detect(WBDetector det, Mat img){ try { std::vector bb; std::vector conf; WBDetector_detect_result result; (*det)->detect(*img, bb, conf); Rect* result_rects = (Rect*)malloc(bb.size()*sizeof(Rect)); float* result_confs = (float*)malloc(conf.size()*sizeof(float)); for(int i = 0; i < bb.size(); i ++) { result_rects[i].x = bb[i].x; result_rects[i].y = bb[i].y; result_rects[i].width = bb[i].width; result_rects[i].height = bb[i].height; } for(int i = 0; i < conf.size(); i ++){ result_confs[i] = conf[i]; } result.bboxes.rects = result_rects; result.bboxes.length = bb.size(); result.confidences.val = result_confs; result.confidences.length = conf.size(); return result; } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); WBDetector_detect_result result; return result; } } void WBDetector_Read(WBDetector det, FileNode node){ try { (*det)->read(*node); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); } } void WBDetector_Train(WBDetector det, const char* pos_samples, const char* neg_imgs){ try { (*det)->train(pos_samples, neg_imgs); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); } } void WBDetector_Write(WBDetector det, FileStorage fs){ try { (*det)->write(*fs); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); } } ================================================ FILE: contrib/xobjdetect.go ================================================ //go:build !gocv_specific_modules || (gocv_specific_modules && gocv_contrib_xobjdetect) package contrib /* #include #include "xobjdetect.h" */ import "C" import ( "image" "unsafe" "gocv.io/x/gocv" ) // WBDetector is a wrapper around the cv::xobjdetect::WBDetector. type WBDetector struct { p C.WBDetector } // NewWBDetector Creates a new WBDetector // // For further details, please see: // https://docs.opencv.org/4.x/de/d0e/classcv_1_1xobjdetect_1_1WBDetector.html#a58377ae61694aac08ad842ac830972d9 func NewWBDetector() WBDetector { p := C.WBDetector_Create() return WBDetector{p: p} } // Close Releases WBDetector allocated resources. func (det *WBDetector) Close() { C.WBDetector_Close(det.p) } // Detect Detect objects on image using WaldBoost detector // // img: Input image for detection // // Returns: // // Bounding boxes coordinates and // Confidence values for bounding boxes output vector // // For further details, please see: // https://docs.opencv.org/4.x/de/d0e/classcv_1_1xobjdetect_1_1WBDetector.html#ad19680e6545f49a9ca42dfc3457319e2 func (det *WBDetector) Detect(img gocv.Mat) ([]image.Rectangle, []float32) { result := C.WBDetector_Detect(det.p, C.Mat(img.Ptr())) defer C.free(unsafe.Pointer(result.bboxes.rects)) defer C.free(unsafe.Pointer(result.confidences.val)) cRects := unsafe.Slice(result.bboxes.rects, result.bboxes.length) cConfs := unsafe.Slice(result.confidences.val, result.confidences.length) goRects := make([]image.Rectangle, int(result.bboxes.length)) goConfs := make([]float32, int(result.confidences.length)) for i := 0; i < int(result.bboxes.length); i++ { r := image.Rect(int(cRects[i].x), int(cRects[i].y), int(cRects[i].width), int(cRects[i].height)) goRects = append(goRects, r) } for i := 0; i < int(result.confidences.length); i++ { goConfs[i] = float32(cConfs[i]) } return goRects, goConfs } // Read Read detector from gocv.FileNode // // For further details, please see: // https://docs.opencv.org/4.x/de/d0e/classcv_1_1xobjdetect_1_1WBDetector.html#aef2df760f45d25aade518196986e139f func (det *WBDetector) Read(node *gocv.FileNode) { C.WBDetector_Read(det.p, C.FileNode(node.Ptr())) } // Train WaldBoost detector. // // Parameters: // // posSamples: Path to directory with cropped positive samples // // negImgs: Path to directory with negative (background) images // // For further details, please see: // https://docs.opencv.org/4.x/de/d0e/classcv_1_1xobjdetect_1_1WBDetector.html#a3720fb425a2d16f6cd0625a2d8bc563e func (det *WBDetector) Train(posSamples string, negImgs string) { pos_samples := C.CString(posSamples) neg_imgs := C.CString(negImgs) defer C.free(unsafe.Pointer(pos_samples)) defer C.free(unsafe.Pointer(neg_imgs)) C.WBDetector_Train(det.p, pos_samples, neg_imgs) } // Write detector to gocv.FileStorage. // // For further details, please see: // https://docs.opencv.org/4.x/de/d0e/classcv_1_1xobjdetect_1_1WBDetector.html#a7d85338895707904ae1ddb4374ec8dac func (det *WBDetector) Write(fs *gocv.FileStorage) { C.WBDetector_Write(det.p, C.FileStorage(fs.Ptr())) } ================================================ FILE: contrib/xobjdetect.h ================================================ #ifndef _OPENCV3_XOBJDETECT_H_ #define _OPENCV3_XOBJDETECT_H_ #ifdef __cplusplus #include #include extern "C" { #endif #include "../core.h" #include "../persistence.h" typedef struct WBDetector_detect_result_t { Rects bboxes; FloatVector confidences; } WBDetector_detect_result; #ifdef __cplusplus typedef cv::Ptr* WBDetector; #else typedef void* WBDetector; #endif WBDetector WBDetector_Create(); void WBDetector_Close(WBDetector det); WBDetector_detect_result WBDetector_Detect(WBDetector det, Mat img); void WBDetector_Read(WBDetector det, FileNode node); void WBDetector_Train(WBDetector det, const char* pos_samples, const char* neg_imgs); void WBDetector_Write(WBDetector det, FileStorage fs); #ifdef __cplusplus } #endif #endif //_OPENCV3_XOBJDETECT_H_ ================================================ FILE: contrib/xobjdetect_test.go ================================================ //go:build !gocv_specific_modules || (gocv_specific_modules && gocv_contrib_xobjdetect) package contrib import ( "testing" "gocv.io/x/gocv" ) func TestWBDetector(t *testing.T) { img := gocv.IMRead("../images/face.jpg", gocv.IMReadAnyColor) if img.Empty() { t.Error("xobjdetect: cannot read image") } det := NewWBDetector() defer det.Close() det.Train("../images/gocvlogo.jpg", "../images/gocvlogo.png") det.Detect(img) fs := gocv.NewFileStorageWithParams("../testdata/WBDetector.json", gocv.FileStorageModeWrite, "utf-8") defer fs.Close() fs.StartWriteStruct("gocv", gocv.FileNodeTypeSeq, "model") det.Write(fs) fs.EndWriteStruct() node := fs.GetFirstTopLevelNode() det.Read(node) } ================================================ FILE: contrib/xphoto.cpp ================================================ //go:build !gocv_specific_modules || (gocv_specific_modules && gocv_contrib_xphoto) #include "xphoto.h" OpenCVResult Xphoto_ApplyChannelGains(Mat src, Mat dst, float gainB, float gainG, float gainR) { try { cv::xphoto::applyChannelGains(*src, *dst, gainB, gainG, gainR); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Xphoto_Bm3dDenoising_Step(Mat src, Mat dststep1, Mat dststep2) { try { cv::xphoto::bm3dDenoising( *src, *dststep1, *dststep2, 1, 4, 16, 2500, 400, 8, 1, 2.0f, cv::NORM_L2, cv::xphoto::BM3D_STEPALL, cv::xphoto::HAAR ); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Xphoto_Bm3dDenoising_Step_WithParams( Mat src, Mat dststep1, Mat dststep2, float h, int templateWindowSize, int searchWindowSize, int blockMatchingStep1, int blockMatchingStep2, int groupSize, int slidingStep, float beta, int normType, int step, int transformType ) { try { cv::xphoto::bm3dDenoising( *src, *dststep1, *dststep2, h, templateWindowSize, searchWindowSize, blockMatchingStep1, blockMatchingStep2, groupSize, slidingStep, beta, normType, step, transformType ); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Xphoto_Bm3dDenoising(Mat src, Mat dst) { try { cv::xphoto::bm3dDenoising(*src, *dst, 1, 4, 16, 2500, 400, 8, 1, 2.0f, cv::NORM_L2, cv::xphoto::BM3D_STEPALL, cv::xphoto::HAAR ); OpenCVResult result = {0, NULL}; return result; } catch(const cv::Exception& e) { OpenCVResult result = {e.code, e.what()}; return result; } } OpenCVResult Xphoto_Bm3dDenoising_WithParams( Mat src, Mat dst, float h, int templateWindowSize, int searchWindowSize, int blockMatchingStep1, int blockMatchingStep2, int groupSize, int slidingStep, float beta, int normType, int step, int transformType ) { try { cv::xphoto::bm3dDenoising(*src, *dst, h, templateWindowSize, searchWindowSize, blockMatchingStep1, blockMatchingStep2, groupSize, slidingStep, beta, normType, step, transformType ); OpenCVResult result = {0, NULL}; return result; } catch(const cv::Exception& e) { OpenCVResult result = {e.code, e.what()}; return result; } } // ----------------------- GrayworldWB ----------------------- GrayworldWB GrayworldWB_Create() { try { return new cv::Ptr(cv::xphoto::createGrayworldWB()); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } void GrayworldWB_Close(GrayworldWB b) { delete b; } void GrayworldWB_SetSaturationThreshold(GrayworldWB b, float saturationThreshold) { try { (*b)->setSaturationThreshold(saturationThreshold); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); } } float GrayworldWB_GetSaturationThreshold(GrayworldWB b) { try { return (*b)->getSaturationThreshold(); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return 0.0; } } OpenCVResult GrayworldWB_BalanceWhite(GrayworldWB b, Mat src, Mat dst) { try { (*b)->balanceWhite(*src, *dst); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } // ----------------------- LearningBasedWB ----------------------- LearningBasedWB LearningBasedWB_Create() { try { return new cv::Ptr(cv::xphoto::createLearningBasedWB()); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } LearningBasedWB LearningBasedWB_CreateWithParams(const char* pathmodel) { try { cv::String path(pathmodel); return new cv::Ptr(cv::xphoto::createLearningBasedWB(path)); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } void LearningBasedWB_Close(LearningBasedWB b) { delete b; } OpenCVResult LearningBasedWB_ExtractSimpleFeatures(LearningBasedWB b, Mat src, Mat dst) { try { (*b)->extractSimpleFeatures(*src, *dst); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } int LearningBasedWB_GetHistBinNum(LearningBasedWB b) { try { return (*b)->getHistBinNum(); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return 0; } } int LearningBasedWB_GetRangeMaxVal(LearningBasedWB b) { try { return (*b)->getRangeMaxVal(); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return 0; } } float LearningBasedWB_GetSaturationThreshold(LearningBasedWB b) { try { return (*b)->getSaturationThreshold(); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return 0.0; } } void LearningBasedWB_SetHistBinNum(LearningBasedWB b, int val) { try { (*b)->setHistBinNum(val); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); } } void LearningBasedWB_SetRangeMaxVal(LearningBasedWB b, int val) { try { (*b)->setRangeMaxVal(val); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); } } void LearningBasedWB_SetSaturationThreshold(LearningBasedWB b, float val) { try { (*b)->setSaturationThreshold(val); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); } } OpenCVResult LearningBasedWB_BalanceWhite(LearningBasedWB b, Mat src, Mat dst) { try { (*b)->balanceWhite(*src, *dst); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } // ----------------------- SimpleWB ----------------------- SimpleWB SimpleWB_Create() { try { return new cv::Ptr(cv::xphoto::createSimpleWB()); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } void SimpleWB_Close(SimpleWB b) { delete b; } // Input image range maximum value. float SimpleWB_GetInputMax(SimpleWB b) { try { return (*b)->getInputMax(); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return 0.0; } } // Input image range minimum value. float SimpleWB_GetInputMin(SimpleWB b) { try { return (*b)->getInputMin(); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return 0.0; } } // Output image range maximum value. float SimpleWB_GetOutputMax(SimpleWB b) { try { return (*b)->getOutputMax(); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return 0.0; } } // Output image range minimum value. float SimpleWB_GetOutputMin(SimpleWB b) { try { return (*b)->getOutputMin(); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return 0.0; } } // Percent of top/bottom values to ignore. float SimpleWB_GetP(SimpleWB b) { try { return (*b)->getP(); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return 0.0; } } // Input image range maximum value. void SimpleWB_SetInputMax(SimpleWB b, float val) { try { (*b)->setInputMax(val); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); } } // Input image range minimum value. void SimpleWB_SetInputMin(SimpleWB b, float val) { try { (*b)->setInputMin(val); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); } } // Output image range maximum value. void SimpleWB_SetOutputMax(SimpleWB b, float val) { try { (*b)->setOutputMax(val); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); } } // Output image range minimum value. void SimpleWB_SetOutputMin(SimpleWB b, float val) { try { (*b)->setOutputMin(val); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); } } // Percent of top/bottom values to ignore. void SimpleWB_SetP(SimpleWB b, float val) { try { (*b)->setP(val); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); } } OpenCVResult SimpleWB_BalanceWhite(SimpleWB b, Mat src, Mat dst) { try { (*b)->balanceWhite(*src, *dst); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } // -------------------- TonemapDurand -------------------- // Creates TonemapDurand object. More... TonemapDurand TonemapDurand_Create() { try { return new cv::Ptr(cv::xphoto::createTonemapDurand(1.0f, 4.0f, 1.0f, 2.0f, 2.0f)); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } TonemapDurand TonemapDurand_CreateWithParams(float gamma, float contrast, float saturation, float sigma_color, float sigma_space) { try { return new cv::Ptr(cv::xphoto::createTonemapDurand(gamma, contrast, saturation, sigma_color, sigma_space)); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } void TonemapDurand_Close(TonemapDurand b) { delete b; } float TonemapDurand_GetContrast(TonemapDurand b) { try { return (*b)->getContrast(); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return 0.0; } } float TonemapDurand_GetSaturation(TonemapDurand b) { try { return (*b)->getSaturation(); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return 0.0; } } float TonemapDurand_GetSigmaColor(TonemapDurand b) { try { return (*b)->getSigmaColor(); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return 0.0; } } float TonemapDurand_GetSigmaSpace(TonemapDurand b) { try { return (*b)->getSigmaSpace(); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return 0.0; } } void TonemapDurand_SetContrast(TonemapDurand b, float contrast) { try { (*b)->setContrast(contrast); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); } } void TonemapDurand_SetSaturation(TonemapDurand b, float saturation) { try { (*b)->setSaturation(saturation); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); } } void TonemapDurand_SetSigmaColor(TonemapDurand b, float sigma_color) { try { (*b)->setSigmaColor(sigma_color); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); } } void TonemapDurand_SetSigmaSpace(TonemapDurand b, float sigma_space) { try { (*b)->setSigmaSpace(sigma_space); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); } } float TonemapDurand_GetGamma(TonemapDurand b) { try { return (*b)->getGamma(); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return 0.0; } } void TonemapDurand_SetGamma(TonemapDurand b, float gamma) { try { (*b)->setGamma(gamma); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); } } OpenCVResult TonemapDurand_Process(TonemapDurand b, Mat src, Mat dst) { try { (*b)->process(*src, *dst); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } // -------------------- cv::xphoto::Inpaint -------------------- OpenCVResult Inpaint(Mat src, Mat mask, Mat dst, int algorithmType) { try { cv::xphoto::inpaint(*src, *mask, *dst, algorithmType); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult OilPaintingWithParams(Mat src, Mat dst, int size, int dynRatio, int code) { try { cv::xphoto::oilPainting(*src, *dst, size, dynRatio, code); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult OilPainting(Mat src, Mat dst, int size, int dynRatio) { try { cv::xphoto::oilPainting(*src, *dst, size, dynRatio); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } ================================================ FILE: contrib/xphoto.go ================================================ //go:build !gocv_specific_modules || (gocv_specific_modules && gocv_contrib_xphoto) package contrib /* #include #include "xphoto.h" */ import "C" import ( "unsafe" "gocv.io/x/gocv" ) // GrayworldWB is a wrapper around the cv::xphoto::GrayworldWB. type GrayworldWB struct { // C.GrayworldWB p unsafe.Pointer } // LearningBasedWB is a wrapper around the cv::xphoto::LearningBasedWB. type LearningBasedWB struct { // C.GrayworldWB p unsafe.Pointer } // SimpleWB is a wrapper around the cv::xphoto::SimpleWB. type SimpleWB struct { // C.GrayworldWB p unsafe.Pointer } // TonemapDurand is a wrapper around the cv::xphoto::TonemapDurand. type TonemapDurand struct { // C.GrayworldWB p unsafe.Pointer } // Bm3dSteps is the type for the various BM3D algorithm steps type Bm3dSteps int const ( Bm3dAlgoStepAll Bm3dSteps = 0 Bm3dAlgoSte1 Bm3dSteps = 1 Bm3dAlgoSte2 Bm3dSteps = 2 ) type TransformTypes int const ( Bm3dTypeHaar TransformTypes = 0 ) type InpaintTypes int const ( ShitMap InpaintTypes = 0 FsrBest InpaintTypes = 1 FsrFast InpaintTypes = 2 ) // ----------------------- --------------------------------------- // ----------------------- Bm3dDenoising ------------------------- // ----------------------- --------------------------------------- func ApplyChannelGains(src gocv.Mat, dst *gocv.Mat, gainB float32, gainG float32, gainR float32) error { return OpenCVResult(C.Xphoto_ApplyChannelGains(C.Mat(src.Ptr()), C.Mat(dst.Ptr()), C.float(gainB), C.float(gainG), C.float(gainR))) } // src = Input 8-bit or 16-bit 1-channel image. func Bm3dDenoisingStep(src gocv.Mat, dststep1 *gocv.Mat, dststep2 *gocv.Mat) error { return OpenCVResult(C.Xphoto_Bm3dDenoising_Step(C.Mat(src.Ptr()), C.Mat(dststep1.Ptr()), C.Mat(dststep2.Ptr()))) } // src = Input 8-bit or 16-bit 1-channel image. func Bm3dDenoisingStepWithParams(src gocv.Mat, dststep1 *gocv.Mat, dststep2 *gocv.Mat, h float32, templateWindowSize int, searchWindowSize int, blockMatchingStep1 int, blockMatchingStep2 int, groupSize int, slidingStep int, beta float32, normType gocv.NormType, step Bm3dSteps, transformType TransformTypes) error { return OpenCVResult(C.Xphoto_Bm3dDenoising_Step_WithParams(C.Mat(src.Ptr()), C.Mat(dststep1.Ptr()), C.Mat(dststep2.Ptr()), C.float(h), C.int(templateWindowSize), C.int(searchWindowSize), C.int(blockMatchingStep1), C.int(blockMatchingStep2), C.int(groupSize), C.int(slidingStep), C.float(beta), C.int(normType), C.int(step), C.int(transformType))) } // src = Input 8-bit or 16-bit 1-channel image. func Bm3dDenoising(src gocv.Mat, dst *gocv.Mat) error { return OpenCVResult(C.Xphoto_Bm3dDenoising(C.Mat(src.Ptr()), C.Mat(dst.Ptr()))) } // src = Input 8-bit or 16-bit 1-channel image. func Bm3dDenoisingWithParams(src gocv.Mat, dst *gocv.Mat, h float32, templateWindowSize int, searchWindowSize int, blockMatchingStep1 int, blockMatchingStep2 int, groupSize int, slidingStep int, beta float32, normType gocv.NormType, step Bm3dSteps, transformType TransformTypes) error { return OpenCVResult(C.Xphoto_Bm3dDenoising_WithParams(C.Mat(src.Ptr()), C.Mat(dst.Ptr()), C.float(h), C.int(templateWindowSize), C.int(searchWindowSize), C.int(blockMatchingStep1), C.int(blockMatchingStep2), C.int(groupSize), C.int(slidingStep), C.float(beta), C.int(normType), C.int(step), C.int(transformType))) } // ----------------------- --------------------------------------- // ----------------------- GrayworldWB --------------------------- // ----------------------- --------------------------------------- // NewGrayworldWBWithParams returns a new Gray-world white balance algorithm. // of type GrayworldWB with customized parameters. GrayworldWB algorithm scales the values // of pixels based on a gray-world assumption which states that the average of all // channels should result in a gray image. // // For further details, please see: // https://docs.opencv.org/master/de/daa/group__xphoto.html // https://docs.opencv.org/master/d7/d71/classcv_1_1xphoto_1_1GrayworldWB.html func NewGrayworldWB() GrayworldWB { return GrayworldWB{p: unsafe.Pointer(C.GrayworldWB_Create())} } // SetSaturationThreshold set a Maximum saturation for a pixel to be included in the gray-world assumption. // // For further details, please see: // https://docs.opencv.org/master/de/daa/group__xphoto.html // https://docs.opencv.org/master/d7/d71/classcv_1_1xphoto_1_1GrayworldWB.html // https://docs.opencv.org/master/d7/d71/classcv_1_1xphoto_1_1GrayworldWB.html#ac6e17766e394adc15588b8522202cc71 func (b *GrayworldWB) SetSaturationThreshold(saturationThreshold float32) { C.GrayworldWB_SetSaturationThreshold((C.GrayworldWB)(b.p), C.float(saturationThreshold)) return } // GetSaturationThreshold return the Maximum saturation for a pixel to be included in the gray-world assumption. // // For further details, please see: // https://docs.opencv.org/master/de/daa/group__xphoto.html // https://docs.opencv.org/master/d7/d71/classcv_1_1xphoto_1_1GrayworldWB.html // https://docs.opencv.org/master/d7/d71/classcv_1_1xphoto_1_1GrayworldWB.html#ac6e17766e394adc15588b8522202cc71 func (b *GrayworldWB) GetSaturationThreshold() float32 { return float32(C.GrayworldWB_GetSaturationThreshold((C.GrayworldWB)(b.p))) } // Close GrayworldWB. func (b *GrayworldWB) Close() error { C.GrayworldWB_Close((C.GrayworldWB)(b.p)) b.p = nil return nil } // BalanceWhite computes a Gray-world white balance using the current GrayworldWB. // // For further details, please see: // https://docs.opencv.org/master/d7/d71/classcv_1_1xphoto_1_1GrayworldWB.html#details func (b *GrayworldWB) BalanceWhite(src gocv.Mat, dst *gocv.Mat) error { return OpenCVResult(C.GrayworldWB_BalanceWhite((C.GrayworldWB)(b.p), C.Mat(src.Ptr()), C.Mat(dst.Ptr()))) } // ----------------------- --------------------------------------- // ----------------------- LearningBasedWB ----------------------- // ----------------------- --------------------------------------- // NewLearningBasedWB returns more sophisticated learning-based // automatic white balance algorithm. // // For further details, please see: // https://docs.opencv.org/master/de/daa/group__xphoto.html // https://docs.opencv.org/master/d4/d3b/classcv_1_1xphoto_1_1LearningBasedWB.html // https://docs.opencv.org/master/de/daa/group__xphoto.html#gac8fb5636b27eac575f4a4c9c54dd1c7c func NewLearningBasedWB() LearningBasedWB { return LearningBasedWB{p: unsafe.Pointer(C.LearningBasedWB_Create())} } // NewLearningBasedWBWithParams returns more sophisticated learning-based // automatic white balance algorithm. // A type LearningBasedWB algorithm with path model parameters. // // For further details, please see: // https://docs.opencv.org/master/de/daa/group__xphoto.html // https://docs.opencv.org/master/d4/d3b/classcv_1_1xphoto_1_1LearningBasedWB.html // https://docs.opencv.org/master/de/daa/group__xphoto.html#gac8fb5636b27eac575f4a4c9c54dd1c7c func NewLearningBasedWBWithParams(pathmodel string) LearningBasedWB { cpath := C.CString(pathmodel) defer C.free(unsafe.Pointer(cpath)) return LearningBasedWB{p: unsafe.Pointer(C.LearningBasedWB_CreateWithParams(cpath))} } // Close LearningBasedWB. func (b *LearningBasedWB) Close() error { C.LearningBasedWB_Close((C.LearningBasedWB)(b.p)) b.p = nil return nil } // ExtractSimpleFeatures // Implements the feature extraction part of the algorithm. // // For further details, please see: // https://docs.opencv.org/master/d4/d3b/classcv_1_1xphoto_1_1LearningBasedWB.html#aeeaca052262a01d0feed6312ccb9a76e func (b *LearningBasedWB) ExtractSimpleFeatures(src gocv.Mat, dst *gocv.Mat) error { return OpenCVResult(C.LearningBasedWB_ExtractSimpleFeatures((C.LearningBasedWB)(b.p), C.Mat(src.Ptr()), C.Mat(dst.Ptr()))) } // GetHistBinNum // Defines the size of one dimension of a three-dimensional RGB histogram that is used internally by the algorithm. // // For further details, please see: // https://docs.opencv.org/master/d4/d3b/classcv_1_1xphoto_1_1LearningBasedWB.html#abfe7d3983f8245a7eba0a7f9de40e3e1 func (b *LearningBasedWB) GetHistBinNum() int { return int(C.LearningBasedWB_GetHistBinNum((C.LearningBasedWB)(b.p))) } // GetRangeMaxVal // Maximum possible value of the input image (e.g. 255 for 8 bit images, 4095 for 12 bit images) // // For further details, please see: // https://docs.opencv.org/master/d4/d3b/classcv_1_1xphoto_1_1LearningBasedWB.html#a764b51265b5a1bd7bd11ce9d14d6f75f func (b *LearningBasedWB) GetRangeMaxVal() int { return int(C.LearningBasedWB_GetRangeMaxVal((C.LearningBasedWB)(b.p))) } // GetSaturationThreshold // Threshold that is used to determine saturated pixels // // For further details, please see: // https://docs.opencv.org/master/d4/d3b/classcv_1_1xphoto_1_1LearningBasedWB.html#ae7eb310249709c2aef41d6399ebd7660 func (b *LearningBasedWB) GetSaturationThreshold() float32 { return float32(C.LearningBasedWB_GetSaturationThreshold((C.LearningBasedWB)(b.p))) } // SetHistBinNum // Defines the size of one dimension of a three-dimensional RGB histogram that is used internally by the algorithm. // // For further details, please see: // https://docs.opencv.org/master/d4/d3b/classcv_1_1xphoto_1_1LearningBasedWB.html#a3381bd425bc4201133c9669071908e7f func (b *LearningBasedWB) SetHistBinNum(val int) { C.LearningBasedWB_SetHistBinNum((C.LearningBasedWB)(b.p), C.int(val)) return } // SetRangeMaxVal // Maximum possible value of the input image (e.g. 255 for 8 bit images, 4095 for 12 bit images) // // For further details, please see: // https://docs.opencv.org/master/d4/d3b/classcv_1_1xphoto_1_1LearningBasedWB.html#a3d9395274be8053b2f09e46d11a24a65 func (b *LearningBasedWB) SetRangeMaxVal(val int) { C.LearningBasedWB_SetRangeMaxVal((C.LearningBasedWB)(b.p), C.int(val)) return } // SetSaturationThreshold // Threshold that is used to determine saturated pixels // // For further details, please see: // https://docs.opencv.org/master/d4/d3b/classcv_1_1xphoto_1_1LearningBasedWB.html#a9bff5a507d4dffc58e16d85b1d07f35f func (b *LearningBasedWB) SetSaturationThreshold(val float32) { C.LearningBasedWB_SetSaturationThreshold((C.LearningBasedWB)(b.p), C.float(val)) return } // BalanceWhite computes a learning-based white balance using the current LearningBasedWB. // // For further details, please see: // https://docs.opencv.org/master/d9/d7a/classcv_1_1xphoto_1_1WhiteBalancer.html#ae23838a1a54f101b255bca1a97418aa3 func (b *LearningBasedWB) BalanceWhite(src gocv.Mat, dst *gocv.Mat) error { return OpenCVResult(C.LearningBasedWB_BalanceWhite((C.LearningBasedWB)(b.p), C.Mat(src.Ptr()), C.Mat(dst.Ptr()))) } // ----------------------- --------------------------------------- // ----------------------- SimpleWB ------------------------------ // ----------------------- --------------------------------------- // NewSimpleWBWithParams returns more sophisticated learning-based // automatic white balance algorithm. // A type SimpleWB algorithm with path model parameters. // // For further details, please see: // https://docs.opencv.org/master/de/daa/group__xphoto.html // https://docs.opencv.org/master/d1/d8b/classcv_1_1xphoto_1_1SimpleWB.html // https://docs.opencv.org/master/de/daa/group__xphoto.html#ga2b48b3b384b5c5ee1b15a2a01c26d5f1 func NewSimpleWB() SimpleWB { return SimpleWB{p: unsafe.Pointer(C.SimpleWB_Create())} } // Close SimpleWB. func (b *SimpleWB) Close() error { C.SimpleWB_Close((C.SimpleWB)(b.p)) b.p = nil return nil } // GetInputMax // Input image range maximum value. // // For further details, please see: // https://docs.opencv.org/master/d1/d8b/classcv_1_1xphoto_1_1SimpleWB.html#a45fef780842168cba868212c71ad8318 func (b *SimpleWB) GetInputMax() float32 { return float32(C.SimpleWB_GetInputMax((C.SimpleWB)(b.p))) } // GetInputMin // Input image range minimum value. // // For further details, please see: // https://docs.opencv.org/master/d1/d8b/classcv_1_1xphoto_1_1SimpleWB.html#a69ee7c05e5ca45cac60040371a4a648c func (b *SimpleWB) GetInputMin() float32 { return float32(C.SimpleWB_GetInputMin((C.SimpleWB)(b.p))) } // GetOutputMax // Output image range maximum value. // // For further details, please see: // https://docs.opencv.org/master/d1/d8b/classcv_1_1xphoto_1_1SimpleWB.html#af8b051a0b2d3e8ad0aa323c195d966c1 func (b *SimpleWB) GetOutputMax() float32 { return float32(C.SimpleWB_GetOutputMax((C.SimpleWB)(b.p))) } // GetOutputMin // Output image range minimum value. // // For further details, please see: // https://docs.opencv.org/master/d1/d8b/classcv_1_1xphoto_1_1SimpleWB.html#ada11ef4159bd6354a98d371f5be68b44 func (b *SimpleWB) GetOutputMin() float32 { return float32(C.SimpleWB_GetOutputMin((C.SimpleWB)(b.p))) } // GetP // Percent of top/bottom values to ignore. // // For further details, please see: // https://docs.opencv.org/master/d1/d8b/classcv_1_1xphoto_1_1SimpleWB.html#a49d63fd73572fc88c944f5ffbcb085a3 func (b *SimpleWB) GetP() float32 { return float32(C.SimpleWB_GetP((C.SimpleWB)(b.p))) } // SetInputMax // Input image range maximum value. // // For further details, please see: // https://docs.opencv.org/master/d1/d8b/classcv_1_1xphoto_1_1SimpleWB.html#a6b2523a8740b353ef50e136d0399bf3a func (b *SimpleWB) SetInputMax(val float32) { C.SimpleWB_SetInputMax((C.SimpleWB)(b.p), C.float(val)) return } // SetInputMin // Input image range minimum value. // // For further details, please see: // https://docs.opencv.org/master/d1/d8b/classcv_1_1xphoto_1_1SimpleWB.html#a1b08a24a8589aae886fbf96ba27691a0 func (b *SimpleWB) SetInputMin(val float32) { C.SimpleWB_SetInputMin((C.SimpleWB)(b.p), C.float(val)) return } // SetOutputMax // Output image range maximum value. // // For further details, please see: // https://docs.opencv.org/master/d1/d8b/classcv_1_1xphoto_1_1SimpleWB.html#a06962b042d9089366bc6347e608481b6 func (b *SimpleWB) SetOutputMax(val float32) { C.SimpleWB_SetOutputMax((C.SimpleWB)(b.p), C.float(val)) return } // SetOutputMin // Output image range minimum value. // // For further details, please see: // https://docs.opencv.org/master/d1/d8b/classcv_1_1xphoto_1_1SimpleWB.html#a60d1e06b122747d416c4f1563167c740 func (b *SimpleWB) SetOutputMin(val float32) { C.SimpleWB_SetOutputMin((C.SimpleWB)(b.p), C.float(val)) return } // SetP // Percent of top/bottom values to ignore. // // For further details, please see: // https://docs.opencv.org/master/d1/d8b/classcv_1_1xphoto_1_1SimpleWB.html#a31b6bb5452afdb5a444920013417f018 func (b *SimpleWB) SetP(val float32) { C.SimpleWB_SetP((C.SimpleWB)(b.p), C.float(val)) return } // BalanceWhite computes a learning-based white balance using the current LearningBasedWB. // // For further details, please see: // https://docs.opencv.org/master/d9/d7a/classcv_1_1xphoto_1_1WhiteBalancer.html#ae23838a1a54f101b255bca1a97418aa3 func (b *SimpleWB) BalanceWhite(src gocv.Mat, dst *gocv.Mat) error { return OpenCVResult(C.SimpleWB_BalanceWhite((C.SimpleWB)(b.p), C.Mat(src.Ptr()), C.Mat(dst.Ptr()))) } // ----------------------- --------------------------------------- // ----------------------- TonemapDurand ------------------------- // ----------------------- --------------------------------------- // NewTonemapDurand returns more sophisticated learning-based // automatic white balance algorithm. // A type TonemapDurand algorithm with path model parameters. // // For further details, please see: // https://docs.opencv.org/master/de/daa/group__xphoto.html // https://docs.opencv.org/master/d1/db3/classcv_1_1xphoto_1_1TonemapDurand.html // https://docs.opencv.org/master/de/daa/group__xphoto.html#ga51a091aa54e26b3546316ce2c1df190b func NewTonemapDurand() TonemapDurand { return TonemapDurand{p: unsafe.Pointer(C.TonemapDurand_Create())} } // NewTonemapDurandWithParams returns more sophisticated learning-based // automatic white balance algorithm. // A type TonemapDurand algorithm with path model parameters. // // For further details, please see: // https://docs.opencv.org/master/de/daa/group__xphoto.html // https://docs.opencv.org/master/d1/db3/classcv_1_1xphoto_1_1TonemapDurand.html // https://docs.opencv.org/master/de/daa/group__xphoto.html#ga51a091aa54e26b3546316ce2c1df190b func NewTonemapDurandWithParams(gamma float32, contrast float32, saturation float32, sigma_color float32, sigma_space float32) TonemapDurand { return TonemapDurand{p: unsafe.Pointer(C.TonemapDurand_CreateWithParams(C.float(gamma), C.float(contrast), C.float(saturation), C.float(sigma_color), C.float(sigma_space)))} } // Close TonemapDurand. func (b *TonemapDurand) Close() error { C.TonemapDurand_Close((C.TonemapDurand)(b.p)) b.p = nil return nil } // GetContrast // // For further details, please see: // https://docs.opencv.org/master/de/daa/group__xphoto.html#ga2df693dd285a7e7fd3b4fc8a8a750cce func (b *TonemapDurand) GetContrast() float32 { return float32(C.TonemapDurand_GetContrast((C.TonemapDurand)(b.p))) } // GetSaturation // // For further details, please see: // https://docs.opencv.org/master/de/daa/group__xphoto.html#gad8ab5850af6fdb3f6bc51d5c9371bbfe func (b *TonemapDurand) GetSaturation() float32 { return float32(C.TonemapDurand_GetSaturation((C.TonemapDurand)(b.p))) } // GetSigmaColor // // For further details, please see: // https://docs.opencv.org/master/de/daa/group__xphoto.html#ga31d7588db7e47fb81890cba7ff014edb func (b *TonemapDurand) GetSigmaColor() float32 { return float32(C.TonemapDurand_GetSigmaColor((C.TonemapDurand)(b.p))) } // GetSigmaSpace // // For further details, please see: // https://docs.opencv.org/master/de/daa/group__xphoto.html#ga078b11014d8a41920f50cab57fce9515 func (b *TonemapDurand) GetSigmaSpace() float32 { return float32(C.TonemapDurand_GetSigmaSpace((C.TonemapDurand)(b.p))) } // SetContrast // // For further details, please see: // https://docs.opencv.org/master/de/daa/group__xphoto.html#ga99eaaa24dc25ba387093e957bfca1cad func (b *TonemapDurand) SetContrast(val float32) { C.TonemapDurand_SetContrast((C.TonemapDurand)(b.p), C.float(val)) return } // SetSaturation // // For further details, please see: // https://docs.opencv.org/master/de/daa/group__xphoto.html#ga9c7de9517f95fd046910fc818e256d55 func (b *TonemapDurand) SetSaturation(val float32) { C.TonemapDurand_SetSaturation((C.TonemapDurand)(b.p), C.float(val)) return } // SetSigmaColor // // For further details, please see: // https://docs.opencv.org/master/de/daa/group__xphoto.html#ga7dec866735ecbae9e05224958d4585fd func (b *TonemapDurand) SetSigmaColor(val float32) { C.TonemapDurand_SetSigmaColor((C.TonemapDurand)(b.p), C.float(val)) return } // SetSigmaSpace // // For further details, please see: // https://docs.opencv.org/master/de/daa/group__xphoto.html#ga8869068912fae078699ce931bdc17fc4 func (b *TonemapDurand) SetSigmaSpace(val float32) { C.TonemapDurand_SetSigmaSpace((C.TonemapDurand)(b.p), C.float(val)) return } // GetGamma // // For further details, please see: // https://docs.opencv.org/master/d8/d5e/classcv_1_1Tonemap.html#a147c2b57ed5a5a0566001f4db2ddc0dd func (b *TonemapDurand) GetGamma() float32 { return float32(C.TonemapDurand_GetGamma((C.TonemapDurand)(b.p))) } // SetGamma // // For further details, please see: // https://docs.opencv.org/master/d8/d5e/classcv_1_1Tonemap.html#ac809d2967f942b038b4bf21c97f8b1b7 func (b *TonemapDurand) SetGamma(val float32) { C.TonemapDurand_SetGamma((C.TonemapDurand)(b.p), C.float(val)) return } // Process // Tonemaps image with gocv.MatTypeCV32FC3 type image // For further details, please see: // https://docs.opencv.org/master/d8/d5e/classcv_1_1Tonemap.html#aa705c3b7226f7028a5c117dffab60fe4 func (b *TonemapDurand) Process(src gocv.Mat, dst *gocv.Mat) error { return OpenCVResult(C.TonemapDurand_Process((C.TonemapDurand)(b.p), C.Mat(src.Ptr()), C.Mat(dst.Ptr()))) } // ----------------------- --------------------------------------- // -------------------------- Inpaint ---------------------------- // ----------------------- --------------------------------------- // The function implements different single-image inpainting algorithms. // // For further details, please see: // https://docs.opencv.org/master/de/daa/group__xphoto.html#gab4febba6be53e5fddc480b8cedf51eee func Inpaint(src *gocv.Mat, mask *gocv.Mat, dst *gocv.Mat, algorithmType InpaintTypes) error { return OpenCVResult(C.Inpaint(C.Mat(src.Ptr()), C.Mat(mask.Ptr()), C.Mat(dst.Ptr()), C.int(algorithmType))) } // oilPainting, See the book for details : // GerPublished by ard J. Holzmann. Beyond Photography: The Digital Darkroom. Prentice Hall in 1988. // // For further details, please see: // https://docs.opencv.org/master/de/daa/group__xphoto.html#gac050a6e876298cb9713cd2c09db9a027 func OilPaintingWithParams(src gocv.Mat, dst gocv.Mat, size int, dynRatio int, code gocv.ColorConversionCode) error { return OpenCVResult(C.OilPaintingWithParams(C.Mat(src.Ptr()), C.Mat(dst.Ptr()), C.int(size), C.int(dynRatio), C.int(code))) } // oilPainting, See the book for details : // GerPublished by ard J. Holzmann. Beyond Photography: The Digital Darkroom. Prentice Hall in 1988. // // For further details, please see: // https://docs.opencv.org/master/de/daa/group__xphoto.html#gac18ef93a7b1e65f703f7dc3b1e8e5235 func OilPainting(src gocv.Mat, dst *gocv.Mat, size int, dynRatio int) error { return OpenCVResult(C.OilPainting(C.Mat(src.Ptr()), C.Mat(dst.Ptr()), C.int(size), C.int(dynRatio))) } ================================================ FILE: contrib/xphoto.h ================================================ #ifndef _OPENCV3_XPHOTO_H_ #define _OPENCV3_XPHOTO_H_ #ifdef __cplusplus #include #include #include #include #include #include extern "C" { #endif #include "../core.h" #ifdef __cplusplus typedef cv::Ptr* GrayworldWB; typedef cv::Ptr* LearningBasedWB; typedef cv::Ptr* SimpleWB; typedef cv::Ptr* TonemapDurand; #else typedef void* GrayworldWB; typedef void* LearningBasedWB; typedef void* SimpleWB; typedef void* TonemapDurand; #endif // ----------------------- bm3d_image_denoising ----------------------- OpenCVResult Xphoto_ApplyChannelGains(Mat src, Mat dst, float gainB, float gainG, float gainR); OpenCVResult Xphoto_Bm3dDenoising_Step(Mat src, Mat dststep1, Mat dststep2); OpenCVResult Xphoto_Bm3dDenoising_Step_WithParams( Mat src, Mat dststep1, Mat dststep2, float h, int templateWindowSize, int searchWindowSize, int blockMatchingStep1, int blockMatchingStep2, int groupSize, int slidingStep, float beta, int normType, int step, int transformType ); OpenCVResult Xphoto_Bm3dDenoising(Mat src, Mat dst); OpenCVResult Xphoto_Bm3dDenoising_WithParams( Mat src, Mat dst, float h, int templateWindowSize, int searchWindowSize, int blockMatchingStep1, int blockMatchingStep2, int groupSize, int slidingStep, float beta, int normType, int step, int transformType ); // ----------------------- GrayworldWB ----------------------- GrayworldWB GrayworldWB_Create(); void GrayworldWB_Close(GrayworldWB b); void GrayworldWB_SetSaturationThreshold(GrayworldWB b, float saturationThreshold); float GrayworldWB_GetSaturationThreshold(GrayworldWB b); OpenCVResult GrayworldWB_BalanceWhite(GrayworldWB b, Mat src, Mat dst); // ----------------------- LearningBasedWB ----------------------- LearningBasedWB LearningBasedWB_Create(); LearningBasedWB LearningBasedWB_CreateWithParams(const char* pathmodel); void LearningBasedWB_Close(LearningBasedWB b); OpenCVResult LearningBasedWB_ExtractSimpleFeatures(LearningBasedWB b, Mat src, Mat dst); int LearningBasedWB_GetHistBinNum(LearningBasedWB b) ; int LearningBasedWB_GetRangeMaxVal(LearningBasedWB b) ; float LearningBasedWB_GetSaturationThreshold(LearningBasedWB b) ; void LearningBasedWB_SetHistBinNum(LearningBasedWB b, int val); void LearningBasedWB_SetRangeMaxVal(LearningBasedWB b, int val); void LearningBasedWB_SetSaturationThreshold(LearningBasedWB b, float val); OpenCVResult LearningBasedWB_BalanceWhite(LearningBasedWB b, Mat src, Mat dst); // ----------------------- SimpleWB ----------------------- SimpleWB SimpleWB_Create(); void SimpleWB_Close(SimpleWB b); float SimpleWB_GetInputMax(SimpleWB b); float SimpleWB_GetInputMin(SimpleWB b); float SimpleWB_GetOutputMax(SimpleWB b); float SimpleWB_GetOutputMin(SimpleWB b); float SimpleWB_GetP(SimpleWB b); void SimpleWB_SetInputMax(SimpleWB b, float val); void SimpleWB_SetInputMin(SimpleWB b, float val); void SimpleWB_SetOutputMax(SimpleWB b, float val); void SimpleWB_SetOutputMin(SimpleWB b, float val); void SimpleWB_SetP(SimpleWB b, float val); OpenCVResult SimpleWB_BalanceWhite(SimpleWB b, Mat src, Mat dst); // -------------------- TonemapDurand -------------------- TonemapDurand TonemapDurand_Create(); TonemapDurand TonemapDurand_CreateWithParams(float gamma, float contrast, float saturation, float sigma_color, float sigma_space) ; void TonemapDurand_Close(TonemapDurand b); float TonemapDurand_GetContrast(TonemapDurand b); float TonemapDurand_GetSaturation(TonemapDurand b); float TonemapDurand_GetSigmaColor(TonemapDurand b); float TonemapDurand_GetSigmaSpace(TonemapDurand b); void TonemapDurand_SetContrast(TonemapDurand b, float contrast); void TonemapDurand_SetSaturation(TonemapDurand b, float saturation); void TonemapDurand_SetSigmaColor(TonemapDurand b, float sigma_color); void TonemapDurand_SetSigmaSpace(TonemapDurand b, float sigma_space); float TonemapDurand_GetGamma(TonemapDurand b); OpenCVResult TonemapDurand_Process(TonemapDurand b, Mat src, Mat dst); void TonemapDurand_SetGamma(TonemapDurand b, float gamma); // ------------------------ Inpaint ----------------------- OpenCVResult Inpaint(Mat src, Mat mask, Mat dst, int algorithmType); OpenCVResult OilPaintingWithParams(Mat src, Mat dst, int size, int dynRatio, int code); OpenCVResult OilPainting(Mat src, Mat dst, int size, int dynRatio); #ifdef __cplusplus } #endif #endif //_OPENCV3_XPHOTO_H ================================================ FILE: contrib/xphoto_test.go ================================================ //go:build !gocv_specific_modules || (gocv_specific_modules && gocv_contrib_xphoto) package contrib //:testing import ( "gocv.io/x/gocv" "testing" ) func TestBm3dDenoisingStepWithParams(t *testing.T) { // src = Input 8-bit or 16-bit 1-channel image. src := gocv.NewMatWithSize(200, 200, gocv.MatTypeCV8UC1) defer src.Close() dst1 := gocv.NewMat() defer dst1.Close() dst2 := gocv.NewMat() defer dst2.Close() Bm3dDenoisingStepWithParams(src, &dst1, &dst2, float32(1.0), int(4), int(16), int(2500), int(400), int(8), int(1), float32(2.0), gocv.NormL2, Bm3dAlgoStepAll, Bm3dTypeHaar) if src.Empty() || dst1.Rows() != src.Rows() || dst1.Cols() != src.Cols() { t.Error("Invlalid TestBm3dDenoisingStepWithParams test") } } func TestBm3dDenoisingWithParams(t *testing.T) { src := gocv.NewMatWithSize(200, 200, gocv.MatTypeCV8UC1) defer src.Close() dst := gocv.NewMat() defer dst.Close() Bm3dDenoisingWithParams(src, &dst, float32(1.0), int(4), int(16), int(2500), int(400), int(8), int(1), float32(2.0), gocv.NormL2, Bm3dAlgoStepAll, Bm3dTypeHaar) if src.Empty() || dst.Rows() != src.Rows() || dst.Cols() != src.Cols() || dst.Type() != src.Type() { t.Error("Invlalid BalanceWhite test") } } func TestSetSaturationThreshold(t *testing.T) { grayworldwb := NewGrayworldWB() var saturation float32 = 0.7 grayworldwb.SetSaturationThreshold(saturation) if grayworldwb.GetSaturationThreshold() < 0 { t.Error(" Invlalid SetSaturationThreshold test") } } func TestBalanceWhite(t *testing.T) { grayworldwb := NewGrayworldWB() defer grayworldwb.Close() src := gocv.NewMatWithSize(200, 200, gocv.MatTypeCV8UC3) defer src.Close() dst := gocv.NewMat() defer dst.Close() grayworldwb.BalanceWhite(src, &dst) if src.Empty() || dst.Rows() != src.Rows() || dst.Cols() != src.Cols() { t.Error("Invlalid BalanceWhite test") } } func TestNewLearningBasedWB(t *testing.T) { learningbasedwb := NewLearningBasedWB() defer learningbasedwb.Close() valueset := 2 learningbasedwb.SetHistBinNum(valueset) learningbasedwb.SetRangeMaxVal(valueset) learningbasedwb.SetSaturationThreshold(float32(valueset)) valuehistbinNum := learningbasedwb.GetHistBinNum() valuerangemaxval := learningbasedwb.GetRangeMaxVal() valuesaturation := learningbasedwb.GetSaturationThreshold() if valueset != valuehistbinNum { t.Error("Invalid TestNewLearningBasedWB : Set/Get HistBinNum test") } if valueset != valuerangemaxval { t.Error("Invalid TestNewLearningBasedWB : Set/Get RangeMaxVal test") } if valuesaturation < 0 { t.Error("Invalid TestNewLearningBasedWB : Set/Get SaturationThreshold test") } } func TestNewSimpleWB(t *testing.T) { simplewb := NewSimpleWB() defer simplewb.Close() } func TestNewTonemapDurand(t *testing.T) { tonemapdurand := NewTonemapDurand() defer tonemapdurand.Close() var valueset float32 = 2.05 tonemapdurand.SetContrast(valueset) tonemapdurand.SetSaturation(valueset) tonemapdurand.SetSigmaColor(valueset) tonemapdurand.SetSigmaSpace(valueset) valuecontrast := tonemapdurand.GetContrast() valuestaturation := tonemapdurand.GetSaturation() valuesigmacolor := tonemapdurand.GetSigmaColor() valuesigmaspace := tonemapdurand.GetSigmaSpace() if valueset != valuecontrast { t.Error("Invalid result TestNewTonemapDurand : Set/Get Contrast test") } if valueset != valuestaturation { t.Error("Invalid result TestNewTonemapDurand : Set/Get Saturation test") } if valueset != valuesigmacolor { t.Error("Invalid result TestNewTonemapDurand : Set/Get SigmaColor test") } if valueset != valuesigmaspace { t.Error("Invalid result TestNewTonemapDurand : Set/Get SigmaSpace test") } tonemapdurand.SetGamma(valueset) valuegamma := tonemapdurand.GetGamma() if valueset != valuegamma { t.Error("Invalid result TestNewTonemapDurand : Set/Get Gamma test") } } func TestTonemapDurandProcess(t *testing.T) { tonemapdurand := NewTonemapDurand() defer tonemapdurand.Close() src := gocv.NewMatWithSize(200, 200, gocv.MatTypeCV32FC3) defer src.Close() dst := gocv.NewMat() defer dst.Close() tonemapdurand.Process(src, &dst) if src.Empty() || dst.Rows() != src.Rows() || dst.Cols() != src.Cols() || dst.Type() != gocv.MatTypeCV32FC3 { t.Error("Invlalid TestTonemapDurandProcess test") } } func TestOilPainting(t *testing.T) { jpgImageOilPainting := gocv.IMRead("../images/space_shuttle.jpg", gocv.IMReadColor) if jpgImageOilPainting.Empty() { t.Error("Invalid read of Source Mat in TestInpaint test") } defer jpgImageOilPainting.Close() t.Logf("Read of Source Mat in TestOilPainting test : %d x %d", jpgImageOilPainting.Cols(), jpgImageOilPainting.Rows()) srcOilPainting := gocv.NewMat() defer srcOilPainting.Close() jpgImageOilPainting.ConvertTo(&srcOilPainting, gocv.MatTypeCV8UC3) dstOilPainting := gocv.NewMat() defer dstOilPainting.Close() OilPainting(srcOilPainting, &dstOilPainting, 2, 2) t.Logf("OilPainting : MAT %d <> %d : %d", dstOilPainting.Rows(), srcOilPainting.Rows(), dstOilPainting.Type()) if srcOilPainting.Empty() || dstOilPainting.Rows() != srcOilPainting.Rows() || dstOilPainting.Cols() != srcOilPainting.Cols() { t.Error("Invlalid TestInpaint OilPainting test") return } gocv.IMWrite("testOilPainting.png", dstOilPainting) } ================================================ FILE: core.cpp ================================================ #include "core.h" #include int lastException = 0; char lastExceptionMessage[1024]; int GetOpenCVException() { return lastException; } const char* GetOpenCVExceptionMessage() { return lastExceptionMessage; } void ClearOpenCVException() { lastException = 0; strncpy(lastExceptionMessage, "", 1024); } void setExceptionInfo(int code, const char* message) { lastException = code; strncpy(lastExceptionMessage, message, 1024); } OpenCVResult successResult() { OpenCVResult ri = {0, "", 0}; return ri; } OpenCVResult errorResult(int code, const char* message) { OpenCVResult ri; ri.Code = code; auto res = (char*)malloc(strlen(message)+1); memset(res, 0, strlen(message)+1); memcpy(res, message, strlen(message)); ri.Message = res; ri.Length = strlen(message); return ri; } // Mat_New creates a new empty Mat Mat Mat_New() { return new cv::Mat(); } // Mat_NewWithSize creates a new Mat with a specific size dimension and number of channels. Mat Mat_NewWithSize(int rows, int cols, int type) { return new cv::Mat(rows, cols, type, 0.0); } // Mat_NewWithSizes creates a new Mat with specific dimension sizes and number of channels. Mat Mat_NewWithSizes(struct IntVector sizes, int type) { std::vector sizess; for (int i = 0; i < sizes.length; ++i) { sizess.push_back(sizes.val[i]); } return new cv::Mat(sizess, type); } // Mat_NewFromScalar creates a new Mat from a Scalar. Intended to be used // for Mat comparison operation such as InRange. Mat Mat_NewFromScalar(Scalar ar, int type) { cv::Scalar c = cv::Scalar(ar.val1, ar.val2, ar.val3, ar.val4); return new cv::Mat(1, 1, type, c); } // Mat_NewWithSizeFromScalar creates a new Mat from a Scalar with a specific size dimension and number of channels Mat Mat_NewWithSizeFromScalar(Scalar ar, int rows, int cols, int type) { cv::Scalar c = cv::Scalar(ar.val1, ar.val2, ar.val3, ar.val4); return new cv::Mat(rows, cols, type, c); } Mat Mat_NewFromBytes(int rows, int cols, int type, struct ByteArray buf) { return new cv::Mat(rows, cols, type, buf.data); } // Mat_NewWithSizesFromScalar creates multidimensional Mat from a scalar Mat Mat_NewWithSizesFromScalar(IntVector sizes, int type, Scalar ar) { std::vector _sizes; for (int i = 0, *v = sizes.val; i < sizes.length; ++v, ++i) { _sizes.push_back(*v); } cv::Scalar c = cv::Scalar(ar.val1, ar.val2, ar.val3, ar.val4); return new cv::Mat(_sizes, type, c); } // Mat_NewWithSizesFromBytes creates multidimensional Mat from a bytes Mat Mat_NewWithSizesFromBytes(IntVector sizes, int type, struct ByteArray buf) { std::vector _sizes; for (int i = 0, *v = sizes.val; i < sizes.length; ++v, ++i) { _sizes.push_back(*v); } return new cv::Mat(_sizes, type, buf.data); } Mat Mat_NewFromPoint2fVector(Point2fVector pfv, bool copy_data) { return new cv::Mat(*pfv, copy_data); } Mat Mat_NewFromPointVector(PointVector pv, bool copy_data) { return new cv::Mat(*pv, copy_data); } Mat Eye(int rows, int cols, int type) { try { cv::Mat* mat = new cv::Mat(rows, cols, type); *mat = cv::Mat::eye(rows, cols, type); return mat; } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return new cv::Mat(); } } Mat Zeros(int rows, int cols, int type) { try { cv::Mat* mat = new cv::Mat(rows, cols, type); *mat = cv::Mat::zeros(rows, cols, type); return mat; } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return new cv::Mat(); } } Mat Ones(int rows, int cols, int type) { try { cv::Mat* mat = new cv::Mat(rows, cols, type); *mat = cv::Mat::ones(rows, cols, type); return mat; } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return new cv::Mat(); } } Mat Mat_FromPtr(Mat m, int rows, int cols, int type, int prow, int pcol) { return new cv::Mat(rows, cols, type, m->ptr(prow, pcol)); } // Mat_Close deletes an existing Mat void Mat_Close(Mat m) { delete m; } // Mat_Empty tests if a Mat is empty int Mat_Empty(Mat m) { return m->empty(); } // Mat_IsContinuous tests if a Mat is continuous bool Mat_IsContinuous(Mat m) { return m->isContinuous(); } void Mat_Inv(Mat m) { m->inv(); } Mat Mat_Col(Mat m, int c) { return new cv::Mat(m->col(c)); } Mat Mat_Row(Mat m, int r) { return new cv::Mat(m->row(r)); } Mat Mat_Copy(Mat m) { return new cv::Mat(*m); } // Mat_Clone returns a clone of this Mat Mat Mat_Clone(Mat m) { return new cv::Mat(m->clone()); } // Mat_CopyTo copies this Mat to another Mat. OpenCVResult Mat_CopyTo(Mat m, Mat dst) { try { m->copyTo(*dst); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } // Mat_CopyToWithMask copies this Mat to another Mat while applying the mask OpenCVResult Mat_CopyToWithMask(Mat m, Mat dst, Mat mask) { try { m->copyTo(*dst, *mask); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Mat_ConvertTo(Mat m, Mat dst, int type) { try { m->convertTo(*dst, type); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Mat_ConvertToWithParams(Mat m, Mat dst, int type, float alpha, float beta) { try { m->convertTo(*dst, type, alpha, beta); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } // Mat_ToBytes returns the bytes representation of the underlying data. struct ByteArray Mat_ToBytes(Mat m) { return toByteArray(reinterpret_cast(m->data), m->total() * m->elemSize()); } struct ByteArray Mat_DataPtr(Mat m) { return ByteArray {reinterpret_cast(m->data), static_cast(m->total() * m->elemSize())}; } // Mat_Region returns a Mat of a region of another Mat Mat Mat_Region(Mat m, Rect r) { return new cv::Mat(*m, cv::Rect(r.x, r.y, r.width, r.height)); } Mat Mat_Reshape(Mat m, int cn, int rows) { try { return new cv::Mat(m->reshape(cn, rows)); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return new cv::Mat(); } } Mat Mat_ReshapeWithSize(Mat m, int cn, struct IntVector dims) { try { std::vector _dims; for (int i = 0, *v = dims.val; i < dims.length; ++v, ++i) { _dims.push_back(*v); } return new cv::Mat(m->reshape(cn, _dims)); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return new cv::Mat(); } } OpenCVResult Mat_PatchNaNs(Mat m) { try { cv::patchNaNs(*m); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } Mat Mat_ConvertFp16(Mat m) { try { Mat dst = new cv::Mat(); cv::convertFp16(*m, *dst); return dst; } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return new cv::Mat(); } } Mat Mat_Sqrt(Mat m) { try { Mat dst = new cv::Mat(); cv::sqrt(*m, *dst); return dst; } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return new cv::Mat(); } } // Mat_Mean calculates the mean value M of array elements, independently for each channel, and return it as Scalar vector Scalar Mat_Mean(Mat m) { cv::Scalar c = cv::mean(*m); Scalar scal = Scalar(); scal.val1 = c.val[0]; scal.val2 = c.val[1]; scal.val3 = c.val[2]; scal.val4 = c.val[3]; return scal; } // Mat_MeanWithMask calculates the mean value M of array elements, // independently for each channel, and returns it as Scalar vector // while applying the mask. Scalar Mat_MeanWithMask(Mat m, Mat mask){ cv::Scalar c = cv::mean(*m, *mask); Scalar scal = Scalar(); scal.val1 = c.val[0]; scal.val2 = c.val[1]; scal.val3 = c.val[2]; scal.val4 = c.val[3]; return scal; } OpenCVResult LUT(Mat src, Mat lut, Mat dst) { try { cv::LUT(*src, *lut, *dst); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } // Mat_Rows returns how many rows in this Mat. int Mat_Rows(Mat m) { return m->rows; } // Mat_Cols returns how many columns in this Mat. int Mat_Cols(Mat m) { return m->cols; } // Mat_Channels returns how many channels in this Mat. int Mat_Channels(Mat m) { return m->channels(); } // Mat_Type returns the type from this Mat. int Mat_Type(Mat m) { return m->type(); } // Mat_Step returns the number of bytes each matrix row occupies. int Mat_Step(Mat m) { return m->step; } int Mat_Total(Mat m) { return m->total(); } int Mat_ElemSize(Mat m){ return m->elemSize(); } void Mat_Size(Mat m, IntVector* res) { cv::MatSize ms(m->size); int* ids = new int[ms.dims()]; for (size_t i = 0; i < ms.dims(); ++i) { ids[i] = ms[i]; } res->length = ms.dims(); res->val = ids; return; } // Mat_GetUChar returns a specific row/col value from this Mat expecting // each element to contain a schar aka CV_8U. uint8_t Mat_GetUChar(Mat m, int row, int col) { return m->at(row, col); } uint8_t Mat_GetUChar3(Mat m, int x, int y, int z) { return m->at(x, y, z); } // Mat_GetSChar returns a specific row/col value from this Mat expecting // each element to contain a schar aka CV_8S. int8_t Mat_GetSChar(Mat m, int row, int col) { return m->at(row, col); } int8_t Mat_GetSChar3(Mat m, int x, int y, int z) { return m->at(x, y, z); } // Mat_GetShort returns a specific row/col value from this Mat expecting // each element to contain a short aka CV_16S. int16_t Mat_GetShort(Mat m, int row, int col) { return m->at(row, col); } int16_t Mat_GetShort3(Mat m, int x, int y, int z) { return m->at(x, y, z); } // Mat_GetInt returns a specific row/col value from this Mat expecting // each element to contain an int aka CV_32S. int32_t Mat_GetInt(Mat m, int row, int col) { return m->at(row, col); } int32_t Mat_GetInt3(Mat m, int x, int y, int z) { return m->at(x, y, z); } // Mat_GetFloat returns a specific row/col value from this Mat expecting // each element to contain a float aka CV_32F. float Mat_GetFloat(Mat m, int row, int col) { return m->at(row, col); } float Mat_GetFloat3(Mat m, int x, int y, int z) { return m->at(x, y, z); } // Mat_GetDouble returns a specific row/col value from this Mat expecting // each element to contain a double aka CV_64F. double Mat_GetDouble(Mat m, int row, int col) { return m->at(row, col); } double Mat_GetDouble3(Mat m, int x, int y, int z) { return m->at(x, y, z); } void Mat_SetTo(Mat m, Scalar value) { cv::Scalar c_value(value.val1, value.val2, value.val3, value.val4); m->setTo(c_value); } // Mat_SetUChar set a specific row/col value from this Mat expecting // each element to contain a schar aka CV_8U. void Mat_SetUChar(Mat m, int row, int col, uint8_t val) { m->at(row, col) = val; } void Mat_SetUChar3(Mat m, int x, int y, int z, uint8_t val) { m->at(x, y, z) = val; } // Mat_SetSChar set a specific row/col value from this Mat expecting // each element to contain a schar aka CV_8S. void Mat_SetSChar(Mat m, int row, int col, int8_t val) { m->at(row, col) = val; } void Mat_SetSChar3(Mat m, int x, int y, int z, int8_t val) { m->at(x, y, z) = val; } // Mat_SetShort set a specific row/col value from this Mat expecting // each element to contain a short aka CV_16S. void Mat_SetShort(Mat m, int row, int col, int16_t val) { m->at(row, col) = val; } void Mat_SetShort3(Mat m, int x, int y, int z, int16_t val) { m->at(x, y, z) = val; } // Mat_SetInt set a specific row/col value from this Mat expecting // each element to contain an int aka CV_32S. void Mat_SetInt(Mat m, int row, int col, int32_t val) { m->at(row, col) = val; } void Mat_SetInt3(Mat m, int x, int y, int z, int32_t val) { m->at(x, y, z) = val; } // Mat_SetFloat set a specific row/col value from this Mat expecting // each element to contain a float aka CV_32F. void Mat_SetFloat(Mat m, int row, int col, float val) { m->at(row, col) = val; } void Mat_SetFloat3(Mat m, int x, int y, int z, float val) { m->at(x, y, z) = val; } // Mat_SetDouble set a specific row/col value from this Mat expecting // each element to contain a double aka CV_64F. void Mat_SetDouble(Mat m, int row, int col, double val) { m->at(row, col) = val; } void Mat_SetDouble3(Mat m, int x, int y, int z, double val) { m->at(x, y, z) = val; } void Mat_AddUChar(Mat m, uint8_t val) { *m += val; } void Mat_SubtractUChar(Mat m, uint8_t val) { *m -= val; } void Mat_MultiplyUChar(Mat m, uint8_t val) { *m *= val; } void Mat_DivideUChar(Mat m, uint8_t val) { *m /= val; } void Mat_AddFloat(Mat m, float val) { *m += val; } void Mat_SubtractFloat(Mat m, float val) { *m -= val; } void Mat_MultiplyFloat(Mat m, float val) { *m *= val; } void Mat_DivideFloat(Mat m, float val) { *m /= val; } Mat Mat_MultiplyMatrix(Mat x, Mat y) { return new cv::Mat((*x) * (*y)); } Mat Mat_T(Mat x) { try { return new cv::Mat(x->t()); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return new cv::Mat(); } } OpenCVResult Mat_AbsDiff(Mat src1, Mat src2, Mat dst) { try { cv::absdiff(*src1, *src2, *dst); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Mat_Add(Mat src1, Mat src2, Mat dst) { try { cv::add(*src1, *src2, *dst); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Mat_AddWeighted(Mat src1, double alpha, Mat src2, double beta, double gamma, Mat dst) { try { cv::addWeighted(*src1, alpha, *src2, beta, gamma, *dst); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Mat_BitwiseAnd(Mat src1, Mat src2, Mat dst) { try { cv::bitwise_and(*src1, *src2, *dst); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Mat_BitwiseAndWithMask(Mat src1, Mat src2, Mat dst, Mat mask){ try { cv::bitwise_and(*src1, *src2, *dst, *mask); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Mat_BitwiseNot(Mat src1, Mat dst) { try { cv::bitwise_not(*src1, *dst); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Mat_BitwiseNotWithMask(Mat src1, Mat dst, Mat mask) { try { cv::bitwise_not(*src1, *dst, *mask); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Mat_BitwiseOr(Mat src1, Mat src2, Mat dst) { try { cv::bitwise_or(*src1, *src2, *dst); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Mat_BitwiseOrWithMask(Mat src1, Mat src2, Mat dst, Mat mask) { try { cv::bitwise_or(*src1, *src2, *dst, *mask); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Mat_BitwiseXor(Mat src1, Mat src2, Mat dst) { try { cv::bitwise_xor(*src1, *src2, *dst); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Mat_BitwiseXorWithMask(Mat src1, Mat src2, Mat dst, Mat mask) { try { cv::bitwise_xor(*src1, *src2, *dst, *mask); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Mat_BatchDistance(Mat src1, Mat src2, Mat dist, int dtype, Mat nidx, int normType, int K, Mat mask, int update, bool crosscheck) { try { cv::batchDistance(*src1, *src2, *dist, dtype, *nidx, normType, K, *mask, update, crosscheck); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } int Mat_BorderInterpolate(int p, int len, int borderType) { try { return cv::borderInterpolate(p, len, borderType); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return 0; } } OpenCVResult Mat_CalcCovarMatrix(Mat samples, Mat covar, Mat mean, int flags, int ctype) { try { cv::calcCovarMatrix(*samples, *covar, *mean, flags, ctype); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Mat_CartToPolar(Mat x, Mat y, Mat magnitude, Mat angle, bool angleInDegrees) { try { cv::cartToPolar(*x, *y, *magnitude, *angle, angleInDegrees); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } bool Mat_CheckRange(Mat m) { try { return cv::checkRange(*m); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return false; } } OpenCVResult Mat_Compare(Mat src1, Mat src2, Mat dst, int ct) { try { cv::compare(*src1, *src2, *dst, ct); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } int Mat_CountNonZero(Mat src) { try { return cv::countNonZero(*src); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return 0; } } OpenCVResult Mat_CompleteSymm(Mat m, bool lowerToUpper) { try { cv::completeSymm(*m, lowerToUpper); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Mat_ConvertScaleAbs(Mat src, Mat dst, double alpha, double beta) { try { cv::convertScaleAbs(*src, *dst, alpha, beta); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Mat_CopyMakeBorder(Mat src, Mat dst, int top, int bottom, int left, int right, int borderType, Scalar value) { try { cv::Scalar c_value(value.val1, value.val2, value.val3, value.val4); cv::copyMakeBorder(*src, *dst, top, bottom, left, right, borderType, c_value); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Mat_DCT(Mat src, Mat dst, int flags) { try { cv::dct(*src, *dst, flags); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } double Mat_Determinant(Mat m) { try { return cv::determinant(*m); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return 0.0; } } OpenCVResult Mat_DFT(Mat m, Mat dst, int flags) { try { cv::dft(*m, *dst, flags); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Mat_Divide(Mat src1, Mat src2, Mat dst) { try { cv::divide(*src1, *src2, *dst); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } bool Mat_Eigen(Mat src, Mat eigenvalues, Mat eigenvectors) { try { return cv::eigen(*src, *eigenvalues, *eigenvectors); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return false; } } OpenCVResult Mat_EigenNonSymmetric(Mat src, Mat eigenvalues, Mat eigenvectors) { try { cv::eigenNonSymmetric(*src, *eigenvalues, *eigenvectors); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Mat_PCABackProject(Mat data, Mat mean, Mat eigenvectors, Mat result) { try { cv::PCABackProject(*data, *mean, *eigenvectors, *result); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Mat_PCACompute(Mat src, Mat mean, Mat eigenvectors, Mat eigenvalues, int maxComponents) { try { cv::PCACompute(*src, *mean, *eigenvectors, *eigenvalues, maxComponents); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Mat_PCAProject(Mat data, Mat mean, Mat eigenvectors, Mat result) { try { cv::PCAProject(*data, *mean, *eigenvectors, *result); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } double PSNR(Mat src1, Mat src2) { try { return cv::PSNR(*src1, *src2); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return 0.0; } } OpenCVResult SVBackSubst(Mat w, Mat u, Mat vt, Mat rhs, Mat dst) { try { cv::SVBackSubst(*w, *u, *vt, *rhs, *dst); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult SVDecomp(Mat src, Mat w, Mat u, Mat vt) { try { cv::SVDecomp(*src, *w, *u, *vt); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Mat_Exp(Mat src, Mat dst) { try { cv::exp(*src, *dst); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Mat_ExtractChannel(Mat src, Mat dst, int coi) { try { cv::extractChannel(*src, *dst, coi); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Mat_FindNonZero(Mat src, Mat idx) { try { cv::findNonZero(*src, *idx); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Mat_Flip(Mat src, Mat dst, int flipCode) { try { cv::flip(*src, *dst, flipCode); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Mat_Gemm(Mat src1, Mat src2, double alpha, Mat src3, double beta, Mat dst, int flags) { try { cv::gemm(*src1, *src2, alpha, *src3, beta, *dst, flags); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } int Mat_GetOptimalDFTSize(int vecsize) { try { return cv::getOptimalDFTSize(vecsize); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return 0; } } OpenCVResult Mat_Hconcat(Mat src1, Mat src2, Mat dst) { try { cv::hconcat(*src1, *src2, *dst); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Mat_Vconcat(Mat src1, Mat src2, Mat dst) { try { cv::vconcat(*src1, *src2, *dst); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Rotate(Mat src, Mat dst, int rotateCode) { try { cv::rotate(*src, *dst, rotateCode); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Mat_Idct(Mat src, Mat dst, int flags) { try { cv::idct(*src, *dst, flags); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Mat_Idft(Mat src, Mat dst, int flags, int nonzeroRows) { try { cv::idft(*src, *dst, flags, nonzeroRows); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Mat_InRange(Mat src, Mat lowerb, Mat upperb, Mat dst) { try { cv::inRange(*src, *lowerb, *upperb, *dst); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Mat_InRangeWithScalar(Mat src, Scalar lowerb, Scalar upperb, Mat dst) { try { cv::Scalar lb = cv::Scalar(lowerb.val1, lowerb.val2, lowerb.val3, lowerb.val4); cv::Scalar ub = cv::Scalar(upperb.val1, upperb.val2, upperb.val3, upperb.val4); cv::inRange(*src, lb, ub, *dst); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Mat_InsertChannel(Mat src, Mat dst, int coi) { try { cv::insertChannel(*src, *dst, coi); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } double Mat_Invert(Mat src, Mat dst, int flags) { try { return cv::invert(*src, *dst, flags); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return 0.0; } } double KMeans(Mat data, int k, Mat bestLabels, TermCriteria criteria, int attempts, int flags, Mat centers) { try { return cv::kmeans(*data, k, *bestLabels, *criteria, attempts, flags, *centers); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return 0.0; } } double KMeansPoints(PointVector points, int k, Mat bestLabels, TermCriteria criteria, int attempts, int flags, Mat centers) { try { std::vector pts; copyPointVectorToPoint2fVector(points, &pts); return cv::kmeans(pts, k, *bestLabels, *criteria, attempts, flags, *centers); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return 0.0; } } OpenCVResult Mat_Log(Mat src, Mat dst) { try { cv::log(*src, *dst); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Mat_Magnitude(Mat x, Mat y, Mat magnitude) { try { cv::magnitude(*x, *y, *magnitude); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } double Mat_Mahalanobis(Mat v1, Mat v2, Mat icovar) { try { return cv::Mahalanobis(*v1, *v2, *icovar); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return 0.0; } } OpenCVResult MulTransposed(Mat src, Mat dest, bool ata) { try { cv::mulTransposed(*src, *dest, ata); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Mat_Max(Mat src1, Mat src2, Mat dst) { try { cv::max(*src1, *src2, *dst); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Mat_MeanStdDev(Mat src, Mat dstMean, Mat dstStdDev) { try { cv::meanStdDev(*src, *dstMean, *dstStdDev); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Mat_MeanStdDevWithMask(Mat src, Mat dstMean, Mat dstStdDev, Mat mask) { try { cv::meanStdDev(*src, *dstMean, *dstStdDev, *mask); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Mat_Merge(struct Mats mats, Mat dst) { try { std::vector images; for (int i = 0; i < mats.length; ++i) { images.push_back(*mats.mats[i]); } cv::merge(images, *dst); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Mat_Min(Mat src1, Mat src2, Mat dst) { try { cv::min(*src1, *src2, *dst); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Mat_MinMaxIdx(Mat m, double* minVal, double* maxVal, int* minIdx, int* maxIdx) { try { cv::minMaxIdx(*m, minVal, maxVal, minIdx, maxIdx); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Mat_MinMaxLoc(Mat m, double* minVal, double* maxVal, Point* minLoc, Point* maxLoc) { try { cv::Point cMinLoc; cv::Point cMaxLoc; cv::minMaxLoc(*m, minVal, maxVal, &cMinLoc, &cMaxLoc); minLoc->x = cMinLoc.x; minLoc->y = cMinLoc.y; maxLoc->x = cMaxLoc.x; maxLoc->y = cMaxLoc.y; return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Mat_MinMaxLocWithMask(Mat m, double* minVal, double* maxVal, Point* minLoc, Point* maxLoc, Mat mask) { try { cv::Point cMinLoc; cv::Point cMaxLoc; cv::minMaxLoc(*m, minVal, maxVal, &cMinLoc, &cMaxLoc, *mask); minLoc->x = cMinLoc.x; minLoc->y = cMinLoc.y; maxLoc->x = cMaxLoc.x; maxLoc->y = cMaxLoc.y; return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Mat_MixChannels(struct Mats src, struct Mats dst, struct IntVector fromTo) { try { std::vector srcMats; for (int i = 0; i < src.length; ++i) { srcMats.push_back(*src.mats[i]); } std::vector dstMats; for (int i = 0; i < dst.length; ++i) { dstMats.push_back(*dst.mats[i]); } std::vector fromTos; for (int i = 0; i < fromTo.length; ++i) { fromTos.push_back(fromTo.val[i]); } cv::mixChannels(srcMats, dstMats, fromTos); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Mat_MulSpectrums(Mat a, Mat b, Mat c, int flags) { try { cv::mulSpectrums(*a, *b, *c, flags); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Mat_Multiply(Mat src1, Mat src2, Mat dst) { try { cv::multiply(*src1, *src2, *dst); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Mat_MultiplyWithParams(Mat src1, Mat src2, Mat dst, double scale, int dtype) { try { cv::multiply(*src1, *src2, *dst, scale, dtype); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Mat_Normalize(Mat src, Mat dst, double alpha, double beta, int typ) { try { cv::normalize(*src, *dst, alpha, beta, typ); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } double Norm(Mat src1, int normType) { try { return cv::norm(*src1, normType); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return 0.0; } } double NormWithMats(Mat src1, Mat src2, int normType) { try { return cv::norm(*src1, *src2, normType); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return 0.0; } } OpenCVResult Mat_PerspectiveTransform(Mat src, Mat dst, Mat tm) { try { cv::perspectiveTransform(*src, *dst, *tm); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } bool Mat_Solve(Mat src1, Mat src2, Mat dst, int flags) { try { return cv::solve(*src1, *src2, *dst, flags); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return false; } } int Mat_SolveCubic(Mat coeffs, Mat roots) { try { return cv::solveCubic(*coeffs, *roots); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return 0; } } double Mat_SolvePoly(Mat coeffs, Mat roots, int maxIters) { try { return cv::solvePoly(*coeffs, *roots, maxIters); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return 0.0; } } OpenCVResult Mat_Reduce(Mat src, Mat dst, int dim, int rType, int dType) { try { cv::reduce(*src, *dst, dim, rType, dType); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Mat_ReduceArgMax(Mat src, Mat dst, int axis, bool lastIndex) { try { cv::reduceArgMax(*src, *dst, axis, lastIndex); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Mat_ReduceArgMin(Mat src, Mat dst, int axis, bool lastIndex) { try { cv::reduceArgMin(*src, *dst, axis, lastIndex); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Mat_Repeat(Mat src, int nY, int nX, Mat dst) { try { cv::repeat(*src, nY, nX, *dst); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Mat_ScaleAdd(Mat src1, double alpha, Mat src2, Mat dst) { try { cv::scaleAdd(*src1, alpha, *src2, *dst); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Mat_SetIdentity(Mat src, double scalar) { try { cv::setIdentity(*src, scalar); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Mat_Sort(Mat src, Mat dst, int flags) { try { cv::sort(*src, *dst, flags); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Mat_SortIdx(Mat src, Mat dst, int flags) { try { cv::sortIdx(*src, *dst, flags); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Mat_Split(Mat src, struct Mats* mats) { try { std::vector channels; cv::split(*src, channels); mats->mats = new Mat[channels.size()]; for (size_t i = 0; i < channels.size(); ++i) { mats->mats[i] = new cv::Mat(channels[i]); } mats->length = (int)channels.size(); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Mat_Subtract(Mat src1, Mat src2, Mat dst) { try { cv::subtract(*src1, *src2, *dst); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } Scalar Mat_Trace(Mat src) { try { cv::Scalar c = cv::trace(*src); Scalar scal = Scalar(); scal.val1 = c.val[0]; scal.val2 = c.val[1]; scal.val3 = c.val[2]; scal.val4 = c.val[3]; return scal; } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return Scalar(); } } OpenCVResult Mat_Transform(Mat src, Mat dst, Mat tm) { try { cv::transform(*src, *dst, *tm); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Mat_Transpose(Mat src, Mat dst) { try { cv::transpose(*src, *dst); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Mat_TransposeND(Mat src, struct IntVector order, Mat dst) { try { std::vector _order; for (int i = 0, *v = order.val; i < order.length; ++v, ++i) { _order.push_back(*v); } cv::transposeND(*src, _order, *dst); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Mat_PolarToCart(Mat magnitude, Mat degree, Mat x, Mat y, bool angleInDegrees) { try { cv::polarToCart(*magnitude, *degree, *x, *y, angleInDegrees); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Mat_Pow(Mat src, double power, Mat dst) { try { cv::pow(*src, power, *dst); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Mat_Phase(Mat x, Mat y, Mat angle, bool angleInDegrees) { try { cv::phase(*x, *y, *angle, angleInDegrees); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } Scalar Mat_Sum(Mat src) { try { cv::Scalar c = cv::sum(*src); Scalar scal = Scalar(); scal.val1 = c.val[0]; scal.val2 = c.val[1]; scal.val3 = c.val[2]; scal.val4 = c.val[3]; return scal; } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return Scalar(); } } // TermCriteria_New creates a new TermCriteria TermCriteria TermCriteria_New(int typ, int maxCount, double epsilon) { try { return new cv::TermCriteria(typ, maxCount, epsilon); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } void Contours_Close(struct Contours cs) { for (int i = 0; i < cs.length; i++) { Points_Close(cs.contours[i]); } delete[] cs.contours; } void CStrings_Close(struct CStrings cstrs) { for ( int i = 0; i < cstrs.length; i++ ) { delete [] cstrs.strs[i]; } delete [] cstrs.strs; } void KeyPoints_Close(struct KeyPoints ks) { delete[] ks.keypoints; } void Points_Close(Points ps) { for (size_t i = 0; i < ps.length; i++) { Point_Close(ps.points[i]); } delete[] ps.points; } void Point_Close(Point p) {} void Points2f_Close(Points2f ps) { for (size_t i = 0; i < ps.length; i++) { Point2f_Close(ps.points[i]); } delete[] ps.points; } void Point2f_Close(Point2f p) {} void Rects_Close(struct Rects rs) { delete[] rs.rects; } void DMatches_Close(struct DMatches ds) { delete[] ds.dmatches; } void MultiDMatches_Close(struct MultiDMatches mds) { for (size_t i = 0; i < mds.length; i++) { DMatches_Close(mds.dmatches[i]); } delete[] mds.dmatches; } struct DMatches MultiDMatches_get(struct MultiDMatches mds, int index) { return mds.dmatches[index]; } // since it is next to impossible to iterate over mats.mats on the cgo side Mat Mats_get(struct Mats mats, int i) { return mats.mats[i]; } void Mats_Close(struct Mats mats) { delete[] mats.mats; } void ByteArray_Release(struct ByteArray buf) { delete[] buf.data; } struct ByteArray toByteArray(const char* buf, int len) { ByteArray ret = {new char[len], len}; memcpy(ret.data, buf, len); return ret; } int64 GetCVTickCount() { try { return cv::getTickCount(); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return 0; } } double GetTickFrequency() { try { return cv::getTickFrequency(); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return 0.0; } } Mat Mat_rowRange(Mat m,int startrow,int endrow) { try { return new cv::Mat(m->rowRange(startrow,endrow)); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return new cv::Mat(); } } Mat Mat_colRange(Mat m,int startrow,int endrow) { try { return new cv::Mat(m->colRange(startrow,endrow)); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return new cv::Mat(); } } PointVector PointVector_New() { return new std::vector< cv::Point >; } PointVector PointVector_NewFromPoints(Contour points) { std::vector* cntr = new std::vector; for (size_t i = 0; i < points.length; i++) { cntr->push_back(cv::Point(points.points[i].x, points.points[i].y)); } return cntr; } PointVector PointVector_NewFromMat(Mat mat) { std::vector* pts = new std::vector; *pts = (std::vector) *mat; return pts; } Point PointVector_At(PointVector pv, int idx) { cv::Point p = pv->at(idx); return Point{.x = p.x, .y = p.y}; } void PointVector_Append(PointVector pv, Point p) { pv->push_back(cv::Point(p.x, p.y)); } int PointVector_Size(PointVector p) { return p->size(); } void PointVector_Close(PointVector p) { p->clear(); delete p; } PointsVector PointsVector_New() { return new std::vector< std::vector< cv::Point > >; } PointsVector PointsVector_NewFromPoints(Contours points) { std::vector< std::vector< cv::Point > >* pv = new std::vector< std::vector< cv::Point > >; for (size_t i = 0; i < points.length; i++) { Contour contour = points.contours[i]; std::vector cntr; for (size_t i = 0; i < contour.length; i++) { cntr.push_back(cv::Point(contour.points[i].x, contour.points[i].y)); } pv->push_back(cntr); } return pv; } int PointsVector_Size(PointsVector ps) { return ps->size(); } PointVector PointsVector_At(PointsVector ps, int idx) { std::vector< cv::Point >* p = &(ps->at(idx)); return p; } void PointsVector_Append(PointsVector psv, PointVector pv) { psv->push_back(*pv); } void PointsVector_Close(PointsVector ps) { ps->clear(); delete ps; } Point2fVector Point2fVector_New() { return new std::vector< cv::Point2f >; } Point2fVector Point2fVector_NewFromPoints(Contour2f points) { std::vector* cntr = new std::vector; for (size_t i = 0; i < points.length; i++) { cntr->push_back(cv::Point2f(points.points[i].x, points.points[i].y)); } return cntr; } Point2fVector Point2fVector_NewFromMat(Mat mat) { std::vector* pts = new std::vector; *pts = (std::vector) *mat; return pts; } Point2f Point2fVector_At(Point2fVector pfv, int idx) { cv::Point2f p = pfv->at(idx); return Point2f{.x = p.x, .y = p.y}; } int Point2fVector_Size(Point2fVector pfv) { return pfv->size(); } void Point2fVector_Close(Point2fVector pv) { pv->clear(); delete pv; } void IntVector_Close(struct IntVector ivec) { delete[] ivec.val; } RNG TheRNG() { return &cv::theRNG(); } void SetRNGSeed(int seed) { cv::setRNGSeed(seed); } void RNG_Fill(RNG rng, Mat mat, int distType, double a, double b, bool saturateRange) { try { rng->fill(*mat, distType, a, b, saturateRange); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); } } double RNG_Gaussian(RNG rng, double sigma) { try { return rng->gaussian(sigma); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return 0.0; } } unsigned int RNG_Next(RNG rng) { try { return rng->next(); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return 0; } } void RandN(Mat mat, Scalar mean, Scalar stddev) { try { cv::Scalar m = cv::Scalar(mean.val1, mean.val2, mean.val3, mean.val4); cv::Scalar s = cv::Scalar(stddev.val1, stddev.val2, stddev.val3, stddev.val4); cv::randn(*mat, m, s); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); } } void RandShuffle(Mat mat) { try { cv::randShuffle(*mat); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); } } void RandShuffleWithParams(Mat mat, double iterFactor, RNG rng) { try { cv::randShuffle(*mat, iterFactor, rng); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); } } void RandU(Mat mat, Scalar low, Scalar high) { try { cv::Scalar l = cv::Scalar(low.val1, low.val2, low.val3, low.val4); cv::Scalar h = cv::Scalar(high.val1, high.val2, high.val3, high.val4); cv::randn(*mat, l, h); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); } } void copyPointVectorToPoint2fVector(PointVector src, Point2fVector dest) { for (size_t i = 0; i < src->size(); i++) { dest->push_back(cv::Point2f(src->at(i).x, src->at(i).y)); } } void StdByteVectorInitialize(void* data) { new (data) std::vector(); } void StdByteVectorFree(void *data) { reinterpret_cast *>(data)->~vector(); } size_t StdByteVectorLen(void *data) { return reinterpret_cast *>(data)->size(); } uint8_t* StdByteVectorData(void *data) { return reinterpret_cast *>(data)->data(); } Points2fVector Points2fVector_New(){ return new std::vector< std::vector< cv::Point2f > >; } Points2fVector Points2fVector_NewFromPoints(Contours2f points) { Points2fVector pv = Points2fVector_New(); for(size_t i = 0;isize(); } Point2fVector Points2fVector_At(Points2fVector ps, int idx) { return &(ps->at(idx)); } void Points2fVector_Append(Points2fVector psv, Point2fVector pv) { psv->push_back(*pv); } void Points2fVector_Close(Points2fVector ps) { ps->clear(); delete ps; } Point3fVector Point3fVector_New() { return new std::vector< cv::Point3f >; } Point3fVector Point3fVector_NewFromPoints(Contour3f points) { std::vector *cntr = new std::vector; for(size_t i = 0;i< points.length;i++) { cntr->push_back(cv::Point3f( points.points[i].x, points.points[i].y, points.points[i].z )); } return cntr; } Point3fVector Point3fVector_NewFromMat(Mat mat) { std::vector *pts = new std::vector; *pts = (std::vector) *mat; return pts; } Point3f Point3fVector_At(Point3fVector pfv, int idx) { cv::Point3f p = pfv->at(idx); return Point3f{ .x = p.x, .y = p.y, .z = p.z }; } void Point3fVector_Append(Point3fVector pfv, Point3f point) { pfv->push_back(cv::Point3f(point.x, point.y, point.z)); } int Point3fVector_Size(Point3fVector pfv) { return pfv->size(); } void Point3fVector_Close(Point3fVector pv) { pv->clear(); delete pv; } Points3fVector Points3fVector_New(){ return new std::vector< std::vector< cv::Point3f > >; } Points3fVector Points3fVector_NewFromPoints(Contours3f points) { Points3fVector pv = Points3fVector_New(); for(size_t i = 0;isize(); } Point3fVector Points3fVector_At(Points3fVector ps, int idx) { return &(ps->at(idx)); } void Points3fVector_Append(Points3fVector psv, Point3fVector pv) { psv->push_back(*pv); } void Points3fVector_Close(Points3fVector ps) { ps->clear(); delete ps; } void SetNumThreads(int n) { cv::setNumThreads(n); } int GetNumThreads() { return cv::getNumThreads(); } struct RotatedRect RotatedRect_Create(struct Point2f center, int width, int height, float angle){ cv::Point2f cvpoint2f = cv::Point2f(center.x, center.y); cv::Size2f cvsize2f = cv::Size2f(width, height); cv::RotatedRect cvrect = cv::RotatedRect(cvpoint2f, cvsize2f, angle); Point* rpts = new Point[4]; cv::Point2f* pts4 = new cv::Point2f[4]; cvrect.points(pts4); for (size_t j = 0; j < 4; j++) { Point pt = {int(lroundf(pts4[j].x)), int(lroundf(pts4[j].y))}; rpts[j] = pt; } delete[] pts4; cv::Rect bRect = cvrect.boundingRect(); Rect r = {bRect.x, bRect.y, bRect.width, bRect.height}; Point centrpt = {int(lroundf(cvrect.center.x)), int(lroundf(cvrect.center.y))}; Size szsz = {int(lroundf(cvrect.size.width)), int(lroundf(cvrect.size.height))}; RotatedRect retrect = {(Contour){rpts, 4}, r, centrpt, szsz, cvrect.angle}; return retrect; } struct RotatedRect2f RotatedRect2f_Create(struct Point2f center, float width, float height, float angle){ cv::Point2f cvpoint2f = cv::Point2f(center.x, center.y); cv::Size2f cvsize2f = cv::Size2f(width, height); cv::RotatedRect cvrect = cv::RotatedRect(cvpoint2f, cvsize2f, angle); Point2f* rpts = new Point2f[4]; cv::Point2f* pts4 = new cv::Point2f[4]; cvrect.points(pts4); for (size_t j = 0; j < 4; j++) { Point2f pt = {pts4[j].x, pts4[j].y}; rpts[j] = pt; } delete[] pts4; cv::Rect bRect = cvrect.boundingRect(); Rect r = {bRect.x, bRect.y, bRect.width, bRect.height}; Point2f centrpt = {cvrect.center.x, cvrect.center.y}; Size2f szsz = {cvrect.size.width, cvrect.size.height}; RotatedRect2f retrect = {(Contour2f){rpts, 4}, r, centrpt, szsz, cvrect.angle}; return retrect; } ================================================ FILE: core.go ================================================ package gocv /* #include #include "core.h" */ import "C" import ( "errors" "image" "image/color" "reflect" "unsafe" ) // GetLastException returns the last exception code from the OpenCV library. func GetLastException() int { return int(C.GetOpenCVException()) } // GetLastExceptionMessage returns the last exception message from the OpenCV library. func GetLastExceptionMessage() string { return C.GoString(C.GetOpenCVExceptionMessage()) } // ClearLastException clears the last exception from the OpenCV library. func ClearLastException() { C.ClearOpenCVException() } // LastExceptionError returns an error if there was an exception in the OpenCV library. func LastExceptionError() error { if GetLastException() == 0 { return nil } defer ClearLastException() return errors.New(GetLastExceptionMessage()) } // Converts a OpenCVResult struct to an error. func OpenCVResult(result C.OpenCVResult) error { if result.Code == 0 { return nil } if result.Message == nil { return errors.New("unknown openCV error") } defer C.free(unsafe.Pointer(result.Message)) return errors.New(C.GoString(result.Message)) } const ( // MatChannels1 is a single channel Mat. MatChannels1 = 0 // MatChannels2 is 2 channel Mat. MatChannels2 = 8 // MatChannels3 is 3 channel Mat. MatChannels3 = 16 // MatChannels4 is 4 channel Mat. MatChannels4 = 24 ) // MatType is the type for the various different kinds of Mat you can create. type MatType int const ( // MatTypeCV8U is a Mat of 8-bit unsigned int MatTypeCV8U MatType = 0 // MatTypeCV8S is a Mat of 8-bit signed int MatTypeCV8S MatType = 1 // MatTypeCV16U is a Mat of 16-bit unsigned int MatTypeCV16U MatType = 2 // MatTypeCV16S is a Mat of 16-bit signed int MatTypeCV16S MatType = 3 // MatTypeCV16SC2 is a Mat of 16-bit signed int with 2 channels MatTypeCV16SC2 = MatTypeCV16S + MatChannels2 // MatTypeCV32S is a Mat of 32-bit signed int MatTypeCV32S MatType = 4 // MatTypeCV32F is a Mat of 32-bit float MatTypeCV32F MatType = 5 // MatTypeCV64F is a Mat of 64-bit float MatTypeCV64F MatType = 6 // MatTypeCV16F is a Mat of 16-bit (half) float MatTypeCV16F MatType = 7 // MatTypeCV8UC1 is a Mat of 8-bit unsigned int with a single channel MatTypeCV8UC1 = MatTypeCV8U + MatChannels1 // MatTypeCV8UC2 is a Mat of 8-bit unsigned int with 2 channels MatTypeCV8UC2 = MatTypeCV8U + MatChannels2 // MatTypeCV8UC3 is a Mat of 8-bit unsigned int with 3 channels MatTypeCV8UC3 = MatTypeCV8U + MatChannels3 // MatTypeCV8UC4 is a Mat of 8-bit unsigned int with 4 channels MatTypeCV8UC4 = MatTypeCV8U + MatChannels4 // MatTypeCV8SC1 is a Mat of 8-bit signed int with a single channel MatTypeCV8SC1 = MatTypeCV8S + MatChannels1 // MatTypeCV8SC2 is a Mat of 8-bit signed int with 2 channels MatTypeCV8SC2 = MatTypeCV8S + MatChannels2 // MatTypeCV8SC3 is a Mat of 8-bit signed int with 3 channels MatTypeCV8SC3 = MatTypeCV8S + MatChannels3 // MatTypeCV8SC4 is a Mat of 8-bit signed int with 4 channels MatTypeCV8SC4 = MatTypeCV8S + MatChannels4 // MatTypeCV16UC1 is a Mat of 16-bit unsigned int with a single channel MatTypeCV16UC1 = MatTypeCV16U + MatChannels1 // MatTypeCV16UC2 is a Mat of 16-bit unsigned int with 2 channels MatTypeCV16UC2 = MatTypeCV16U + MatChannels2 // MatTypeCV16UC3 is a Mat of 16-bit unsigned int with 3 channels MatTypeCV16UC3 = MatTypeCV16U + MatChannels3 // MatTypeCV16UC4 is a Mat of 16-bit unsigned int with 4 channels MatTypeCV16UC4 = MatTypeCV16U + MatChannels4 // MatTypeCV16SC1 is a Mat of 16-bit signed int with a single channel MatTypeCV16SC1 = MatTypeCV16S + MatChannels1 // MatTypeCV16SC3 is a Mat of 16-bit signed int with 3 channels MatTypeCV16SC3 = MatTypeCV16S + MatChannels3 // MatTypeCV16SC4 is a Mat of 16-bit signed int with 4 channels MatTypeCV16SC4 = MatTypeCV16S + MatChannels4 // MatTypeCV32SC1 is a Mat of 32-bit signed int with a single channel MatTypeCV32SC1 = MatTypeCV32S + MatChannels1 // MatTypeCV32SC2 is a Mat of 32-bit signed int with 2 channels MatTypeCV32SC2 = MatTypeCV32S + MatChannels2 // MatTypeCV32SC3 is a Mat of 32-bit signed int with 3 channels MatTypeCV32SC3 = MatTypeCV32S + MatChannels3 // MatTypeCV32SC4 is a Mat of 32-bit signed int with 4 channels MatTypeCV32SC4 = MatTypeCV32S + MatChannels4 // MatTypeCV32FC1 is a Mat of 32-bit float int with a single channel MatTypeCV32FC1 = MatTypeCV32F + MatChannels1 // MatTypeCV32FC2 is a Mat of 32-bit float int with 2 channels MatTypeCV32FC2 = MatTypeCV32F + MatChannels2 // MatTypeCV32FC3 is a Mat of 32-bit float int with 3 channels MatTypeCV32FC3 = MatTypeCV32F + MatChannels3 // MatTypeCV32FC4 is a Mat of 32-bit float int with 4 channels MatTypeCV32FC4 = MatTypeCV32F + MatChannels4 // MatTypeCV64FC1 is a Mat of 64-bit float int with a single channel MatTypeCV64FC1 = MatTypeCV64F + MatChannels1 // MatTypeCV64FC2 is a Mat of 64-bit float int with 2 channels MatTypeCV64FC2 = MatTypeCV64F + MatChannels2 // MatTypeCV64FC3 is a Mat of 64-bit float int with 3 channels MatTypeCV64FC3 = MatTypeCV64F + MatChannels3 // MatTypeCV64FC4 is a Mat of 64-bit float int with 4 channels MatTypeCV64FC4 = MatTypeCV64F + MatChannels4 // MatTypeCV16FC1 is a Mat of 16-bit float with a single channel MatTypeCV16FC1 = MatTypeCV16F + MatChannels1 // MatTypeCV16FC2 is a Mat of 16-bit float with 2 channels MatTypeCV16FC2 = MatTypeCV16F + MatChannels2 // MatTypeCV16FC3 is a Mat of 16-bit float with 3 channels MatTypeCV16FC3 = MatTypeCV16F + MatChannels3 // MatTypeCV16FC4 is a Mat of 16-bit float with 4 channels MatTypeCV16FC4 = MatTypeCV16F + MatChannels4 ) // CompareType is used for Compare operations to indicate which kind of // comparison to use. type CompareType int const ( // CompareEQ src1 is equal to src2. CompareEQ CompareType = 0 // CompareGT src1 is greater than src2. CompareGT CompareType = 1 // CompareGE src1 is greater than or equal to src2. CompareGE CompareType = 2 // CompareLT src1 is less than src2. CompareLT CompareType = 3 // CompareLE src1 is less than or equal to src2. CompareLE CompareType = 4 // CompareNE src1 is unequal to src2. CompareNE CompareType = 5 ) type Point2f struct { X float32 Y float32 } func NewPoint2f(x, y float32) Point2f { return Point2f{x, y} } var ErrEmptyByteSlice = errors.New("empty byte array") // Mat represents an n-dimensional dense numerical single-channel // or multi-channel array. It can be used to store real or complex-valued // vectors and matrices, grayscale or color images, voxel volumes, // vector fields, point clouds, tensors, and histograms. // // For further details, please see: // http://docs.opencv.org/master/d3/d63/classcv_1_1Mat.html type Mat struct { p C.Mat // Non-nil if Mat was created with a []byte (using NewMatFromBytes()). Nil otherwise. d []byte } // NewMat returns a new empty Mat. func NewMat() Mat { return newMat(C.Mat_New()) } // NewMatFromCMat returns a new Mat from an unsafe.Pointer(C.Mat). func NewMatFromCMat(c_mat unsafe.Pointer) Mat { return newMat(C.Mat(c_mat)) } // NewMatWithSize returns a new Mat with a specific size and type. func NewMatWithSize(rows int, cols int, mt MatType) Mat { return newMat(C.Mat_NewWithSize(C.int(rows), C.int(cols), C.int(mt))) } // NewMatWithSizes returns a new multidimensional Mat with a specific size and type. func NewMatWithSizes(sizes []int, mt MatType) Mat { sizesArray := make([]C.int, len(sizes)) for i, s := range sizes { sizesArray[i] = C.int(s) } sizesIntVector := C.IntVector{ val: (*C.int)(&sizesArray[0]), length: C.int(len(sizes)), } return newMat(C.Mat_NewWithSizes(sizesIntVector, C.int(mt))) } // NewMatWithSizesWithScalar returns a new multidimensional Mat with a specific size, type and scalar value. func NewMatWithSizesWithScalar(sizes []int, mt MatType, s Scalar) Mat { csizes := []C.int{} for _, v := range sizes { csizes = append(csizes, C.int(v)) } sizesVector := C.struct_IntVector{} sizesVector.val = (*C.int)(&csizes[0]) sizesVector.length = (C.int)(len(csizes)) sVal := C.struct_Scalar{ val1: C.double(s.Val1), val2: C.double(s.Val2), val3: C.double(s.Val3), val4: C.double(s.Val4), } return newMat(C.Mat_NewWithSizesFromScalar(sizesVector, C.int(mt), sVal)) } // NewMatWithSizesFromBytes returns a new multidimensional Mat with a specific size, type and preexisting data. func NewMatWithSizesFromBytes(sizes []int, mt MatType, data []byte) (Mat, error) { cBytes, err := toByteArray(data) if err != nil { return Mat{}, err } csizes := []C.int{} for _, v := range sizes { csizes = append(csizes, C.int(v)) } sizesVector := C.struct_IntVector{} sizesVector.val = (*C.int)(&csizes[0]) sizesVector.length = (C.int)(len(csizes)) return newMat(C.Mat_NewWithSizesFromBytes(sizesVector, C.int(mt), *cBytes)), nil } // NewMatFromScalar returns a new Mat for a specific Scalar value func NewMatFromScalar(s Scalar, mt MatType) Mat { sVal := C.struct_Scalar{ val1: C.double(s.Val1), val2: C.double(s.Val2), val3: C.double(s.Val3), val4: C.double(s.Val4), } return newMat(C.Mat_NewFromScalar(sVal, C.int(mt))) } // NewMatWithSizeFromScalar returns a new Mat for a specific Scala value with a specific size and type // This simplifies creation of specific color filters or creating Mats of specific colors and sizes func NewMatWithSizeFromScalar(s Scalar, rows int, cols int, mt MatType) Mat { sVal := C.struct_Scalar{ val1: C.double(s.Val1), val2: C.double(s.Val2), val3: C.double(s.Val3), val4: C.double(s.Val4), } return newMat(C.Mat_NewWithSizeFromScalar(sVal, C.int(rows), C.int(cols), C.int(mt))) } // NewMatFromBytes returns a new Mat with a specific size and type, initialized from a []byte. func NewMatFromBytes(rows int, cols int, mt MatType, data []byte) (Mat, error) { cBytes, err := toByteArray(data) if err != nil { return Mat{}, err } mat := newMat(C.Mat_NewFromBytes(C.int(rows), C.int(cols), C.int(mt), *cBytes)) // Store a reference to the backing data slice. This is needed because we pass the backing // array directly to C code and without keeping a Go reference to it, it might end up // garbage collected which would result in crashes. // // TODO(bga): This could live in newMat() but I wanted to reduce the change surface. // TODO(bga): Code that needs access to the array from Go could use this directly. mat.d = data return mat, nil } // NewMatFromPoint2fVector returns a new Mat from a gocv.Point2fVector. func NewMatFromPoint2fVector(pfv Point2fVector, copyData bool) Mat { mat := newMat(C.Mat_NewFromPoint2fVector(pfv.p, C.bool(copyData))) return mat } // NewMatFromPointVector returns a new Mat from a gocv.PointVector. func NewMatFromPointVector(pv PointVector, copyData bool) Mat { mat := newMat(C.Mat_NewFromPointVector(pv.p, C.bool(copyData))) return mat } // Returns an identity matrix of the specified size and type. // // The method returns a Matlab-style identity matrix initializer, similarly to Mat::zeros. Similarly to Mat::ones. // For further details, please see: // https://docs.opencv.org/master/d3/d63/classcv_1_1Mat.html#a2cf9b9acde7a9852542bbc20ef851ed2 func Eye(rows int, cols int, mt MatType) Mat { return newMat(C.Eye(C.int(rows), C.int(cols), C.int(mt))) } // Returns a zero array of the specified size and type. // // The method returns a Matlab-style zero array initializer. // For further details, please see: // https://docs.opencv.org/master/d3/d63/classcv_1_1Mat.html#a0b57b6a326c8876d944d188a46e0f556 func Zeros(rows int, cols int, mt MatType) Mat { return newMat(C.Zeros(C.int(rows), C.int(cols), C.int(mt))) } // Returns an array of all 1's of the specified size and type. // // The method returns a Matlab-style 1's array initializer // For further details, please see: // https://docs.opencv.org/master/d3/d63/classcv_1_1Mat.html#a69ae0402d116fc9c71908d8508dc2f09 func Ones(rows int, cols int, mt MatType) Mat { return newMat(C.Ones(C.int(rows), C.int(cols), C.int(mt))) } // FromPtr returns a new Mat with a specific size and type, initialized from a Mat Ptr. func (m *Mat) FromPtr(rows int, cols int, mt MatType, prow int, pcol int) (Mat, error) { return newMat(C.Mat_FromPtr(m.p, C.int(rows), C.int(cols), C.int(mt), C.int(prow), C.int(pcol))), nil } // Ptr returns the Mat's underlying object pointer. func (m *Mat) Ptr() C.Mat { return m.p } // Empty determines if the Mat is empty or not. func (m *Mat) Empty() bool { isEmpty := C.Mat_Empty(m.p) return isEmpty != 0 } // Closed determines if the Mat is closed or not. func (m *Mat) Closed() bool { return m.p == nil } // IsContinuous determines if the Mat is continuous. // // For further details, please see: // https://docs.opencv.org/master/d3/d63/classcv_1_1Mat.html#aa90cea495029c7d1ee0a41361ccecdf3 func (m *Mat) IsContinuous() bool { return bool(C.Mat_IsContinuous(m.p)) } // Inv inverses a matrix. // // For further details, please see: // https://docs.opencv.org/4.x/d3/d63/classcv_1_1Mat.html#a039eb3c6740a850696a12519a4b8bfc6 func (m *Mat) Inv() { C.Mat_Inv(m.p) } // Col creates a matrix header for the specified matrix column. // The underlying data of the new matrix is shared with the original matrix. func (m *Mat) Col(col int) Mat { return newMat(C.Mat_Col(m.p, C.int(col))) } // Row creates a matrix header for the specified matrix row. // The underlying data of the new matrix is shared with the original matrix. func (m *Mat) Row(row int) Mat { return newMat(C.Mat_Row(m.p, C.int(row))) } // Copy returns a shallow copy of the Mat. No data is copied. // // For further details, please see: // https://docs.opencv.org/4.x/d3/d63/classcv_1_1Mat.html#a294eaf8a95d2f9c7be19ff594d06278e func (m *Mat) Copy() Mat { return Mat{ p: C.Mat_Copy(m.p), d: m.d, } } // Clone returns a cloned full copy of the Mat. func (m *Mat) Clone() Mat { return newMat(C.Mat_Clone(m.p)) } // CopyTo copies Mat into destination Mat. // // For further details, please see: // https://docs.opencv.org/master/d3/d63/classcv_1_1Mat.html#a33fd5d125b4c302b0c9aa86980791a77 func (m *Mat) CopyTo(dst *Mat) error { return OpenCVResult(C.Mat_CopyTo(m.p, dst.p)) } // CopyToWithMask copies Mat into destination Mat after applying the mask Mat. // // For further details, please see: // https://docs.opencv.org/master/d3/d63/classcv_1_1Mat.html#a626fe5f96d02525e2604d2ad46dd574f func (m *Mat) CopyToWithMask(dst *Mat, mask Mat) error { return OpenCVResult(C.Mat_CopyToWithMask(m.p, dst.p, mask.p)) } // ConvertTo converts Mat into destination Mat. // // For further details, please see: // https://docs.opencv.org/master/d3/d63/classcv_1_1Mat.html#adf88c60c5b4980e05bb556080916978b func (m *Mat) ConvertTo(dst *Mat, mt MatType) error { return OpenCVResult(C.Mat_ConvertTo(m.p, dst.p, C.int(mt))) } func (m *Mat) ConvertToWithParams(dst *Mat, mt MatType, alpha, beta float32) error { return OpenCVResult(C.Mat_ConvertToWithParams(m.p, dst.p, C.int(mt), C.float(alpha), C.float(beta))) } // Total returns the total number of array elements. // // For further details, please see: // https://docs.opencv.org/master/d3/d63/classcv_1_1Mat.html#aa4d317d43fb0cba9c2503f3c61b866c8 func (m *Mat) Total() int { return int(C.Mat_Total(m.p)) } // Size returns an array with one element for each dimension containing the size of that dimension for the Mat. // // For further details, please see: // https://docs.opencv.org/master/d3/d63/classcv_1_1Mat.html#aa4d317d43fb0cba9c2503f3c61b866c8 func (m *Mat) Size() (dims []int) { cdims := C.IntVector{} C.Mat_Size(m.p, &cdims) defer C.IntVector_Close(cdims) h := &reflect.SliceHeader{ Data: uintptr(unsafe.Pointer(cdims.val)), Len: int(cdims.length), Cap: int(cdims.length), } pdims := *(*[]C.int)(unsafe.Pointer(h)) for i := 0; i < int(cdims.length); i++ { dims = append(dims, int(pdims[i])) } return } // ToBytes copies the underlying Mat data to a byte array. // // For further details, please see: // https://docs.opencv.org/3.3.1/d3/d63/classcv_1_1Mat.html#a4d33bed1c850265370d2af0ff02e1564 func (m *Mat) ToBytes() []byte { b := C.Mat_DataPtr(m.p) return toGoBytes(b) } // DataPtrUint8 returns a slice that references the OpenCV allocated data. // // The data is no longer valid once the Mat has been closed. Any data that // needs to be accessed after the Mat is closed must be copied into Go memory. func (m *Mat) DataPtrUint8() ([]uint8, error) { if !m.IsContinuous() { return nil, errors.New("DataPtrUint8 requires continuous Mat") } p := C.Mat_DataPtr(m.p) h := &reflect.SliceHeader{ Data: uintptr(unsafe.Pointer(p.data)), Len: int(p.length), Cap: int(p.length), } return *(*[]uint8)(unsafe.Pointer(h)), nil } // DataPtrInt8 returns a slice that references the OpenCV allocated data. // // The data is no longer valid once the Mat has been closed. Any data that // needs to be accessed after the Mat is closed must be copied into Go memory. func (m *Mat) DataPtrInt8() ([]int8, error) { if m.Type()&MatTypeCV8S != MatTypeCV8S { return nil, errors.New("DataPtrInt8 only supports MatTypeCV8S") } if !m.IsContinuous() { return nil, errors.New("DataPtrInt8 requires continuous Mat") } p := C.Mat_DataPtr(m.p) h := &reflect.SliceHeader{ Data: uintptr(unsafe.Pointer(p.data)), Len: int(p.length), Cap: int(p.length), } return *(*[]int8)(unsafe.Pointer(h)), nil } // DataPtrUint16 returns a slice that references the OpenCV allocated data. // // The data is no longer valid once the Mat has been closed. Any data that // needs to be accessed after the Mat is closed must be copied into Go memory. func (m *Mat) DataPtrUint16() ([]uint16, error) { if m.Type()&MatTypeCV16U != MatTypeCV16U { return nil, errors.New("DataPtrUint16 only supports MatTypeCV16U") } if !m.IsContinuous() { return nil, errors.New("DataPtrUint16 requires continuous Mat") } p := C.Mat_DataPtr(m.p) h := &reflect.SliceHeader{ Data: uintptr(unsafe.Pointer(p.data)), Len: int(p.length) / 2, Cap: int(p.length) / 2, } return *(*[]uint16)(unsafe.Pointer(h)), nil } // DataPtrInt16 returns a slice that references the OpenCV allocated data. // // The data is no longer valid once the Mat has been closed. Any data that // needs to be accessed after the Mat is closed must be copied into Go memory. func (m *Mat) DataPtrInt16() ([]int16, error) { if m.Type()&MatTypeCV16S != MatTypeCV16S { return nil, errors.New("DataPtrInt16 only supports MatTypeCV16S") } if !m.IsContinuous() { return nil, errors.New("DataPtrInt16 requires continuous Mat") } p := C.Mat_DataPtr(m.p) h := &reflect.SliceHeader{ Data: uintptr(unsafe.Pointer(p.data)), Len: int(p.length) / 2, Cap: int(p.length) / 2, } return *(*[]int16)(unsafe.Pointer(h)), nil } // DataPtrFloat32 returns a slice that references the OpenCV allocated data. // // The data is no longer valid once the Mat has been closed. Any data that // needs to be accessed after the Mat is closed must be copied into Go memory. func (m *Mat) DataPtrFloat32() ([]float32, error) { if m.Type()&MatTypeCV32F != MatTypeCV32F { return nil, errors.New("DataPtrFloat32 only supports MatTypeCV32F") } if !m.IsContinuous() { return nil, errors.New("DataPtrFloat32 requires continuous Mat") } p := C.Mat_DataPtr(m.p) h := &reflect.SliceHeader{ Data: uintptr(unsafe.Pointer(p.data)), Len: int(p.length) / 4, Cap: int(p.length) / 4, } return *(*[]float32)(unsafe.Pointer(h)), nil } // DataPtrFloat64 returns a slice that references the OpenCV allocated data. // // The data is no longer valid once the Mat has been closed. Any data that // needs to be accessed after the Mat is closed must be copied into Go memory. func (m *Mat) DataPtrFloat64() ([]float64, error) { if m.Type()&MatTypeCV64F != MatTypeCV64F { return nil, errors.New("DataPtrFloat64 only supports MatTypeCV64F") } if !m.IsContinuous() { return nil, errors.New("DataPtrFloat64 requires continuous Mat") } p := C.Mat_DataPtr(m.p) h := &reflect.SliceHeader{ Data: uintptr(unsafe.Pointer(p.data)), Len: int(p.length) / 8, Cap: int(p.length) / 8, } return *(*[]float64)(unsafe.Pointer(h)), nil } // Region returns a new Mat that points to a region of this Mat. Changes made to the // region Mat will affect the original Mat, since they are pointers to the underlying // OpenCV Mat object. func (m *Mat) Region(rio image.Rectangle) Mat { cRect := C.struct_Rect{ x: C.int(rio.Min.X), y: C.int(rio.Min.Y), width: C.int(rio.Size().X), height: C.int(rio.Size().Y), } return newMat(C.Mat_Region(m.p, cRect)) } // Reshape changes the shape and/or the number of channels of a 2D matrix without copying the data. // // For further details, please see: // https://docs.opencv.org/master/d3/d63/classcv_1_1Mat.html#a4eb96e3251417fa88b78e2abd6cfd7d8 func (m *Mat) Reshape(cn int, rows int) Mat { return newMat(C.Mat_Reshape(m.p, C.int(cn), C.int(rows))) } // ReshapeWithSize changes the shape and/or the number of channels of a 2D matrix without copying the data. // // For further details, please see: // https://docs.opencv.org/master/d3/d63/classcv_1_1Mat.html#a4eb96e3251417fa88b78e2abd6cfd7d8 func (m *Mat) ReshapeWithSize(cn int, dims []int) Mat { cDimsArray := make([]C.int, len(dims)) for i, ft := range dims { cDimsArray[i] = C.int(ft) } cDimsVector := C.IntVector{ val: (*C.int)(&cDimsArray[0]), length: C.int(len(dims)), } return newMat(C.Mat_ReshapeWithSize(m.p, C.int(cn), cDimsVector)) } // ConvertFp16 converts a Mat to half-precision floating point. // // For further details, please see: // https://docs.opencv.org/master/d2/de8/group__core__array.html#ga9c25d9ef44a2a48ecc3774b30cb80082 func (m *Mat) ConvertFp16() Mat { return newMat(C.Mat_ConvertFp16(m.p)) } // Mean calculates the mean value M of array elements, independently for each channel, and return it as Scalar // For further details, please see: // https://docs.opencv.org/master/d2/de8/group__core__array.html#ga191389f8a0e58180bb13a727782cd461 func (m *Mat) Mean() Scalar { s := C.Mat_Mean(m.p) return NewScalar(float64(s.val1), float64(s.val2), float64(s.val3), float64(s.val4)) } // MeanWithMask calculates the mean value M of array elements,independently for each channel, // and returns it as Scalar vector while applying the mask. // https://docs.opencv.org/master/d2/de8/group__core__array.html#ga191389f8a0e58180bb13a727782cd461 func (m *Mat) MeanWithMask(mask Mat) Scalar { s := C.Mat_MeanWithMask(m.p, mask.p) return NewScalar(float64(s.val1), float64(s.val2), float64(s.val3), float64(s.val4)) } // Sqrt calculates a square root of array elements. // // For further details, please see: // https://docs.opencv.org/master/d2/de8/group__core__array.html#ga186222c3919657890f88df5a1f64a7d7 func (m *Mat) Sqrt() Mat { return newMat(C.Mat_Sqrt(m.p)) } // Sum calculates the per-channel pixel sum of an image. // // For further details, please see: // https://docs.opencv.org/master/d2/de8/group__core__array.html#ga716e10a2dd9e228e4d3c95818f106722 func (m *Mat) Sum() Scalar { s := C.Mat_Sum(m.p) return NewScalar(float64(s.val1), float64(s.val2), float64(s.val3), float64(s.val4)) } // PatchNaNs converts NaN's to zeros. // // For further details, please see: // https://docs.opencv.org/master/d2/de8/group__core__array.html#ga62286befb7cde3568ff8c7d14d5079da func (m *Mat) PatchNaNs() error { return OpenCVResult(C.Mat_PatchNaNs(m.p)) } // LUT performs a look-up table transform of an array. // // The function LUT fills the output array with values from the look-up table. // Indices of the entries are taken from the input array. // // For further details, please see: // https://docs.opencv.org/master/d2/de8/group__core__array.html#gab55b8d062b7f5587720ede032d34156f func LUT(src, wbLUT Mat, dst *Mat) error { return OpenCVResult(C.LUT(src.p, wbLUT.p, dst.p)) } // Rows returns the number of rows for this Mat. func (m *Mat) Rows() int { return int(C.Mat_Rows(m.p)) } // Cols returns the number of columns for this Mat. func (m *Mat) Cols() int { return int(C.Mat_Cols(m.p)) } // Channels returns the number of channels for this Mat. func (m *Mat) Channels() int { return int(C.Mat_Channels(m.p)) } // Type returns the type for this Mat. func (m *Mat) Type() MatType { return MatType(C.Mat_Type(m.p)) } // Step returns the number of bytes each matrix row occupies. func (m *Mat) Step() int { return int(C.Mat_Step(m.p)) } // ElemSize returns the matrix element size in bytes. func (m *Mat) ElemSize() int { return int(C.Mat_ElemSize(m.p)) } // GetUCharAt returns a value from a specific row/col // in this Mat expecting it to be of type uchar aka CV_8U. func (m *Mat) GetUCharAt(row int, col int) uint8 { return uint8(C.Mat_GetUChar(m.p, C.int(row), C.int(col))) } // GetUCharAt3 returns a value from a specific x, y, z coordinate location // in this Mat expecting it to be of type uchar aka CV_8U. func (m *Mat) GetUCharAt3(x, y, z int) uint8 { return uint8(C.Mat_GetUChar3(m.p, C.int(x), C.int(y), C.int(z))) } // GetSCharAt returns a value from a specific row/col // in this Mat expecting it to be of type schar aka CV_8S. func (m *Mat) GetSCharAt(row int, col int) int8 { return int8(C.Mat_GetSChar(m.p, C.int(row), C.int(col))) } // GetSCharAt3 returns a value from a specific x, y, z coordinate location // in this Mat expecting it to be of type schar aka CV_8S. func (m *Mat) GetSCharAt3(x, y, z int) int8 { return int8(C.Mat_GetSChar3(m.p, C.int(x), C.int(y), C.int(z))) } // GetShortAt returns a value from a specific row/col // in this Mat expecting it to be of type short aka CV_16S. func (m *Mat) GetShortAt(row int, col int) int16 { return int16(C.Mat_GetShort(m.p, C.int(row), C.int(col))) } // GetShortAt3 returns a value from a specific x, y, z coordinate location // in this Mat expecting it to be of type short aka CV_16S. func (m *Mat) GetShortAt3(x, y, z int) int16 { return int16(C.Mat_GetShort3(m.p, C.int(x), C.int(y), C.int(z))) } // GetIntAt returns a value from a specific row/col // in this Mat expecting it to be of type int aka CV_32S. func (m *Mat) GetIntAt(row int, col int) int32 { return int32(C.Mat_GetInt(m.p, C.int(row), C.int(col))) } // GetIntAt3 returns a value from a specific x, y, z coordinate location // in this Mat expecting it to be of type int aka CV_32S. func (m *Mat) GetIntAt3(x, y, z int) int32 { return int32(C.Mat_GetInt3(m.p, C.int(x), C.int(y), C.int(z))) } // GetFloatAt returns a value from a specific row/col // in this Mat expecting it to be of type float aka CV_32F. func (m *Mat) GetFloatAt(row int, col int) float32 { return float32(C.Mat_GetFloat(m.p, C.int(row), C.int(col))) } // GetFloatAt3 returns a value from a specific x, y, z coordinate location // in this Mat expecting it to be of type float aka CV_32F. func (m *Mat) GetFloatAt3(x, y, z int) float32 { return float32(C.Mat_GetFloat3(m.p, C.int(x), C.int(y), C.int(z))) } // GetDoubleAt returns a value from a specific row/col // in this Mat expecting it to be of type double aka CV_64F. func (m *Mat) GetDoubleAt(row int, col int) float64 { return float64(C.Mat_GetDouble(m.p, C.int(row), C.int(col))) } // GetDoubleAt3 returns a value from a specific x, y, z coordinate location // in this Mat expecting it to be of type double aka CV_64F. func (m *Mat) GetDoubleAt3(x, y, z int) float64 { return float64(C.Mat_GetDouble3(m.p, C.int(x), C.int(y), C.int(z))) } // SetTo sets all or some of the array elements to the specified scalar value. func (m *Mat) SetTo(s Scalar) { sVal := C.struct_Scalar{ val1: C.double(s.Val1), val2: C.double(s.Val2), val3: C.double(s.Val3), val4: C.double(s.Val4), } C.Mat_SetTo(m.p, sVal) } // SetUCharAt sets a value at a specific row/col // in this Mat expecting it to be of type uchar aka CV_8U. func (m *Mat) SetUCharAt(row int, col int, val uint8) { C.Mat_SetUChar(m.p, C.int(row), C.int(col), C.uint8_t(val)) } // SetUCharAt3 sets a value at a specific x, y, z coordinate location // in this Mat expecting it to be of type uchar aka CV_8U. func (m *Mat) SetUCharAt3(x, y, z int, val uint8) { C.Mat_SetUChar3(m.p, C.int(x), C.int(y), C.int(z), C.uint8_t(val)) } // SetSCharAt sets a value at a specific row/col // in this Mat expecting it to be of type schar aka CV_8S. func (m *Mat) SetSCharAt(row int, col int, val int8) { C.Mat_SetSChar(m.p, C.int(row), C.int(col), C.int8_t(val)) } // SetSCharAt3 sets a value at a specific x, y, z coordinate location // in this Mat expecting it to be of type schar aka CV_8S. func (m *Mat) SetSCharAt3(x, y, z int, val int8) { C.Mat_SetSChar3(m.p, C.int(x), C.int(y), C.int(z), C.int8_t(val)) } // SetShortAt sets a value at a specific row/col // in this Mat expecting it to be of type short aka CV_16S. func (m *Mat) SetShortAt(row int, col int, val int16) { C.Mat_SetShort(m.p, C.int(row), C.int(col), C.int16_t(val)) } // SetShortAt3 sets a value at a specific x, y, z coordinate location // in this Mat expecting it to be of type short aka CV_16S. func (m *Mat) SetShortAt3(x, y, z int, val int16) { C.Mat_SetShort3(m.p, C.int(x), C.int(y), C.int(z), C.int16_t(val)) } // SetIntAt sets a value at a specific row/col // in this Mat expecting it to be of type int aka CV_32S. func (m *Mat) SetIntAt(row int, col int, val int32) { C.Mat_SetInt(m.p, C.int(row), C.int(col), C.int32_t(val)) } // SetIntAt3 sets a value at a specific x, y, z coordinate location // in this Mat expecting it to be of type int aka CV_32S. func (m *Mat) SetIntAt3(x, y, z int, val int32) { C.Mat_SetInt3(m.p, C.int(x), C.int(y), C.int(z), C.int32_t(val)) } // SetFloatAt sets a value at a specific row/col // in this Mat expecting it to be of type float aka CV_32F. func (m *Mat) SetFloatAt(row int, col int, val float32) { C.Mat_SetFloat(m.p, C.int(row), C.int(col), C.float(val)) } // SetFloatAt3 sets a value at a specific x, y, z coordinate location // in this Mat expecting it to be of type float aka CV_32F. func (m *Mat) SetFloatAt3(x, y, z int, val float32) { C.Mat_SetFloat3(m.p, C.int(x), C.int(y), C.int(z), C.float(val)) } // SetDoubleAt sets a value at a specific row/col // in this Mat expecting it to be of type double aka CV_64F. func (m *Mat) SetDoubleAt(row int, col int, val float64) { C.Mat_SetDouble(m.p, C.int(row), C.int(col), C.double(val)) } // SetDoubleAt3 sets a value at a specific x, y, z coordinate location // in this Mat expecting it to be of type double aka CV_64F. func (m *Mat) SetDoubleAt3(x, y, z int, val float64) { C.Mat_SetDouble3(m.p, C.int(x), C.int(y), C.int(z), C.double(val)) } // AddUChar adds a uchar value to each element in the Mat. Performs a // mat += val operation. func (m *Mat) AddUChar(val uint8) { C.Mat_AddUChar(m.p, C.uint8_t(val)) } // SubtractUChar subtracts a uchar value from each element in the Mat. Performs a // mat -= val operation. func (m *Mat) SubtractUChar(val uint8) { C.Mat_SubtractUChar(m.p, C.uint8_t(val)) } // MultiplyUChar multiplies each element in the Mat by a uint value. Performs a // mat *= val operation. func (m *Mat) MultiplyUChar(val uint8) { C.Mat_MultiplyUChar(m.p, C.uint8_t(val)) } // DivideUChar divides each element in the Mat by a uint value. Performs a // mat /= val operation. func (m *Mat) DivideUChar(val uint8) { C.Mat_DivideUChar(m.p, C.uint8_t(val)) } // AddFloat adds a float value to each element in the Mat. Performs a // mat += val operation. func (m *Mat) AddFloat(val float32) { C.Mat_AddFloat(m.p, C.float(val)) } // SubtractFloat subtracts a float value from each element in the Mat. Performs a // mat -= val operation. func (m *Mat) SubtractFloat(val float32) { C.Mat_SubtractFloat(m.p, C.float(val)) } // MultiplyFloat multiplies each element in the Mat by a float value. Performs a // mat *= val operation. func (m *Mat) MultiplyFloat(val float32) { C.Mat_MultiplyFloat(m.p, C.float(val)) } // DivideFloat divides each element in the Mat by a float value. Performs a // mat /= val operation. func (m *Mat) DivideFloat(val float32) { C.Mat_DivideFloat(m.p, C.float(val)) } // MultiplyMatrix multiplies matrix (m*x) func (m *Mat) MultiplyMatrix(x Mat) Mat { return newMat(C.Mat_MultiplyMatrix(m.p, x.p)) } // T transpose matrix // https://docs.opencv.org/4.1.2/d3/d63/classcv_1_1Mat.html#aaa428c60ccb6d8ea5de18f63dfac8e11 func (m *Mat) T() Mat { return newMat(C.Mat_T(m.p)) } // AbsDiff calculates the per-element absolute difference between two arrays // or between an array and a scalar. // // For further details, please see: // https://docs.opencv.org/master/d2/de8/group__core__array.html#ga6fef31bc8c4071cbc114a758a2b79c14 func AbsDiff(src1, src2 Mat, dst *Mat) error { return OpenCVResult(C.Mat_AbsDiff(src1.p, src2.p, dst.p)) } // Add calculates the per-element sum of two arrays or an array and a scalar. // // For further details, please see: // https://docs.opencv.org/master/d2/de8/group__core__array.html#ga10ac1bfb180e2cfda1701d06c24fdbd6 func Add(src1, src2 Mat, dst *Mat) error { return OpenCVResult(C.Mat_Add(src1.p, src2.p, dst.p)) } // AddWeighted calculates the weighted sum of two arrays. // // For further details, please see: // https://docs.opencv.org/master/d2/de8/group__core__array.html#gafafb2513349db3bcff51f54ee5592a19 func AddWeighted(src1 Mat, alpha float64, src2 Mat, beta float64, gamma float64, dst *Mat) error { return OpenCVResult(C.Mat_AddWeighted(src1.p, C.double(alpha), src2.p, C.double(beta), C.double(gamma), dst.p)) } // BitwiseAnd computes bitwise conjunction of the two arrays (dst = src1 & src2). // Calculates the per-element bit-wise conjunction of two arrays // or an array and a scalar. // // For further details, please see: // https://docs.opencv.org/master/d2/de8/group__core__array.html#ga60b4d04b251ba5eb1392c34425497e14 func BitwiseAnd(src1 Mat, src2 Mat, dst *Mat) error { return OpenCVResult(C.Mat_BitwiseAnd(src1.p, src2.p, dst.p)) } // BitwiseAndWithMask computes bitwise conjunction of the two arrays (dst = src1 & src2). // Calculates the per-element bit-wise conjunction of two arrays // or an array and a scalar. It has an additional parameter for a mask. // // For further details, please see: // https://docs.opencv.org/master/d2/de8/group__core__array.html#ga60b4d04b251ba5eb1392c34425497e14 func BitwiseAndWithMask(src1 Mat, src2 Mat, dst *Mat, mask Mat) error { return OpenCVResult(C.Mat_BitwiseAndWithMask(src1.p, src2.p, dst.p, mask.p)) } // BitwiseNot inverts every bit of an array. // // For further details, please see: // https://docs.opencv.org/master/d2/de8/group__core__array.html#ga0002cf8b418479f4cb49a75442baee2f func BitwiseNot(src1 Mat, dst *Mat) error { return OpenCVResult(C.Mat_BitwiseNot(src1.p, dst.p)) } // BitwiseNotWithMask inverts every bit of an array. It has an additional parameter for a mask. // // For further details, please see: // https://docs.opencv.org/master/d2/de8/group__core__array.html#ga0002cf8b418479f4cb49a75442baee2f func BitwiseNotWithMask(src1 Mat, dst *Mat, mask Mat) error { return OpenCVResult(C.Mat_BitwiseNotWithMask(src1.p, dst.p, mask.p)) } // BitwiseOr calculates the per-element bit-wise disjunction of two arrays // or an array and a scalar. // // For further details, please see: // https://docs.opencv.org/master/d2/de8/group__core__array.html#gab85523db362a4e26ff0c703793a719b4 func BitwiseOr(src1 Mat, src2 Mat, dst *Mat) error { return OpenCVResult(C.Mat_BitwiseOr(src1.p, src2.p, dst.p)) } // BitwiseOrWithMask calculates the per-element bit-wise disjunction of two arrays // or an array and a scalar. It has an additional parameter for a mask. // // For further details, please see: // https://docs.opencv.org/master/d2/de8/group__core__array.html#gab85523db362a4e26ff0c703793a719b4 func BitwiseOrWithMask(src1 Mat, src2 Mat, dst *Mat, mask Mat) error { return OpenCVResult(C.Mat_BitwiseOrWithMask(src1.p, src2.p, dst.p, mask.p)) } // BitwiseXor calculates the per-element bit-wise "exclusive or" operation // on two arrays or an array and a scalar. // // For further details, please see: // https://docs.opencv.org/master/d2/de8/group__core__array.html#ga84b2d8188ce506593dcc3f8cd00e8e2c func BitwiseXor(src1 Mat, src2 Mat, dst *Mat) error { return OpenCVResult(C.Mat_BitwiseXor(src1.p, src2.p, dst.p)) } // BitwiseXorWithMask calculates the per-element bit-wise "exclusive or" operation // on two arrays or an array and a scalar. It has an additional parameter for a mask. // // For further details, please see: // https://docs.opencv.org/master/d2/de8/group__core__array.html#ga84b2d8188ce506593dcc3f8cd00e8e2c func BitwiseXorWithMask(src1 Mat, src2 Mat, dst *Mat, mask Mat) error { return OpenCVResult(C.Mat_BitwiseXorWithMask(src1.p, src2.p, dst.p, mask.p)) } // BatchDistance is a naive nearest neighbor finder. // // For further details, please see: // https://docs.opencv.org/master/d2/de8/group__core__array.html#ga4ba778a1c57f83233b1d851c83f5a622 func BatchDistance(src1 Mat, src2 Mat, dist Mat, dtype MatType, nidx Mat, normType NormType, K int, mask Mat, update int, crosscheck bool) error { return OpenCVResult(C.Mat_BatchDistance(src1.p, src2.p, dist.p, C.int(dtype), nidx.p, C.int(normType), C.int(K), mask.p, C.int(update), C.bool(crosscheck))) } // BorderInterpolate computes the source location of an extrapolated pixel. // // For further details, please see: // https://docs.opencv.org/master/d2/de8/group__core__array.html#ga247f571aa6244827d3d798f13892da58 func BorderInterpolate(p int, len int, borderType CovarFlags) int { ret := C.Mat_BorderInterpolate(C.int(p), C.int(len), C.int(borderType)) return int(ret) } // CovarFlags are the covariation flags used by functions such as BorderInterpolate. // // For further details, please see: // https://docs.opencv.org/master/d0/de1/group__core.html#ga719ebd4a73f30f4fab258ab7616d0f0f type CovarFlags int const ( // CovarScrambled indicates to scramble the results. CovarScrambled CovarFlags = 0 // CovarNormal indicates to use normal covariation. CovarNormal CovarFlags = 1 // CovarUseAvg indicates to use average covariation. CovarUseAvg CovarFlags = 2 // CovarScale indicates to use scaled covariation. CovarScale CovarFlags = 4 // CovarRows indicates to use covariation on rows. CovarRows CovarFlags = 8 // CovarCols indicates to use covariation on columns. CovarCols CovarFlags = 16 ) // CalcCovarMatrix calculates the covariance matrix of a set of vectors. // // For further details, please see: // https://docs.opencv.org/master/d2/de8/group__core__array.html#ga017122d912af19d7d0d2cccc2d63819f func CalcCovarMatrix(samples Mat, covar *Mat, mean *Mat, flags CovarFlags, ctype MatType) error { return OpenCVResult(C.Mat_CalcCovarMatrix(samples.p, covar.p, mean.p, C.int(flags), C.int(ctype))) } // CartToPolar calculates the magnitude and angle of 2D vectors. // // For further details, please see: // https://docs.opencv.org/master/d2/de8/group__core__array.html#gac5f92f48ec32cacf5275969c33ee837d func CartToPolar(x Mat, y Mat, magnitude *Mat, angle *Mat, angleInDegrees bool) error { return OpenCVResult(C.Mat_CartToPolar(x.p, y.p, magnitude.p, angle.p, C.bool(angleInDegrees))) } // CheckRange checks every element of an input array for invalid values. // // For further details, please see: // https://docs.opencv.org/master/d2/de8/group__core__array.html#ga2bd19d89cae59361416736f87e3c7a64 func CheckRange(src Mat) bool { return bool(C.Mat_CheckRange(src.p)) } // Compare performs the per-element comparison of two arrays // or an array and scalar value. // // For further details, please see: // https://docs.opencv.org/master/d2/de8/group__core__array.html#ga303cfb72acf8cbb36d884650c09a3a97 func Compare(src1 Mat, src2 Mat, dst *Mat, ct CompareType) error { return OpenCVResult(C.Mat_Compare(src1.p, src2.p, dst.p, C.int(ct))) } // CountNonZero counts non-zero array elements. // // For further details, please see: // https://docs.opencv.org/master/d2/de8/group__core__array.html#gaa4b89393263bb4d604e0fe5986723914 func CountNonZero(src Mat) int { return int(C.Mat_CountNonZero(src.p)) } // CompleteSymm copies the lower or the upper half of a square matrix to its another half. // // For further details, please see: // https://docs.opencv.org/master/d2/de8/group__core__array.html#gaa9d88dcd0e54b6d1af38d41f2a3e3d25 func CompleteSymm(m Mat, lowerToUpper bool) error { return OpenCVResult(C.Mat_CompleteSymm(m.p, C.bool(lowerToUpper))) } // ConvertScaleAbs scales, calculates absolute values, and converts the result to 8-bit. // // For further details, please see: // https://docs.opencv.org/master/d2/de8/group__core__array.html#ga3460e9c9f37b563ab9dd550c4d8c4e7d func ConvertScaleAbs(src Mat, dst *Mat, alpha float64, beta float64) error { return OpenCVResult(C.Mat_ConvertScaleAbs(src.p, dst.p, C.double(alpha), C.double(beta))) } // CopyMakeBorder forms a border around an image (applies padding). // // For further details, please see: // https://docs.opencv.org/master/d2/de8/group__core__array.html#ga2ac1049c2c3dd25c2b41bffe17658a36 func CopyMakeBorder(src Mat, dst *Mat, top int, bottom int, left int, right int, bt BorderType, value color.RGBA) error { cValue := C.struct_Scalar{ val1: C.double(value.B), val2: C.double(value.G), val3: C.double(value.R), val4: C.double(value.A), } return OpenCVResult(C.Mat_CopyMakeBorder(src.p, dst.p, C.int(top), C.int(bottom), C.int(left), C.int(right), C.int(bt), cValue)) } // DftFlags represents a DFT or DCT flag. // // For further details, please see: // https://docs.opencv.org/master/d2/de8/group__core__array.html#gaf4dde112b483b38175621befedda1f1c type DftFlags int const ( // DftForward performs forward 1D or 2D dft or dct. DftForward DftFlags = 0 // DftInverse performs an inverse 1D or 2D transform. DftInverse DftFlags = 1 // DftScale scales the result: divide it by the number of array elements. Normally, it is combined with DFT_INVERSE. DftScale DftFlags = 2 // DftRows performs a forward or inverse transform of every individual row of the input matrix. DftRows DftFlags = 4 // DftComplexOutput performs a forward transformation of 1D or 2D real array; the result, though being a complex array, has complex-conjugate symmetry DftComplexOutput DftFlags = 16 // DftRealOutput performs an inverse transformation of a 1D or 2D complex array; the result is normally a complex array of the same size, // however, if the input array has conjugate-complex symmetry (for example, it is a result of forward transformation with DFT_COMPLEX_OUTPUT flag), // the output is a real array. DftRealOutput DftFlags = 32 // DftComplexInput specifies that input is complex input. If this flag is set, the input must have 2 channels. DftComplexInput DftFlags = 64 // DctInverse performs an inverse 1D or 2D dct transform. DctInverse = DftInverse // DctRows performs a forward or inverse dct transform of every individual row of the input matrix. DctRows = DftRows ) // DCT performs a forward or inverse discrete Cosine transform of 1D or 2D array. // // For further details, please see: // https://docs.opencv.org/master/d2/de8/group__core__array.html#ga85aad4d668c01fbd64825f589e3696d4 func DCT(src Mat, dst *Mat, flags DftFlags) error { return OpenCVResult(C.Mat_DCT(src.p, dst.p, C.int(flags))) } // Determinant returns the determinant of a square floating-point matrix. // // For further details, please see: // https://docs.opencv.org/master/d2/de8/group__core__array.html#gaf802bd9ca3e07b8b6170645ef0611d0c func Determinant(src Mat) float64 { return float64(C.Mat_Determinant(src.p)) } // DFT performs a forward or inverse Discrete Fourier Transform (DFT) // of a 1D or 2D floating-point array. // // For further details, please see: // https://docs.opencv.org/master/d2/de8/group__core__array.html#gadd6cf9baf2b8b704a11b5f04aaf4f39d func DFT(src Mat, dst *Mat, flags DftFlags) error { return OpenCVResult(C.Mat_DFT(src.p, dst.p, C.int(flags))) } // Divide performs the per-element division // on two arrays or an array and a scalar. // // For further details, please see: // https://docs.opencv.org/master/d2/de8/group__core__array.html#ga6db555d30115642fedae0cda05604874 func Divide(src1 Mat, src2 Mat, dst *Mat) error { return OpenCVResult(C.Mat_Divide(src1.p, src2.p, dst.p)) } // Eigen calculates eigenvalues and eigenvectors of a symmetric matrix. // // For further details, please see: // https://docs.opencv.org/master/d2/de8/group__core__array.html#ga9fa0d58657f60eaa6c71f6fbb40456e3 func Eigen(src Mat, eigenvalues *Mat, eigenvectors *Mat) bool { ret := C.Mat_Eigen(src.p, eigenvalues.p, eigenvectors.p) return bool(ret) } // EigenNonSymmetric calculates eigenvalues and eigenvectors of a non-symmetric matrix (real eigenvalues only). // // For further details, please see: // https://docs.opencv.org/master/d2/de8/group__core__array.html#gaf51987e03cac8d171fbd2b327cf966f6 func EigenNonSymmetric(src Mat, eigenvalues *Mat, eigenvectors *Mat) error { return OpenCVResult(C.Mat_EigenNonSymmetric(src.p, eigenvalues.p, eigenvectors.p)) } // PCABackProject reconstructs vectors from their PC projections. // // For further details, please see: // https://docs.opencv.org/4.x/d2/de8/group__core__array.html#gab26049f30ee8e94f7d69d82c124faafc func PCABackProject(data Mat, mean Mat, eigenvectors Mat, result *Mat) error { return OpenCVResult(C.Mat_PCABackProject(data.p, mean.p, eigenvectors.p, result.p)) } // PCACompute performs PCA. // // The computed eigenvalues are sorted from the largest to the smallest and the corresponding // eigenvectors are stored as eigenvectors rows. // // Note: Calling with maxComponents == 0 (opencv default) will cause all components to be retained. // // For further details, please see: // https://docs.opencv.org/4.x/d2/de8/group__core__array.html#ga27a565b31d820b05dcbcd47112176b6e func PCACompute(src Mat, mean *Mat, eigenvectors *Mat, eigenvalues *Mat, maxComponents int) error { return OpenCVResult(C.Mat_PCACompute(src.p, mean.p, eigenvectors.p, eigenvalues.p, C.int(maxComponents))) } // PCAProject projects vector(s) to the principal component subspace. // // For further details, please see: // https://docs.opencv.org/4.x/d2/de8/group__core__array.html#ga6b9fbc7b3a99ebfd441bbec0a6bc4f88 func PCAProject(data Mat, mean Mat, eigenvectors Mat, result *Mat) error { return OpenCVResult(C.Mat_PCAProject(data.p, mean.p, eigenvectors.p, result.p)) } // PSNR computes the Peak Signal-to-Noise Ratio (PSNR) image quality metric. // // For further details, please see: // https://docs.opencv.org/4.x/d2/de8/group__core__array.html#ga3119e3ea73010a6f810bb05aa36ac8d6 func PSNR(src1 Mat, src2 Mat) float64 { return float64(C.PSNR(src1.p, src2.p)) } // SVBackSubst performs a singular value back substitution. // // For further details, please see: // https://docs.opencv.org/4.x/d2/de8/group__core__array.html#gab4e620e6fc6c8a27bb2be3d50a840c0b func SVBackSubst(w Mat, u Mat, vt Mat, rhs Mat, dst *Mat) error { return OpenCVResult(C.SVBackSubst(w.p, u.p, vt.p, rhs.p, dst.p)) } // SVDecomp decomposes matrix and stores the results to user-provided matrices. // // For further details, please see: // https://docs.opencv.org/4.x/d2/de8/group__core__array.html#gab477b5b7b39b370bb03e75b19d2d5109 func SVDecomp(src Mat, w *Mat, u *Mat, vt *Mat) error { return OpenCVResult(C.SVDecomp(src.p, w.p, u.p, vt.p)) } // Exp calculates the exponent of every array element. // // For further details, please see: // https://docs.opencv.org/master/d2/de8/group__core__array.html#ga3e10108e2162c338f1b848af619f39e5 func Exp(src Mat, dst *Mat) error { return OpenCVResult(C.Mat_Exp(src.p, dst.p)) } // ExtractChannel extracts a single channel from src (coi is 0-based index). // // For further details, please see: // https://docs.opencv.org/master/d2/de8/group__core__array.html#gacc6158574aa1f0281878c955bcf35642 func ExtractChannel(src Mat, dst *Mat, coi int) error { return OpenCVResult(C.Mat_ExtractChannel(src.p, dst.p, C.int(coi))) } // FindNonZero returns the list of locations of non-zero pixels. // // For further details, please see: // https://docs.opencv.org/master/d2/de8/group__core__array.html#gaed7df59a3539b4cc0fe5c9c8d7586190 func FindNonZero(src Mat, idx *Mat) error { return OpenCVResult(C.Mat_FindNonZero(src.p, idx.p)) } // Flip flips a 2D array around horizontal(0), vertical(1), or both axes(-1). // // For further details, please see: // https://docs.opencv.org/master/d2/de8/group__core__array.html#gaca7be533e3dac7feb70fc60635adf441 func Flip(src Mat, dst *Mat, flipCode int) error { return OpenCVResult(C.Mat_Flip(src.p, dst.p, C.int(flipCode))) } // Gemm performs generalized matrix multiplication. // // For further details, please see: // https://docs.opencv.org/master/d2/de8/group__core__array.html#gacb6e64071dffe36434e1e7ee79e7cb35 func Gemm(src1, src2 Mat, alpha float64, src3 Mat, beta float64, dst *Mat, flags int) error { return OpenCVResult(C.Mat_Gemm(src1.p, src2.p, C.double(alpha), src3.p, C.double(beta), dst.p, C.int(flags))) } // GetOptimalDFTSize returns the optimal Discrete Fourier Transform (DFT) size // for a given vector size. // // For further details, please see: // https://docs.opencv.org/master/d2/de8/group__core__array.html#ga6577a2e59968936ae02eb2edde5de299 func GetOptimalDFTSize(vecsize int) int { return int(C.Mat_GetOptimalDFTSize(C.int(vecsize))) } // Hconcat applies horizontal concatenation to given matrices. // // For further details, please see: // https://docs.opencv.org/master/d2/de8/group__core__array.html#gaab5ceee39e0580f879df645a872c6bf7 func Hconcat(src1, src2 Mat, dst *Mat) error { return OpenCVResult(C.Mat_Hconcat(src1.p, src2.p, dst.p)) } // Vconcat applies vertical concatenation to given matrices. // // For further details, please see: // https://docs.opencv.org/master/d2/de8/group__core__array.html#gaab5ceee39e0580f879df645a872c6bf7 func Vconcat(src1, src2 Mat, dst *Mat) error { return OpenCVResult(C.Mat_Vconcat(src1.p, src2.p, dst.p)) } // RotateFlag for image rotation // // For further details please see: // https://docs.opencv.org/master/d2/de8/group__core__array.html#ga6f45d55c0b1cc9d97f5353a7c8a7aac2 type RotateFlag int const ( // Rotate90Clockwise allows to rotate image 90 degrees clockwise Rotate90Clockwise RotateFlag = 0 // Rotate180Clockwise allows to rotate image 180 degrees clockwise Rotate180Clockwise RotateFlag = 1 // Rotate90CounterClockwise allows to rotate 270 degrees clockwise Rotate90CounterClockwise RotateFlag = 2 ) // Rotate rotates a 2D array in multiples of 90 degrees // // For further details, please see: // https://docs.opencv.org/master/d2/de8/group__core__array.html#ga4ad01c0978b0ce64baa246811deeac24 func Rotate(src Mat, dst *Mat, code RotateFlag) error { return OpenCVResult(C.Rotate(src.p, dst.p, C.int(code))) } // IDCT calculates the inverse Discrete Cosine Transform of a 1D or 2D array. // // For further details, please see: // https://docs.opencv.org/master/d2/de8/group__core__array.html#ga77b168d84e564c50228b69730a227ef2 func IDCT(src Mat, dst *Mat, flags int) error { return OpenCVResult(C.Mat_Idct(src.p, dst.p, C.int(flags))) } // IDFT calculates the inverse Discrete Fourier Transform of a 1D or 2D array. // // For further details, please see: // https://docs.opencv.org/master/d2/de8/group__core__array.html#gaa708aa2d2e57a508f968eb0f69aa5ff1 func IDFT(src Mat, dst *Mat, flags, nonzeroRows int) error { return OpenCVResult(C.Mat_Idft(src.p, dst.p, C.int(flags), C.int(nonzeroRows))) } // InRange checks if array elements lie between the elements of two Mat arrays. // // For further details, please see: // https://docs.opencv.org/master/d2/de8/group__core__array.html#ga48af0ab51e36436c5d04340e036ce981 func InRange(src, lb, ub Mat, dst *Mat) error { return OpenCVResult(C.Mat_InRange(src.p, lb.p, ub.p, dst.p)) } // InRangeWithScalar checks if array elements lie between the elements of two Scalars // // For further details, please see: // https://docs.opencv.org/master/d2/de8/group__core__array.html#ga48af0ab51e36436c5d04340e036ce981 func InRangeWithScalar(src Mat, lb, ub Scalar, dst *Mat) error { lbVal := C.struct_Scalar{ val1: C.double(lb.Val1), val2: C.double(lb.Val2), val3: C.double(lb.Val3), val4: C.double(lb.Val4), } ubVal := C.struct_Scalar{ val1: C.double(ub.Val1), val2: C.double(ub.Val2), val3: C.double(ub.Val3), val4: C.double(ub.Val4), } return OpenCVResult(C.Mat_InRangeWithScalar(src.p, lbVal, ubVal, dst.p)) } // InsertChannel inserts a single channel to dst (coi is 0-based index) // (it replaces channel i with another in dst). // // For further details, please see: // https://docs.opencv.org/master/d2/de8/group__core__array.html#ga1d4bd886d35b00ec0b764cb4ce6eb515 func InsertChannel(src Mat, dst *Mat, coi int) error { return OpenCVResult(C.Mat_InsertChannel(src.p, dst.p, C.int(coi))) } // Invert finds the inverse or pseudo-inverse of a matrix. // // For further details, please see: // https://docs.opencv.org/master/d2/de8/group__core__array.html#gad278044679d4ecf20f7622cc151aaaa2 func Invert(src Mat, dst *Mat, flags SolveDecompositionFlags) float64 { ret := C.Mat_Invert(src.p, dst.p, C.int(flags)) return float64(ret) } // KMeansFlags for kmeans center selection // // For further details, please see: // https://docs.opencv.org/master/d0/de1/group__core.html#ga276000efe55ee2756e0c471c7b270949 type KMeansFlags int const ( // KMeansRandomCenters selects random initial centers in each attempt. KMeansRandomCenters KMeansFlags = 0 // KMeansPPCenters uses kmeans++ center initialization by Arthur and Vassilvitskii [Arthur2007]. KMeansPPCenters KMeansFlags = 1 // KMeansUseInitialLabels uses the user-supplied lables during the first (and possibly the only) attempt // instead of computing them from the initial centers. For the second and further attempts, use the random or semi-random // centers. Use one of KMEANS_*_CENTERS flag to specify the exact method. KMeansUseInitialLabels KMeansFlags = 2 ) // KMeans finds centers of clusters and groups input samples around the clusters. // // For further details, please see: // https://docs.opencv.org/master/d5/d38/group__core__cluster.html#ga9a34dc06c6ec9460e90860f15bcd2f88 func KMeans(data Mat, k int, bestLabels *Mat, criteria TermCriteria, attempts int, flags KMeansFlags, centers *Mat) float64 { ret := C.KMeans(data.p, C.int(k), bestLabels.p, criteria.p, C.int(attempts), C.int(flags), centers.p) return float64(ret) } // KMeansPoints finds centers of clusters and groups input samples around the clusters. // // For further details, please see: // https://docs.opencv.org/master/d5/d38/group__core__cluster.html#ga9a34dc06c6ec9460e90860f15bcd2f88 func KMeansPoints(points PointVector, k int, bestLabels *Mat, criteria TermCriteria, attempts int, flags KMeansFlags, centers *Mat) float64 { ret := C.KMeansPoints(points.p, C.int(k), bestLabels.p, criteria.p, C.int(attempts), C.int(flags), centers.p) return float64(ret) } // Log calculates the natural logarithm of every array element. // // For further details, please see: // https://docs.opencv.org/master/d2/de8/group__core__array.html#ga937ecdce4679a77168730830a955bea7 func Log(src Mat, dst *Mat) error { return OpenCVResult(C.Mat_Log(src.p, dst.p)) } // Magnitude calculates the magnitude of 2D vectors. // // For further details, please see: // https://docs.opencv.org/master/d2/de8/group__core__array.html#ga6d3b097586bca4409873d64a90fe64c3 func Magnitude(x, y Mat, magnitude *Mat) error { return OpenCVResult(C.Mat_Magnitude(x.p, y.p, magnitude.p)) } // Mahalanobis calculates the Mahalanobis distance between two vectors. // // For further details, please see: // https://docs.opencv.org/4.x/d2/de8/group__core__array.html#ga4493aee129179459cbfc6064f051aa7d func Mahalanobis(v1, v2, icovar Mat) float64 { return float64(C.Mat_Mahalanobis(v1.p, v2.p, icovar.p)) } // MulTransposed calculates the product of a matrix and its transposition. // // For further details, please see: // https://docs.opencv.org/4.x/d2/de8/group__core__array.html#gadc4e49f8f7a155044e3be1b9e3b270ab func MulTransposed(src Mat, dest *Mat, ata bool) error { return OpenCVResult(C.MulTransposed(src.p, dest.p, C.bool(ata))) } // Max calculates per-element maximum of two arrays or an array and a scalar. // // For further details, please see: // https://docs.opencv.org/master/d2/de8/group__core__array.html#gacc40fa15eac0fb83f8ca70b7cc0b588d func Max(src1, src2 Mat, dst *Mat) error { return OpenCVResult(C.Mat_Max(src1.p, src2.p, dst.p)) } // MeanStdDev calculates a mean and standard deviation of array elements. // // For further details, please see: // https://docs.opencv.org/master/d2/de8/group__core__array.html#ga846c858f4004d59493d7c6a4354b301d func MeanStdDev(src Mat, dst *Mat, dstStdDev *Mat) error { return OpenCVResult(C.Mat_MeanStdDev(src.p, dst.p, dstStdDev.p)) } // MeanStdDevWithMask calculates a mean and standard deviation of array elements while applying the mask. // // For further details, please see: // https://docs.opencv.org/4.x/d2/de8/group__core__array.html#ga846c858f4004d59493d7c6a4354b301d func MeanStdDevWithMask(src Mat, dstMean *Mat, dstStdDev *Mat, mask Mat) error { return OpenCVResult(C.Mat_MeanStdDevWithMask(src.p, dstMean.p, dstStdDev.p, mask.p)) } // Merge creates one multi-channel array out of several single-channel ones. // // For further details, please see: // https://docs.opencv.org/master/d2/de8/group__core__array.html#ga7d7b4d6c6ee504b30a20b1680029c7b4 func Merge(mv []Mat, dst *Mat) error { cMatArray := make([]C.Mat, len(mv)) for i, r := range mv { cMatArray[i] = r.p } cMats := C.struct_Mats{ mats: (*C.Mat)(&cMatArray[0]), length: C.int(len(mv)), } return OpenCVResult(C.Mat_Merge(cMats, dst.p)) } // Min calculates per-element minimum of two arrays or an array and a scalar. // // For further details, please see: // https://docs.opencv.org/master/d2/de8/group__core__array.html#ga9af368f182ee76d0463d0d8d5330b764 func Min(src1, src2 Mat, dst *Mat) error { return OpenCVResult(C.Mat_Min(src1.p, src2.p, dst.p)) } // MinMaxIdx finds the global minimum and maximum in an array. // // For further details, please see: // https://docs.opencv.org/master/d2/de8/group__core__array.html#ga7622c466c628a75d9ed008b42250a73f func MinMaxIdx(input Mat) (minVal, maxVal float32, minIdx, maxIdx int) { var cMinVal C.double var cMaxVal C.double var cMinIdx C.int var cMaxIdx C.int C.Mat_MinMaxIdx(input.p, &cMinVal, &cMaxVal, &cMinIdx, &cMaxIdx) return float32(cMinVal), float32(cMaxVal), int(minIdx), int(maxIdx) } // MinMaxLoc finds the global minimum and maximum in an array. // // For further details, please see: // https://docs.opencv.org/trunk/d2/de8/group__core__array.html#gab473bf2eb6d14ff97e89b355dac20707 func MinMaxLoc(input Mat) (minVal, maxVal float32, minLoc, maxLoc image.Point) { var cMinVal C.double var cMaxVal C.double var cMinLoc C.struct_Point var cMaxLoc C.struct_Point C.Mat_MinMaxLoc(input.p, &cMinVal, &cMaxVal, &cMinLoc, &cMaxLoc) minLoc = image.Pt(int(cMinLoc.x), int(cMinLoc.y)) maxLoc = image.Pt(int(cMaxLoc.x), int(cMaxLoc.y)) return float32(cMinVal), float32(cMaxVal), minLoc, maxLoc } // MinMaxLocWithMask finds the global minimum and maximum in an array with a mask used to select a sub-array. // // For further details, please see: // https://docs.opencv.org/4.x/d2/de8/group__core__array.html#gab473bf2eb6d14ff97e89b355dac20707 func MinMaxLocWithMask(input, mask Mat) (minVal, maxVal float32, minLoc, maxLoc image.Point) { var cMinVal C.double var cMaxVal C.double var cMinLoc C.struct_Point var cMaxLoc C.struct_Point C.Mat_MinMaxLocWithMask(input.p, &cMinVal, &cMaxVal, &cMinLoc, &cMaxLoc, mask.p) minLoc = image.Pt(int(cMinLoc.x), int(cMinLoc.y)) maxLoc = image.Pt(int(cMaxLoc.x), int(cMaxLoc.y)) return float32(cMinVal), float32(cMaxVal), minLoc, maxLoc } // Copies specified channels from input arrays to the specified channels of output arrays. // // For further details, please see: // https://docs.opencv.org/master/d2/de8/group__core__array.html#ga51d768c270a1cdd3497255017c4504be func MixChannels(src []Mat, dst []Mat, fromTo []int) error { cSrcArray := make([]C.Mat, len(src)) for i, r := range src { cSrcArray[i] = r.p } cSrcMats := C.struct_Mats{ mats: (*C.Mat)(&cSrcArray[0]), length: C.int(len(src)), } cDstArray := make([]C.Mat, len(dst)) for i, r := range dst { cDstArray[i] = r.p } cDstMats := C.struct_Mats{ mats: (*C.Mat)(&cDstArray[0]), length: C.int(len(dst)), } cFromToArray := make([]C.int, len(fromTo)) for i, ft := range fromTo { cFromToArray[i] = C.int(ft) } cFromToIntVector := C.IntVector{ val: (*C.int)(&cFromToArray[0]), length: C.int(len(fromTo)), } C.Mat_MixChannels(cSrcMats, cDstMats, cFromToIntVector) for i := C.int(0); i < cDstMats.length; i++ { dst[i].p = C.Mats_get(cDstMats, i) } return LastExceptionError() } // Mulspectrums performs the per-element multiplication of two Fourier spectrums. // // For further details, please see: // https://docs.opencv.org/master/d2/de8/group__core__array.html#ga3ab38646463c59bf0ce962a9d51db64f func MulSpectrums(a Mat, b Mat, dst *Mat, flags DftFlags) error { return OpenCVResult(C.Mat_MulSpectrums(a.p, b.p, dst.p, C.int(flags))) } // Multiply calculates the per-element scaled product of two arrays. // Both input arrays must be of the same size and the same type. // // For further details, please see: // https://docs.opencv.org/master/d2/de8/group__core__array.html#ga979d898a58d7f61c53003e162e7ad89f func Multiply(src1 Mat, src2 Mat, dst *Mat) error { return OpenCVResult(C.Mat_Multiply(src1.p, src2.p, dst.p)) } // MultiplyWithParams calculates the per-element scaled product of two arrays. // Both input arrays must be of the same size and the same type. // // For further details, please see: // https://docs.opencv.org/master/d2/de8/group__core__array.html#ga979d898a58d7f61c53003e162e7ad89f func MultiplyWithParams(src1 Mat, src2 Mat, dst *Mat, scale float64, dtype MatType) error { return OpenCVResult(C.Mat_MultiplyWithParams(src1.p, src2.p, dst.p, C.double(scale), C.int(dtype))) } // NormType for normalization operations. // // For further details, please see: // https://docs.opencv.org/master/d2/de8/group__core__array.html#gad12cefbcb5291cf958a85b4b67b6149f type NormType int const ( // NormInf indicates use infinite normalization. NormInf NormType = 1 // NormL1 indicates use L1 normalization. NormL1 NormType = 2 // NormL2 indicates use L2 normalization. NormL2 NormType = 4 // NormL2Sqr indicates use L2 squared normalization. NormL2Sqr NormType = 5 // NormHamming indicates use Hamming normalization. NormHamming NormType = 6 // NormHamming2 indicates use Hamming 2-bit normalization. NormHamming2 NormType = 7 // NormTypeMask indicates use type mask for normalization. NormTypeMask NormType = 7 // NormRelative indicates use relative normalization. NormRelative NormType = 8 // NormMinMax indicates use min/max normalization. NormMinMax NormType = 32 ) // Normalize normalizes the norm or value range of an array. // // For further details, please see: // https://docs.opencv.org/master/d2/de8/group__core__array.html#ga87eef7ee3970f86906d69a92cbf064bd func Normalize(src Mat, dst *Mat, alpha float64, beta float64, typ NormType) error { return OpenCVResult(C.Mat_Normalize(src.p, dst.p, C.double(alpha), C.double(beta), C.int(typ))) } // Norm calculates the absolute norm of an array. // // For further details, please see: // https://docs.opencv.org/master/d2/de8/group__core__array.html#ga7c331fb8dd951707e184ef4e3f21dd33 func Norm(src1 Mat, normType NormType) float64 { return float64(C.Norm(src1.p, C.int(normType))) } // Norm calculates the absolute difference/relative norm of two arrays. // // For further details, please see: // https://docs.opencv.org/master/d2/de8/group__core__array.html#ga7c331fb8dd951707e184ef4e3f21dd33 func NormWithMats(src1 Mat, src2 Mat, normType NormType) float64 { return float64(C.NormWithMats(src1.p, src2.p, C.int(normType))) } // PerspectiveTransform performs the perspective matrix transformation of vectors. // // For further details, please see: // https://docs.opencv.org/master/d2/de8/group__core__array.html#gad327659ac03e5fd6894b90025e6900a7 func PerspectiveTransform(src Mat, dst *Mat, tm Mat) error { return OpenCVResult(C.Mat_PerspectiveTransform(src.p, dst.p, tm.p)) } // TermCriteriaType for TermCriteria. // // For further details, please see: // https://docs.opencv.org/master/d9/d5d/classcv_1_1TermCriteria.html#a56fecdc291ccaba8aad27d67ccf72c57 type TermCriteriaType int const ( // Count is the maximum number of iterations or elements to compute. Count TermCriteriaType = 1 // MaxIter is the maximum number of iterations or elements to compute. MaxIter TermCriteriaType = 1 // EPS is the desired accuracy or change in parameters at which the // iterative algorithm stops. EPS TermCriteriaType = 2 ) type SolveDecompositionFlags int const ( // Gaussian elimination with the optimal pivot element chosen. SolveDecompositionLu SolveDecompositionFlags = 0 // Singular value decomposition (SVD) method. The system can be over-defined and/or the matrix src1 can be singular. SolveDecompositionSvd SolveDecompositionFlags = 1 // Eigenvalue decomposition. The matrix src1 must be symmetrical. SolveDecompositionEing SolveDecompositionFlags = 2 // Cholesky LL^T factorization. The matrix src1 must be symmetrical and positively defined. SolveDecompositionCholesky SolveDecompositionFlags = 3 // QR factorization. The system can be over-defined and/or the matrix src1 can be singular. SolveDecompositionQr SolveDecompositionFlags = 4 // While all the previous flags are mutually exclusive, this flag can be used together with any of the previous. // It means that the normal equations 𝚜𝚛𝚌𝟷^T⋅𝚜𝚛𝚌𝟷⋅𝚍𝚜𝚝=𝚜𝚛𝚌𝟷^T𝚜𝚛𝚌𝟸 are solved instead of the original system // 𝚜𝚛𝚌𝟷⋅𝚍𝚜𝚝=𝚜𝚛𝚌𝟸. SolveDecompositionNormal SolveDecompositionFlags = 5 ) // Solve solves one or more linear systems or least-squares problems. // // For further details, please see: // https://docs.opencv.org/master/d2/de8/group__core__array.html#ga12b43690dbd31fed96f213eefead2373 func Solve(src1 Mat, src2 Mat, dst *Mat, flags SolveDecompositionFlags) bool { return bool(C.Mat_Solve(src1.p, src2.p, dst.p, C.int(flags))) } // SolveCubic finds the real roots of a cubic equation. // // For further details, please see: // https://docs.opencv.org/master/d2/de8/group__core__array.html#ga1c3b0b925b085b6e96931ee309e6a1da func SolveCubic(coeffs Mat, roots *Mat) int { return int(C.Mat_SolveCubic(coeffs.p, roots.p)) } // SolvePoly finds the real or complex roots of a polynomial equation. // // For further details, please see: // https://docs.opencv.org/master/d2/de8/group__core__array.html#gac2f5e953016fabcdf793d762f4ec5dce func SolvePoly(coeffs Mat, roots *Mat, maxIters int) float64 { return float64(C.Mat_SolvePoly(coeffs.p, roots.p, C.int(maxIters))) } type ReduceTypes int const ( // The output is the sum of all rows/columns of the matrix. ReduceSum ReduceTypes = 0 // The output is the mean vector of all rows/columns of the matrix. ReduceAvg ReduceTypes = 1 // The output is the maximum (column/row-wise) of all rows/columns of the matrix. ReduceMax ReduceTypes = 2 // The output is the minimum (column/row-wise) of all rows/columns of the matrix. ReduceMin ReduceTypes = 3 ) // Reduce reduces a matrix to a vector. // // For further details, please see: // https://docs.opencv.org/master/d2/de8/group__core__array.html#ga4b78072a303f29d9031d56e5638da78e func Reduce(src Mat, dst *Mat, dim int, rType ReduceTypes, dType MatType) error { return OpenCVResult(C.Mat_Reduce(src.p, dst.p, C.int(dim), C.int(rType), C.int(dType))) } // Finds indices of max elements along provided axis. // // For further details, please see: // https://docs.opencv.org/master/d2/de8/group__core__array.html#gaa87ea34d99bcc5bf9695048355163da0 func ReduceArgMax(src Mat, dst *Mat, axis int, lastIndex bool) error { return OpenCVResult(C.Mat_ReduceArgMax(src.p, dst.p, C.int(axis), C.bool(lastIndex))) } // Finds indices of min elements along provided axis. // // For further details, please see: // https://docs.opencv.org/master/d2/de8/group__core__array.html#gaeecd548276bfb91b938989e66b722088 func ReduceArgMin(src Mat, dst *Mat, axis int, lastIndex bool) error { return OpenCVResult(C.Mat_ReduceArgMin(src.p, dst.p, C.int(axis), C.bool(lastIndex))) } // Repeat fills the output array with repeated copies of the input array. // // For further details, please see: // https://docs.opencv.org/master/d2/de8/group__core__array.html#ga496c3860f3ac44c40b48811333cfda2d func Repeat(src Mat, nY int, nX int, dst *Mat) error { return OpenCVResult(C.Mat_Repeat(src.p, C.int(nY), C.int(nX), dst.p)) } // Calculates the sum of a scaled array and another array. // // For further details, please see: // https://docs.opencv.org/master/d2/de8/group__core__array.html#ga9e0845db4135f55dcf20227402f00d98 func ScaleAdd(src1 Mat, alpha float64, src2 Mat, dst *Mat) error { return OpenCVResult(C.Mat_ScaleAdd(src1.p, C.double(alpha), src2.p, dst.p)) } // SetIdentity initializes a scaled identity matrix. // For further details, please see: // // https://docs.opencv.org/master/d2/de8/group__core__array.html#ga388d7575224a4a277ceb98ccaa327c99 func SetIdentity(src Mat, scalar float64) error { return OpenCVResult(C.Mat_SetIdentity(src.p, C.double(scalar))) } type SortFlags int const ( // Each matrix row is sorted independently SortEveryRow SortFlags = 0 // Each matrix column is sorted independently; this flag and the previous one are mutually exclusive. SortEveryColumn SortFlags = 1 // Each matrix row is sorted in the ascending order. SortAscending SortFlags = 0 // Each matrix row is sorted in the descending order; this flag and the previous one are also mutually exclusive. SortDescending SortFlags = 16 ) // Sort sorts each row or each column of a matrix. // // For further details, please see: // https://docs.opencv.org/master/d2/de8/group__core__array.html#ga45dd56da289494ce874be2324856898f func Sort(src Mat, dst *Mat, flags SortFlags) error { return OpenCVResult(C.Mat_Sort(src.p, dst.p, C.int(flags))) } // SortIdx sorts each row or each column of a matrix. // Instead of reordering the elements themselves, it stores the indices of sorted elements in the output array // // For further details, please see: // https://docs.opencv.org/master/d2/de8/group__core__array.html#gadf35157cbf97f3cb85a545380e383506 func SortIdx(src Mat, dst *Mat, flags SortFlags) error { return OpenCVResult(C.Mat_SortIdx(src.p, dst.p, C.int(flags))) } // Split creates an array of single channel images from a multi-channel image // Created images should be closed manualy to avoid memory leaks. // // For further details, please see: // https://docs.opencv.org/master/d2/de8/group__core__array.html#ga0547c7fed86152d7e9d0096029c8518a func Split(src Mat) (mv []Mat) { cMats := C.struct_Mats{} C.Mat_Split(src.p, &(cMats)) defer C.Mats_Close(cMats) mv = make([]Mat, cMats.length) for i := C.int(0); i < cMats.length; i++ { mv[i].p = C.Mats_get(cMats, i) addMatToProfile(mv[i].p) } return } // Subtract calculates the per-element subtraction of two arrays or an array and a scalar. // // For further details, please see: // https://docs.opencv.org/master/d2/de8/group__core__array.html#gaa0f00d98b4b5edeaeb7b8333b2de353b func Subtract(src1 Mat, src2 Mat, dst *Mat) error { return OpenCVResult(C.Mat_Subtract(src1.p, src2.p, dst.p)) } // Trace returns the trace of a matrix. // // For further details, please see: // https://docs.opencv.org/master/d2/de8/group__core__array.html#ga3419ac19c7dcd2be4bd552a23e147dd8 func Trace(src Mat) Scalar { s := C.Mat_Trace(src.p) return NewScalar(float64(s.val1), float64(s.val2), float64(s.val3), float64(s.val4)) } // Transform performs the matrix transformation of every array element. // // For further details, please see: // https://docs.opencv.org/master/d2/de8/group__core__array.html#ga393164aa54bb9169ce0a8cc44e08ff22 func Transform(src Mat, dst *Mat, tm Mat) error { return OpenCVResult(C.Mat_Transform(src.p, dst.p, tm.p)) } // Transpose transposes a matrix. // // For further details, please see: // https://docs.opencv.org/master/d2/de8/group__core__array.html#ga46630ed6c0ea6254a35f447289bd7404 func Transpose(src Mat, dst *Mat) error { return OpenCVResult(C.Mat_Transpose(src.p, dst.p)) } // TransposeND transpose for n-dimensional matrices. // // For further details, please see: // https://docs.opencv.org/master/d2/de8/group__core__array.html#gab1b1274b4a563be34cdfa55b8919a4ec func TransposeND(src Mat, order []int, dst *Mat) error { cOrderArray := make([]C.int, len(order)) for i, o := range order { cOrderArray[i] = C.int(o) } cOrderVector := C.IntVector{ val: (*C.int)(&cOrderArray[0]), length: C.int(len(order)), } return OpenCVResult(C.Mat_TransposeND(src.p, cOrderVector, dst.p)) } // Pow raises every array element to a power. // // For further details, please see: // https://docs.opencv.org/master/d2/de8/group__core__array.html#gaf0d056b5bd1dc92500d6f6cf6bac41ef func Pow(src Mat, power float64, dst *Mat) error { return OpenCVResult(C.Mat_Pow(src.p, C.double(power), dst.p)) } // PolatToCart calculates x and y coordinates of 2D vectors from their magnitude and angle. // // For further details, please see: // https://docs.opencv.org/master/d2/de8/group__core__array.html#ga581ff9d44201de2dd1b40a50db93d665 func PolarToCart(magnitude Mat, degree Mat, x *Mat, y *Mat, angleInDegrees bool) error { return OpenCVResult(C.Mat_PolarToCart(magnitude.p, degree.p, x.p, y.p, C.bool(angleInDegrees))) } // Phase calculates the rotation angle of 2D vectors. // // For further details, please see: // https://docs.opencv.org/master/d2/de8/group__core__array.html#ga9db9ca9b4d81c3bde5677b8f64dc0137 func Phase(x, y Mat, angle *Mat, angleInDegrees bool) error { return OpenCVResult(C.Mat_Phase(x.p, y.p, angle.p, C.bool(angleInDegrees))) } // TermCriteria is the criteria for iterative algorithms. // // For further details, please see: // https://docs.opencv.org/master/d9/d5d/classcv_1_1TermCriteria.html type TermCriteria struct { p C.TermCriteria } // NewTermCriteria returns a new TermCriteria. func NewTermCriteria(typ TermCriteriaType, maxCount int, epsilon float64) TermCriteria { return TermCriteria{p: C.TermCriteria_New(C.int(typ), C.int(maxCount), C.double(epsilon))} } // Ptr returns the underlying C.TermCriteria func (tc *TermCriteria) Ptr() C.TermCriteria { return tc.p } // Scalar is a 4-element vector widely used in OpenCV to pass pixel values. // // For further details, please see: // http://docs.opencv.org/master/d1/da0/classcv_1_1Scalar__.html type Scalar struct { Val1 float64 Val2 float64 Val3 float64 Val4 float64 } // NewScalar returns a new Scalar. These are usually colors typically being in BGR order. func NewScalar(v1 float64, v2 float64, v3 float64, v4 float64) Scalar { s := Scalar{Val1: v1, Val2: v2, Val3: v3, Val4: v4} return s } // KeyPoint is data structure for salient point detectors. // // For further details, please see: // https://docs.opencv.org/master/d2/d29/classcv_1_1KeyPoint.html type KeyPoint struct { X, Y float64 Size, Angle, Response float64 Octave, ClassID int } // DMatch is data structure for matching keypoint descriptors. // // For further details, please see: // https://docs.opencv.org/master/d4/de0/classcv_1_1DMatch.html#a546ddb9a87898f06e510e015a6de596e type DMatch struct { QueryIdx int TrainIdx int ImgIdx int Distance float64 } // Vecb is a generic vector of bytes. type Vecb []uint8 // GetVecbAt returns a vector of bytes. Its size corresponds to the number // of channels of the Mat. func (m *Mat) GetVecbAt(row int, col int) Vecb { ch := m.Channels() v := make(Vecb, ch) for c := 0; c < ch; c++ { v[c] = m.GetUCharAt(row, col*ch+c) } return v } // Vecf is a generic vector of floats. type Vecf []float32 // GetVecfAt returns a vector of floats. Its size corresponds to the number of // channels of the Mat. func (m *Mat) GetVecfAt(row int, col int) Vecf { ch := m.Channels() v := make(Vecf, ch) for c := 0; c < ch; c++ { v[c] = m.GetFloatAt(row, col*ch+c) } return v } // Vecd is a generic vector of float64/doubles. type Vecd []float64 // GetVecdAt returns a vector of float64s. Its size corresponds to the number // of channels of the Mat. func (m *Mat) GetVecdAt(row int, col int) Vecd { ch := m.Channels() v := make(Vecd, ch) for c := 0; c < ch; c++ { v[c] = m.GetDoubleAt(row, col*ch+c) } return v } // Veci is a generic vector of integers. type Veci []int32 // GetVeciAt returns a vector of integers. Its size corresponds to the number // of channels of the Mat. func (m *Mat) GetVeciAt(row int, col int) Veci { ch := m.Channels() v := make(Veci, ch) for c := 0; c < ch; c++ { v[c] = m.GetIntAt(row, col*ch+c) } return v } // PointVector is a wrapper around a std::vector< cv::Point >* // This is needed anytime that you need to pass or receive a collection of points. type PointVector struct { p C.PointVector } // NewPointVector returns a new empty PointVector. func NewPointVector() PointVector { return PointVector{p: C.PointVector_New()} } // NewPointVectorFromPoints returns a new PointVector that has been // initialized to a slice of image.Point. func NewPointVectorFromPoints(pts []image.Point) PointVector { p := (*C.struct_Point)(C.malloc(C.size_t(C.sizeof_struct_Point * len(pts)))) defer C.free(unsafe.Pointer(p)) h := unsafe.Slice(p, len(pts)) for j, point := range pts { h[j] = C.struct_Point{ x: C.int(point.X), y: C.int(point.Y), } } cpoints := C.struct_Points{ points: (*C.Point)(p), length: C.int(len(pts)), } return PointVector{p: C.PointVector_NewFromPoints(cpoints)} } // NewPointVectorFromMat returns a new PointVector that has been // wrapped around a Mat of type CV_32SC2 with a single columm. func NewPointVectorFromMat(mat Mat) PointVector { return PointVector{p: C.PointVector_NewFromMat(mat.p)} } // IsNil checks the CGo pointer in the PointVector. func (pv PointVector) IsNil() bool { return pv.p == nil } // Size returns how many Point are in the PointVector. func (pv PointVector) Size() int { return int(C.PointVector_Size(pv.p)) } // At returns the image.Point func (pv PointVector) At(idx int) image.Point { if idx > pv.Size() { return image.Point{} } cp := C.PointVector_At(pv.p, C.int(idx)) return image.Pt(int(cp.x), int(cp.y)) } // Append appends an image.Point at end of the PointVector. func (pv PointVector) Append(point image.Point) { p := C.struct_Point{ x: C.int(point.X), y: C.int(point.Y), } C.PointVector_Append(pv.p, p) return } // ToPoints returns a slice of image.Point for the data in this PointVector. func (pv PointVector) ToPoints() []image.Point { points := make([]image.Point, pv.Size()) for j := 0; j < pv.Size(); j++ { points[j] = pv.At(j) } return points } // Close closes and frees memory for this PointVector. func (pv PointVector) Close() { C.PointVector_Close(pv.p) } // PointsVector is a wrapper around a std::vector< std::vector< cv::Point > >* type PointsVector struct { p C.PointsVector } // NewPointsVector returns a new empty PointsVector. func NewPointsVector() PointsVector { return PointsVector{p: C.PointsVector_New()} } // NewPointsVectorFromPoints returns a new PointsVector that has been // initialized to a slice of slices of image.Point. func NewPointsVectorFromPoints(pts [][]image.Point) PointsVector { if len(pts) <= 0 { return NewPointsVector() } points := make([]C.struct_Points, len(pts)) for i, pt := range pts { p := (*C.struct_Point)(C.malloc(C.size_t(C.sizeof_struct_Point * len(pt)))) defer C.free(unsafe.Pointer(p)) h := &reflect.SliceHeader{ Data: uintptr(unsafe.Pointer(p)), Len: len(pt), Cap: len(pt), } pa := *(*[]C.Point)(unsafe.Pointer(h)) for j, point := range pt { pa[j] = C.struct_Point{ x: C.int(point.X), y: C.int(point.Y), } } points[i] = C.struct_Points{ points: (*C.Point)(p), length: C.int(len(pt)), } } cPoints := C.struct_Contours{ contours: (*C.struct_Points)(&points[0]), length: C.int(len(pts)), } return PointsVector{p: C.PointsVector_NewFromPoints(cPoints)} } func (pvs PointsVector) P() C.PointsVector { return pvs.p } // ToPoints returns a slice of slices of image.Point for the data in this PointsVector. func (pvs PointsVector) ToPoints() [][]image.Point { ppoints := make([][]image.Point, pvs.Size()) for i := 0; i < pvs.Size(); i++ { pts := pvs.At(i) points := make([]image.Point, pts.Size()) for j := 0; j < pts.Size(); j++ { points[j] = pts.At(j) } ppoints[i] = points } return ppoints } // IsNil checks the CGo pointer in the PointsVector. func (pvs PointsVector) IsNil() bool { return pvs.p == nil } // Size returns how many vectors of Points are in the PointsVector. func (pvs PointsVector) Size() int { return int(C.PointsVector_Size(pvs.p)) } // At returns the PointVector at that index of the PointsVector. func (pvs PointsVector) At(idx int) PointVector { if idx > pvs.Size() { return PointVector{} } return PointVector{p: C.PointsVector_At(pvs.p, C.int(idx))} } // Append appends a PointVector at end of the PointsVector. func (pvs PointsVector) Append(pv PointVector) { if !pv.IsNil() { C.PointsVector_Append(pvs.p, pv.p) } return } // Close closes and frees memory for this PointsVector. func (pvs PointsVector) Close() { C.PointsVector_Close(pvs.p) } // Point2fVector is a wrapper around a std::vector< cv::Point2f >* // This is needed anytime that you need to pass or receive a collection of points. type Point2fVector struct { p C.Point2fVector } // NewPoint2fVector returns a new empty Point2fVector. func NewPoint2fVector() Point2fVector { return Point2fVector{p: C.Point2fVector_New()} } // NewPoint2fVectorFromPoints returns a new Point2fVector that has been // initialized to a slice of image.Point. func NewPoint2fVectorFromPoints(pts []Point2f) Point2fVector { p := (*C.struct_Point2f)(C.malloc(C.size_t(C.sizeof_struct_Point2f * len(pts)))) defer C.free(unsafe.Pointer(p)) h := &reflect.SliceHeader{ Data: uintptr(unsafe.Pointer(p)), Len: len(pts), Cap: len(pts), } pa := *(*[]C.Point2f)(unsafe.Pointer(h)) for j, point := range pts { pa[j] = C.struct_Point2f{ x: C.float(point.X), y: C.float(point.Y), } } cpoints := C.struct_Points2f{ points: (*C.Point2f)(p), length: C.int(len(pts)), } return Point2fVector{p: C.Point2fVector_NewFromPoints(cpoints)} } // NewPoint2fVectorFromMat returns a new Point2fVector that has been // wrapped around a Mat of type CV_32FC2 with a single columm. func NewPoint2fVectorFromMat(mat Mat) Point2fVector { return Point2fVector{p: C.Point2fVector_NewFromMat(mat.p)} } // IsNil checks the CGo pointer in the Point2fVector. func (pfv Point2fVector) IsNil() bool { return pfv.p == nil } // Size returns how many Point are in the PointVector. func (pfv Point2fVector) Size() int { return int(C.Point2fVector_Size(pfv.p)) } // At returns the image.Point func (pfv Point2fVector) At(idx int) Point2f { if idx > pfv.Size() { return Point2f{} } cp := C.Point2fVector_At(pfv.p, C.int(idx)) return Point2f{float32(cp.x), float32(cp.y)} } // ToPoints returns a slice of image.Point for the data in this PointVector. func (pfv Point2fVector) ToPoints() []Point2f { points := make([]Point2f, pfv.Size()) for j := 0; j < pfv.Size(); j++ { points[j] = pfv.At(j) } return points } // Close closes and frees memory for this Point2fVector. func (pfv Point2fVector) Close() { C.Point2fVector_Close(pfv.p) } // GetTickCount returns the number of ticks. // // For further details, please see: // https://docs.opencv.org/master/db/de0/group__core__utils.html#gae73f58000611a1af25dd36d496bf4487 func GetTickCount() float64 { return float64(C.GetCVTickCount()) } // GetTickFrequency returns the number of ticks per second. // // For further details, please see: // https://docs.opencv.org/master/db/de0/group__core__utils.html#ga705441a9ef01f47acdc55d87fbe5090c func GetTickFrequency() float64 { return float64(C.GetTickFrequency()) } func toByteArray(b []byte) (*C.struct_ByteArray, error) { if len(b) == 0 { return nil, ErrEmptyByteSlice } return &C.struct_ByteArray{ data: (*C.char)(unsafe.Pointer(&b[0])), length: C.int(len(b)), }, nil } func toGoBytes(b C.struct_ByteArray) []byte { return C.GoBytes(unsafe.Pointer(b.data), b.length) } // Converts CStrings to a slice of Go strings even when the C strings are not contiguous in memory func toGoStrings(strs C.CStrings) []string { length := int(strs.length) tmpslice := (*[1 << 20]*C.char)(unsafe.Pointer(strs.strs))[:length:length] gostrings := make([]string, length) for i, s := range tmpslice { gostrings[i] = C.GoString(s) } return gostrings } func toRectangles(ret C.Rects) []image.Rectangle { cArray := ret.rects length := int(ret.length) hdr := reflect.SliceHeader{ Data: uintptr(unsafe.Pointer(cArray)), Len: length, Cap: length, } s := *(*[]C.Rect)(unsafe.Pointer(&hdr)) rects := make([]image.Rectangle, length) for i, r := range s { rects[i] = image.Rect(int(r.x), int(r.y), int(r.x+r.width), int(r.y+r.height)) } return rects } func toRect(rect C.Rect) image.Rectangle { return image.Rect(int(rect.x), int(rect.y), int(rect.x+rect.width), int(rect.y+rect.height)) } func toCPoints(points []image.Point) C.struct_Points { cPointSlice := make([]C.struct_Point, len(points)) for i, point := range points { cPointSlice[i] = C.struct_Point{ x: C.int(point.X), y: C.int(point.Y), } } return C.struct_Points{ points: (*C.Point)(&cPointSlice[0]), length: C.int(len(points)), } } func toCPoints2f(points []Point2f) C.struct_Points2f { cPointSlice := make([]C.struct_Point2f, len(points)) for i, point := range points { cPointSlice[i] = C.struct_Point2f{ x: C.float(point.X), y: C.float(point.Y), } } return C.struct_Points2f{ points: (*C.Point2f)(&cPointSlice[0]), length: C.int(len(points)), } } func toCStrings(strs []string) C.struct_CStrings { cStringsSlice := make([]*C.char, len(strs)) for i, s := range strs { cStringsSlice[i] = C.CString(s) } return C.struct_CStrings{ strs: (**C.char)(&cStringsSlice[0]), length: C.int(len(strs)), } } // RowRange creates a matrix header for the specified row span. // // For further details, please see: // https://docs.opencv.org/master/d3/d63/classcv_1_1Mat.html#aa6542193430356ad631a9beabc624107 func (m *Mat) RowRange(start, end int) Mat { return newMat(C.Mat_rowRange(m.p, C.int(start), C.int(end))) } // ColRange creates a matrix header for the specified column span. // // For further details, please see: // https://docs.opencv.org/master/d3/d63/classcv_1_1Mat.html#aadc8f9210fe4dec50513746c246fa8d9 func (m *Mat) ColRange(start, end int) Mat { return newMat(C.Mat_colRange(m.p, C.int(start), C.int(end))) } // RNG Random Number Generator. // It encapsulates the state (currently, a 64-bit integer) and // has methods to return scalar random values and to fill arrays // with random values // // For further details, please see: // https://docs.opencv.org/master/d1/dd6/classcv_1_1RNG.html type RNG struct { p C.RNG } type RNGDistType int const ( // Uniform distribution RNGDistUniform RNGDistType = 0 // Normal distribution RNGDistNormal RNGDistType = 1 ) // TheRNG Returns the default random number generator. // // For further details, please see: // https://docs.opencv.org/master/d2/de8/group__core__array.html#ga75843061d150ad6564b5447e38e57722 func TheRNG() RNG { return RNG{ p: C.TheRNG(), } } // TheRNG Sets state of default random number generator. // // For further details, please see: // https://docs.opencv.org/master/d2/de8/group__core__array.html#ga757e657c037410d9e19e819569e7de0f func SetRNGSeed(seed int) { C.SetRNGSeed(C.int(seed)) } // Fill Fills arrays with random numbers. // // For further details, please see: // https://docs.opencv.org/master/d1/dd6/classcv_1_1RNG.html#ad26f2b09d9868cf108e84c9814aa682d func (r *RNG) Fill(mat *Mat, distType RNGDistType, a, b float64, saturateRange bool) { C.RNG_Fill(r.p, mat.p, C.int(distType), C.double(a), C.double(b), C.bool(saturateRange)) } // Gaussian Returns the next random number sampled from // the Gaussian distribution. // // For further details, please see: // https://docs.opencv.org/master/d1/dd6/classcv_1_1RNG.html#a8df8ce4dc7d15916cee743e5a884639d func (r *RNG) Gaussian(sigma float64) float64 { return float64(C.RNG_Gaussian(r.p, C.double(sigma))) } // Next The method updates the state using the MWC algorithm // and returns the next 32-bit random number. // // For further details, please see: // https://docs.opencv.org/master/d1/dd6/classcv_1_1RNG.html#a8df8ce4dc7d15916cee743e5a884639d func (r *RNG) Next() uint { return uint(C.RNG_Next(r.p)) } // RandN Fills the array with normally distributed random numbers. // // For further details, please see: // https://docs.opencv.org/master/d2/de8/group__core__array.html#gaeff1f61e972d133a04ce3a5f81cf6808 func RandN(mat *Mat, mean, stddev Scalar) { meanVal := C.struct_Scalar{ val1: C.double(mean.Val1), val2: C.double(mean.Val2), val3: C.double(mean.Val3), val4: C.double(mean.Val4), } stddevVal := C.struct_Scalar{ val1: C.double(stddev.Val1), val2: C.double(stddev.Val2), val3: C.double(stddev.Val3), val4: C.double(stddev.Val4), } C.RandN(mat.p, meanVal, stddevVal) } // RandShuffle Shuffles the array elements randomly. // // For further details, please see: // https://docs.opencv.org/master/d2/de8/group__core__array.html#ga6a789c8a5cb56c6dd62506179808f763 func RandShuffle(mat *Mat) { C.RandShuffle(mat.p) } // RandShuffleWithParams Shuffles the array elements randomly. // // For further details, please see: // https://docs.opencv.org/master/d2/de8/group__core__array.html#ga6a789c8a5cb56c6dd62506179808f763 func RandShuffleWithParams(mat *Mat, iterFactor float64, rng RNG) { C.RandShuffleWithParams(mat.p, C.double(iterFactor), rng.p) } // RandU Generates a single uniformly-distributed random // number or an array of random numbers. // // For further details, please see: // https://docs.opencv.org/master/d2/de8/group__core__array.html#ga1ba1026dca0807b27057ba6a49d258c0 func RandU(mat *Mat, low, high Scalar) { lowVal := C.struct_Scalar{ val1: C.double(low.Val1), val2: C.double(low.Val2), val3: C.double(low.Val3), val4: C.double(low.Val4), } highVal := C.struct_Scalar{ val1: C.double(high.Val1), val2: C.double(high.Val2), val3: C.double(high.Val3), val4: C.double(high.Val4), } C.RandU(mat.p, lowVal, highVal) } type NativeByteBuffer struct { // std::vector is build of 3 pointers And this will not change ever. stdVectorOpaq [3]uintptr } func newNativeByteBuffer() *NativeByteBuffer { buffer := &NativeByteBuffer{} C.StdByteVectorInitialize(buffer.nativePointer()) return buffer } func (buffer *NativeByteBuffer) nativePointer() unsafe.Pointer { return unsafe.Pointer(&buffer.stdVectorOpaq[0]) } func (buffer *NativeByteBuffer) dataPointer() unsafe.Pointer { return unsafe.Pointer(C.StdByteVectorData(buffer.nativePointer())) } // GetBytes returns slice of bytes backed by native buffer func (buffer *NativeByteBuffer) GetBytes() []byte { var result []byte sliceHeader := (*reflect.SliceHeader)(unsafe.Pointer(&result)) vectorLen := int(C.StdByteVectorLen(buffer.nativePointer())) sliceHeader.Cap = vectorLen sliceHeader.Len = vectorLen sliceHeader.Data = uintptr(buffer.dataPointer()) return result } // Len - returns length in bytes of underlying buffer func (buffer *NativeByteBuffer) Len() int { return int(C.StdByteVectorLen(buffer.nativePointer())) } // Close the buffer releasing all its resources func (buffer *NativeByteBuffer) Close() { C.StdByteVectorFree(buffer.nativePointer()) } // Points2fVector is a wrapper around a std::vector< std::vector< cv::Point2f > >* type Points2fVector struct { p C.Points2fVector } // NewPoints2fVector returns a new empty Points2fVector. func NewPoints2fVector() Points2fVector { return Points2fVector{p: C.Points2fVector_New()} } // NewPoints2fVectorFromPoints returns a new Points2fVector that has been // initialized to a slice of slices of Point2f. func NewPoints2fVectorFromPoints(pts [][]Point2f) Points2fVector { pvf := NewPoints2fVector() for j := 0; j < len(pts); j++ { pv := NewPoint2fVectorFromPoints(pts[j]) pvf.Append(pv) pv.Close() } return pvf } func (pvs Points2fVector) P() C.Points2fVector { return pvs.p } // ToPoints returns a slice of slices of Point2f for the data in this Points2fVector. func (pvs Points2fVector) ToPoints() [][]Point2f { ppoints := make([][]Point2f, pvs.Size()) for j := 0; j < pvs.Size(); j++ { pts := pvs.At(j) points := pts.ToPoints() ppoints[j] = points } return ppoints } // IsNil checks the CGo pointer in the Points2fVector. func (pvs Points2fVector) IsNil() bool { return pvs.p == nil } // Size returns how many vectors of Points are in the Points2fVector. func (pvs Points2fVector) Size() int { return int(C.Points2fVector_Size(pvs.p)) } // At returns the Point2fVector at that index of the Points2fVector. func (pvs Points2fVector) At(idx int) Point2fVector { if idx > pvs.Size() { return Point2fVector{} } return Point2fVector{p: C.Points2fVector_At(pvs.p, C.int(idx))} } // Append appends a Point2fVector at end of the Points2fVector. func (pvs Points2fVector) Append(pv Point2fVector) { if !pv.IsNil() { C.Points2fVector_Append(pvs.p, pv.p) } } // Close closes and frees memory for this Points2fVector. func (pvs Points2fVector) Close() { C.Points2fVector_Close(pvs.p) } type Point3f struct { X float32 Y float32 Z float32 } func NewPoint3f(x, y, z float32) Point3f { return Point3f{x, y, z} } // Point3fVector is a wrapper around a std::vector< cv::Point3f >* type Point3fVector struct { p C.Point3fVector } // NewPoint3fVector returns a new empty Point3fVector. func NewPoint3fVector() Point3fVector { return Point3fVector{p: C.Point3fVector_New()} } // NewPoint3fVectorFromPoints returns a new Point3fVector that has been // initialized to a slice of image.Point. func NewPoint3fVectorFromPoints(pts []Point3f) Point3fVector { p := (*C.struct_Point3f)(C.malloc(C.size_t(C.sizeof_struct_Point3f * len(pts)))) defer C.free(unsafe.Pointer(p)) h := &reflect.SliceHeader{ Data: uintptr(unsafe.Pointer(p)), Len: len(pts), Cap: len(pts), } pa := *(*[]C.Point3f)(unsafe.Pointer(h)) for j, point := range pts { pa[j] = C.struct_Point3f{ x: C.float(point.X), y: C.float(point.Y), z: C.float(point.Z), } } cPoints := C.struct_Points3f{ points: (*C.Point3f)(p), length: C.int(len(pts)), } return Point3fVector{p: C.Point3fVector_NewFromPoints(cPoints)} } // NewPoint3fVectorFromMat returns a new Point3fVector that has been // wrapped around a Mat of type CV_32FC3 with a single columm. func NewPoint3fVectorFromMat(mat Mat) Point3fVector { return Point3fVector{p: C.Point3fVector_NewFromMat(mat.p)} } // IsNil checks the CGo pointer in the Point3fVector. func (pfv Point3fVector) IsNil() bool { return pfv.p == nil } // Size returns how many Point are in the Point3fVector. func (pfv Point3fVector) Size() int { return int(C.Point3fVector_Size(pfv.p)) } // At returns the Point3f func (pfv Point3fVector) At(idx int) Point3f { if idx > pfv.Size() { return Point3f{} } cp := C.Point3fVector_At(pfv.p, C.int(idx)) return Point3f{X: float32(cp.x), Y: float32(cp.y), Z: float32(cp.z)} } func (pfv Point3fVector) Append(point Point3f) { C.Point3fVector_Append(pfv.p, C.Point3f{ x: C.float(point.X), y: C.float(point.Y), z: C.float(point.Z), }) } // ToPoints returns a slice of Point3f for the data in this Point3fVector. func (pfv Point3fVector) ToPoints() []Point3f { points := make([]Point3f, pfv.Size()) for j := 0; j < pfv.Size(); j++ { points[j] = pfv.At(j) } return points } // Close closes and frees memory for this Point3fVector. func (pfv Point3fVector) Close() { C.Point3fVector_Close(pfv.p) } // Points3fVector is a wrapper around a std::vector< std::vector< cv::Point3f > >* type Points3fVector struct { p C.Points3fVector } // NewPoints3fVector returns a new empty Points3fVector. func NewPoints3fVector() Points3fVector { return Points3fVector{p: C.Points3fVector_New()} } // NewPoints3fVectorFromPoints returns a new Points3fVector that has been // initialized to a slice of slices of Point3f. func NewPoints3fVectorFromPoints(pts [][]Point3f) Points3fVector { pvf := NewPoints3fVector() for j := 0; j < len(pts); j++ { pv := NewPoint3fVectorFromPoints(pts[j]) pvf.Append(pv) pv.Close() } return pvf } // ToPoints returns a slice of slices of Point3f for the data in this Points3fVector. func (pvs Points3fVector) ToPoints() [][]Point3f { ppoints := make([][]Point3f, pvs.Size()) for j := 0; j < pvs.Size(); j++ { pts := pvs.At(j) points := pts.ToPoints() ppoints[j] = points } return ppoints } // IsNil checks the CGo pointer in the Points3fVector. func (pvs Points3fVector) IsNil() bool { return pvs.p == nil } // Size returns how many vectors of Points are in the Points3fVector. func (pvs Points3fVector) Size() int { return int(C.Points3fVector_Size(pvs.p)) } // At returns the Point3fVector at that index of the Points3fVector. func (pvs Points3fVector) At(idx int) Point3fVector { if idx > pvs.Size() { return Point3fVector{} } return Point3fVector{p: C.Points3fVector_At(pvs.p, C.int(idx))} } // Append appends a Point3fVector at end of the Points3fVector. func (pvs Points3fVector) Append(pv Point3fVector) { if !pv.IsNil() { C.Points3fVector_Append(pvs.p, pv.p) } } // Close closes and frees memory for this Points3fVector. func (pvs Points3fVector) Close() { C.Points3fVector_Close(pvs.p) } // Set the number of threads for OpenCV. func SetNumThreads(n int) { C.SetNumThreads(C.int(n)) } // Get the number of threads for OpenCV. func GetNumThreads() int { return int(C.GetNumThreads()) } // NewRotatedRect creates [RotatedRect] (i.e. not up-right) rectangle on a plane. // // For further information, see: // https://docs.opencv.org/4.x/db/dd6/classcv_1_1RotatedRect.html#aba20dfc8444fff72bd820b616f0297ee func NewRotatedRect(center image.Point, width int, height int, angle float64) RotatedRect { p2f := C.struct_Point2f{ x: C.float(float32(center.X)), y: C.float(float32(center.Y)), } c_rotRect := C.RotatedRect_Create(p2f, C.int(width), C.int(height), C.float(angle)) defer C.Points_Close(c_rotRect.pts) return RotatedRect{ Points: toPoints(c_rotRect.pts), BoundingRect: image.Rect(int(c_rotRect.boundingRect.x), int(c_rotRect.boundingRect.y), int(c_rotRect.boundingRect.x)+int(c_rotRect.boundingRect.width), int(c_rotRect.boundingRect.y)+int(c_rotRect.boundingRect.height)), Center: image.Pt(int(c_rotRect.center.x), int(c_rotRect.center.y)), Width: int(c_rotRect.size.width), Height: int(c_rotRect.size.height), Angle: float64(c_rotRect.angle), } } // NewRotatedRect2f creates [RotatedRect2f] (i.e. not up-right) rectangle on a plane. // // For further information, see: // https://docs.opencv.org/4.x/db/dd6/classcv_1_1RotatedRect.html#aba20dfc8444fff72bd820b616f0297ee func NewRotatedRect2f(center Point2f, width float32, height float32, angle float64) RotatedRect2f { p2f := C.struct_Point2f{ x: C.float(center.X), y: C.float(center.Y), } c_rotRect2f := C.RotatedRect2f_Create(p2f, C.float(width), C.float(height), C.float(angle)) defer C.Points2f_Close(c_rotRect2f.pts) return RotatedRect2f{ Points: toPoints2f(c_rotRect2f.pts), BoundingRect: image.Rect(int(c_rotRect2f.boundingRect.x), int(c_rotRect2f.boundingRect.y), int(c_rotRect2f.boundingRect.x)+int(c_rotRect2f.boundingRect.width), int(c_rotRect2f.boundingRect.y)+int(c_rotRect2f.boundingRect.height)), Center: NewPoint2f(float32(c_rotRect2f.center.x), float32(c_rotRect2f.center.y)), Width: float32(c_rotRect2f.size.width), Height: float32(c_rotRect2f.size.height), Angle: float64(c_rotRect2f.angle), } } ================================================ FILE: core.h ================================================ #ifndef _OPENCV3_CORE_H_ #define _OPENCV3_CORE_H_ #include #include // Wrapper for std::vector typedef struct CStrings { const char** strs; int length; } CStrings; typedef struct ByteArray { char* data; int length; } ByteArray; // Wrapper for std::vector typedef struct IntVector { int* val; int length; } IntVector; // Wrapper for std::vector typedef struct FloatVector { float* val; int length; } FloatVector; #ifdef __cplusplus #include extern "C" { #endif typedef struct RawData { int width; int height; struct ByteArray data; } RawData; // Wrapper for an individual cv::Point2f typedef struct Point2f { float x; float y; } Point2f; typedef struct Point3f { float x; float y; float z; } Point3f; // Wrapper for an individual cv::cvPoint typedef struct Point { int x; int y; } Point; // Wrapper for the vector of Point structs aka std::vector typedef struct Points { Point* points; int length; } Points; // Wrapper for the vector of Point2f structs aka std::vector typedef struct Points2f { Point2f* points; int length; } Points2f; typedef struct Points3f { Point3f *points; int length; } Points3f; // Contour is alias for Points typedef Points Contour; // Contour2f is alias for Points2f typedef Points2f Contour2f; typedef struct Contours2f { Contour2f *contours; int length; } Contours2f; // Contour3f is alias for Points3f typedef Points3f Contour3f; // Wrapper for the vector of Points3f vectors aka std::vector< std::vector > typedef struct Contours3f { Contour3f *contours; int length; } Contours3f; // Wrapper for the vector of Points vectors aka std::vector< std::vector > typedef struct Contours { Contour* contours; int length; } Contours; // Wrapper for an individual cv::cvRect typedef struct Rect { int x; int y; int width; int height; } Rect; // Wrapper for an individual cv::cvRect2f typedef struct Rect2f { float x; float y; float width; float height; } Rect2f; // Wrapper for the vector of Rect struct aka std::vector typedef struct Rects { Rect* rects; int length; } Rects; // Wrapper for an individual cv::cvSize typedef struct Size { int width; int height; } Size; // Wrapper for an individual cv::cvSize typedef struct Size2f { float width; float height; } Size2f; // Wrapper for an individual cv::RotatedRect typedef struct RotatedRect { Points pts; Rect boundingRect; Point center; Size size; double angle; } RotatedRect; // Wrapper for an individual cv::RotatedRect2f typedef struct RotatedRect2f { Points2f pts; Rect boundingRect; Point2f center; Size2f size; double angle; } RotatedRect2f; // Wrapper for an individual cv::cvScalar typedef struct Scalar { double val1; double val2; double val3; double val4; } Scalar; // Wrapper for a individual cv::KeyPoint typedef struct KeyPoint { double x; double y; double size; double angle; double response; int octave; int classID; } KeyPoint; // Wrapper for the vector of KeyPoint struct aka std::vector typedef struct KeyPoints { KeyPoint* keypoints; int length; } KeyPoints; // Wrapper for SimpleBlobDetectorParams aka SimpleBlobDetector::Params typedef struct SimpleBlobDetectorParams { unsigned char blobColor; bool filterByArea; bool filterByCircularity; bool filterByColor; bool filterByConvexity; bool filterByInertia; float maxArea; float maxCircularity; float maxConvexity; float maxInertiaRatio; float maxThreshold; float minArea; float minCircularity; float minConvexity; float minDistBetweenBlobs; float minInertiaRatio; size_t minRepeatability; float minThreshold; float thresholdStep; } SimpleBlobDetectorParams; typedef struct GFTTDetectorParams { int maxCorners; double qualityLevel; double minDistance; int blockSize; bool useHarrisDetector; double k; }GFTTDetectorParams; // Wrapper for an individual cv::DMatch typedef struct DMatch { int queryIdx; int trainIdx; int imgIdx; float distance; } DMatch; // Wrapper for the vector of DMatch struct aka std::vector typedef struct DMatches { DMatch* dmatches; int length; } DMatches; // Wrapper for the vector vector of DMatch struct aka std::vector> typedef struct MultiDMatches { DMatches* dmatches; int length; } MultiDMatches; // Wrapper for an individual cv::Moment typedef struct Moment { double m00; double m10; double m01; double m20; double m11; double m02; double m30; double m21; double m12; double m03; double mu20; double mu11; double mu02; double mu30; double mu21; double mu12; double mu03; double nu20; double nu11; double nu02; double nu30; double nu21; double nu12; double nu03; } Moment; // OpenCVResult is a struct that contains the result of an OpenCV operation. // It contains a code and a message. The code of 0 mean success, while a non-zero // code means an error occurred. // This is needed to wrap the result of an OpenCV operation, since Go does not // have exceptions. typedef struct OpenCVResult { int Code; const char* Message; int Length; } OpenCVResult; int GetOpenCVException(); const char* GetOpenCVExceptionMessage(); void ClearOpenCVException(); #ifdef __cplusplus typedef cv::Mat* Mat; typedef cv::TermCriteria* TermCriteria; typedef cv::RNG* RNG; typedef std::vector< cv::Point >* PointVector; typedef std::vector< std::vector< cv::Point > >* PointsVector; typedef std::vector< cv::Point2f >* Point2fVector; typedef std::vector< std::vector< cv::Point2f> >* Points2fVector; typedef std::vector< cv::Point3f >* Point3fVector; typedef std::vector< std::vector< cv::Point3f > >* Points3fVector; typedef cv::RotatedRect* RotatedRectT; #else typedef void* Mat; typedef void* TermCriteria; typedef void* RNG; typedef void* PointVector; typedef void* PointsVector; typedef void* Point2fVector; typedef void* Points2fVector; typedef void* Point3fVector; typedef void* Points3fVector; typedef void* RotatedRectT; #endif void setExceptionInfo(int code, const char* message); OpenCVResult successResult(); OpenCVResult errorResult(int code, const char* message); // Wrapper for the vector of Mat aka std::vector typedef struct Mats { Mat* mats; int length; } Mats; Mat Mats_get(struct Mats mats, int i); struct DMatches MultiDMatches_get(struct MultiDMatches mds, int index); struct ByteArray toByteArray(const char* buf, int len); void ByteArray_Release(struct ByteArray buf); void Contours_Close(struct Contours cs); void KeyPoints_Close(struct KeyPoints ks); void Rects_Close(struct Rects rs); void Mats_Close(struct Mats mats); void Point_Close(struct Point p); void Points_Close(struct Points ps); void Point2f_Close(struct Point2f p); void Points2f_Close(struct Points2f ps); void DMatches_Close(struct DMatches ds); void MultiDMatches_Close(struct MultiDMatches mds); Mat Mat_New(); Mat Mat_NewWithSize(int rows, int cols, int type); Mat Mat_NewWithSizes(struct IntVector sizes, int type); Mat Mat_NewWithSizesFromScalar(IntVector sizes, int type, Scalar ar); Mat Mat_NewWithSizesFromBytes(IntVector sizes, int type, struct ByteArray buf); Mat Mat_NewFromScalar(const Scalar ar, int type); Mat Mat_NewWithSizeFromScalar(const Scalar ar, int rows, int cols, int type); Mat Mat_NewFromBytes(int rows, int cols, int type, struct ByteArray buf); Mat Mat_NewFromPoint2fVector(Point2fVector pfv, bool copy_data); Mat Mat_NewFromPointVector(PointVector pv, bool copy_data); Mat Mat_FromPtr(Mat m, int rows, int cols, int type, int prows, int pcols); void Mat_Close(Mat m); int Mat_Empty(Mat m); bool Mat_IsContinuous(Mat m); void Mat_Inv(Mat m); Mat Mat_Col(Mat m, int c); Mat Mat_Row(Mat m, int r); Mat Mat_Copy(Mat m); Mat Mat_Clone(Mat m); OpenCVResult Mat_CopyTo(Mat m, Mat dst); int Mat_Total(Mat m); void Mat_Size(Mat m, IntVector* res); OpenCVResult Mat_CopyToWithMask(Mat m, Mat dst, Mat mask); OpenCVResult Mat_ConvertTo(Mat m, Mat dst, int type); OpenCVResult Mat_ConvertToWithParams(Mat m, Mat dst, int type, float alpha, float beta); struct ByteArray Mat_ToBytes(Mat m); struct ByteArray Mat_DataPtr(Mat m); Mat Mat_Region(Mat m, Rect r); Mat Mat_Reshape(Mat m, int cn, int rows); Mat Mat_ReshapeWithSize(Mat m, int cn, struct IntVector dims); OpenCVResult Mat_PatchNaNs(Mat m); Mat Mat_ConvertFp16(Mat m); Scalar Mat_Mean(Mat m); Scalar Mat_MeanWithMask(Mat m, Mat mask); Mat Mat_Sqrt(Mat m); int Mat_Rows(Mat m); int Mat_Cols(Mat m); int Mat_Channels(Mat m); int Mat_Type(Mat m); int Mat_Step(Mat m); int Mat_ElemSize(Mat m); Mat Eye(int rows, int cols, int type); Mat Zeros(int rows, int cols, int type); Mat Ones(int rows, int cols, int type); uint8_t Mat_GetUChar(Mat m, int row, int col); uint8_t Mat_GetUChar3(Mat m, int x, int y, int z); int8_t Mat_GetSChar(Mat m, int row, int col); int8_t Mat_GetSChar3(Mat m, int x, int y, int z); int16_t Mat_GetShort(Mat m, int row, int col); int16_t Mat_GetShort3(Mat m, int x, int y, int z); int32_t Mat_GetInt(Mat m, int row, int col); int32_t Mat_GetInt3(Mat m, int x, int y, int z); float Mat_GetFloat(Mat m, int row, int col); float Mat_GetFloat3(Mat m, int x, int y, int z); double Mat_GetDouble(Mat m, int row, int col); double Mat_GetDouble3(Mat m, int x, int y, int z); void Mat_SetTo(Mat m, Scalar value); void Mat_SetUChar(Mat m, int row, int col, uint8_t val); void Mat_SetUChar3(Mat m, int x, int y, int z, uint8_t val); void Mat_SetSChar(Mat m, int row, int col, int8_t val); void Mat_SetSChar3(Mat m, int x, int y, int z, int8_t val); void Mat_SetShort(Mat m, int row, int col, int16_t val); void Mat_SetShort3(Mat m, int x, int y, int z, int16_t val); void Mat_SetInt(Mat m, int row, int col, int32_t val); void Mat_SetInt3(Mat m, int x, int y, int z, int32_t val); void Mat_SetFloat(Mat m, int row, int col, float val); void Mat_SetFloat3(Mat m, int x, int y, int z, float val); void Mat_SetDouble(Mat m, int row, int col, double val); void Mat_SetDouble3(Mat m, int x, int y, int z, double val); void Mat_AddUChar(Mat m, uint8_t val); void Mat_SubtractUChar(Mat m, uint8_t val); void Mat_MultiplyUChar(Mat m, uint8_t val); void Mat_DivideUChar(Mat m, uint8_t val); void Mat_AddFloat(Mat m, float val); void Mat_SubtractFloat(Mat m, float val); void Mat_MultiplyFloat(Mat m, float val); void Mat_DivideFloat(Mat m, float val); Mat Mat_MultiplyMatrix(Mat x, Mat y); Mat Mat_T(Mat x); OpenCVResult LUT(Mat src, Mat lut, Mat dst); OpenCVResult Mat_AbsDiff(Mat src1, Mat src2, Mat dst); OpenCVResult Mat_Add(Mat src1, Mat src2, Mat dst); OpenCVResult Mat_AddWeighted(Mat src1, double alpha, Mat src2, double beta, double gamma, Mat dst); OpenCVResult Mat_BitwiseAnd(Mat src1, Mat src2, Mat dst); OpenCVResult Mat_BitwiseAndWithMask(Mat src1, Mat src2, Mat dst, Mat mask); OpenCVResult Mat_BitwiseNot(Mat src1, Mat dst); OpenCVResult Mat_BitwiseNotWithMask(Mat src1, Mat dst, Mat mask); OpenCVResult Mat_BitwiseOr(Mat src1, Mat src2, Mat dst); OpenCVResult Mat_BitwiseOrWithMask(Mat src1, Mat src2, Mat dst, Mat mask); OpenCVResult Mat_BitwiseXor(Mat src1, Mat src2, Mat dst); OpenCVResult Mat_BitwiseXorWithMask(Mat src1, Mat src2, Mat dst, Mat mask); OpenCVResult Mat_Compare(Mat src1, Mat src2, Mat dst, int ct); OpenCVResult Mat_BatchDistance(Mat src1, Mat src2, Mat dist, int dtype, Mat nidx, int normType, int K, Mat mask, int update, bool crosscheck); int Mat_BorderInterpolate(int p, int len, int borderType); OpenCVResult Mat_CalcCovarMatrix(Mat samples, Mat covar, Mat mean, int flags, int ctype); OpenCVResult Mat_CartToPolar(Mat x, Mat y, Mat magnitude, Mat angle, bool angleInDegrees); bool Mat_CheckRange(Mat m); OpenCVResult Mat_CompleteSymm(Mat m, bool lowerToUpper); OpenCVResult Mat_ConvertScaleAbs(Mat src, Mat dst, double alpha, double beta); OpenCVResult Mat_CopyMakeBorder(Mat src, Mat dst, int top, int bottom, int left, int right, int borderType, Scalar value); int Mat_CountNonZero(Mat src); OpenCVResult Mat_DCT(Mat src, Mat dst, int flags); double Mat_Determinant(Mat m); OpenCVResult Mat_DFT(Mat m, Mat dst, int flags); OpenCVResult Mat_Divide(Mat src1, Mat src2, Mat dst); bool Mat_Eigen(Mat src, Mat eigenvalues, Mat eigenvectors); OpenCVResult Mat_EigenNonSymmetric(Mat src, Mat eigenvalues, Mat eigenvectors); OpenCVResult Mat_PCABackProject(Mat data, Mat mean, Mat eigenvectors, Mat result); OpenCVResult Mat_PCACompute(Mat src, Mat mean, Mat eigenvectors, Mat eigenvalues, int maxComponents); OpenCVResult Mat_PCAProject(Mat data, Mat mean, Mat eigenvectors, Mat result); double PSNR(Mat src1, Mat src2); OpenCVResult SVBackSubst(Mat w, Mat u, Mat vt, Mat rhs, Mat dst); OpenCVResult SVDecomp(Mat src, Mat w, Mat u, Mat vt); OpenCVResult Mat_Exp(Mat src, Mat dst); OpenCVResult Mat_ExtractChannel(Mat src, Mat dst, int coi); OpenCVResult Mat_FindNonZero(Mat src, Mat idx); OpenCVResult Mat_Flip(Mat src, Mat dst, int flipCode); OpenCVResult Mat_Gemm(Mat src1, Mat src2, double alpha, Mat src3, double beta, Mat dst, int flags); int Mat_GetOptimalDFTSize(int vecsize); OpenCVResult Mat_Hconcat(Mat src1, Mat src2, Mat dst); OpenCVResult Mat_Vconcat(Mat src1, Mat src2, Mat dst); OpenCVResult Rotate(Mat src, Mat dst, int rotationCode); OpenCVResult Mat_Idct(Mat src, Mat dst, int flags); OpenCVResult Mat_Idft(Mat src, Mat dst, int flags, int nonzeroRows); OpenCVResult Mat_InRange(Mat src, Mat lowerb, Mat upperb, Mat dst); OpenCVResult Mat_InRangeWithScalar(Mat src, const Scalar lowerb, const Scalar upperb, Mat dst); OpenCVResult Mat_InsertChannel(Mat src, Mat dst, int coi); double Mat_Invert(Mat src, Mat dst, int flags); double KMeans(Mat data, int k, Mat bestLabels, TermCriteria criteria, int attempts, int flags, Mat centers); double KMeansPoints(PointVector pts, int k, Mat bestLabels, TermCriteria criteria, int attempts, int flags, Mat centers); OpenCVResult Mat_Log(Mat src, Mat dst); OpenCVResult Mat_Magnitude(Mat x, Mat y, Mat magnitude); double Mat_Mahalanobis(Mat v1, Mat v2, Mat icovar); OpenCVResult MulTransposed(Mat src, Mat dest, bool ata); OpenCVResult Mat_Max(Mat src1, Mat src2, Mat dst); OpenCVResult Mat_MeanStdDev(Mat src, Mat dstMean, Mat dstStdDev); OpenCVResult Mat_MeanStdDevWithMask(Mat src, Mat dstMean, Mat dstStdDev, Mat mask); OpenCVResult Mat_Merge(struct Mats mats, Mat dst); OpenCVResult Mat_Min(Mat src1, Mat src2, Mat dst); OpenCVResult Mat_MinMaxIdx(Mat m, double* minVal, double* maxVal, int* minIdx, int* maxIdx); OpenCVResult Mat_MinMaxLoc(Mat m, double* minVal, double* maxVal, Point* minLoc, Point* maxLoc); OpenCVResult Mat_MinMaxLocWithMask(Mat m, double* minVal, double* maxVal, Point* minLoc, Point* maxLoc, Mat mask); OpenCVResult Mat_MixChannels(struct Mats src, struct Mats dst, struct IntVector fromTo); OpenCVResult Mat_MulSpectrums(Mat a, Mat b, Mat c, int flags); OpenCVResult Mat_Multiply(Mat src1, Mat src2, Mat dst); OpenCVResult Mat_MultiplyWithParams(Mat src1, Mat src2, Mat dst, double scale, int dtype); OpenCVResult Mat_Subtract(Mat src1, Mat src2, Mat dst); OpenCVResult Mat_Normalize(Mat src, Mat dst, double alpha, double beta, int typ); double Norm(Mat src1, int normType); double NormWithMats(Mat src1, Mat src2, int normType); OpenCVResult Mat_PerspectiveTransform(Mat src, Mat dst, Mat tm); bool Mat_Solve(Mat src1, Mat src2, Mat dst, int flags); int Mat_SolveCubic(Mat coeffs, Mat roots); double Mat_SolvePoly(Mat coeffs, Mat roots, int maxIters); OpenCVResult Mat_Reduce(Mat src, Mat dst, int dim, int rType, int dType); OpenCVResult Mat_ReduceArgMax(Mat src, Mat dst, int axis, bool lastIndex); OpenCVResult Mat_ReduceArgMin(Mat src, Mat dst, int axis, bool lastIndex); OpenCVResult Mat_Repeat(Mat src, int nY, int nX, Mat dst); OpenCVResult Mat_ScaleAdd(Mat src1, double alpha, Mat src2, Mat dst); OpenCVResult Mat_SetIdentity(Mat src, double scalar); OpenCVResult Mat_Sort(Mat src, Mat dst, int flags); OpenCVResult Mat_SortIdx(Mat src, Mat dst, int flags); OpenCVResult Mat_Split(Mat src, struct Mats* mats); OpenCVResult Mat_Subtract(Mat src1, Mat src2, Mat dst); Scalar Mat_Trace(Mat src); OpenCVResult Mat_Transform(Mat src, Mat dst, Mat tm); OpenCVResult Mat_Transpose(Mat src, Mat dst); OpenCVResult Mat_TransposeND(Mat src, struct IntVector order, Mat dst); OpenCVResult Mat_PolarToCart(Mat magnitude, Mat degree, Mat x, Mat y, bool angleInDegrees); OpenCVResult Mat_Pow(Mat src, double power, Mat dst); OpenCVResult Mat_Phase(Mat x, Mat y, Mat angle, bool angleInDegrees); Scalar Mat_Sum(Mat src1); TermCriteria TermCriteria_New(int typ, int maxCount, double epsilon); int64_t GetCVTickCount(); double GetTickFrequency(); Mat Mat_rowRange(Mat m,int startrow,int endrow); Mat Mat_colRange(Mat m,int startrow,int endrow); PointVector PointVector_New(); PointVector PointVector_NewFromPoints(Contour points); PointVector PointVector_NewFromMat(Mat mat); Point PointVector_At(PointVector pv, int idx); void PointVector_Append(PointVector pv, Point p); int PointVector_Size(PointVector pv); void PointVector_Close(PointVector pv); PointsVector PointsVector_New(); PointsVector PointsVector_NewFromPoints(Contours points); PointVector PointsVector_At(PointsVector psv, int idx); void PointsVector_Append(PointsVector psv, PointVector pv); int PointsVector_Size(PointsVector psv); void PointsVector_Close(PointsVector psv); Point2fVector Point2fVector_New(); void Point2fVector_Close(Point2fVector pfv); Point2fVector Point2fVector_NewFromPoints(Contour2f pts); Point2fVector Point2fVector_NewFromMat(Mat mat); Point2f Point2fVector_At(Point2fVector pfv, int idx); int Point2fVector_Size(Point2fVector pfv); void IntVector_Close(struct IntVector ivec); void CStrings_Close(struct CStrings cstrs); RNG TheRNG(); void SetRNGSeed(int seed); void RNG_Fill(RNG rng, Mat mat, int distType, double a, double b, bool saturateRange); double RNG_Gaussian(RNG rng, double sigma); unsigned int RNG_Next(RNG rng); void RandN(Mat mat, Scalar mean, Scalar stddev); void RandShuffle(Mat mat); void RandShuffleWithParams(Mat mat, double iterFactor, RNG rng); void RandU(Mat mat, Scalar low, Scalar high); void copyPointVectorToPoint2fVector(PointVector src, Point2fVector dest); void StdByteVectorInitialize(void* data); void StdByteVectorFree(void *data); size_t StdByteVectorLen(void *data); uint8_t* StdByteVectorData(void *data); Points2fVector Points2fVector_New(); Points2fVector Points2fVector_NewFromPoints(Contours2f points); int Points2fVector_Size(Points2fVector ps); Point2fVector Points2fVector_At(Points2fVector ps, int idx); void Points2fVector_Append(Points2fVector psv, Point2fVector pv); void Points2fVector_Close(Points2fVector ps); Point3fVector Point3fVector_New(); Point3fVector Point3fVector_NewFromPoints(Contour3f points); Point3fVector Point3fVector_NewFromMat(Mat mat); void Point3fVector_Append(Point3fVector pfv, Point3f point); Point3f Point3fVector_At(Point3fVector pfv, int idx); int Point3fVector_Size(Point3fVector pfv); void Point3fVector_Close(Point3fVector pv); Points3fVector Points3fVector_New(); Points3fVector Points3fVector_NewFromPoints(Contours3f points); int Points3fVector_Size(Points3fVector ps); Point3fVector Points3fVector_At(Points3fVector ps, int idx); void Points3fVector_Append(Points3fVector psv, Point3fVector pv); void Points3fVector_Close(Points3fVector ps); void SetNumThreads(int n); int GetNumThreads(); struct RotatedRect RotatedRect_Create(struct Point2f center, int width, int height, float angle); struct RotatedRect2f RotatedRect2f_Create(struct Point2f center, float width, float height, float angle); #ifdef __cplusplus } #endif #endif //_OPENCV3_CORE_H_ ================================================ FILE: core_string.go ================================================ package gocv func (c MatType) String() string { switch c { case MatTypeCV8U: return "CV8U" case MatTypeCV8UC2: return "CV8UC2" case MatTypeCV8UC3: return "CV8UC3" case MatTypeCV8UC4: return "CV8UC4" case MatTypeCV16U: return "CV16U" case MatTypeCV16UC2: return "CV16UC2" case MatTypeCV16UC3: return "CV16UC3" case MatTypeCV16UC4: return "CV16UC4" case MatTypeCV16S: return "CV16S" case MatTypeCV16SC2: return "CV16SC2" case MatTypeCV16SC3: return "CV16SC3" case MatTypeCV16SC4: return "CV16SC4" case MatTypeCV32S: return "CV32S" case MatTypeCV32SC2: return "CV32SC2" case MatTypeCV32SC3: return "CV32SC3" case MatTypeCV32SC4: return "CV32SC4" case MatTypeCV32F: return "CV32F" case MatTypeCV32FC2: return "CV32FC2" case MatTypeCV32FC3: return "CV32FC3" case MatTypeCV32FC4: return "CV32FC4" case MatTypeCV64F: return "CV64F" case MatTypeCV64FC2: return "CV64FC2" case MatTypeCV64FC3: return "CV64FC3" case MatTypeCV64FC4: return "CV64FC4" } return "" } func (c CompareType) String() string { switch c { case CompareEQ: return "eq" case CompareGT: return "gt" case CompareGE: return "ge" case CompareLT: return "lt" case CompareLE: return "le" case CompareNE: return "ne" } return "" } func (c CovarFlags) String() string { switch c { case CovarScrambled: return "covar-scrambled" case CovarNormal: return "covar-normal" case CovarUseAvg: return "covar-use-avg" case CovarScale: return "covar-scale" case CovarRows: return "covar-rows" case CovarCols: return "covar-cols" } return "" } func (c DftFlags) String() string { switch c { case DftForward: return "dft-forward" case DftInverse: return "dft-inverse" case DftScale: return "dft-scale" case DftRows: return "dft-rows" case DftComplexOutput: return "dft-complex-output" case DftRealOutput: return "dft-real-output" case DftComplexInput: return "dft-complex-input" } return "" } func (c RotateFlag) String() string { switch c { case Rotate90Clockwise: return "rotate-90-clockwise" case Rotate180Clockwise: return "rotate-180-clockwise" case Rotate90CounterClockwise: return "rotate-90-counter-clockwise" } return "" } func (c KMeansFlags) String() string { switch c { case KMeansRandomCenters: return "kmeans-random-centers" case KMeansPPCenters: return "kmeans-pp-centers" case KMeansUseInitialLabels: return "kmeans-use-initial-labels" } return "" } func (c NormType) String() string { switch c { case NormInf: return "norm-inf" case NormL1: return "norm-l1" case NormL2: return "norm-l2" case NormL2Sqr: return "norm-l2-sqr" case NormHamming: return "norm-hamming" case NormHamming2: return "norm-hamming2" case NormRelative: return "norm-relative" case NormMinMax: return "norm-minmax" } return "" } func (c TermCriteriaType) String() string { switch c { case Count: return "count" case EPS: return "eps" } return "" } func (c SolveDecompositionFlags) String() string { switch c { case SolveDecompositionLu: return "solve-decomposition-lu" case SolveDecompositionSvd: return "solve-decomposition-svd" case SolveDecompositionEing: return "solve-decomposition-eing" case SolveDecompositionCholesky: return "solve-decomposition-cholesky" case SolveDecompositionQr: return "solve-decomposition-qr" case SolveDecompositionNormal: return "solve-decomposition-normal" } return "" } func (c ReduceTypes) String() string { switch c { case ReduceSum: return "reduce-sum" case ReduceAvg: return "reduce-avg" case ReduceMax: return "reduce-max" case ReduceMin: return "reduce-min" } return "" } func (c SortFlags) String() string { switch c { case SortEveryRow: return "sort-every-row" case SortEveryColumn: return "sort-every-column" case SortDescending: return "sort-descending" } return "" } ================================================ FILE: core_test.go ================================================ package gocv import ( "bytes" "image" "image/color" _ "image/jpeg" _ "image/png" "runtime" "strings" "testing" ) func TestMat(t *testing.T) { mat := NewMat() defer mat.Close() if !mat.Empty() { t.Error("New Mat should be empty") } } func TestMatClosed(t *testing.T) { mat := NewMat() mat.Close() if !mat.Closed() { t.Error("Closed Mat should be closed") } } func TestMatWithSizes(t *testing.T) { t.Run("create mat with multidimensional array", func(t *testing.T) { sizes := []int{100, 100, 100} mat := NewMatWithSizes(sizes, MatTypeCV8U) defer mat.Close() if mat.Empty() { t.Error("NewMatWithSizes should not be empty") } for i, val := range mat.Size() { if val != sizes[i] { t.Errorf("NewMatWithSizes incorrect size: %v\n", mat.Size()) } } if mat.Rows() != -1 { t.Errorf("NewMatWithSizes incorrect row count: %v\n", mat.Rows()) } if mat.Cols() != -1 { t.Errorf("NewMatWithSizes incorrect col count: %v\n", mat.Cols()) } if mat.Channels() != 1 { t.Errorf("NewMatWithSizes incorrect channels count: %v\n", mat.Channels()) } if mat.Type() != MatTypeCV8U { t.Errorf("NewMatWithSizes incorrect type: %v\n", mat.Type()) } if mat.Total() != 100*100*100 { t.Errorf("NewMatWithSizes incorrect total: %v\n", mat.Total()) } }) t.Run("create 2x3x3 multidimensional array with 3 channels and scalar", func(t *testing.T) { sizes := []int{2, 3, 3} s := NewScalar(255.0, 105.0, 180.0, 0.0) mat := NewMatWithSizesWithScalar(sizes, MatTypeCV32FC3, s) defer mat.Close() if mat.Empty() { t.Error("NewMatWithSizesWithScalar should not be empty") } for i, val := range mat.Size() { if val != sizes[i] { t.Errorf("NewMatWithSizesWithScalar incorrect size: %v\n", mat.Size()) } } if mat.Rows() != -1 { t.Errorf("NewMatWithSizesWithScalar incorrect row count: %v\n", mat.Rows()) } if mat.Cols() != -1 { t.Errorf("NewMatWithSizesWithScalar incorrect col count: %v\n", mat.Cols()) } if mat.Channels() != 3 { t.Errorf("NewMatWithSizesWithScalar incorrect channels count: %v\n", mat.Channels()) } if mat.Type() != MatTypeCV32FC3 { t.Errorf("NewMatWithSizesWithScalar incorrect type: %v\n", mat.Type()) } if mat.Total() != 2*3*3 { t.Errorf("NewMatWithSizesWithScalar incorrect total: %v\n", mat.Total()) } matChans := Split(mat) scalar := []float32{255.0, 105.0, 180.0} for c := 0; c < mat.Channels(); c++ { for x := 0; x < sizes[0]; x++ { for y := 0; y < sizes[1]; y++ { for z := 0; z < sizes[2]; z++ { if s := matChans[c].GetFloatAt3(x, y, z); s != scalar[c] { t.Errorf("NewMatWithSizesWithScalar incorrect scalar: %v\n", s) } } } } } for _, ch := range matChans { ch.Close() } }) t.Run("create 1x2x3 multidimensional array with 3 channel and data", func(t *testing.T) { sizes := []int{1, 2, 3} // generate byte array s := NewScalar(255.0, 123.0, 55.0, 0.0) mat1 := NewMatWithSizesWithScalar(sizes, MatTypeCV32FC2, s) defer mat1.Close() b := mat1.ToBytes() mat, err := NewMatWithSizesFromBytes(sizes, MatTypeCV32FC2, b) defer mat.Close() if err != nil { t.Errorf("NewMatWithSizesFromBytes %v\n", err) } if mat.Empty() { t.Error("NewMatWithSizesFromBytes should not be empty") } mat2, err := NewMatWithSizesFromBytes(sizes, MatTypeCV32FC2, nil) defer mat2.Close() if err == nil { t.Error("NewMatWithSizesFromBytes should return error with empty bytes") } b1 := mat.ToBytes() if !bytes.Equal(b, b1) { t.Error("NewMatWithSizesFromBytes byte arrays not equal") } for i, val := range mat.Size() { if val != sizes[i] { t.Errorf("NewMatWithSizesFromBytes incorrect size: %v\n", mat.Size()) } } if mat.Rows() != -1 { t.Errorf("NewMatWithSizesFromBytes incorrect row count: %v\n", mat.Rows()) } if mat.Cols() != -1 { t.Errorf("NewMatWithSizesFromBytes incorrect col count: %v\n", mat.Cols()) } if mat.Channels() != 2 { t.Errorf("NewMatWithSizesFromBytes incorrect channels count: %v\n", mat.Channels()) } if mat.Type() != MatTypeCV32FC2 { t.Errorf("NewMatWithSizesFromBytes incorrect type: %v\n", mat.Type()) } if mat.Total() != 1*2*3 { t.Errorf("NewMatWithSizesFromBytes incorrect total: %v\n", mat.Total()) } matChans := Split(mat) scalar := []float32{255.0, 123.0, 55.0} for c := 0; c < mat.Channels(); c++ { for x := 0; x < sizes[0]; x++ { for y := 0; y < sizes[1]; y++ { for z := 0; z < sizes[2]; z++ { if s := matChans[c].GetFloatAt3(x, y, z); s != scalar[c] { t.Errorf("NewMatWithSizesFromBytes incorrect value: %v\n", s) } } } } } for _, ch := range matChans { ch.Close() } }) } func TestMatFromBytesWithEmptyByteSlice(t *testing.T) { _, err := NewMatFromBytes(600, 800, MatTypeCV8U, []byte{}) if err == nil { t.Error("TestMatFromBytesWithEmptyByteSlise: " + "must fail because of an empty byte slice") } if !strings.Contains(err.Error(), ErrEmptyByteSlice.Error()) { t.Errorf("TestMatFromBytesWithEmptyByteSlice: "+ "error must contain the following description: "+ "%v, but have: %v", ErrEmptyByteSlice, err) } } func TestMatFromBytesSliceGarbageCollected(t *testing.T) { data := []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} m, err := NewMatFromBytes(2, 5, MatTypeCV8U, data) if err != nil { t.Error("TestMatFromBytesSliceGarbageCollected: " + "failed to create Mat") } defer m.Close() // Force garbage collection. As data is not used after this, its backing array should // be collected. runtime.GC() v := m.GetUCharAt(0, 0) if v != 0 { t.Errorf("TestMatFromBytesSliceGarbageCollected: "+ "unexpected value. Want %d, got %d.", 0, v) } } func TestMatWithSize(t *testing.T) { mat := NewMatWithSize(101, 102, MatTypeCV8U) defer mat.Close() if mat.Empty() { t.Error("NewMatWithSize should not be empty") } if mat.Rows() != 101 { t.Errorf("NewMatWithSize incorrect row count: %v\n", mat.Rows()) } if mat.Cols() != 102 { t.Errorf("NewMatWithSize incorrect col count: %v\n", mat.Cols()) } if mat.Channels() != 1 { t.Errorf("NewMatWithSize incorrect channels count: %v\n", mat.Channels()) } if mat.Type() != 0 { t.Errorf("NewMatWithSize incorrect type: %v\n", mat.Type()) } if mat.Step() != 102 { t.Errorf("NewMatWithSize incorrect step count: %v\n", mat.Step()) } } func TestMatWithSizeFromScalar(t *testing.T) { s := NewScalar(255.0, 105.0, 180.0, 0.0) mat := NewMatWithSizeFromScalar(s, 2, 3, MatTypeCV8UC3) defer mat.Close() if mat.Empty() { t.Error("NewMatWithSizeFromScalar should not be empty") } if mat.Rows() != 2 { t.Errorf("NewMatWithSizeFromScalar incorrect row count: %v\n", mat.Rows()) } if mat.Cols() != 3 { t.Errorf("NewMatWithSizeFromScalar incorrect col count: %v\n", mat.Cols()) } if mat.Channels() != 3 { t.Errorf("NewMatWithSizeFromScalar incorrect channels count: %v\n", mat.Channels()) } if mat.Type() != 16 { t.Errorf("NewMatWithSizeFromScalar incorrect type: %v\n", mat.Type()) } if mat.Total() != 6 { t.Errorf("incorrect total: %v\n", mat.Total()) } if mat.Step() != 9 { t.Errorf("NewMatWithSizeFromScalar incorrect step count: %v\n", mat.Step()) } sz := mat.Size() if sz[0] != 2 && sz[1] != 3 { t.Errorf("NewMatWithSize incorrect size: %v\n", sz) } matChans := Split(mat) scalarByte := []byte{255, 105, 180} for c := 0; c < mat.Channels(); c++ { for i := 0; i < mat.Rows(); i++ { for j := 0; j < mat.Cols(); j++ { if s := matChans[c].GetUCharAt(i, j); s != scalarByte[c] { t.Errorf("NewMatWithSizeFromScalar incorrect scalar: %v\n", s) } } } } for _, i := range matChans { i.Close() } } func TestMatFromPtr(t *testing.T) { mat := NewMatWithSize(101, 102, MatTypeCV8U) defer mat.Close() pmat, _ := mat.FromPtr(11, 12, MatTypeCV8U, 10, 10) defer pmat.Close() if pmat.Rows() != 11 { t.Errorf("Mat copy incorrect row count: %v\n", pmat.Rows()) } if pmat.Cols() != 12 { t.Errorf("Mat copy incorrect col count: %v\n", pmat.Cols()) } } func TestMatClone(t *testing.T) { mat := NewMatWithSize(101, 102, MatTypeCV8U) defer mat.Close() clone := mat.Clone() defer clone.Close() if clone.Rows() != 101 { t.Errorf("Mat clone incorrect row count: %v\n", clone.Rows()) } if clone.Cols() != 102 { t.Errorf("Mat clone incorrect col count: %v\n", clone.Cols()) } } func TestMatCopyTo(t *testing.T) { mat := NewMatWithSize(101, 102, MatTypeCV8U) defer mat.Close() copy := NewMat() defer copy.Close() mat.CopyTo(©) if copy.Rows() != 101 { t.Errorf("Mat copy incorrect row count: %v\n", copy.Rows()) } if copy.Cols() != 102 { t.Errorf("Mat copy incorrect col count: %v\n", copy.Cols()) } } func TestMatCopyToWithMask(t *testing.T) { mat := NewMatWithSize(101, 102, MatTypeCV8U) defer mat.Close() mask := NewMatWithSize(101, 102, MatTypeCV8U) defer mask.Close() diff := NewMat() defer diff.Close() mat.SetUCharAt(0, 0, 255) mat.SetUCharAt(0, 1, 255) mask.SetUCharAt(0, 0, 255) copy := NewMat() defer copy.Close() mat.CopyToWithMask(©, mask) if copy.Rows() != 101 { t.Errorf("Mat copy incorrect row count: %v\n", copy.Rows()) } if copy.Cols() != 102 { t.Errorf("Mat copy incorrect col count: %v\n", copy.Cols()) } if copy.GetUCharAt(0, 0) != 255 || copy.GetUCharAt(0, 1) != 0 { t.Errorf("Mask failed to apply to source image") } Compare(mat, copy, &diff, CompareEQ) if CountNonZero(diff) == 0 { t.Errorf("Mat CopyToWithMask incorrect diff: %v\n", CountNonZero(diff)) } } func TestMatToBytes(t *testing.T) { mat1 := NewMatWithSize(101, 102, MatTypeCV8U) defer mat1.Close() b := mat1.ToBytes() if len(b) != 101*102 { t.Errorf("Mat bytes incorrect length: %v\n", len(b)) } copy, err := NewMatFromBytes(101, 102, MatTypeCV8U, b) if err != nil { t.Error(err.Error()) } defer copy.Close() if copy.Rows() != 101 { t.Errorf("Mat from bytes incorrect row count: %v\n", copy.Rows()) } if copy.Cols() != 102 { t.Errorf("Mat region incorrect col count: %v\n", copy.Cols()) } mat2 := NewMatWithSize(101, 102, MatTypeCV16S) defer mat2.Close() b = mat2.ToBytes() if len(b) != 101*102*2 { t.Errorf("Mat bytes incorrect length: %v\n", len(b)) } mat3 := NewMatFromScalar(NewScalar(255.0, 105.0, 180.0, 0.0), MatTypeCV8UC3) defer mat3.Close() b = mat3.ToBytes() if len(b) != 3 { t.Errorf("Mat bytes incorrect length: %v\n", len(b)) } if bytes.Compare(b, []byte{255, 105, 180}) != 0 { t.Errorf("Mat bytes unexpected values: %v\n", b) } } func TestMatEye(t *testing.T) { data := []byte{1, 0, 0, 1} e := Eye(2, 2, MatTypeCV8U) if bytes.Compare(e.ToBytes(), data) != 0 { t.Errorf("Mat bytes are not equal") } e.Close() data2 := []byte{1, 0, 0, 0, 1, 0} e2 := Eye(2, 3, MatTypeCV8U) if bytes.Compare(e2.ToBytes(), data2) != 0 { t.Errorf("Mat bytes are not equal") } val := e2.GetUCharAt(0, 2) if val != 0 { t.Errorf("Mat bytes unexpected value at [0,2]: %v\n", val) } e2.Close() } func TestMatZeros(t *testing.T) { expected := NewMatWithSize(2, 3, MatTypeCV8U) z := Zeros(2, 3, MatTypeCV8U) if bytes.Compare(z.ToBytes(), expected.ToBytes()) != 0 { t.Errorf("Mat bytes are not equal") } expected.Close() z.Close() expected2 := NewMatWithSize(2, 3, MatTypeCV64F) z2 := Zeros(2, 3, MatTypeCV64F) if bytes.Compare(z2.ToBytes(), expected2.ToBytes()) != 0 { t.Errorf("Mat bytes are not equal") } expected2.Close() z2.Close() } func TestMatOnes(t *testing.T) { expected := NewMatWithSizeFromScalar(Scalar{Val1: 1}, 2, 3, MatTypeCV8U) o := Ones(2, 3, MatTypeCV8U) if bytes.Compare(o.ToBytes(), expected.ToBytes()) != 0 { t.Errorf("Mat bytes are not equal") } defer expected.Close() defer o.Close() expected2 := NewMatWithSizeFromScalar(Scalar{Val1: 1}, 2, 1, MatTypeCV64F) o2 := Ones(2, 1, MatTypeCV64F) if bytes.Compare(o2.ToBytes(), expected2.ToBytes()) != 0 { t.Errorf("Mat bytes are not equal") } expected2.Close() o2.Close() } func TestMatDataPtr(t *testing.T) { const ( rows = 101 cols = 102 ) t.Run("Uint8", func(t *testing.T) { testPoints := []struct { row int col int val uint8 }{ {row: 0, col: 0, val: 10}, {row: 30, col: 31, val: 20}, {row: rows - 1, col: cols - 1, val: 30}, } mat1 := NewMatWithSize(rows, cols, MatTypeCV8U) defer mat1.Close() b, err := mat1.DataPtrUint8() if err != nil { t.Error(err) } if len(b) != 101*102 { t.Errorf("Mat bytes incorrect length: %v\n", len(b)) } for _, p := range testPoints { mat1.SetUCharAt(p.row, p.col, p.val) if got := b[p.row*cols+p.col]; got != p.val { t.Errorf("Expected %d,%d = %d, but it was %d", p.row, p.col, p.val, got) } } mat2 := NewMatWithSize(3, 9, MatTypeCV32F) defer mat2.Close() b, err = mat2.DataPtrUint8() if err != nil { t.Error(err) } if len(b) != 3*9*4 { t.Errorf("Mat bytes incorrect length: %v\n", len(b)) } mat3 := mat1.Region(image.Rect(25, 25, 75, 75)) defer mat3.Close() _, err = mat3.DataPtrUint8() if err == nil { t.Errorf("Expected error.") } }) t.Run("Int8", func(t *testing.T) { testPoints := []struct { row int col int val int8 }{ {row: 0, col: 0, val: 10}, {row: 30, col: 31, val: 20}, {row: rows - 1, col: cols - 1, val: 30}, } mat1 := NewMatWithSize(101, 102, MatTypeCV8S) defer mat1.Close() b, err := mat1.DataPtrInt8() if err != nil { t.Error(err) } if len(b) != rows*cols { t.Errorf("Mat bytes incorrect length: %v\n", len(b)) } for _, p := range testPoints { mat1.SetSCharAt(p.row, p.col, p.val) if got := b[p.row*cols+p.col]; got != p.val { t.Errorf("Expected %d,%d = %d, but it was %d", p.row, p.col, p.val, got) } } mat2 := NewMatWithSize(3, 9, MatTypeCV32F) defer mat2.Close() b, err = mat2.DataPtrInt8() if err != nil { t.Error(err) } if len(b) != 3*9*4 { t.Errorf("Mat bytes incorrect length: %v\n", len(b)) } mat3 := mat1.Region(image.Rect(25, 25, 75, 75)) defer mat3.Close() _, err = mat3.DataPtrInt8() if err == nil { t.Errorf("Expected error.") } }) t.Run("Uint16", func(t *testing.T) { testPoints := []struct { row int col int val uint16 }{ {row: 0, col: 0, val: 10}, {row: 30, col: 31, val: 20}, {row: rows - 1, col: cols - 1, val: 30}, } mat1 := NewMatWithSize(rows, cols, MatTypeCV16U) defer mat1.Close() b, err := mat1.DataPtrUint16() if err != nil { t.Error(err) } if len(b) != rows*cols { t.Errorf("Mat bytes incorrect length: %v\n", len(b)) } for _, p := range testPoints { mat1.SetShortAt(p.row, p.col, int16(p.val)) if got := b[p.row*cols+p.col]; got != p.val { t.Errorf("Expected %d,%d = %d, but it was %d", p.row, p.col, p.val, got) } } mat2 := NewMatWithSize(3, 9, MatTypeCV32F) defer mat2.Close() _, err = mat2.DataPtrUint16() if err == nil { t.Errorf("Expected error.") } mat3 := mat1.Region(image.Rect(25, 25, 75, 75)) defer mat3.Close() _, err = mat3.DataPtrUint16() if err == nil { t.Errorf("Expected error.") } }) t.Run("Int16", func(t *testing.T) { testPoints := []struct { row int col int val int16 }{ {row: 0, col: 0, val: 10}, {row: 30, col: 31, val: 20}, {row: rows - 1, col: cols - 1, val: 30}, } mat1 := NewMatWithSize(rows, cols, MatTypeCV16S) defer mat1.Close() b, err := mat1.DataPtrInt16() if err != nil { t.Error(err) } if len(b) != rows*cols { t.Errorf("Mat bytes incorrect length: %v\n", len(b)) } for _, p := range testPoints { mat1.SetShortAt(p.row, p.col, p.val) if got := b[p.row*cols+p.col]; got != p.val { t.Errorf("Expected %d,%d = %d, but it was %d", p.row, p.col, p.val, got) } } mat2 := NewMatWithSize(3, 9, MatTypeCV32F) defer mat2.Close() _, err = mat2.DataPtrInt16() if err == nil { t.Errorf("Expected error.") } mat3 := mat1.Region(image.Rect(25, 25, 75, 75)) defer mat3.Close() _, err = mat3.DataPtrInt16() if err == nil { t.Errorf("Expected error.") } }) t.Run("Float32", func(t *testing.T) { testPoints := []struct { row int col int val float32 }{ {row: 0, col: 0, val: 10.5}, {row: 30, col: 31, val: 20.5}, {row: rows - 1, col: cols - 1, val: 30.5}, } mat1 := NewMatWithSize(rows, cols, MatTypeCV32F) defer mat1.Close() b, err := mat1.DataPtrFloat32() if err != nil { t.Error(err) } if len(b) != rows*cols { t.Errorf("Mat bytes incorrect length: %v\n", len(b)) } for _, p := range testPoints { mat1.SetFloatAt(p.row, p.col, p.val) if got := b[p.row*cols+p.col]; got != p.val { t.Errorf("Expected %d,%d = %f, but it was %f", p.row, p.col, p.val, got) } } mat2 := NewMatWithSize(3, 9, MatTypeCV16S) defer mat2.Close() _, err = mat2.DataPtrFloat32() if err == nil { t.Errorf("Expected error.") } mat3 := mat1.Region(image.Rect(25, 25, 75, 75)) defer mat3.Close() _, err = mat3.DataPtrFloat32() if err == nil { t.Errorf("Expected error.") } }) t.Run("Float64", func(t *testing.T) { testPoints := []struct { row int col int val float64 }{ {row: 0, col: 0, val: 10.5}, {row: 30, col: 31, val: 20.5}, {row: rows - 1, col: cols - 1, val: 30.5}, } mat1 := NewMatWithSize(rows, cols, MatTypeCV64F) defer mat1.Close() b, err := mat1.DataPtrFloat64() if err != nil { t.Error(err) } if len(b) != rows*cols { t.Errorf("Mat bytes incorrect length: %v\n", len(b)) } for _, p := range testPoints { mat1.SetDoubleAt(p.row, p.col, p.val) if got := b[p.row*cols+p.col]; got != p.val { t.Errorf("Expected %d,%d = %f, but it was %f", p.row, p.col, p.val, got) } } mat2 := NewMatWithSize(3, 9, MatTypeCV16S) defer mat2.Close() _, err = mat2.DataPtrFloat64() if err == nil { t.Errorf("Expected error.") } mat3 := mat1.Region(image.Rect(25, 25, 75, 75)) defer mat3.Close() _, err = mat3.DataPtrFloat64() if err == nil { t.Errorf("Expected error.") } }) } func TestMatRegion(t *testing.T) { mat := NewMatWithSize(100, 100, MatTypeCV8U) defer mat.Close() region := mat.Region(image.Rect(20, 25, 80, 75)) defer region.Close() if region.Rows() != 50 { t.Errorf("Mat region incorrect row count: %v\n", region.Rows()) } if region.Cols() != 60 { t.Errorf("Mat region incorrect col count: %v\n", region.Cols()) } } func TestMatReshape(t *testing.T) { mat := NewMatWithSize(100, 100, MatTypeCV8UC4) defer mat.Close() r := mat.Reshape(1, 1) defer r.Close() if r.Rows() != 1 { t.Errorf("Mat reshape incorrect row count: %v\n", r.Rows()) } if r.Cols() != 40000 { t.Errorf("Mat reshape incorrect col count: %v\n", r.Cols()) } } func TestMatReshapeWithSize(t *testing.T) { mat := NewMatWithSize(512, 512, MatTypeCV32FC3) defer mat.Close() r := mat.ReshapeWithSize(0, []int{512, 512}) defer r.Close() if r.Rows() != 512 { t.Errorf("Mat reshape with size incorrect row count: %v\n", r.Rows()) } if r.Cols() != 512 { t.Errorf("Mat reshape with size incorrect col count: %v\n", r.Cols()) } } func TestMatPatchNaNs(t *testing.T) { mat := NewMatWithSize(100, 100, MatTypeCV32F) defer mat.Close() mat.PatchNaNs() if mat.Empty() { t.Error("TestMatPatchNaNs error.") } } func TestMatConvert(t *testing.T) { src := NewMatWithSize(100, 100, MatTypeCV32F) defer src.Close() dst := NewMat() defer dst.Close() src.ConvertTo(&dst, MatTypeCV16S) if dst.Empty() { t.Error("TestConvert dst should not be empty.") } } func TestMatConvertWithParams(t *testing.T) { src := NewMatWithSize(100, 100, MatTypeCV8U) defer src.Close() dst := NewMat() defer dst.Close() src.ConvertToWithParams(&dst, MatTypeCV32F, 1.0/255.0, 0.0) if dst.Empty() { t.Error("TestConvertWithParams dst should not be empty.") } } func TestMatConvertFp16(t *testing.T) { src := NewMatWithSize(100, 100, MatTypeCV32F) defer src.Close() dst := src.ConvertFp16() defer dst.Close() if dst.Empty() { t.Error("TestConvertFp16 dst should not be empty.") } } func TestMatSqrt(t *testing.T) { src := NewMatWithSize(100, 100, MatTypeCV32F) defer src.Close() dst := src.Sqrt() defer dst.Close() if dst.Empty() { t.Error("TestSqrt dst should not be empty.") } } func TestMatMean(t *testing.T) { mat := NewMatWithSize(100, 100, MatTypeCV8U) defer mat.Close() mean := mat.Mean() if mean.Val1 != 0 { t.Errorf("Mat Mean incorrect Val1") } } func TestMatMeanWithMask(t *testing.T) { mat := NewMatWithSize(100, 100, MatTypeCV8U) defer mat.Close() mask := NewMatWithSize(100, 100, MatTypeCV8U) defer mask.Close() mean := mat.MeanWithMask(mask) if mean.Val1 != 0 { t.Errorf("Mat Mean incorrect Val1") } } func TestLUT(t *testing.T) { src := IMRead("images/gocvlogo.jpg", IMReadColor) if src.Empty() { t.Error("Invalid read of Source Mat in LUT test") } defer src.Close() lut := IMRead("images/lut.png", IMReadColor) if lut.Empty() { t.Error("Invalid read of LUT Mat in LUT test") } defer lut.Close() dst := NewMat() defer dst.Close() LUT(src, lut, &dst) if dst.Cols() != 400 || dst.Rows() != 343 { t.Errorf("Expected dst size of 200x172 got %dx%d", dst.Cols(), dst.Rows()) } } func TestMatAccessors(t *testing.T) { mat := NewMatWithSize(101, 102, MatTypeCV8U) if mat.GetUCharAt(50, 50) != 0 { t.Errorf("GetUCharAt incorrect value: %v\n", mat.GetUCharAt(50, 50)) } if mat.GetUCharAt3(50, 50, 0) != 0 { t.Errorf("GetUCharAt3 incorrect value: %v\n", mat.GetUCharAt3(50, 50, 0)) } mat.Close() mat = NewMatWithSize(101, 102, MatTypeCV8S) if mat.GetSCharAt(50, 50) != 0 { t.Errorf("GetSCharAt incorrect value: %v\n", mat.GetSCharAt(50, 50)) } if mat.GetSCharAt3(50, 50, 0) != 0 { t.Errorf("GetSCharAt3 incorrect value: %v\n", mat.GetSCharAt3(50, 50, 0)) } mat.Close() mat = NewMatWithSize(101, 102, MatTypeCV16S) if mat.GetShortAt(50, 50) != 0 { t.Errorf("GetShortAt incorrect value: %v\n", mat.GetShortAt(50, 50)) } if mat.GetShortAt3(50, 50, 0) != 0 { t.Errorf("GetShortAt3 incorrect value: %v\n", mat.GetShortAt3(50, 50, 0)) } mat.Close() mat = NewMatWithSize(101, 102, MatTypeCV32S) if mat.GetIntAt(50, 50) != 0 { t.Errorf("GetIntAt incorrect value: %v\n", mat.GetIntAt(50, 50)) } if mat.GetIntAt3(50, 50, 0) != 0 { t.Errorf("GetIntAt3 incorrect value: %v\n", mat.GetIntAt3(50, 50, 0)) } mat.Close() mat = NewMatWithSize(101, 102, MatTypeCV32F) if mat.GetFloatAt(50, 50) != 0.0 { t.Errorf("GetFloatAt incorrect value: %v\n", mat.GetFloatAt(50, 50)) } if mat.GetFloatAt3(50, 50, 0) != 0.0 { t.Errorf("GetFloatAt3 incorrect value: %v\n", mat.GetFloatAt3(50, 50, 0)) } mat.Close() mat = NewMatWithSize(101, 102, MatTypeCV64F) if mat.GetDoubleAt(50, 50) != 0.0 { t.Errorf("GetDoubleAt incorrect value: %v\n", mat.GetDoubleAt(50, 50)) } if mat.GetDoubleAt3(50, 50, 0) != 0.0 { t.Errorf("GetDoubleAt3 incorrect value: %v\n", mat.GetDoubleAt3(50, 50, 0)) } mat.Close() } func TestMatMutators(t *testing.T) { t.Run("SetTo", func(t *testing.T) { mat := NewMatWithSizeFromScalar(NewScalar(0, 0, 0, 0), 1, 1, MatTypeCV8U) mat.SetTo(NewScalar(255, 255, 255, 255)) for z := 0; z < mat.Channels(); z++ { if mat.GetUCharAt3(0, 0, z) != 255 { t.Errorf("SetTo incorrect value: z=%v: %v\n", z, mat.GetUCharAt3(0, 0, z)) } } mat.Close() }) t.Run("SetUCharAt", func(t *testing.T) { mat := NewMatWithSize(101, 102, MatTypeCV8U) mat.SetUCharAt(50, 50, 25) if mat.GetUCharAt(50, 50) != 25 { t.Errorf("SetUCharAt incorrect value: %v\n", mat.GetUCharAt(50, 50)) } mat.Close() }) t.Run("SetUCharAt3", func(t *testing.T) { mat := NewMatWithSize(101, 102, MatTypeCV8U) mat.SetUCharAt3(50, 50, 0, 25) if mat.GetUCharAt3(50, 50, 0) != 25 { t.Errorf("SetUCharAt3 incorrect value: %v\n", mat.GetUCharAt3(50, 50, 0)) } mat.Close() }) t.Run("SetSCharAt", func(t *testing.T) { mat := NewMatWithSize(101, 102, MatTypeCV8S) mat.SetSCharAt(50, 50, 25) if mat.GetSCharAt(50, 50) != 25 { t.Errorf("SetSCharAt incorrect value: %v\n", mat.GetSCharAt(50, 50)) } mat.Close() }) t.Run("SetSCharAt3", func(t *testing.T) { mat := NewMatWithSize(101, 102, MatTypeCV8S) mat.SetSCharAt3(50, 50, 0, 25) if mat.GetSCharAt3(50, 50, 0) != 25 { t.Errorf("SetSCharAt3 incorrect value: %v\n", mat.GetSCharAt3(50, 50, 0)) } mat.Close() }) t.Run("SetShortAt", func(t *testing.T) { mat := NewMatWithSize(101, 102, MatTypeCV16S) mat.SetShortAt(50, 50, 25) if mat.GetShortAt(50, 50) != 25 { t.Errorf("SetShortAt incorrect value: %v\n", mat.GetShortAt(50, 50)) } mat.Close() }) t.Run("SetShortAt3", func(t *testing.T) { mat := NewMatWithSize(101, 102, MatTypeCV16S) mat.SetShortAt3(50, 50, 0, 25) if mat.GetShortAt3(50, 50, 0) != 25 { t.Errorf("SetShortAt3 incorrect value: %v\n", mat.GetShortAt3(50, 50, 0)) } mat.Close() }) t.Run("SetIntAt", func(t *testing.T) { mat := NewMatWithSize(101, 102, MatTypeCV32S) mat.SetIntAt(50, 50, 25) if mat.GetIntAt(50, 50) != 25 { t.Errorf("SetIntAt incorrect value: %v\n", mat.GetIntAt(50, 50)) } mat.Close() }) t.Run("SetIntAt3", func(t *testing.T) { mat := NewMatWithSize(101, 102, MatTypeCV32S) mat.SetIntAt3(50, 50, 0, 25) if mat.GetIntAt3(50, 50, 0) != 25 { t.Errorf("SetIntAt3 incorrect value: %v\n", mat.GetIntAt3(50, 50, 0)) } mat.Close() }) t.Run("SetFloatAt", func(t *testing.T) { mat := NewMatWithSize(101, 102, MatTypeCV32F) mat.SetFloatAt(50, 50, 25.0) if mat.GetFloatAt(50, 50) != 25 { t.Errorf("SetFloatAt incorrect value: %v\n", mat.GetFloatAt(50, 50)) } mat.Close() }) t.Run("SetFloatAt3", func(t *testing.T) { mat := NewMatWithSize(101, 102, MatTypeCV32F) mat.SetFloatAt3(50, 50, 0, 25.0) if mat.GetFloatAt3(50, 50, 0) != 25 { t.Errorf("SetFloatAt incorrect value: %v\n", mat.GetFloatAt3(50, 50, 0)) } mat.Close() }) t.Run("SetDoubleAt", func(t *testing.T) { mat := NewMatWithSize(101, 102, MatTypeCV64F) mat.SetDoubleAt(50, 50, 25.0) if mat.GetDoubleAt(50, 50) != 25.0 { t.Errorf("SetDoubleAt incorrect value: %v\n", mat.GetDoubleAt(50, 50)) } mat.Close() }) t.Run("SetDoubleAt3", func(t *testing.T) { mat := NewMatWithSize(101, 102, MatTypeCV64F) mat.SetDoubleAt3(50, 50, 0, 25.0) if mat.GetDoubleAt3(50, 50, 0) != 25.0 { t.Errorf("SetDoubleAt3 incorrect value: %v\n", mat.GetDoubleAt3(50, 50, 0)) } mat.Close() }) t.Run("AddUChar", func(t *testing.T) { mat := NewMatWithSize(101, 102, MatTypeCV8U) mat.AddUChar(42) if mat.GetUCharAt(50, 50) != 42 { t.Errorf("AddUChar incorrect value: %v\n", mat.GetUCharAt(50, 50)) } mat.Close() }) t.Run("SubtractUChar", func(t *testing.T) { mat := NewMatWithSizeFromScalar(NewScalar(42.0, 0, 0, 0), 101, 102, MatTypeCV8U) mat.SubtractUChar(40) if mat.GetUCharAt(50, 50) != 2 { t.Errorf("SubtractUChar incorrect value: %v\n", mat.GetUCharAt(50, 50)) } mat.Close() }) t.Run("MultiplyUChar", func(t *testing.T) { mat := NewMatWithSizeFromScalar(NewScalar(5.0, 0, 0, 0), 101, 102, MatTypeCV8U) mat.MultiplyUChar(5) if mat.GetUCharAt(50, 50) != 25 { t.Errorf("MultiplyUChar incorrect value: %v\n", mat.GetUCharAt(50, 50)) } mat.Close() }) t.Run("DivideUChar", func(t *testing.T) { mat := NewMatWithSizeFromScalar(NewScalar(25.0, 0, 0, 0), 101, 102, MatTypeCV8U) mat.DivideUChar(5) if mat.GetUCharAt(50, 50) != 5 { t.Errorf("DivideUChar incorrect value: %v\n", mat.GetUCharAt(50, 50)) } mat.Close() }) t.Run("AddFloat", func(t *testing.T) { mat := NewMatWithSizeFromScalar(NewScalar(30.0, 0, 0, 0), 101, 102, MatTypeCV32F) mat.AddFloat(1.0) if mat.GetFloatAt(50, 50) != 31.0 { t.Errorf("AddFloat incorrect value: %v\n", mat.GetFloatAt(50, 50)) } mat.Close() }) t.Run("SubtractFloat", func(t *testing.T) { mat := NewMatWithSizeFromScalar(NewScalar(30.0, 0, 0, 0), 101, 102, MatTypeCV32F) mat.SubtractFloat(1.0) if mat.GetFloatAt(50, 50) != 29.0 { t.Errorf("SubtractFloat incorrect value: %v\n", mat.GetFloatAt(50, 50)) } mat.Close() }) t.Run("MultiplyFloat", func(t *testing.T) { mat := NewMatWithSizeFromScalar(NewScalar(30.0, 0, 0, 0), 101, 102, MatTypeCV32F) mat.MultiplyFloat(2.0) if mat.GetFloatAt(50, 50) != 60.0 { t.Errorf("MultiplyFloat incorrect value: %v\n", mat.GetFloatAt(50, 50)) } mat.Close() }) t.Run("DivideFloat", func(t *testing.T) { mat := NewMatWithSizeFromScalar(NewScalar(30.0, 0, 0, 0), 101, 102, MatTypeCV32F) mat.DivideFloat(2.0) if mat.GetFloatAt(50, 50) != 15.0 { t.Errorf("DivideFloat incorrect value: %v\n", mat.GetFloatAt(50, 50)) } mat.Close() }) t.Run("MultiplyMatrix", func(t *testing.T) { mat := NewMatWithSizeFromScalar(NewScalar(30.0, 0, 0, 0), 2, 1, MatTypeCV32F) mat2 := NewMatWithSizeFromScalar(NewScalar(30.0, 0, 0, 0), 1, 2, MatTypeCV32F) mat3 := mat.MultiplyMatrix(mat2) for i := 0; i < mat3.Cols(); i++ { for j := 0; j < mat3.Rows(); j++ { if mat3.GetFloatAt(i, j) != 900.0 { t.Errorf("MultiplyMatrix incorrect value: %v\n", mat3.GetFloatAt(i, j)) } } } mat.Close() mat2.Close() mat3.Close() }) } func TestMatAbsDiff(t *testing.T) { mat1 := NewMatWithSize(101, 102, MatTypeCV8U) defer mat1.Close() mat2 := NewMatWithSize(101, 102, MatTypeCV8U) defer mat2.Close() mat3 := NewMat() defer mat3.Close() AbsDiff(mat1, mat2, &mat3) if mat3.Empty() { t.Error("TestMatAbsDiff dest mat3 should not be empty.") } } func TestMatAdd(t *testing.T) { mat1 := NewMatWithSize(101, 102, MatTypeCV8U) defer mat1.Close() mat2 := NewMatWithSize(101, 102, MatTypeCV8U) defer mat2.Close() mat3 := NewMat() defer mat3.Close() Add(mat1, mat2, &mat3) if mat3.Empty() { t.Error("TestMatAdd dest mat3 should not be empty.") } } func TestMatAddWeighted(t *testing.T) { mat1 := NewMatWithSize(101, 102, MatTypeCV8U) defer mat1.Close() mat2 := NewMatWithSize(101, 102, MatTypeCV8U) defer mat2.Close() mat3 := NewMat() defer mat3.Close() AddWeighted(mat1, 2.0, mat2, 3.0, 4.0, &mat3) if mat3.Empty() { t.Error("TestMatAddWeighted dest mat3 should not be empty.") } } func TestMatBitwiseOperations(t *testing.T) { mat1 := NewMatWithSize(101, 102, MatTypeCV8U) defer mat1.Close() mat2 := NewMatWithSize(101, 102, MatTypeCV8U) defer mat2.Close() mat3 := NewMat() defer mat3.Close() BitwiseAnd(mat1, mat2, &mat3) if mat3.Empty() { t.Error("TestMatBitwiseAnd dest mat3 should not be empty.") } BitwiseOr(mat1, mat2, &mat3) if mat3.Empty() { t.Error("TestMatBitwiseOr dest mat3 should not be empty.") } BitwiseXor(mat1, mat2, &mat3) if mat3.Empty() { t.Error("TestMatBitwiseXor dest mat3 should not be empty.") } BitwiseNot(mat1, &mat3) if mat3.Empty() { t.Error("TestMatBitwiseNot dest mat3 should not be empty.") } } func TestMatBitwiseOperationsWithMasks(t *testing.T) { mat1 := NewMatWithSize(101, 102, MatTypeCV8U) defer mat1.Close() mat2 := NewMatWithSize(101, 102, MatTypeCV8U) defer mat2.Close() mat3 := NewMat() defer mat3.Close() mat4 := NewMatWithSize(101, 102, MatTypeCV8U) defer mat4.Close() BitwiseAndWithMask(mat1, mat2, &mat3, mat4) if mat3.Empty() { t.Error("TestMatBitwiseAndWithMask dest mat3 should not be empty.") } BitwiseOrWithMask(mat1, mat2, &mat3, mat4) if mat3.Empty() { t.Error("TestMatBitwiseOrWithMask dest mat3 should not be empty.") } BitwiseXorWithMask(mat1, mat2, &mat3, mat4) if mat3.Empty() { t.Error("TestMatBitwiseXorWithMask dest mat3 should not be empty.") } BitwiseNotWithMask(mat1, &mat3, mat4) if mat3.Empty() { t.Error("TestMatBitwiseNotWithMask dest mat3 should not be empty.") } } func TestMatInRange(t *testing.T) { mat1 := NewMatWithSize(101, 102, MatTypeCV8U) defer mat1.Close() lb := NewMatFromScalar(NewScalar(20.0, 100.0, 100.0, 0.0), MatTypeCV8U) defer lb.Close() ub := NewMatFromScalar(NewScalar(20.0, 100.0, 100.0, 0.0), MatTypeCV8U) defer ub.Close() dst := NewMat() defer dst.Close() InRange(mat1, lb, ub, &dst) if dst.Empty() { t.Error("TestMatAddWeighted dest mat3 should not be empty.") } } func TestMatInRangeWithScalar(t *testing.T) { mat1 := NewMatWithSize(101, 102, MatTypeCV8U) defer mat1.Close() lb := NewScalar(20.0, 100.0, 100.0, 0.0) ub := NewScalar(20.0, 100.0, 100.0, 0.0) dst := NewMat() defer dst.Close() InRangeWithScalar(mat1, lb, ub, &dst) if dst.Empty() { t.Error("TestMatAddWeighted dest mat3 should not be empty.") } } func TestMatDCT(t *testing.T) { src := NewMatWithSize(64, 64, MatTypeCV32F) defer src.Close() dst := NewMat() defer dst.Close() DCT(src, &dst, DftForward) if dst.Empty() { t.Error("TestMatDCT dst should not be empty.") } } func TestMatDFT(t *testing.T) { src := NewMatWithSize(101, 102, MatTypeCV32F) defer src.Close() dst := NewMat() defer dst.Close() m := GetOptimalDFTSize(101) n := GetOptimalDFTSize(102) if m != 108 { t.Errorf("TestMatOptimalDFT dst error: %d", m) } if n != 108 { t.Errorf("TestMatOptimalDFT dst error: %d", n) } DFT(src, &dst, DftForward) if dst.Empty() { t.Error("TestMatDFT dst should not be empty.") } } func TestMatDivide(t *testing.T) { mat1 := NewMatWithSize(101, 102, MatTypeCV8U) defer mat1.Close() mat2 := NewMatWithSize(101, 102, MatTypeCV8U) defer mat2.Close() mat3 := NewMat() defer mat3.Close() Divide(mat1, mat2, &mat3) if mat3.Empty() { t.Error("TestMatDivide dest mat3 should not be empty.") } } func TestMeanStdDev(t *testing.T) { src := NewMatWithSize(101, 102, MatTypeCV8U) defer src.Close() dst := NewMat() defer dst.Close() dstStdDev := NewMat() defer dstStdDev.Close() MeanStdDev(src, &dst, &dstStdDev) if dst.Empty() { t.Error("TestMeanStdDev dst should not be empty.") } if dstStdDev.Empty() { t.Error("TestMeanStdDev dstStdDev should not be empty.") } } func TestMeanStdDevWithMask(t *testing.T) { src := NewMatWithSize(2, 2, MatTypeCV8U) defer src.Close() src.SetUCharAt(0, 0, 0) src.SetUCharAt(0, 1, 0) src.SetUCharAt(1, 0, 60) src.SetUCharAt(1, 1, 60) mask := NewMatWithSize(2, 2, MatTypeCV8U) mask.SetUCharAt(0, 0, 1) mask.SetUCharAt(0, 1, 1) mask.SetUCharAt(1, 0, 1) mask.SetUCharAt(1, 1, 1) defer mask.Close() dstMean := NewMat() defer dstMean.Close() dstStdDev := NewMat() defer dstStdDev.Close() MeanStdDevWithMask(src, &dstMean, &dstStdDev, mask) if dstMean.Empty() { t.Error("TestMeanStdDevWithMask dstMean should not be empty.") } if dstStdDev.Empty() { t.Error("TestMeanStdDevWithMask dstStdDev should not be empty.") } if gotMean := dstMean.GetDoubleAt(0, 0); gotMean != 30.0 { t.Errorf("TestMeanStdDevWithMask dstMean got %f, want %f", gotMean, 30.0) } if gotStdDev := dstStdDev.GetDoubleAt(0, 0); gotStdDev != 30.0 { t.Errorf("TestMeanStdDevWithMask dstStdDev got %f, want %f", gotStdDev, 30.0) } } func TestMatMerge(t *testing.T) { src := NewMatWithSize(101, 102, MatTypeCV8U) defer src.Close() src2 := NewMatWithSize(101, 102, MatTypeCV8U) defer src2.Close() src3 := NewMatWithSize(101, 102, MatTypeCV8U) defer src3.Close() dst := NewMat() defer dst.Close() Merge([]Mat{src, src2, src3}, &dst) if dst.Empty() { t.Error("TestMatMerge dst should not be empty.") } } func TestMatMulSpectrums(t *testing.T) { a := NewMatWithSize(101, 102, MatTypeCV32F) defer a.Close() b := NewMatWithSize(101, 102, MatTypeCV32F) defer b.Close() dst := NewMat() defer dst.Close() MulSpectrums(a, b, &dst, 0) if dst.Empty() { t.Error("TestMatMulSpectrums dst should not be empty.") } dst2 := NewMat() defer dst2.Close() //test with dftrows flag (the only flag accepted in addition to 0) MulSpectrums(a, b, &dst2, DftRows) if dst2.Empty() { t.Error("TestMatMulSpectrums dst should not be empty.") } } func TestMatMultiply(t *testing.T) { mat1 := NewMatWithSize(101, 102, MatTypeCV64F) defer mat1.Close() mat2 := NewMatWithSize(101, 102, MatTypeCV64F) defer mat2.Close() mat3 := NewMat() defer mat3.Close() Multiply(mat1, mat2, &mat3) if mat3.Empty() { t.Error("TestMatMultiply dest mat3 should not be empty.") } // since this is a single channel Mat, only the first value in the scalar is used mat4 := NewMatWithSizeFromScalar(NewScalar(2.0, 0.0, 0.0, 0.0), 101, 102, MatTypeCV64F) defer mat4.Close() mat5 := NewMatWithSizeFromScalar(NewScalar(3.0, 0.0, 0.0, 0.0), 101, 102, MatTypeCV64F) defer mat5.Close() Multiply(mat4, mat5, &mat3) if mat3.Empty() { t.Error("TestMatMultiply dest mat3 should not be empty.") } if mat3.GetDoubleAt(0, 0) != 6.0 { t.Error("TestMatMultiply invalue value in dest mat3.") } } func TestMatMultiplyWithParams(t *testing.T) { mat1 := NewMatWithSize(101, 102, MatTypeCV64F) defer mat1.Close() mat2 := NewMatWithSize(101, 102, MatTypeCV64F) defer mat2.Close() mat3 := NewMat() defer mat3.Close() MultiplyWithParams(mat1, mat2, &mat3, 0.5, -1) if mat3.Empty() { t.Error("TestMatMultiplyWithParams dest mat3 should not be empty.") } // since this is a single channel Mat, only the first value in the scalar is used mat4 := NewMatWithSizeFromScalar(NewScalar(2.0, 0.0, 0.0, 0.0), 101, 102, MatTypeCV64F) defer mat4.Close() mat5 := NewMatWithSizeFromScalar(NewScalar(3.0, 0.0, 0.0, 0.0), 101, 102, MatTypeCV64F) defer mat5.Close() MultiplyWithParams(mat4, mat5, &mat3, 2.0, -1) if mat3.Empty() { t.Error("TestMatMultiplyWithParams dest mat3 should not be empty.") } if mat3.GetDoubleAt(0, 0) != 12.0 { t.Error("TestMatMultiplyWithParams invalue value in dest mat3.") } } func TestMatNormalize(t *testing.T) { src := NewMatWithSize(101, 102, MatTypeCV8U) defer src.Close() dst := NewMat() defer dst.Close() Normalize(src, &dst, 0.0, 255.0, NormMinMax) if dst.Empty() { t.Error("TestMatNormalize dst should not be empty.") } } func TestMatPerspectiveTransform(t *testing.T) { src := NewMatWithSize(100, 1, MatTypeCV32F+MatChannels2) defer src.Close() dst := NewMat() defer dst.Close() tm := NewMatWithSize(3, 3, MatTypeCV32F) defer tm.Close() PerspectiveTransform(src, &dst, tm) if dst.Empty() { t.Error("PerspectiveTransform error") } } func TestMatSolve(t *testing.T) { a := NewMatWithSize(3, 3, MatTypeCV32F) defer a.Close() b := NewMatWithSize(3, 1, MatTypeCV32F) defer b.Close() solve := NewMat() defer solve.Close() testPoints := []struct { x2 float32 x float32 c float32 y float32 }{ {x2: 1, x: 1, c: 1, y: 0}, {x2: 0, x: 0, c: 1, y: 2}, {x2: 9, x: 3, c: 1, y: 2}, } for row, p := range testPoints { a.SetFloatAt(row, 0, p.x2) a.SetFloatAt(row, 1, p.x) a.SetFloatAt(row, 2, p.c) b.SetFloatAt(row, 0, p.y) } solved := Solve(a, b, &solve, SolveDecompositionLu) if !solved { t.Errorf("TestMatSolve could not solve linear equations") } if solve.GetFloatAt(0, 0) != 1 || solve.GetFloatAt(1, 0) != -3 || solve.GetFloatAt(2, 0) != 2 { t.Errorf("TestMatSolve incorrect results: got %v expected %v, got %v expected %v, got %v expected %v", solve.GetFloatAt(0, 0), 1, solve.GetFloatAt(1, 0), -3, solve.GetFloatAt(2, 0), 2) } } func TestSolveCubic(t *testing.T) { coeffs := NewMatWithSize(1, 4, MatTypeCV32F) defer coeffs.Close() roots := NewMat() defer roots.Close() coeffs.SetFloatAt(0, 0, 2.0) coeffs.SetFloatAt(0, 1, 3.0) coeffs.SetFloatAt(0, 2, -11.0) coeffs.SetFloatAt(0, 3, -6.0) rootsCount := SolveCubic(coeffs, &roots) expectedRootsCount := 3 if rootsCount != expectedRootsCount { t.Errorf("TestSolveCubic incorrect numbers of roots %d, expected %d", rootsCount, expectedRootsCount) } if roots.GetFloatAt(0, 0) != -3.0 || roots.GetFloatAt(0, 1) != 2.0 || roots.GetFloatAt(0, 0) != -3.0 { t.Errorf("TestSolveCubic incorrect roots: got %f expected %f, got %f expected %f, got %f expected %f", roots.GetFloatAt(0, 0), -3.0, roots.GetFloatAt(0, 1), -0.5, roots.GetFloatAt(0, 0), -3.0) } } func TestSolvePoly(t *testing.T) { coeffs := NewMatWithSize(1, 3, MatTypeCV32F) defer coeffs.Close() roots := NewMat() defer roots.Close() // x² - 14x + 49 = 0 coeffs.SetFloatAt(0, 0, 49.0) coeffs.SetFloatAt(0, 1, -14.0) coeffs.SetFloatAt(0, 2, 1) diffError := SolvePoly(coeffs, &roots, 300) diffTolerance := 1.0e-61 if diffError > diffTolerance { t.Errorf("TestSolvePoly was not exact, got an error of %e and should have been less than %f", diffError, diffTolerance) } if roots.GetFloatAt(0, 0) != 7.0 { t.Errorf("TestSolvePoly incorrect roots: got %f expected %f", roots.GetFloatAt(0, 0), 7.0) } } func TestMatReduceToSingleRow(t *testing.T) { rows := 2 cols := 3 src := NewMatWithSize(rows, cols, MatTypeCV8U) defer src.Close() dst := NewMat() defer dst.Close() for row := 0; row < rows; row++ { for col := 0; col < cols; col++ { src.SetUCharAt(row, col, uint8(col+1)) } } Reduce(src, &dst, 0, ReduceSum, MatTypeCV32F) sz := dst.Size() if sz[0] != 1 && sz[1] != 3 { t.Errorf("TestMatReduceToSingleRow incorrect size: %v\n", sz) } if dst.GetFloatAt(0, 0) != 2 || dst.GetFloatAt(0, 1) != 4 || dst.GetFloatAt(0, 2) != 6 { t.Errorf("TestMatReduceToSingleRow incorrect reduce result: %v at (0, 0) expected 2, %v at (0, 1) expected 4, %v at (0, 2) expected 6", dst.GetFloatAt(0, 0), dst.GetFloatAt(0, 1), dst.GetFloatAt(0, 2)) } } func TestMatReduceToSingleColumn(t *testing.T) { rows := 2 cols := 3 src := NewMatWithSize(rows, cols, MatTypeCV8U) defer src.Close() dst := NewMat() defer dst.Close() for row := 0; row < rows; row++ { for col := 0; col < cols; col++ { src.SetUCharAt(row, col, uint8(col+1)) } } Reduce(src, &dst, 1, ReduceSum, MatTypeCV32F) sz := dst.Size() if sz[0] != 3 && sz[1] != 1 { t.Errorf("TestMatReduceToSingleColumn incorrect size: %v\n", sz) } if dst.GetFloatAt(0, 0) != 6 || dst.GetFloatAt(1, 0) != 6 { t.Errorf("TestMatReduceToSingleColumn incorrect reduce result: %v at (0, 0) expected 6, %v at (1, 0) expected 6", dst.GetFloatAt(0, 0), dst.GetFloatAt(1, 0)) } } func TestMatReduceArgMax(t *testing.T) { rows := 2 cols := 3 src := NewMatWithSize(rows, cols, MatTypeCV8U) defer src.Close() dst := NewMat() defer dst.Close() for row := 0; row < rows; row++ { for col := 0; col < cols; col++ { src.SetUCharAt(row, col, uint8(col+1)) } } ReduceArgMax(src, &dst, 1, false) sz := dst.Size() if sz[0] != 2 && sz[1] != 1 { t.Errorf("TestMatReduceArgMax incorrect size: %v\n", sz) } if dst.GetUCharAt(0, 0) != 2 || dst.GetUCharAt(1, 0) != 2 { t.Errorf("TestMatReduceArgMax incorrect reduce result: %v at (0, 0) expected 1, %v at (1, 0) expected 1", dst.GetUCharAt(0, 0), dst.GetUCharAt(1, 0)) } } func TestMatReduceArgMin(t *testing.T) { rows := 2 cols := 3 src := NewMatWithSize(rows, cols, MatTypeCV8U) defer src.Close() dst := NewMat() defer dst.Close() for row := 0; row < rows; row++ { for col := 0; col < cols; col++ { src.SetUCharAt(row, col, uint8(col+1)) } } ReduceArgMin(src, &dst, 1, false) sz := dst.Size() if sz[0] != 2 && sz[1] != 1 { t.Errorf("TestMatReduceArgMax incorrect size: %v\n", sz) } if dst.GetUCharAt(0, 0) != 0 || dst.GetUCharAt(1, 0) != 0 { t.Errorf("TestMatReduceArgMax incorrect reduce result: %v at (0, 0) expected 0, %v at (1, 0) expected 0", dst.GetUCharAt(0, 0), dst.GetUCharAt(1, 0)) } } func TestRepeat(t *testing.T) { rows := 1 cols := 3 src := NewMatWithSize(rows, cols, MatTypeCV8U) defer src.Close() for row := 0; row < rows; row++ { for col := 0; col < cols; col++ { src.SetUCharAt(row, col, uint8(col)) } } dst := NewMat() defer dst.Close() Repeat(src, 3, 1, &dst) size := dst.Size() expectedRows := 3 expectedCols := 3 if size[0] != expectedRows || size[1] != expectedCols { t.Errorf("TestRepeat incorrect size, got y=%d x=%d, expected y=%d x=%d.", size[0], size[1], expectedRows, expectedCols) } for row := 0; row < expectedRows; row++ { for col := 0; col < expectedCols; col++ { result := dst.GetUCharAt(row, col) if result != uint8(col) { t.Errorf("TestRepeat dst at row=%d col=%d should be %d and got %d.", row, col, col, result) } } } } func TestScaleAdd(t *testing.T) { rows := 2 cols := 3 src1 := NewMatWithSize(rows, cols, MatTypeCV64F) defer src1.Close() for row := 0; row < rows; row++ { for col := 0; col < cols; col++ { src1.SetDoubleAt(row, col, float64(col)) } } src2 := NewMatWithSize(rows, cols, MatTypeCV64F) defer src2.Close() for row := 0; row < rows; row++ { for col := 0; col < cols; col++ { src2.SetDoubleAt(row, col, 1.0) } } dst := NewMat() defer dst.Close() alpha := 1.5 ScaleAdd(src1, alpha, src2, &dst) if dst.Empty() { t.Error("TestScaleAdd dst should not be empty.") } for row := 0; row < rows; row++ { for col := 0; col < cols; col++ { expected := float64(col)*alpha + 1.0 result := dst.GetDoubleAt(row, col) if result != expected { t.Errorf("TestScaleAdd dst at row=%d col=%d should be %f and got %f.", row, col, expected, result) } } } } func TestSetIdentity(t *testing.T) { rows := 4 cols := 3 src := NewMatWithSize(rows, cols, MatTypeCV64F) defer src.Close() scalar := 2.5 SetIdentity(src, scalar) if src.Empty() { t.Error("TestSetIdentity src should not be empty.") } for row := 0; row < rows; row++ { for col := 0; col < cols; col++ { result := src.GetDoubleAt(row, col) expected := 0.0 if row == col { expected = scalar } if result != expected { t.Errorf("TestSetIdentity src at row=%d col=%d should be %f and got %f.", row, col, expected, result) } } } } func TestMatSortEveryRowDescending(t *testing.T) { rows := 2 cols := 3 src := NewMatWithSize(rows, cols, MatTypeCV8U) defer src.Close() for row := 0; row < rows; row++ { for col := 0; col < cols; col++ { src.SetUCharAt(row, col, uint8(col)) } } dst := NewMat() defer dst.Close() flags := SortEveryRow + SortDescending Sort(src, &dst, flags) if dst.Empty() { t.Error("TestMatSortEveryRowDescending dst should not be empty.") } for row := 0; row < rows; row++ { for col := 0; col < cols; col++ { expected := cols - col - 1 result := dst.GetUCharAt(row, col) if result != uint8(expected) { t.Errorf("TestMatSortEveryRowDescending dst at row=%d col=%d should be %d and got %d.", row, col, expected, result) } } } } func TestMatSortIdxEveryRowDescending(t *testing.T) { rows := 2 cols := 3 src := NewMatWithSize(rows, cols, MatTypeCV8U) defer src.Close() for row := 0; row < rows; row++ { for col := 0; col < cols; col++ { src.SetUCharAt(row, col, uint8(col)) } } dst := NewMat() defer dst.Close() flags := SortEveryRow + SortDescending SortIdx(src, &dst, flags) if dst.Empty() { t.Error("TestMatSortIdxEveryRowDescending dst should not be empty.") } } func TestMatSplit(t *testing.T) { src := IMRead("images/face.jpg", 1) defer src.Close() chans := Split(src) if len(chans) != src.Channels() { t.Error("Split Channel count differs") } dst := NewMat() defer dst.Close() Merge(chans, &dst) for _, ch := range chans { ch.Close() } diff := NewMat() defer diff.Close() AbsDiff(src, dst, &diff) sum := diff.Sum() if sum.Val1 != 0 || sum.Val2 != 0 || sum.Val3 != 0 { t.Error("Split/Merged images differ") } } func TestMatSubtract(t *testing.T) { src1 := IMRead("images/lut.png", 1) defer src1.Close() src2 := IMRead("images/lut.png", 1) defer src2.Close() dst := NewMat() defer dst.Close() Subtract(src1, src2, &dst) sum := dst.Sum() if sum.Val1 != 0 || sum.Val2 != 0 || sum.Val3 != 0 { t.Error("Sum of Subtracting equal images is not 0") } } func TestMatTrace(t *testing.T) { rows := 3 cols := 3 src := NewMatWithSize(rows, cols, MatTypeCV8U) defer src.Close() // Create and identity eye matrix for row := 0; row <= rows; row++ { for col := 0; col <= cols; col++ { if row == col { src.SetUCharAt(row, col, uint8(1)) } } } trace := Trace(src) expected := NewScalar(3, 0, 0, 0) if trace.Val1 != expected.Val1 || trace.Val2 != expected.Val2 || trace.Val3 != expected.Val3 || trace.Val4 != expected.Val4 { t.Errorf("Trace values should be %v and was %v", expected, trace) } } func TestMatTransform(t *testing.T) { src := IMRead("images/lut.png", 1) defer src.Close() dst := NewMat() defer dst.Close() tm := NewMatWithSize(4, 4, MatTypeCV8UC4) defer tm.Close() Transform(src, &dst, tm) if dst.Empty() { t.Error("Transform error") } } func TestMatTranspose(t *testing.T) { src := IMRead("images/lut.png", 1) defer src.Close() dst := NewMat() defer dst.Close() Transpose(src, &dst) if dst.Empty() { t.Error("Transpose error") } } func TestMatTransposeND(t *testing.T) { rows := 1 cols := 3 src := NewMatWithSize(rows, cols, MatTypeCV8U) defer src.Close() for row := 0; row < rows; row++ { for col := 0; col < cols; col++ { src.SetUCharAt(row, col, uint8(col)) } } dst := NewMat() defer dst.Close() TransposeND(src, []int{1, 0}, &dst) if dst.Empty() { t.Error("TransposeND error") } } func TestPolarToCart(t *testing.T) { magnitude := NewMatWithSize(101, 102, MatTypeCV32F) angle := NewMatWithSize(101, 102, MatTypeCV32F) x := NewMat() y := NewMat() PolarToCart(magnitude, angle, &x, &y, false) if x.Empty() || y.Empty() { t.Error("TestPolarToCart neither x nor y should be empty.") } x.Close() y.Close() magnitude.Close() angle.Close() } func TestMatPow(t *testing.T) { src := NewMatWithSize(101, 102, MatTypeCV8U) defer src.Close() dst := NewMat() defer dst.Close() power := 2.0 Pow(src, power, &dst) if dst.Empty() { t.Error("TestMatPow dest should not be empty.") } } func TestMatSum(t *testing.T) { src := NewMatFromScalar(NewScalar(1, 2, 3, 4), MatTypeCV8UC4) defer src.Close() sum := src.Sum() if sum.Val1 != 1 || sum.Val2 != 2 || sum.Val3 != 3 || sum.Val4 != 4 { t.Error("Sum values do not match constructor") } } func TestTermCriteria(t *testing.T) { tc := NewTermCriteria(Count, 50, 2.0) if tc.p == nil { t.Error("TermCriteria has invalid value") } } func TestScalar(t *testing.T) { s := NewScalar(127.0, 255.0, 64.0, 0.0) if s.Val1 != 127.0 || s.Val2 != 255.0 || s.Val3 != 64.0 || s.Val4 != 0.0 { t.Error("Scalar has invalid value") } } func TestToCPoints(t *testing.T) { points := []image.Point{ image.Pt(0, 0), image.Pt(1, 1), } cPoints := toCPoints(points) if int(cPoints.length) != len(points) { t.Error("Invalid C Points length") } } func TestToCStrings(t *testing.T) { strs := []string{ "hello", "fellow", "CStrings", } cStrs := toCStrings(strs) if int(cStrs.length) != len(strs) { t.Error("Invalid CStrings length") } } func TestMatBatchDistance(t *testing.T) { src1 := NewMatWithSize(100, 100, MatTypeCV8U) src2 := NewMatWithSize(100, 100, MatTypeCV8U) mask := NewMatWithSize(100, 100, MatTypeCV8U) dist := NewMat() nidx := NewMat() BatchDistance(src1, src2, dist, -1, nidx, NormL2, 15, mask, 0, false) if dist.Empty() { t.Error("TestBatchDistance dst should not be empty.") } src1.Close() src2.Close() mask.Close() dist.Close() nidx.Close() } func TestMatBorderInterpolate(t *testing.T) { n := BorderInterpolate(1, 5, 1) if n == 0 { t.Error("TestBorderInterpolate dst should not be 0.") } } func TestMatCalcCovarMatrix(t *testing.T) { samples := NewMatWithSize(10, 10, MatTypeCV32F) covar := NewMat() mean := NewMat() CalcCovarMatrix(samples, &covar, &mean, CovarRows, MatTypeCV64F) if covar.Empty() { t.Error("TestCalcCovarMatrix dst should not be empty.") } samples.Close() covar.Close() mean.Close() } func TestMatCartToPolar(t *testing.T) { x := NewMatWithSize(100, 100, MatTypeCV32F) y := NewMatWithSize(100, 100, MatTypeCV32F) magnitude := NewMat() angle := NewMat() CartToPolar(x, y, &magnitude, &angle, false) if magnitude.Empty() || angle.Empty() { t.Error("TestCartToPolar neither magnitude nor angle should be empty.") } x.Close() y.Close() magnitude.Close() angle.Close() } func TestMatCheckRange(t *testing.T) { mat1 := NewMatWithSize(101, 102, MatTypeCV8U) defer mat1.Close() ret := CheckRange(mat1) if !ret { t.Error("TestCheckRange error.") } } func TestMatCompleteSymm(t *testing.T) { src := NewMatWithSize(100, 100, MatTypeCV32F) CompleteSymm(src, false) if src.Empty() { t.Error("TestCompleteSymm src should not be empty.") } src.Close() } func TestMatConvertScaleAbs(t *testing.T) { src := NewMatWithSize(100, 100, MatTypeCV32F) dst := NewMat() ConvertScaleAbs(src, &dst, 1, 0) if dst.Empty() { t.Error("TestConvertScaleAbs dst should not be empty.") } src.Close() dst.Close() } func TestMatCopyMakeBorder(t *testing.T) { src := NewMatWithSize(100, 100, MatTypeCV32F) dst := NewMat() CopyMakeBorder(src, &dst, 10, 10, 10, 10, BorderReflect, color.RGBA{0, 0, 0, 0}) if dst.Empty() { t.Error("TestCopyMakeBorder dst should not be empty.") } src.Close() dst.Close() } func TestMatDeterminant(t *testing.T) { mat1 := NewMatWithSize(101, 101, MatTypeCV32F) defer mat1.Close() ret := Determinant(mat1) if ret != 0 { t.Error("TestMatDeterminant error.") } } func TestMatEigen(t *testing.T) { src := NewMatWithSize(10, 10, MatTypeCV32F) eigenvalues := NewMat() eigenvectors := NewMat() Eigen(src, &eigenvalues, &eigenvectors) if eigenvectors.Empty() || eigenvalues.Empty() { t.Error("TestEigen should not have empty eigenvectors or eigenvalues.") } src.Close() eigenvectors.Close() eigenvalues.Close() } func TestMatEigenNonSymmetric(t *testing.T) { src := NewMatWithSizeFromScalar(NewScalar(0.1, 0.1, 0.1, 0.1), 10, 10, MatTypeCV32F) eigenvalues := NewMat() eigenvectors := NewMat() EigenNonSymmetric(src, &eigenvalues, &eigenvectors) if eigenvectors.Empty() || eigenvalues.Empty() { t.Error("TestEigenNonSymmetric should not have empty eigenvectors or eigenvalues.") } src.Close() eigenvectors.Close() eigenvalues.Close() } func TestPCABackProject(t *testing.T) { data := NewMatWithSize(3, 1, MatTypeCV32F) defer data.Close() data.SetFloatAt(0, 0, float32(-5)) data.SetFloatAt(1, 0, float32(0)) data.SetFloatAt(2, 0, float32(-10)) mean := NewMatWithSize(1, 4, MatTypeCV32F) defer mean.Close() mean.SetFloatAt(0, 0, float32(2)) mean.SetFloatAt(0, 1, float32(4)) mean.SetFloatAt(0, 2, float32(4)) mean.SetFloatAt(0, 3, float32(8)) vectors := NewMatWithSizeFromScalar(NewScalar(0, 0, 0, 0), 1, 4, MatTypeCV32F) defer vectors.Close() vectors.SetFloatAt(0, 0, float32(0.2)) vectors.SetFloatAt(0, 1, float32(0.4)) vectors.SetFloatAt(0, 2, float32(0.4)) vectors.SetFloatAt(0, 3, float32(0.8)) result := NewMat() defer result.Close() PCABackProject(data, mean, vectors, &result) if result.Empty() { t.Error("PCABackProject should not have empty result.") } } func TestPCACompute(t *testing.T) { src := NewMatWithSize(10, 10, MatTypeCV32F) // Set some source data so the PCA is done on a non-zero matrix. src.SetFloatAt(0, 0, 17) src.SetFloatAt(2, 1, 5) src.SetFloatAt(9, 9, 25) mean := NewMat() eigenvectors := NewMat() eigenvalues := NewMat() maxComponents := 2 PCACompute(src, &mean, &eigenvectors, &eigenvalues, maxComponents) if mean.Empty() || eigenvectors.Empty() || eigenvalues.Empty() { t.Error("TestPCACompute should not have empty eigenvectors or eigenvalues.") } if eigenvectors.Rows() > maxComponents { t.Errorf("TestPCACompute unexpected numComponents, got=%d, want<=%d", eigenvectors.Rows(), maxComponents) } src.Close() mean.Close() eigenvectors.Close() eigenvalues.Close() } func TestPCAProject(t *testing.T) { data := NewMatWithSize(3, 4, MatTypeCV32F) defer data.Close() data.SetFloatAt(0, 0, float32(1)) data.SetFloatAt(0, 1, float32(2)) data.SetFloatAt(0, 2, float32(2)) data.SetFloatAt(0, 3, float32(4)) data.SetFloatAt(1, 0, float32(2)) data.SetFloatAt(1, 1, float32(4)) data.SetFloatAt(1, 2, float32(4)) data.SetFloatAt(1, 3, float32(8)) data.SetFloatAt(2, 0, float32(0)) data.SetFloatAt(2, 1, float32(0)) data.SetFloatAt(2, 2, float32(0)) data.SetFloatAt(2, 3, float32(0)) mean := NewMatWithSize(1, 4, MatTypeCV32F) defer mean.Close() mean.SetFloatAt(0, 0, float32(2)) mean.SetFloatAt(0, 1, float32(4)) mean.SetFloatAt(0, 2, float32(4)) mean.SetFloatAt(0, 3, float32(8)) vectors := NewMatWithSizeFromScalar(NewScalar(0, 0, 0, 0), 1, 4, MatTypeCV32F) defer vectors.Close() vectors.SetFloatAt(0, 0, float32(0.2)) vectors.SetFloatAt(0, 1, float32(0.4)) vectors.SetFloatAt(0, 2, float32(0.4)) vectors.SetFloatAt(0, 3, float32(0.8)) result := NewMat() defer result.Close() PCAProject(data, mean, vectors, &result) if result.Empty() { t.Error("PCABackProject should not have empty result.") } } func TestPSNR(t *testing.T) { src := IMRead("images/gocvlogo.jpg", IMReadColor) if src.Empty() { t.Error("Invalid read of Source Mat in PSNR test") } defer src.Close() result := PSNR(src, src) if result == 0 { t.Error("Unexpected PSNR of 0") } } func TestSVBackSubst(t *testing.T) { w := NewMatWithSizeFromScalar(NewScalar(2, 0, 0, 0), 2, 2, MatTypeCV32F) defer w.Close() u := NewMatWithSizeFromScalar(NewScalar(4, 0, 0, 0), 2, 2, MatTypeCV32F) defer u.Close() vt := NewMatWithSizeFromScalar(NewScalar(2, 0, 0, 0), 2, 2, MatTypeCV32F) defer vt.Close() rhs := NewMatWithSizeFromScalar(NewScalar(1, 0, 0, 0), 2, 2, MatTypeCV32F) defer rhs.Close() dst := NewMat() defer dst.Close() SVBackSubst(w, u, vt, rhs, &dst) if dst.Empty() { t.Error("SVBackSubst should not have empty result.") } } func TestSVDecomp(t *testing.T) { src := NewMatWithSize(1, 4, MatTypeCV32F) defer src.Close() src.SetFloatAt(0, 0, float32(1)) src.SetFloatAt(0, 1, float32(4)) src.SetFloatAt(0, 2, float32(8)) src.SetFloatAt(0, 3, float32(6)) w := NewMat() defer w.Close() u := NewMat() defer u.Close() vt := NewMat() defer vt.Close() SVDecomp(src, &w, &u, &vt) if w.Empty() || u.Empty() || vt.Empty() { t.Error("SVDecomp should not have empty results.") } } func TestMatExp(t *testing.T) { src := NewMatWithSize(10, 10, MatTypeCV32F) dst := NewMat() Exp(src, &dst) if dst.Empty() { t.Error("TestExp dst should not be empty.") } src.Close() dst.Close() } func TestMatExtractChannel(t *testing.T) { src := NewMatWithSize(10, 10, MatTypeCV32F+MatChannels3) dst := NewMat() ExtractChannel(src, &dst, 1) if dst.Empty() { t.Error("TestExtractChannel dst should not be empty.") } src.Close() dst.Close() } func TestMatFindNonZero(t *testing.T) { src := NewMatWithSize(10, 10, MatTypeCV8U) defer src.Close() src.SetFloatAt(3, 3, 17) src.SetFloatAt(4, 4, 17) dst := NewMat() defer dst.Close() FindNonZero(src, &dst) if dst.Empty() { t.Error("TestMatFindNonZero dst should not be empty.") } if dst.Rows() != 2*2 { t.Error("TestMatFindNonZero didn't find all nonzero locations.") } } func TestMatFlip(t *testing.T) { src := NewMatWithSize(10, 10, MatTypeCV32F) defer src.Close() dst := NewMat() defer dst.Close() Flip(src, &dst, 0) if dst.Empty() { t.Error("TestMatFlip dst should not be empty.") } if dst.Rows() != src.Rows() { t.Error("TestMatFlip src and dst size should be same.") } } func TestMatPhase(t *testing.T) { x := NewMatFromScalar(NewScalar(1.2, 2.3, 3.4, 4.5), MatTypeCV32F) defer x.Close() y := NewMatFromScalar(NewScalar(5.6, 6.7, 7.8, 8.9), MatTypeCV32F) defer y.Close() angle := NewMatWithSize(4, 5, MatTypeCV32F) defer angle.Close() Phase(x, y, &angle, false) if angle.Empty() { t.Error("TestMatPhase angle should not be empty.") } if angle.Rows() != x.Rows() { t.Error("TestMatPhase x and angle size should be same.") } } func TestMatGemm(t *testing.T) { src1 := NewMatWithSize(3, 4, MatTypeCV32F) defer src1.Close() src2 := NewMatWithSize(4, 3, MatTypeCV32F) defer src2.Close() src3 := NewMat() defer src3.Close() dst := NewMat() defer dst.Close() Gemm(src1, src2, 1, src3, 0, &dst, 0) if dst.Empty() { t.Error("Gemm dst should not be empty.") } if dst.Rows() != src1.Rows() { t.Error("Gemm src and dst size should be same.") } } func TestMatHconcat(t *testing.T) { src := NewMatWithSize(10, 10, MatTypeCV32F) defer src.Close() dst := NewMat() defer dst.Close() Hconcat(src, src, &dst) if dst.Empty() { t.Error("TestMatHconcat dst should not be empty.") } if dst.Cols() != 2*src.Cols() { t.Error("TestMatHconcat dst.Cols should be 2 x src.Cols.") } } func TestMatVconcat(t *testing.T) { src := NewMatWithSize(10, 10, MatTypeCV32F) defer src.Close() dst := NewMat() defer dst.Close() Vconcat(src, src, &dst) if dst.Empty() { t.Error("TestMatVconcat dst should not be empty.") } if dst.Rows() != 2*src.Rows() { t.Error("TestMatVconcat dst.Cols should be 2 x src.Rows().") } } func TestRotate(t *testing.T) { src := NewMatWithSize(1, 2, MatTypeCV64F) defer src.Close() dst := NewMat() defer dst.Close() Rotate(src, &dst, Rotate90Clockwise) if dst.Rows() != 2 { t.Errorf("expected rows: %d got %d", src.Cols(), dst.Rows()) } dst2src := NewMat() defer dst2src.Close() Rotate(dst, &dst2src, Rotate90CounterClockwise) if dst2src.Rows() != 1 { t.Errorf("expected rows: %d got %d", src.Rows(), dst2src.Rows()) } } func TestMatIdct(t *testing.T) { src := NewMatWithSize(4, 4, MatTypeCV32F) defer src.Close() dst := NewMat() defer dst.Close() IDCT(src, &dst, 0) if dst.Empty() { t.Error("Idct dst should not be empty.") } if dst.Rows() != src.Rows() { t.Error("Idct src and dst size should be same.") } } func TestMatIdft(t *testing.T) { src := NewMatWithSize(4, 4, MatTypeCV32F) defer src.Close() dst := NewMat() defer dst.Close() IDFT(src, &dst, 0, 0) if dst.Empty() { t.Error("Idct dst should not be empty.") } if dst.Rows() != src.Rows() { t.Error("Idct src and dst size should be same.") } } func TestMatInsertChannel(t *testing.T) { src := NewMatWithSize(4, 4, MatTypeCV8U) defer src.Close() dst := NewMatWithSize(4, 4, MatTypeCV8UC3) defer dst.Close() InsertChannel(src, &dst, 1) if dst.Channels() != 3 { t.Error("TestMatInsertChannel dst should change the channel count") } } func TestMatInvert(t *testing.T) { src := NewMatWithSize(4, 4, MatTypeCV32F) // only implemented for symm. Mats defer src.Close() dst := NewMat() defer dst.Close() Invert(src, &dst, SolveDecompositionLu) if dst.Empty() { t.Error("Invert dst should not be empty.") } } func TestKMeans(t *testing.T) { src := NewMatWithSize(4, 4, MatTypeCV32F) // only implemented for symm. Mats defer src.Close() bestLabels := NewMat() defer bestLabels.Close() centers := NewMat() defer centers.Close() criteria := NewTermCriteria(Count, 10, 1.0) KMeans(src, 2, &bestLabels, criteria, 2, KMeansRandomCenters, ¢ers) if bestLabels.Empty() { t.Error("bla") } } func TestKMeansPoints(t *testing.T) { points := []image.Point{ image.Pt(0, 0), image.Pt(1, 1), } pv := NewPointVectorFromPoints(points) defer pv.Close() bestLabels := NewMat() defer bestLabels.Close() centers := NewMat() defer centers.Close() criteria := NewTermCriteria(Count, 10, 1.0) KMeansPoints(pv, 2, &bestLabels, criteria, 2, KMeansRandomCenters, ¢ers) if bestLabels.Empty() || bestLabels.Size()[0] != len(points) { t.Error("Labels is not proper") } } func TestMatLog(t *testing.T) { src := NewMatWithSize(4, 3, MatTypeCV32F) defer src.Close() dst := NewMat() defer dst.Close() Log(src, &dst) if dst.Empty() { t.Error("Log dst should not be empty.") } } func TestMatMagnitude(t *testing.T) { src1 := NewMatWithSize(4, 4, MatTypeCV32F) defer src1.Close() src2 := NewMatWithSize(4, 4, MatTypeCV32F) defer src2.Close() dst := NewMat() defer dst.Close() Magnitude(src1, src2, &dst) if dst.Empty() { t.Error("Magnitude dst should not be empty.") } } func TestMatMahalanobis(t *testing.T) { src := NewMatWithSize(10, 10, MatTypeCV32F) defer src.Close() RandU(&src, Scalar{Val1: -128}, Scalar{Val1: 128}) icovar := NewMatWithSize(10, 10, MatTypeCV32F) defer icovar.Close() mean := NewMatWithSize(1, 10, MatTypeCV32F) defer mean.Close() CalcCovarMatrix(src, &icovar, &mean, CovarRows|CovarNormal, MatTypeCV32F) icovar.Inv() line1 := src.Row(0) defer line1.Close() line2 := src.Row(1) defer line2.Close() result := Mahalanobis(line1, line2, icovar) if result == 0 { t.Error("Mahalanobis result should not be empty.") } } func TestMulTransposed(t *testing.T) { src := Eye(10, 10, MatTypeCV32FC1) defer src.Close() dst := NewMat() defer dst.Close() MulTransposed(src, &dst, true) if dst.Empty() { t.Error("MulTransposed dst should not be empty.") } } func TestMatMax(t *testing.T) { src1 := NewMatWithSize(4, 4, MatTypeCV32F) defer src1.Close() src2 := NewMatWithSize(4, 4, MatTypeCV32F) defer src2.Close() dst := NewMat() defer dst.Close() Max(src1, src2, &dst) if dst.Empty() { t.Error("Max dst should not be empty.") } } func TestMatMin(t *testing.T) { src1 := NewMatWithSize(4, 4, MatTypeCV32F) defer src1.Close() src2 := NewMatWithSize(4, 4, MatTypeCV32F) defer src2.Close() dst := NewMat() defer dst.Close() Min(src1, src2, &dst) if dst.Empty() { t.Error("Min dst should not be empty.") } } func TestMatMinMaxIdx(t *testing.T) { src := NewMatWithSize(10, 10, MatTypeCV32F) defer src.Close() src.SetFloatAt(3, 3, 17) src.SetFloatAt(4, 4, 16) minVal, maxVal, _, _ := MinMaxIdx(src) if minVal != 0 { t.Error("TestMatMinMaxIdx minVal should be 0.") } if maxVal != 17 { t.Errorf("TestMatMinMaxIdx maxVal should be 17, was %f", maxVal) } } func TestMixChannels(t *testing.T) { bgra := NewMatWithSizeFromScalar(NewScalar(255, 0, 0, 255), 10, 10, MatTypeCV8UC4) defer bgra.Close() bgr := NewMatWithSize(bgra.Rows(), bgra.Cols(), MatTypeCV8UC3) defer bgr.Close() alpha := NewMatWithSize(bgra.Rows(), bgra.Cols(), MatTypeCV8UC1) defer alpha.Close() dst := []Mat{bgr, alpha} // bgra[0] -> bgr[2], bgra[1] -> bgr[1], // bgra[2] -> bgr[0], bgra[3] -> alpha[0] fromTo := []int{0, 2, 1, 1, 2, 0, 3, 3} MixChannels([]Mat{bgra}, dst, fromTo) bgrChans := Split(bgr) scalarByte := []byte{0, 0, 255} for c := 0; c < bgr.Channels(); c++ { for i := 0; i < bgr.Rows(); i++ { for j := 0; j < bgr.Cols(); j++ { if s := bgrChans[c].GetUCharAt(i, j); s != scalarByte[c] { t.Errorf("TestMixChannels incorrect bgr scalar: %v\n", s) } } } } for _, ch := range bgrChans { ch.Close() } alphaChans := Split(alpha) scalarByte = []byte{255} for c := 0; c < alpha.Channels(); c++ { for i := 0; i < alpha.Rows(); i++ { for j := 0; j < alpha.Cols(); j++ { if s := alphaChans[c].GetUCharAt(i, j); s != scalarByte[c] { t.Errorf("TestMixChannels incorrect alpha scalar: %v\n", s) } } } } for _, ch := range alphaChans { ch.Close() } } func TestGetVecfAt(t *testing.T) { var cases = []struct { m Mat expectedSize int }{ {NewMatWithSize(1, 1, MatTypeCV32FC1), 1}, {NewMatWithSize(1, 1, MatTypeCV32FC2), 2}, {NewMatWithSize(1, 1, MatTypeCV32FC3), 3}, {NewMatWithSize(1, 1, MatTypeCV32FC4), 4}, } for _, c := range cases { vec := c.m.GetVecfAt(0, 0) if len := len(vec); len != c.expectedSize { t.Errorf("TestGetVecfAt: expected %d, got: %d.", c.expectedSize, len) } c.m.Close() } } func TestGetVecdAt(t *testing.T) { var cases = []struct { m Mat expectedSize int }{ {NewMatWithSize(1, 1, MatTypeCV64FC1), 1}, {NewMatWithSize(1, 1, MatTypeCV64FC2), 2}, {NewMatWithSize(1, 1, MatTypeCV64FC3), 3}, {NewMatWithSize(1, 1, MatTypeCV64FC4), 4}, } for _, c := range cases { vec := c.m.GetVecdAt(0, 0) if len := len(vec); len != c.expectedSize { t.Errorf("TestGetVecdAt: expected %d, got: %d.", c.expectedSize, len) } c.m.Close() } } func TestGetVecbAt(t *testing.T) { var cases = []struct { m Mat expectedSize int }{ {NewMatWithSize(1, 1, MatTypeCV8UC1), 1}, {NewMatWithSize(1, 1, MatTypeCV8UC2), 2}, {NewMatWithSize(1, 1, MatTypeCV8UC3), 3}, {NewMatWithSize(1, 1, MatTypeCV8UC4), 4}, } for _, c := range cases { vec := c.m.GetVecbAt(0, 0) if len := len(vec); len != c.expectedSize { t.Errorf("TestGetVecbAt: expected %d, got: %d.", c.expectedSize, len) } c.m.Close() } } func TestGetVeciAt(t *testing.T) { var cases = []struct { m Mat expectedSize int }{ {NewMatWithSize(1, 1, MatTypeCV8UC1), 1}, {NewMatWithSize(1, 1, MatTypeCV8UC2), 2}, {NewMatWithSize(1, 1, MatTypeCV8UC3), 3}, {NewMatWithSize(1, 1, MatTypeCV8UC4), 4}, } for _, c := range cases { vec := c.m.GetVeciAt(0, 0) if len := len(vec); len != c.expectedSize { t.Errorf("TestGetVeciAt: expected %d, got: %d.", c.expectedSize, len) } c.m.Close() } } func TestGetTickFrequencyCount(t *testing.T) { freq := GetTickFrequency() if freq == 0 { t.Error("GetTickFrequency expected non zero.") } count := GetTickCount() if count == 0 { t.Error("GetTickCount expected non zero.") } } func TestMatT(t *testing.T) { var q = []float32{1, 3, 2, 4} src := NewMatWithSize(2, 2, MatTypeCV32F) defer src.Close() src.SetFloatAt(0, 0, 1) src.SetFloatAt(0, 1, 2) src.SetFloatAt(1, 0, 3) src.SetFloatAt(1, 1, 4) dst := src.T() defer dst.Close() ret, err := dst.DataPtrFloat32() if err != nil { t.Error(err) } for i := 0; i < len(ret); i++ { if ret[i] != q[i] { t.Errorf("MatT incorrect value: %v\n", ret[i]) } } } func compareImages(img0, img1 image.Image) bool { bounds0 := img0.Bounds() bounds1 := img1.Bounds() dx0 := bounds0.Dx() dy0 := bounds0.Dy() if dx0 != bounds1.Dx() || dy0 != bounds1.Dy() { return false } xMin0 := bounds0.Min.X xMin1 := bounds1.Min.X yMin0 := bounds0.Min.Y yMin1 := bounds1.Min.Y for i := 0; i < dx0; i++ { for j := 0; j < dy0; j++ { point0 := img0.At(xMin0+i, yMin0+j) point1 := img1.At(xMin1+i, yMin1+j) r0, g0, b0, a0 := point0.RGBA() r1, g1, b1, a1 := point1.RGBA() r0 >>= 8 g0 >>= 8 b0 >>= 8 a0 >>= 8 r1 >>= 8 g1 >>= 8 b1 >>= 8 a1 >>= 8 if r0 != r1 || g0 != g1 || b0 != b1 || a0 != a1 { return false } } } return true } func TestColRowRange(t *testing.T) { mat := NewMatWithSize(101, 102, MatTypeCV8U) defer mat.Close() if mat.Empty() { t.Error("TestColRowRange should not be empty") } if mat.Rows() != 101 { t.Errorf("TestColRowRange incorrect row count: %v\n", mat.Rows()) } if mat.Cols() != 102 { t.Errorf("TestColRowRange incorrect col count: %v\n", mat.Cols()) } submatRow := mat.RowRange(0, 50) defer submatRow.Close() if submatRow.Rows() != 50 { t.Errorf("TestColRowRange incorrect submatRow count: %v\n", submatRow.Rows()) } submatCols := mat.ColRange(0, 50) defer submatCols.Close() if submatCols.Cols() != 50 { t.Errorf("TestColRowRange incorrect submatCols count: %v\n", submatCols.Cols()) } } func TestNormWithMats(t *testing.T) { mat1 := NewMatWithSize(100, 100, MatTypeCV8UC1) defer mat1.Close() mat2 := NewMatWithSize(100, 100, MatTypeCV8UC1) defer mat2.Close() d := NormWithMats(mat1, mat2, NormInf) if d != 0 { t.Fatal("expected 0") } } func Test_toGoStrings(t *testing.T) { goStrings := []string{"foo", "bar"} cStrings := toCStrings(goStrings) result := toGoStrings(cStrings) if len(goStrings) != len(result) { t.Errorf("TesttoGoStrings failed: length of converted string is not equal to original \n") } for i, s := range goStrings { if s != result[i] { t.Errorf("TesttoGoStrings failed: strings are not equal. expected=%s, actusal=%s", s, result[i]) } } } func TestTheRNG(t *testing.T) { rng := TheRNG() if rng.p == nil { t.Errorf("got no rng") } } func TestSetRNGSeed(t *testing.T) { SetRNGSeed(123) } func TestRNG_Fill(t *testing.T) { rng := TheRNG() mat := NewMatWithSize(20, 20, MatTypeCV8UC3) defer mat.Close() rng.Fill(&mat, RNGDistNormal, 10, 20, false) } func TestRNG_Gaussian(t *testing.T) { rng := TheRNG() _ = rng.Gaussian(0.5) } func TestRNG_Next(t *testing.T) { rng := TheRNG() _ = rng.Next() } func TestRandN(t *testing.T) { mat := NewMatWithSize(5, 5, MatTypeCV8UC3) defer mat.Close() RandN(&mat, NewScalar(10, 10, 10, 10), NewScalar(20, 20, 20, 20)) } func TestRandShuffle(t *testing.T) { mat := NewMatWithSize(5, 5, MatTypeCV8UC3) defer mat.Close() RandShuffle(&mat) } func TestRandShuffleWithParams(t *testing.T) { mat := NewMatWithSize(5, 5, MatTypeCV8UC3) defer mat.Close() RandShuffleWithParams(&mat, 1, TheRNG()) } func TestRandU(t *testing.T) { mat := NewMatWithSize(5, 5, MatTypeCV8UC3) defer mat.Close() RandU(&mat, NewScalar(10, 10, 10, 10), NewScalar(20, 20, 20, 20)) } func TestNewPointsVector(t *testing.T) { epv := NewPointsVector() defer epv.Close() if epv.Size() != 0 { t.Fatal("expected empty pointsvector size not 0") } pts := [][]image.Point{ { image.Pt(10, 10), image.Pt(10, 20), image.Pt(20, 20), image.Pt(20, 10), }, } psv := NewPointsVectorFromPoints(pts) defer psv.Close() if psv.IsNil() { t.Fatal("pointsvector pointer was nil") } if psv.Size() != 1 { t.Fatal("expected pointsvector size 1") } ipv := psv.At(10) if !ipv.IsNil() { t.Fatal("expected pointvector nil") } pv := psv.At(0) if pv.Size() != 4 { t.Fatal("expected pointvector size 4") } p := pv.At(0) if p != image.Pt(10, 10) { t.Fatal("invalid At() point") } p = pv.At(10) if p != image.Pt(0, 0) { t.Fatal("invalid At() point beyond range") } out := psv.ToPoints() if out[0][0] != image.Pt(10, 10) { t.Fatal("invalid ToPoints() point") } ps := []image.Point{ image.Pt(10, 10), image.Pt(10, 20), image.Pt(20, 20), image.Pt(20, 10), } apv := NewPointVectorFromPoints(ps) defer apv.Close() psv.Append(apv) if psv.Size() != 2 { t.Fatal("unable to append to PointsVector") } } func TestNewPointVector(t *testing.T) { epv := NewPointVector() defer epv.Close() if epv.Size() != 0 { t.Fatal("expected empty pointvector size not 0") } pts := []image.Point{ image.Pt(10, 10), image.Pt(10, 20), image.Pt(20, 20), image.Pt(20, 10), } pv := NewPointVectorFromPoints(pts) defer pv.Close() if pv.IsNil() { t.Fatal("pointvector pointer was nil") } if pv.Size() != 4 { t.Fatal("expected pointvector size 4") } p := pv.At(0) if p != image.Pt(10, 10) { t.Fatal("invalid point") } np := image.Pt(50, 50) pv.Append(np) if pv.Size() != 5 { t.Fatal("unable to append to PointVector") } mat := NewMatWithSize(4, 1, MatTypeCV32SC2) defer mat.Close() pvm := NewPointVectorFromMat(mat) defer pvm.Close() if pvm.Size() != 4 { t.Fatalf("expected size of NewPointVectorFromMat to be 4, was %d", pvm.Size()) } } func TestNewPoint2fVector(t *testing.T) { epv := NewPoint2fVector() defer epv.Close() if epv.Size() != 0 { t.Fatal("expected empty pointvector size not 0") } pts := []Point2f{ {10.0, 10.0}, {10.0, 20.0}, {20.5, 21.5}, {25.5, 30.5}, } pv := NewPoint2fVectorFromPoints(pts) defer pv.Close() if pv.IsNil() { t.Fatal("point2fvector pointer was nil") } if pv.Size() != 4 { t.Fatal("expected point2fvector size 4") } p := pv.At(0) want := Point2f{10.0, 10.0} if p != want { t.Fatal("invalid point") } p = pv.At(10) nopoint := Point2f{0, 0} if p != nopoint { t.Fatal("invalid At() point beyond range") } out := pv.ToPoints() if len(out) != 4 && out[0] != want { t.Fatal("invalid ToPoints()") } mat := NewMatWithSize(4, 1, MatTypeCV32FC2) defer mat.Close() pvm := NewPoint2fVectorFromMat(mat) defer pvm.Close() if pvm.Size() != 4 { t.Fatalf("expected size of NewPoint2fVectorFromMat to be 4, was %d", pvm.Size()) } } func TestNewPoints2fVector(t *testing.T) { epv := NewPoints2fVector() defer epv.Close() if epv.Size() != 0 { t.Fatal("expected empty points2fvector size not 0") } pts := [][]Point2f{ { NewPoint2f(10.0, 10.0), NewPoint2f(10.0, 20.0), NewPoint2f(20.0, 20.0), NewPoint2f(20.0, 10.0), }, } psv := NewPoints2fVectorFromPoints(pts) defer psv.Close() if psv.IsNil() { t.Fatal("points2fvector pointer was nil") } if psv.Size() != 1 { t.Fatal("expected points2fvector size 1") } ipv := psv.At(10) if !ipv.IsNil() { t.Fatal("expected pointvector nil") } pv := psv.At(0) if pv.Size() != 4 { t.Fatal("expected pointvector size 4") } p := pv.At(0) if p != NewPoint2f(10.0, 10.0) { t.Fatal("invalid At() point") } p = pv.At(10) if p != NewPoint2f(0, 0) { t.Fatal("invalid At() point beyond range") } out := psv.ToPoints() if out[0][0] != NewPoint2f(10.0, 10.0) { t.Fatal("invalid ToPoints() point") } ps := []Point2f{ NewPoint2f(10, 10), NewPoint2f(10, 20), NewPoint2f(20, 20), NewPoint2f(20, 10), } apv := NewPoint2fVectorFromPoints(ps) defer apv.Close() psv.Append(apv) if psv.Size() != 2 { t.Fatal("unable to append to Points2fVector") } } func TestNewPoint3fVector(t *testing.T) { epv := NewPoint3fVector() defer epv.Close() if epv.Size() != 0 { t.Fatal("expected empty pointvector size not 0") } pts := []Point3f{ {10.0, 10.0, 0.1}, {10.0, 20.0, 1.0}, {20.5, 21.5, 2.0}, } pv := NewPoint3fVectorFromPoints(pts) defer pv.Close() pv.Append(NewPoint3f(25.5, 30.5, 3.0)) if pv.IsNil() { t.Fatal("point3fvector pointer was nil") } if pv.Size() != 4 { t.Fatal("expected point3fvector size 4") } p := pv.At(0) want := Point3f{10.0, 10.0, 0.1} if p != want { t.Fatal("invalid point") } want2 := NewPoint3f(25.5, 30.5, 3.0) if pv.At(3) != want2 { t.Fatal("fail to append point to Point3fVector") } p = pv.At(10) nopoint := Point3f{0, 0, 0} if p != nopoint { t.Fatal("invalid At() point beyond range") } out := pv.ToPoints() if len(out) != 4 && out[0] != want { t.Fatal("invalid ToPoints()") } mat := NewMatWithSize(4, 1, MatTypeCV32FC3) defer mat.Close() pvm := NewPoint3fVectorFromMat(mat) defer pvm.Close() if pvm.Size() != 4 { t.Fatalf("expected size of NewPoint3fVectorFromMat to be 4, was %d", pvm.Size()) } } func TestNewPoints3fVector(t *testing.T) { epv := NewPoints3fVector() defer epv.Close() if epv.Size() != 0 { t.Fatal("expected empty points3fvector size not 0") } pts := [][]Point3f{ { NewPoint3f(10.0, 10.0, 0.1), NewPoint3f(10.0, 20.0, 0.2), NewPoint3f(20.0, 20.0, 0.3), NewPoint3f(20.0, 10.0, 0.4), }, } psv := NewPoints3fVectorFromPoints(pts) defer psv.Close() if psv.IsNil() { t.Fatal("points3fvector pointer was nil") } if psv.Size() != 1 { t.Fatal("expected points3fvector size 1") } ipv := psv.At(10) if !ipv.IsNil() { t.Fatal("expected pointvector nil") } pv := psv.At(0) if pv.Size() != 4 { t.Fatal("expected pointvector size 4") } p := pv.At(0) if p != NewPoint3f(10.0, 10.0, 0.1) { t.Fatal("invalid At() point") } p = pv.At(10) if p != NewPoint3f(0, 0, 0) { t.Fatal("invalid At() point beyond range") } out := psv.ToPoints() if out[0][0] != NewPoint3f(10.0, 10.0, 0.1) { t.Fatal("invalid ToPoints() point") } ps := []Point3f{ NewPoint3f(10, 10, 0.1), NewPoint3f(10, 20, 0.2), NewPoint3f(20, 20, 0.3), NewPoint3f(20, 10, 0.4), } apv := NewPoint3fVectorFromPoints(ps) defer apv.Close() psv.Append(apv) if psv.Size() != 2 { t.Fatal("unable to append to Points3fVector") } } func TestElemSize(t *testing.T) { m1 := NewMat() defer m1.Close() if m1.ElemSize() != 0 { t.Error("incorrect element size") } m2 := NewMatWithSize(2, 2, MatTypeCV16S) defer m2.Close() if m2.ElemSize() != 2 { t.Error("incorrect element size of MatTypeCV16S") } m3 := NewMatWithSize(2, 2, MatTypeCV16SC3) defer m3.Close() if m3.ElemSize() != 6 { t.Error("incorrect element size of MatTypeCV16SC3") } m4 := NewMatWithSize(2, 2, MatTypeCV32SC4) defer m4.Close() if m4.ElemSize() != 16 { t.Error("incorrect element size of MatTypeCV32SC4") return } } func TestSetThreadNumber(t *testing.T) { original := GetNumThreads() SetNumThreads(-1) if num := GetNumThreads(); num != original { t.Errorf("incorrect number of threads, got %d, want %d", num, original) } SetNumThreads(0) if num := GetNumThreads(); num < 1 { t.Errorf("incorrect number of threads, got %d, want at least 1", num) } SetNumThreads(1) if num := GetNumThreads(); num != 1 { t.Errorf("incorrect number of threads, got %d, want %d", num, 1) } SetNumThreads(original) } func TestMinMaxLoc(t *testing.T) { input := NewMatWithSize(2, 2, MatTypeCV32F) defer input.Close() input.SetFloatAt(0, 0, 1) input.SetFloatAt(0, 1, 2) input.SetFloatAt(1, 0, 3) input.SetFloatAt(1, 1, 4) minVal, maxVal, minLoc, maxLoc := MinMaxLoc(input) wantMinVal, wantMaxValue := float32(1.0), float32(4.0) if minVal != wantMinVal { t.Errorf("minVal got: %v, want %v", minVal, wantMinVal) } if maxVal != wantMaxValue { t.Errorf("maxVal got: %v, want %v", maxVal, wantMaxValue) } wantMinLoc, wantMaxLoc := image.Point{Y: 0, X: 0}, image.Point{Y: 1, X: 1} if minLoc != wantMinLoc { t.Errorf("minLoc got: %v, want %v", minLoc, wantMinLoc) } if maxLoc != wantMaxLoc { t.Errorf("maxLoc got: %v, want %v", maxLoc, wantMaxLoc) } } func TestMinMaxLocWithMask(t *testing.T) { input := NewMatWithSize(2, 2, MatTypeCV32F) defer input.Close() input.SetFloatAt(0, 0, 1) input.SetFloatAt(0, 1, 2) input.SetFloatAt(1, 0, 3) input.SetFloatAt(1, 1, 4) mask := NewMatWithSize(2, 2, MatTypeCV8U) defer mask.Close() mask.SetUCharAt(1, 0, 1) mask.SetUCharAt(1, 1, 1) minVal, maxVal, minLoc, maxLoc := MinMaxLocWithMask(input, mask) wantMinVal, wantMaxValue := float32(3.0), float32(4.0) if minVal != wantMinVal { t.Errorf("minVal got: %v, want %v", minVal, wantMinVal) } if maxVal != wantMaxValue { t.Errorf("maxVal got: %v, want %v", maxVal, wantMaxValue) } wantMinLoc, wantMaxLoc := image.Point{Y: 1, X: 0}, image.Point{Y: 1, X: 1} if minLoc != wantMinLoc { t.Errorf("minLoc got: %v, want %v", minLoc, wantMinLoc) } if maxLoc != wantMaxLoc { t.Errorf("maxLoc got: %v, want %v", maxLoc, wantMaxLoc) } } func TestNewRotatedRect(t *testing.T) { rr := NewRotatedRect(image.Pt(1, 1), 10, 10, 75.0) if rr.Angle != 75.0 { t.Errorf("NewRotatedRect not working as intended") } } func TestNewRotatedRect2f(t *testing.T) { pts := Point2f{ X: 1.5, Y: 1.5, } rr := NewRotatedRect2f(pts, 10.5, 10.5, 75.0) if rr.Angle != 75.0 { t.Errorf("NewRotatedRect not working as intended") } } func TestNewMatFromPointVector(t *testing.T) { img := NewMatWithSize(320, 200, MatTypeCV32SC1) defer img.Close() size := img.Size() points := []image.Point{ image.Pt(0, 0), image.Pt(0, size[0]-1), image.Pt(size[1]-1, size[0]-1), image.Pt(size[1]-1, 0), } pv := NewPointVectorFromPoints(points) defer pv.Close() m := NewMatFromPointVector(pv, false) defer m.Close() if m.Empty() { t.Error("Mat shlould not be empty") } } func TestNewMatFromPoint2fVector(t *testing.T) { pv2f := NewPoint2fVectorFromPoints([]Point2f{NewPoint2f(1.1, 2.2)}) defer pv2f.Close() m := NewMatFromPoint2fVector(pv2f, false) defer m.Close() if m.Empty() { t.Error("Mat shlould not be empty") } } ================================================ FILE: cuda/README.md ================================================ # CUDA In order to use the GoCV `cuda` package, the CUDA toolkit from nvidia needs to be installed on the host system. The CUDA backend for DNN module requires CC (Compute Capability) 5.3 or higher. Check your GPU https://developer.nvidia.com/cuda-gpus Please see https://docs.nvidia.com/cuda/index.html for more information. Furthermore opencv must be compiled with CUDA support. GoCV also supports using CUDA as a backend for the OpenCV deep neural network (DNN) module. ## How to use ### Deep Neural Network (DNN) module This code loads a Caffe model, and then uses CUDA to prepare it for execution on the GPU: ```go net := gocv.ReadNet("/path/to/your/model.caffemodel", "/path/to/your/config.proto") if net.Empty() { fmt.Println("Error reading network model") return } net.SetPreferableBackend(gocv.NetBackendType(gocv.NetBackendCUDA)) net.SetPreferableTarget(gocv.NetTargetType(gocv.NetTargetCUDA)) ``` ### OpenCV CUDA modules You can use calls directly to the OpenCV CUDA wrappers, both the synchronous and asynchronous versions. Here is an example that uses the synchronous CUDA calls: ```go cimg, mimg, dimg := NewGpuMat(), NewGpuMat(), NewGpuMat() defer cimg.Close() defer mimg.Close() defer dimg.Close() canny := NewCannyEdgeDetector(50, 100) defer canny.Close() detector := NewHoughSegmentDetector(1, math.Pi/180, 150, 50) defer detector.Close() dest := gocv.NewMat() defer dest.Close() // after each call, CPU thread is blocked until GPU operation is completed. cimg.Upload(src) canny.Detect(cimg, &mimg) detector.Detect(mimg, &dimg) dimg.Download(&dest) ``` Here is an example that uses the `Stream` type for calling CUDA using the asynchronous interface: ```go cimg, mimg, dimg := NewGpuMat(), NewGpuMat(), NewGpuMat() defer cimg.Close() defer mimg.Close() defer dimg.Close() stream := NewStream() defer stream.Close() canny := NewCannyEdgeDetector(50, 100) defer canny.Close() detector := NewHoughSegmentDetector(1, math.Pi/180, 150, 50) defer detector.Close() dest := gocv.NewMat() defer dest.Close() // all calls return immediately to CPU, work is scheduled to be done on GPU. cimg.UploadWithStream(src, stream) canny.DetectWithStream(cimg, &mimg, stream) detector.DetectWithStream(mimg, &dimg, stream) dimg.DownloadWithStream(&dest, stream) // CPU thread blocks until all GPU calls have completed. stream.WaitForCompletion() ``` ## Installing CUDA Download and install packages from https://developer.nvidia.com/cuda-downloads For example, download 'cuda_10.2.89_440.33.01_linux.run' Download and install packages from https://developer.nvidia.com/rdp/cudnn-archive For example the 'cuDNN Runtime Library for Ubuntu18.04 (Deb)' and 'cuDNN Developer Library for Ubuntu18.04 (Deb)' ## Compiling OpenCV with CUDA We have included the make target `install_cuda` that compiles OpenCV with CUDA support. (For more details on the compilation process please see the `Makefile`) Run the command `make install_cuda` and you should be good to go. If you need static opencv libraries make install_cuda BUILD_SHARED_LIBS=OFF Then finally verify that it is all working cd $GOPATH/src/gocv.io/x/gocv go run ./cmd/cuda/main.go You should see something along the lines of: gocv version: 0.25.0 cuda information: Device 0: "GeForce MX150" 2003Mb, sm_61, Driver/Runtime ver.10.0/10.0 ================================================ FILE: cuda/arithm.cpp ================================================ //go:build !gocv_specific_modules || (gocv_specific_modules && gocv_cuda_arithm) #include "../core.h" #include "arithm.h" #include OpenCVResult GpuAbs(GpuMat src, GpuMat dst, Stream s) { try { if (s == NULL) { cv::cuda::abs(*src, *dst); } else { cv::cuda::abs(*src, *dst, *s); } return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult GpuAbsDiff(GpuMat src1, GpuMat src2, GpuMat dst, Stream s) { try { if (s == NULL) { cv::cuda::absdiff(*src1, *src2, *dst); } else { cv::cuda::absdiff(*src1, *src2, *dst, *s); } return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult GpuAdd(GpuMat src1, GpuMat src2, GpuMat dst, Stream s) { try { if (s == NULL) { cv::cuda::add(*src1, *src2, *dst); } else { cv::cuda::add(*src1, *src2, *dst, cv::noArray(), -1, *s); } return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult GpuBitwiseAnd(GpuMat src1, GpuMat src2, GpuMat dst, Stream s) { try { if (s == NULL) { cv::cuda::bitwise_and(*src1, *src2, *dst); } else { cv::cuda::bitwise_and(*src1, *src2, *dst, cv::noArray(), *s); } return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult GpuBitwiseNot(GpuMat src, GpuMat dst, Stream s) { try { if (s == NULL) { cv::cuda::bitwise_not(*src, *dst); } else { cv::cuda::bitwise_not(*src, *dst, cv::noArray(), *s); } return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult GpuBitwiseOr(GpuMat src1, GpuMat src2, GpuMat dst, Stream s) { try { if (s == NULL) { cv::cuda::bitwise_or(*src1, *src2, *dst); } else { cv::cuda::bitwise_or(*src1, *src2, *dst, cv::noArray(), *s); } return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult GpuBitwiseXor(GpuMat src1, GpuMat src2, GpuMat dst, Stream s) { try { if (s == NULL) { cv::cuda::bitwise_xor(*src1, *src2, *dst); } else { cv::cuda::bitwise_xor(*src1, *src2, *dst, cv::noArray(), *s); } return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult GpuDivide(GpuMat src1, GpuMat src2, GpuMat dst, Stream s) { try { if (s == NULL) { cv::cuda::divide(*src1, *src2, *dst); } else { cv::cuda::divide(*src1, *src2, *dst, 1, -1, *s); } return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult GpuExp(GpuMat src, GpuMat dst, Stream s) { try { if (s == NULL) { cv::cuda::exp(*src, *dst); } else { cv::cuda::exp(*src, *dst, *s); } return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult GpuLog(GpuMat src, GpuMat dst, Stream s) { try { if (s == NULL) { cv::cuda::log(*src, *dst); } else { cv::cuda::log(*src, *dst, *s); } return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult GpuMax(GpuMat src1, GpuMat src2, GpuMat dst, Stream s) { try { if (s == NULL) { cv::cuda::max(*src1, *src2, *dst); } else { cv::cuda::max(*src1, *src2, *dst, *s); } return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult GpuMin(GpuMat src1, GpuMat src2, GpuMat dst, Stream s) { try { if (s == NULL) { cv::cuda::min(*src1, *src2, *dst); } else { cv::cuda::min(*src1, *src2, *dst, *s); } return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult GpuMultiply(GpuMat src1, GpuMat src2, GpuMat dst, Stream s) { try { if (s == NULL) { cv::cuda::multiply(*src1, *src2, *dst); } else { cv::cuda::multiply(*src1, *src2, *dst, 1, -1, *s); } return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult GpuSqr(GpuMat src, GpuMat dst, Stream s) { try { if (s == NULL) { cv::cuda::sqr(*src, *dst); } else { cv::cuda::sqr(*src, *dst, *s); } return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult GpuSqrt(GpuMat src, GpuMat dst, Stream s) { try { if (s == NULL) { cv::cuda::sqrt(*src, *dst); } else { cv::cuda::sqrt(*src, *dst, *s); } return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult GpuSubtract(GpuMat src1, GpuMat src2, GpuMat dst, Stream s) { try { if (s == NULL) { cv::cuda::subtract(*src1, *src2, *dst); } else { cv::cuda::subtract(*src1, *src2, *dst, cv::noArray(), -1, *s); } return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult GpuThreshold(GpuMat src, GpuMat dst, double thresh, double maxval, int typ, Stream s) { try { if (s == NULL) { cv::cuda::threshold(*src, *dst, thresh, maxval, typ); } else { cv::cuda::threshold(*src, *dst, thresh, maxval, typ, *s); } return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult GpuFlip(GpuMat src, GpuMat dst, int flipCode, Stream s) { try { if (s == NULL) { cv::cuda::flip(*src, *dst, flipCode); } else { cv::cuda::flip(*src, *dst, flipCode, *s); } return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult GpuMerge(struct GpuMats mats, GpuMat dst, Stream s) { try { std::vector images; for (int i = 0; i < mats.length; ++i) { images.push_back(*mats.mats[i]); } if (s == NULL) { cv::cuda::merge(images, *dst); } else { cv::cuda::merge(images, *dst, *s); } return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult GpuTranspose(GpuMat src, GpuMat dst, Stream s) { try { if (s == NULL) { cv::cuda::transpose(*src, *dst); } else { cv::cuda::transpose(*src, *dst, *s); } return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult GpuAddWeighted(GpuMat src1, double alpha, GpuMat src2, double beta, double gamma, GpuMat dst, int dType, Stream s) { try { if (s == NULL) { cv::cuda::addWeighted(*src1, alpha, *src2, beta, gamma, *dst, dType); } else { cv::cuda::addWeighted(*src1, alpha, *src2, beta, gamma, *dst, dType, *s); } return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult GpuCopyMakeBorder(GpuMat src, GpuMat dst, int top, int bottom, int left, int right, int borderType, Scalar value, Stream s) { try { cv::Scalar cValue = cv::Scalar(value.val1, value.val2, value.val3, value.val4); if (s == NULL) { cv::cuda::copyMakeBorder(*src, *dst, top, bottom, left, right, borderType, cValue); } else { cv::cuda::copyMakeBorder(*src, *dst, top, bottom, left, right, borderType, cValue, *s); } return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } LookUpTable Cuda_Create_LookUpTable(GpuMat lut){ try { return new cv::Ptr(cv::cuda::createLookUpTable(*lut)); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } void Cuda_LookUpTable_Close(LookUpTable lt) { delete lt; } bool Cuda_LookUpTable_Empty(LookUpTable lut) { try { return lut->empty(); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return true; } } OpenCVResult Cuda_LookUpTable_Transform(LookUpTable lt, GpuMat src, GpuMat dst, Stream s) { try { cv::Ptr< cv::cuda::LookUpTable> p = cv::Ptr< cv::cuda::LookUpTable>(*lt); if(s == NULL) { p->transform(*src, *dst); } else { p->transform(*src, *dst, *s); } return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Cuda_Split(GpuMat src, GpuMats dst, Stream s) { try { std::vector< cv::cuda::GpuMat > dstv; for(int i = 0; i < dst.length; i++) { dstv.push_back(*(dst.mats[i])); } if(s == NULL){ cv::cuda::split(*src, dstv); } else { cv::cuda::split(*src, dstv, *s); } return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult GpuCalcNorm(GpuMat src, GpuMat dst, int typ, Stream s) { try { if (s == NULL) { cv::cuda::calcNorm(*src, *dst, typ); } else { cv::cuda::calcNorm(*src, *dst, typ, cv::noArray(), *s); } return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult GpuCalcNormDiff(GpuMat src1, GpuMat src2, GpuMat dst, int typ, Stream s) { try { if (s == NULL) { cv::cuda::calcNormDiff(*src1, *src2, *dst, typ); } else { cv::cuda::calcNormDiff(*src1, *src2, *dst, typ, *s); } return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } double GpuNorm(GpuMat src1, GpuMat src2, int typ) { try { return cv::cuda::norm(*src1, *src2, typ); } catch(const cv::Exception& e) { setExceptionInfo(e.code, e.what()); return 0.0; } } OpenCVResult GpuCompare(GpuMat src1, GpuMat src2, GpuMat dst, int typ, Stream s) { try { if (s == NULL) { cv::cuda::compare(*src1, *src2, *dst, typ); } else { cv::cuda::compare(*src1, *src2, *dst, typ, *s); } return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult GpuLShift(GpuMat src, Scalar shift, GpuMat dst, Stream s) { try { cv::Scalar cValue = cv::Scalar(shift.val1, shift.val2, shift.val3, shift.val4); if (s == NULL) { cv::cuda::lshift(*src, cValue, *dst); } else { cv::cuda::lshift(*src, cValue, *dst, *s); } return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult GpuRShift(GpuMat src, Scalar shift, GpuMat dst, Stream s) { try { cv::Scalar cValue = cv::Scalar(shift.val1, shift.val2, shift.val3, shift.val4); if (s == NULL) { cv::cuda::rshift(*src, cValue, *dst); } else { cv::cuda::rshift(*src, cValue, *dst, *s); } return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult GpuAbsSum(GpuMat src, GpuMat mask, struct Scalar* result) { try { cv::Scalar s = cv::cuda::absSum(*src, mask == NULL ? cv::noArray() : *mask); result->val1 = s[0]; result->val2 = s[1]; result->val3 = s[2]; result->val4 = s[3]; return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult GpuCalcAbsSum(GpuMat src, GpuMat dst, GpuMat mask, Stream s) { try { if (s == NULL) { cv::cuda::calcAbsSum(*src, *dst, mask == NULL ? cv::noArray() : *mask); } else { cv::cuda::calcAbsSum(*src, *dst, mask == NULL ? cv::noArray() : *mask, *s); } return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult GpuMinMax(GpuMat src, GpuMat mask, double* minVal, double* maxVal) { try { if (mask == NULL) { cv::cuda::minMax(*src, minVal, maxVal, cv::noArray()); } else { cv::cuda::minMax(*src, minVal, maxVal, *mask); } return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult GpuMinMaxLoc(GpuMat src, GpuMat mask, double* minVal, double* maxVal, int* minLocX, int* minLocY, int* maxLocX, int* maxLocY) { try { cv::Point minLoc, maxLoc; if (mask == NULL) { cv::cuda::minMaxLoc(*src, minVal, maxVal, &minLoc, &maxLoc, cv::noArray()); } else { cv::cuda::minMaxLoc(*src, minVal, maxVal, &minLoc, &maxLoc, *mask); } *minLocX = minLoc.x; *minLocY = minLoc.y; *maxLocX = maxLoc.x; *maxLocY = maxLoc.y; return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult GpuNormalize(GpuMat src, GpuMat dst, double alpha, double beta, int normType, int dtype, GpuMat mask, Stream s) { try { if (s == NULL) { cv::cuda::normalize(*src, *dst, alpha, beta, normType, dtype, mask == NULL ? cv::noArray() : *mask); } else { cv::cuda::normalize(*src, *dst, alpha, beta, normType, dtype, mask == NULL ? cv::noArray() : *mask, *s); } return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult GpuFindMinMaxLoc(GpuMat src, GpuMat minMaxVals, GpuMat loc, GpuMat mask, Stream s) { try { if (s == NULL) { cv::cuda::findMinMaxLoc(*src, *minMaxVals, *loc, mask == NULL ? cv::noArray() : *mask); } else { cv::cuda::findMinMaxLoc(*src, *minMaxVals, *loc, mask == NULL ? cv::noArray() : *mask, *s); } return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult GpuFindMinMax(GpuMat src, GpuMat dst, GpuMat mask, Stream s) { try { if (s == NULL) { cv::cuda::findMinMax(*src, *dst, mask == NULL ? cv::noArray() : *mask); } else { cv::cuda::findMinMax(*src, *dst, mask == NULL ? cv::noArray() : *mask, *s); } return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } ================================================ FILE: cuda/arithm.go ================================================ //go:build !gocv_specific_modules || (gocv_specific_modules && gocv_cuda_arithm) package cuda /* #include #include "../core.h" #include "core.h" #include "arithm.h" */ import "C" import ( "image" "unsafe" "gocv.io/x/gocv" ) // Abs computes an absolute value of each matrix element. // // For further details, please see: // https://docs.opencv.org/master/d8/d34/group__cudaarithm__elem.html#ga54a72bd772494ab34d05406fd76df2b6 func Abs(src GpuMat, dst *GpuMat) error { return OpenCVResult(C.GpuAbs(src.p, dst.p, nil)) } // AbsWithStream computes an absolute value of each matrix element // using a Stream for concurrency. // // For further details, please see: // https://docs.opencv.org/master/d8/d34/group__cudaarithm__elem.html#ga54a72bd772494ab34d05406fd76df2b6 func AbsWithStream(src GpuMat, dst *GpuMat, stream Stream) error { return OpenCVResult(C.GpuAbs(src.p, dst.p, stream.p)) } // AbsDiff computes per-element absolute difference of two matrices // (or of a matrix and scalar) using a Stream for concurrency. // // For further details, please see: // https://docs.opencv.org/master/d8/d34/group__cudaarithm__elem.html#gac062b283cf46ee90f74a773d3382ab54 func AbsDiff(src1, src2 GpuMat, dst *GpuMat) error { return OpenCVResult(C.GpuAbsDiff(src1.p, src2.p, dst.p, nil)) } // AbsDiffWithStream computes an absolute value of each matrix element // using a Stream for concurrency. // // For further details, please see: // https://docs.opencv.org/master/d8/d34/group__cudaarithm__elem.html#gac062b283cf46ee90f74a773d3382ab54 func AbsDiffWithStream(src1, src2 GpuMat, dst *GpuMat, s Stream) error { return OpenCVResult(C.GpuAbsDiff(src1.p, src2.p, dst.p, s.p)) } // Add computes a matrix-matrix or matrix-scalar sum. // // For further details, please see: // https://docs.opencv.org/master/d8/d34/group__cudaarithm__elem.html#ga5d9794bde97ed23d1c1485249074a8b1 func Add(src1, src2 GpuMat, dst *GpuMat) error { return OpenCVResult(C.GpuAdd(src1.p, src2.p, dst.p, nil)) } // AddWithStream computes a matrix-matrix or matrix-scalar sum // using a Stream for concurrency. // // For further details, please see: // https://docs.opencv.org/master/d8/d34/group__cudaarithm__elem.html#ga5d9794bde97ed23d1c1485249074a8b1 func AddWithStream(src1, src2 GpuMat, dst *GpuMat, s Stream) error { return OpenCVResult(C.GpuAdd(src1.p, src2.p, dst.p, s.p)) } // BitwiseAnd performs a per-element bitwise conjunction of two matrices // (or of matrix and scalar). // // For further details, please see: // https://docs.opencv.org/master/d8/d34/group__cudaarithm__elem.html#ga78d7c1a013877abd4237fbfc4e13bd76 func BitwiseAnd(src1, src2 GpuMat, dst *GpuMat) error { return OpenCVResult(C.GpuBitwiseAnd(src1.p, src2.p, dst.p, nil)) } // BitwiseAndWithStream performs a per-element bitwise conjunction of two matrices // (or of matrix and scalar) using a Stream for concurrency. // // For further details, please see: // https://docs.opencv.org/master/d8/d34/group__cudaarithm__elem.html#ga78d7c1a013877abd4237fbfc4e13bd76 func BitwiseAndWithStream(src1, src2 GpuMat, dst *GpuMat, s Stream) error { return OpenCVResult(C.GpuBitwiseAnd(src1.p, src2.p, dst.p, s.p)) } // BitwiseNot performs a per-element bitwise inversion. // // For further details, please see: // https://docs.opencv.org/master/d8/d34/group__cudaarithm__elem.html#gae58159a2259ae1acc76b531c171cf06a func BitwiseNot(src GpuMat, dst *GpuMat) error { return OpenCVResult(C.GpuBitwiseNot(src.p, dst.p, nil)) } // BitwiseNotWithStream performs a per-element bitwise inversion // using a Stream for concurrency. // // For further details, please see: // https://docs.opencv.org/master/d8/d34/group__cudaarithm__elem.html#gae58159a2259ae1acc76b531c171cf06a func BitwiseNotWithStream(src GpuMat, dst *GpuMat, s Stream) error { return OpenCVResult(C.GpuBitwiseNot(src.p, dst.p, s.p)) } // BitwiseOr performs a per-element bitwise disjunction of two matrices // (or of matrix and scalar). // // For further details, please see: // https://docs.opencv.org/master/d8/d34/group__cudaarithm__elem.html#gafd098ee3e51c68daa793999c1da3dfb7 func BitwiseOr(src1, src2 GpuMat, dst *GpuMat) error { return OpenCVResult(C.GpuBitwiseOr(src1.p, src2.p, dst.p, nil)) } // BitwiseOrWithStream performs a per-element bitwise disjunction of two matrices // (or of matrix and scalar) using a Stream for concurrency. // // For further details, please see: // https://docs.opencv.org/master/d8/d34/group__cudaarithm__elem.html#gafd098ee3e51c68daa793999c1da3dfb7 func BitwiseOrWithStream(src1, src2 GpuMat, dst *GpuMat, s Stream) error { return OpenCVResult(C.GpuBitwiseXor(src1.p, src2.p, dst.p, s.p)) } // BitwiseXor performs a per-element exclusive or of two matrices // (or of matrix and scalar). // // For further details, please see: // https://docs.opencv.org/master/d8/d34/group__cudaarithm__elem.html#ga3d95d4faafb099aacf18e8b915a4ad8d func BitwiseXor(src1, src2 GpuMat, dst *GpuMat) error { return OpenCVResult(C.GpuBitwiseXor(src1.p, src2.p, dst.p, nil)) } // BitwiseXorWithStream performs a per-element exclusive or of two matrices // (or of matrix and scalar) using a Stream for concurrency. // // For further details, please see: // https://docs.opencv.org/master/d8/d34/group__cudaarithm__elem.html#ga3d95d4faafb099aacf18e8b915a4ad8d func BitwiseXorWithStream(src1, src2 GpuMat, dst *GpuMat, s Stream) error { return OpenCVResult(C.GpuBitwiseXor(src1.p, src2.p, dst.p, s.p)) } // Divide computes a matrix-matrix or matrix-scalar division. // // For further details, please see: // https://docs.opencv.org/master/d8/d34/group__cudaarithm__elem.html#ga124315aa226260841e25cc0b9ea99dc3 func Divide(src1, src2 GpuMat, dst *GpuMat) error { return OpenCVResult(C.GpuDivide(src1.p, src2.p, dst.p, nil)) } // DivideWithStream computes a matrix-matrix or matrix-scalar division // using a Stream for concurrency. // // For further details, please see: // https://docs.opencv.org/master/d8/d34/group__cudaarithm__elem.html#ga124315aa226260841e25cc0b9ea99dc3 func DivideWithStream(src1, src2 GpuMat, dst *GpuMat, s Stream) error { return OpenCVResult(C.GpuDivide(src1.p, src2.p, dst.p, s.p)) } // Exp computes an exponent of each matrix element. // // For further details, please see: // https://docs.opencv.org/master/d8/d34/group__cudaarithm__elem.html#gac6e51541d3bb0a7a396128e4d5919b61 func Exp(src GpuMat, dst *GpuMat) error { return OpenCVResult(C.GpuExp(src.p, dst.p, nil)) } // ExpWithStream computes an exponent of each matrix element // using a Stream for concurrency. // // For further details, please see: // https://docs.opencv.org/master/d8/d34/group__cudaarithm__elem.html#gac6e51541d3bb0a7a396128e4d5919b61 func ExpWithStream(src GpuMat, dst *GpuMat, s Stream) error { return OpenCVResult(C.GpuExp(src.p, dst.p, s.p)) } // Log computes natural logarithm of absolute value of each matrix element. // // For further details, please see: // https://docs.opencv.org/master/d8/d34/group__cudaarithm__elem.html#gac6e51541d3bb0a7a396128e4d5919b61 func Log(src GpuMat, dst *GpuMat) error { return OpenCVResult(C.GpuLog(src.p, dst.p, nil)) } // LogWithStream computes natural logarithm of absolute value of each matrix element // using a Stream for concurrency. // // For further details, please see: // https://docs.opencv.org/master/d8/d34/group__cudaarithm__elem.html#gac6e51541d3bb0a7a396128e4d5919b61 func LogWithStream(src GpuMat, dst *GpuMat, s Stream) error { return OpenCVResult(C.GpuLog(src.p, dst.p, s.p)) } // Max computes the per-element maximum of two matrices (or a matrix and a scalar). // // For further details, please see: // https://docs.opencv.org/master/d8/d34/group__cudaarithm__elem.html#gadb5dd3d870f10c0866035755b929b1e7 func Max(src1, src2 GpuMat, dst *GpuMat) error { return OpenCVResult(C.GpuMax(src1.p, src2.p, dst.p, nil)) } // MaxWithStream computes the per-element maximum of two matrices (or a matrix and a scalar). // using a Stream for concurrency. // // For further details, please see: // https://docs.opencv.org/master/d8/d34/group__cudaarithm__elem.html#gadb5dd3d870f10c0866035755b929b1e7 func MaxWithStream(src1, src2 GpuMat, dst *GpuMat, s Stream) error { return OpenCVResult(C.GpuMax(src1.p, src2.p, dst.p, s.p)) } // Min computes the per-element minimum of two matrices (or a matrix and a scalar). // // For further details, please see: // https://docs.opencv.org/master/d8/d34/group__cudaarithm__elem.html#ga74f0b05a65b3d949c237abb5e6c60867 func Min(src1, src2 GpuMat, dst *GpuMat) error { return OpenCVResult(C.GpuMin(src1.p, src2.p, dst.p, nil)) } // MinWithStream computes the per-element minimum of two matrices (or a matrix and a scalar). // using a Stream for concurrency. // // For further details, please see: // https://docs.opencv.org/master/d8/d34/group__cudaarithm__elem.html#ga74f0b05a65b3d949c237abb5e6c60867 func MinWithStream(src1, src2 GpuMat, dst *GpuMat, s Stream) error { return OpenCVResult(C.GpuMin(src1.p, src2.p, dst.p, s.p)) } // Multiply computes a matrix-matrix or matrix-scalar multiplication. // // For further details, please see: // https://docs.opencv.org/master/d8/d34/group__cudaarithm__elem.html#ga497cc0615bf717e1e615143b56f00591 func Multiply(src1, src2 GpuMat, dst *GpuMat) error { return OpenCVResult(C.GpuMultiply(src1.p, src2.p, dst.p, nil)) } // MultiplyWithStream computes a matrix-matrix or matrix-scalar multiplication. // // For further details, please see: // https://docs.opencv.org/master/d8/d34/group__cudaarithm__elem.html#ga497cc0615bf717e1e615143b56f00591 func MultiplyWithStream(src1, src2 GpuMat, dst *GpuMat, s Stream) error { return OpenCVResult(C.GpuMultiply(src1.p, src2.p, dst.p, s.p)) } // Sqr computes a square value of each matrix element. // // For further details, please see: // https://docs.opencv.org/master/d8/d34/group__cudaarithm__elem.html#ga8aae233da90ce0ffe309ab8004342acb func Sqr(src GpuMat, dst *GpuMat) error { return OpenCVResult(C.GpuSqr(src.p, dst.p, nil)) } // SqrWithStream computes a square value of each matrix element // using a Stream for concurrency. // // For further details, please see: // https://docs.opencv.org/master/d8/d34/group__cudaarithm__elem.html#ga8aae233da90ce0ffe309ab8004342acb func SqrWithStream(src GpuMat, dst *GpuMat, s Stream) error { return OpenCVResult(C.GpuSqr(src.p, dst.p, s.p)) } // Sqrt computes a square root of each matrix element. // // For further details, please see: // https://docs.opencv.org/master/d8/d34/group__cudaarithm__elem.html#ga09303680cb1a5521a922b6d392028d8c func Sqrt(src GpuMat, dst *GpuMat) error { return OpenCVResult(C.GpuSqrt(src.p, dst.p, nil)) } // SqrtWithStream computes a square root of each matrix element. // using a Stream for concurrency. // // For further details, please see: // https://docs.opencv.org/master/d8/d34/group__cudaarithm__elem.html#ga09303680cb1a5521a922b6d392028d8c func SqrtWithStream(src GpuMat, dst *GpuMat, s Stream) error { return OpenCVResult(C.GpuSqrt(src.p, dst.p, s.p)) } // Subtract computes a matrix-matrix or matrix-scalar difference. // // For further details, please see: // https://docs.opencv.org/master/d8/d34/group__cudaarithm__elem.html#ga6eab60fc250059e2fda79c5636bd067f func Subtract(src1, src2 GpuMat, dst *GpuMat) error { return OpenCVResult(C.GpuSubtract(src1.p, src2.p, dst.p, nil)) } // SubtractWithStream computes a matrix-matrix or matrix-scalar difference // using a Stream for concurrency. // // For further details, please see: // https://docs.opencv.org/master/d8/d34/group__cudaarithm__elem.html#ga6eab60fc250059e2fda79c5636bd067f func SubtractWithStream(src1, src2 GpuMat, dst *GpuMat, s Stream) error { return OpenCVResult(C.GpuSubtract(src1.p, src2.p, dst.p, s.p)) } // Threshold applies a fixed-level threshold to each array element. // // For further details, please see: // https://docs.opencv.org/master/d8/d34/group__cudaarithm__elem.html#ga40f1c94ae9a9456df3cad48e3cb008e1 func Threshold(src GpuMat, dst *GpuMat, thresh, maxval float64, typ gocv.ThresholdType) error { return OpenCVResult(C.GpuThreshold(src.p, dst.p, C.double(thresh), C.double(maxval), C.int(typ), nil)) } // ThresholdWithStream applies a fixed-level threshold to each array element // using a Stream for concurrency. // // For further details, please see: // https://docs.opencv.org/master/d8/d34/group__cudaarithm__elem.html#ga40f1c94ae9a9456df3cad48e3cb008e1 func ThresholdWithStream(src GpuMat, dst *GpuMat, thresh, maxval float64, typ gocv.ThresholdType, s Stream) error { return OpenCVResult(C.GpuThreshold(src.p, dst.p, C.double(thresh), C.double(maxval), C.int(typ), s.p)) } // Flip flips a 2D matrix around vertical, horizontal, or both axes. // // For further details, please see: // https://docs.opencv.org/master/de/d09/group__cudaarithm__core.html#ga4d0a3f2b46e8f0f1ec2b5ac178dcd871 func Flip(src GpuMat, dst *GpuMat, flipCode int) error { return OpenCVResult(C.GpuFlip(src.p, dst.p, C.int(flipCode), nil)) } // FlipWithStream flips a 2D matrix around vertical, horizontal, or both axes // using a Stream for concurrency. // // For further details, please see: // https://docs.opencv.org/master/de/d09/group__cudaarithm__core.html#ga4d0a3f2b46e8f0f1ec2b5ac178dcd871 func FlipWithStream(src GpuMat, dst *GpuMat, flipCode int, stream Stream) error { return OpenCVResult(C.GpuFlip(src.p, dst.p, C.int(flipCode), stream.p)) } // Merge makes a multi-channel matrix out of several single-channel matrices. // // For further details, please see: // https://docs.opencv.org/4.x/de/d09/group__cudaarithm__core.html#gafce19eb0fcad23f67ab45d544992436d func Merge(mv []GpuMat, dst *GpuMat) error { cMatArray := make([]C.GpuMat, len(mv)) for i, r := range mv { cMatArray[i] = r.p } cMats := C.GpuMats{ mats: (*C.GpuMat)(&cMatArray[0]), length: C.int(len(mv)), } return OpenCVResult(C.GpuMerge(cMats, dst.p, nil)) } // MergeWithStream makes a multi-channel matrix out of several single-channel matrices // using a Stream for concurrency. // // For further details, please see: // https://docs.opencv.org/4.x/de/d09/group__cudaarithm__core.html#gafce19eb0fcad23f67ab45d544992436d func MergeWithStream(mv []GpuMat, dst *GpuMat, s Stream) error { cMatArray := make([]C.GpuMat, len(mv)) for i, r := range mv { cMatArray[i] = r.p } cMats := C.GpuMats{ mats: (*C.GpuMat)(&cMatArray[0]), length: C.int(len(mv)), } return OpenCVResult(C.GpuMerge(cMats, dst.p, s.p)) } // Transpose transposes a matrix. // // For further details, please see: // https://docs.opencv.org/4.x/de/d09/group__cudaarithm__core.html#ga327b71c3cb811a904ccf5fba37fc29f2 func Transpose(src GpuMat, dst *GpuMat) error { return OpenCVResult(C.GpuTranspose(src.p, dst.p, nil)) } // Transpose transposes a matrix using a Stream for concurrency. // // For further details, please see: // https://docs.opencv.org/4.x/de/d09/group__cudaarithm__core.html#ga327b71c3cb811a904ccf5fba37fc29f2 func TransposeWithStream(src GpuMat, dst *GpuMat, s Stream) error { return OpenCVResult(C.GpuTranspose(src.p, dst.p, s.p)) } // AddWeighted computes a weighted sum of two matrices. // // For further details, please see: // https://docs.opencv.org/4.x/d8/d34/group__cudaarithm__elem.html#ga2cd14a684ea70c6ab2a63ee90ffe6201 func AddWeighted(src1 GpuMat, alpha float64, src2 GpuMat, beta float64, gamma float64, dst *GpuMat, dType int) error { return OpenCVResult(C.GpuAddWeighted(src1.p, C.double(alpha), src2.p, C.double(beta), C.double(gamma), dst.p, C.int(dType), nil)) } // AddWeightedWithStream computes a weighted sum of two matrices using a Stream for concurrency. // // For further details, please see: // https://docs.opencv.org/4.x/d8/d34/group__cudaarithm__elem.html#ga2cd14a684ea70c6ab2a63ee90ffe6201 func AddWeightedWithStream(src1 GpuMat, alpha float64, src2 GpuMat, beta float64, gamma float64, dst *GpuMat, dType int, s Stream) error { return OpenCVResult(C.GpuAddWeighted(src1.p, C.double(alpha), src2.p, C.double(beta), C.double(gamma), dst.p, C.int(dType), s.p)) } // CopyMakeBorder forms a border around an image. // // For further details, please see: // https://docs.opencv.org/master/de/d09/group__cudaarithm__core.html#ga5368db7656eacf846b40089c98053a49 func CopyMakeBorder(src GpuMat, dst *GpuMat, top, bottom, left, right int, borderType gocv.BorderType, value gocv.Scalar) error { bv := C.struct_Scalar{ val1: C.double(value.Val1), val2: C.double(value.Val2), val3: C.double(value.Val3), val4: C.double(value.Val4), } return OpenCVResult(C.GpuCopyMakeBorder(src.p, dst.p, C.int(top), C.int(bottom), C.int(left), C.int(right), C.int(borderType), bv, nil)) } // CopyMakeBorderWithStream forms a border around an image using a Stream for concurrency. // // For further details, please see: // https://docs.opencv.org/master/de/d09/group__cudaarithm__core.html#ga5368db7656eacf846b40089c98053a49 func CopyMakeBorderWithStream(src GpuMat, dst *GpuMat, top, bottom, left, right int, borderType gocv.BorderType, value gocv.Scalar, s Stream) error { bv := C.struct_Scalar{ val1: C.double(value.Val1), val2: C.double(value.Val2), val3: C.double(value.Val3), val4: C.double(value.Val4), } return OpenCVResult(C.GpuCopyMakeBorder(src.p, dst.p, C.int(top), C.int(bottom), C.int(left), C.int(right), C.int(borderType), bv, s.p)) } type LookUpTable struct { p C.LookUpTable } // NewLookUpTable Creates implementation for cuda::LookUpTable . // // lut Look-up table of 256 elements. It is a continuous CV_8U matrix. // // For further details, please see: // https://docs.opencv.org/4.x/de/d09/group__cudaarithm__core.html#gaa75254a07dcf7996b4b5a68d383847f8 func NewLookUpTable(lut GpuMat) LookUpTable { return LookUpTable{p: C.Cuda_Create_LookUpTable(lut.p)} } // Close releases LookUpTable resources. func (lt *LookUpTable) Close() { C.Cuda_LookUpTable_Close(lt.p) } // Transform Transforms the source matrix into the destination // matrix using the given look-up table: dst(I) = lut(src(I)) . // // src: Source matrix. CV_8UC1 and CV_8UC3 matrices are supported for now. // // dst: Destination matrix. // // For further details, please see: // https://docs.opencv.org/4.x/df/d29/classcv_1_1cuda_1_1LookUpTable.html#afdbcbd3047f847451892f3b18cd018de func (lt *LookUpTable) Transform(src GpuMat, dst *GpuMat) error { return OpenCVResult(C.Cuda_LookUpTable_Transform(lt.p, src.p, dst.p, nil)) } // Empty Returns true if the Algorithm is empty // (e.g. in the very beginning or after unsuccessful read. // // For further details, please see: // https://docs.opencv.org/4.x/d3/d46/classcv_1_1Algorithm.html#a827c8b2781ed17574805f373e6054ff1 func (lt *LookUpTable) Empty() bool { b := C.Cuda_LookUpTable_Empty(lt.p) return bool(b) } // TransformWithStream Transforms the source matrix into the destination // matrix using the given look-up table: dst(I) = lut(src(I)) . // // src: Source matrix. CV_8UC1 and CV_8UC3 matrices are supported for now. // // dst: Destination matrix. // // stream: Stream for the asynchronous version. // // For further details, please see: // https://docs.opencv.org/4.x/df/d29/classcv_1_1cuda_1_1LookUpTable.html#afdbcbd3047f847451892f3b18cd018de func (lt *LookUpTable) TransformWithStream(src GpuMat, dst *GpuMat, s Stream) error { return OpenCVResult(C.Cuda_LookUpTable_Transform(lt.p, src.p, dst.p, s.p)) } // Split Copies each plane of a multi-channel matrix into an array. // // src: Source matrix. // // dst: Destination array/vector of single-channel matrices. // // For further details, please see: // https://docs.opencv.org/4.x/de/d09/group__cudaarithm__core.html#gaf1714e7a9ea0719c29bf378beaf5f99d func Split(src GpuMat, dst []GpuMat) error { dstv := make([]C.GpuMat, len(dst)) for i := range dst { dstv[i] = dst[i].p } c_dstv := C.GpuMats{ mats: unsafe.SliceData(dstv), length: C.int(len(dstv)), } return OpenCVResult(C.Cuda_Split(src.p, c_dstv, nil)) } // SplitWithStream Copies each plane of a multi-channel matrix into an array. // // src: Source matrix. // // dst: Destination array/vector of single-channel matrices. // // stream: Stream for the asynchronous version. // // For further details, please see: // https://docs.opencv.org/4.x/de/d09/group__cudaarithm__core.html#gaf1714e7a9ea0719c29bf378beaf5f99d func SplitWithStream(src GpuMat, dst []GpuMat, s Stream) error { dstv := make([]C.GpuMat, len(dst)) for i := range dst { dstv[i] = dst[i].p } c_dstv := C.GpuMats{ mats: unsafe.SliceData(dstv), length: C.int(len(dstv)), } return OpenCVResult(C.Cuda_Split(src.p, c_dstv, s.p)) } // CalcNorm calculates the norm of a matrix. // // For further details, please see: // https://docs.opencv.org/4.x/d5/de6/group__cudaarithm__reduce.html#ga39d2826990d29b7e4b69dbe02bdae2e1 func CalcNorm(src, dst GpuMat, normType gocv.NormType) error { return OpenCVResult(C.GpuCalcNorm(src.p, dst.p, C.int(normType), nil)) } // CalcNormWithStream calculates the norm of a matrix. // // For further details, please see: // https://docs.opencv.org/4.x/d5/de6/group__cudaarithm__reduce.html#ga39d2826990d29b7e4b69dbe02bdae2e1 func CalcNormWithStream(src, dst GpuMat, normType gocv.NormType, s Stream) error { return OpenCVResult(C.GpuCalcNorm(src.p, dst.p, C.int(normType), s.p)) } // CalcNormDiff calculates the norm of a matrix. // // For further details, please see: // https://docs.opencv.org/4.x/d5/de6/group__cudaarithm__reduce.html#ga9be3d9a7b6c5760955f37d1039d01265 func CalcNormDiff(src1, src2, dst GpuMat, normType gocv.NormType) error { return OpenCVResult(C.GpuCalcNormDiff(src1.p, src2.p, dst.p, C.int(normType), nil)) } // CalcNormDiffWithStream calculates the norm of a matrix. // // For further details, please see: // https://docs.opencv.org/4.x/d5/de6/group__cudaarithm__reduce.html#ga9be3d9a7b6c5760955f37d1039d01265 func CalcNormDiffWithStream(src1, src2, dst GpuMat, normType gocv.NormType, s Stream) error { return OpenCVResult(C.GpuCalcNormDiff(src1.p, src2.p, dst.p, C.int(normType), s.p)) } // Norm returns the difference of two matrices. // // For further details, please see: // https://docs.opencv.org/4.x/d5/de6/group__cudaarithm__reduce.html#ga48b6298589b80a6915d076e2dcdbd11b func Norm(src1, src2 GpuMat, normType gocv.NormType) float64 { return float64(C.GpuNorm(src1.p, src2.p, C.int(normType))) } // Compare compares elements of two matrices (or of a matrix and scalar). // // For further details, please see: // https://docs.opencv.org/4.x/d8/d34/group__cudaarithm__elem.html#ga4d41cd679f4a83862a3de71a6057db54 func Compare(src1, src2, dst GpuMat, compareType gocv.CompareType) error { return OpenCVResult(C.GpuCompare(src1.p, src2.p, dst.p, C.int(compareType), nil)) } // CompareWithStream compares elements of two matrices (or of a matrix and scalar) // // For further details, please see: // https://docs.opencv.org/4.x/d8/d34/group__cudaarithm__elem.html#ga4d41cd679f4a83862a3de71a6057db54 func CompareWithStream(src1, src2, dst GpuMat, compareType gocv.CompareType, s Stream) error { return OpenCVResult(C.GpuCompare(src1.p, src2.p, dst.p, C.int(compareType), s.p)) } // LShift performs a per-element left bit-shift of a matrix by a constant amount. // // For further details, please see: // https://docs.opencv.org/4.x/d8/d34/group__cudaarithm__elem.html#ga79fd71721b04444eb87c6c4844c22a6e func LShift(src GpuMat, shift gocv.Scalar, dst *GpuMat) error { cShift := C.struct_Scalar{ val1: C.double(shift.Val1), val2: C.double(shift.Val2), val3: C.double(shift.Val3), val4: C.double(shift.Val4), } return OpenCVResult(C.GpuLShift(src.p, cShift, dst.p, nil)) } // LShiftWithStream performs a per-element left bit-shift of a matrix by a constant amount using a Stream for concurrency. // // For further details, please see: // https://docs.opencv.org/4.x/d8/d34/group__cudaarithm__elem.html#ga79fd71721b04444eb87c6c4844c22a6e func LShiftWithStream(src GpuMat, shift gocv.Scalar, dst *GpuMat, s Stream) error { cShift := C.struct_Scalar{ val1: C.double(shift.Val1), val2: C.double(shift.Val2), val3: C.double(shift.Val3), val4: C.double(shift.Val4), } return OpenCVResult(C.GpuLShift(src.p, cShift, dst.p, s.p)) } // RShift performs a per-element right bit-shift of a matrix by a constant amount. // // For further details, please see: // https://docs.opencv.org/4.x/d8/d34/group__cudaarithm__elem.html#ga513719d25e508160a245724369d68346 func RShift(src GpuMat, shift gocv.Scalar, dst *GpuMat) error { cShift := C.struct_Scalar{ val1: C.double(shift.Val1), val2: C.double(shift.Val2), val3: C.double(shift.Val3), val4: C.double(shift.Val4), } return OpenCVResult(C.GpuRShift(src.p, cShift, dst.p, nil)) } // RShiftWithStream performs a per-element right bit-shift of a matrix by a constant amount using a Stream for concurrency. // // For further details, please see: // https://docs.opencv.org/4.x/d8/d34/group__cudaarithm__elem.html#ga513719d25e508160a245724369d68346 func RShiftWithStream(src GpuMat, shift gocv.Scalar, dst *GpuMat, s Stream) error { cShift := C.struct_Scalar{ val1: C.double(shift.Val1), val2: C.double(shift.Val2), val3: C.double(shift.Val3), val4: C.double(shift.Val4), } return OpenCVResult(C.GpuRShift(src.p, cShift, dst.p, s.p)) } // AbsSum computes the sum of absolute values of array elements. // For further details, see: // https://docs.opencv.org/4.x/d5/de6/group__cudaarithm__reduce.html#ga690fa79ba4426c53f7d2bebf3d37a32a func AbsSum(src GpuMat) (gocv.Scalar, error) { var cResult C.struct_Scalar err := OpenCVResult(C.GpuAbsSum(src.p, nil, &cResult)) return gocv.Scalar{ Val1: float64(cResult.val1), Val2: float64(cResult.val2), Val3: float64(cResult.val3), Val4: float64(cResult.val4), }, err } // AbsSumWithMask computes the sum of absolute values of array elements using a mask. // For further details, see: // https://docs.opencv.org/4.x/d5/de6/group__cudaarithm__reduce.html#ga690fa79ba4426c53f7d2bebf3d37a32a func AbsSumWithMask(src, mask GpuMat) (gocv.Scalar, error) { var cResult C.struct_Scalar err := OpenCVResult(C.GpuAbsSum(src.p, mask.p, &cResult)) return gocv.Scalar{ Val1: float64(cResult.val1), Val2: float64(cResult.val2), Val3: float64(cResult.val3), Val4: float64(cResult.val4), }, err } // CalcAbsSum computes the sum of absolute values of array elements and stores the result in dst. // For further details, see: // https://docs.opencv.org/4.x/d5/de6/group__cudaarithm__reduce.html#ga15c403b76ab2c4d7ed0f5edc09891b7e func CalcAbsSum(src GpuMat, dst *GpuMat) error { return OpenCVResult(C.GpuCalcAbsSum(src.p, dst.p, nil, nil)) } // CalcAbsSumWithMask computes the sum of absolute values of array elements using a mask and stores the result in dst. // For further details, see: // https://docs.opencv.org/4.x/d5/de6/group__cudaarithm__reduce.html#ga15c403b76ab2c4d7ed0f5edc09891b7e func CalcAbsSumWithMask(src GpuMat, dst *GpuMat, mask GpuMat) error { return OpenCVResult(C.GpuCalcAbsSum(src.p, dst.p, mask.p, nil)) } // CalcAbsSumWithStream computes the sum of absolute values of array elements and stores the result in dst using a Stream. // For further details, see: // https://docs.opencv.org/4.x/d5/de6/group__cudaarithm__reduce.html#ga15c403b76ab2c4d7ed0f5edc09891b7e func CalcAbsSumWithStream(src GpuMat, dst *GpuMat, mask GpuMat, s Stream) error { return OpenCVResult(C.GpuCalcAbsSum(src.p, dst.p, mask.p, s.p)) } // MinMax computes the global minimum and maximum in a GpuMat. // For further details, see: // https://docs.opencv.org/4.x/d5/de6/group__cudaarithm__reduce.html#ga8d7de68c10717cf25e787e3c20d2dfee func MinMax(src GpuMat) (minVal, maxVal float64, err error) { var cMin, cMax C.double e := OpenCVResult(C.GpuMinMax(src.p, nil, &cMin, &cMax)) return float64(cMin), float64(cMax), e } // MinMaxWithMask computes the global minimum and maximum in a GpuMat using a mask. // For further details, see: // https://docs.opencv.org/4.x/d5/de6/group__cudaarithm__reduce.html#ga8d7de68c10717cf25e787e3c20d2dfee func MinMaxWithMask(src, mask GpuMat) (minVal, maxVal float64, err error) { var cMin, cMax C.double e := OpenCVResult(C.GpuMinMax(src.p, mask.p, &cMin, &cMax)) return float64(cMin), float64(cMax), e } // MinMaxLoc finds the global minimum and maximum in a GpuMat as well as their locations. // For further details, see: // https://docs.opencv.org/4.x/d5/de6/group__cudaarithm__reduce.html#ga5cacbc2a2323c4eaa81e7390c5d9f530 func MinMaxLoc(src GpuMat) (minVal, maxVal float64, minLoc, maxLoc image.Point, err error) { var cMin, cMax C.double var minLocX, minLocY, maxLocX, maxLocY C.int e := OpenCVResult(C.GpuMinMaxLoc(src.p, nil, &cMin, &cMax, &minLocX, &minLocY, &maxLocX, &maxLocY)) return float64(cMin), float64(cMax), image.Pt(int(minLocX), int(minLocY)), image.Pt(int(maxLocX), int(maxLocY)), e } // MinMaxLocWithMask finds the global minimum and maximum in a GpuMat as well as their locations, using a mask. // For further details, see: // https://docs.opencv.org/4.x/d5/de6/group__cudaarithm__reduce.html#ga5cacbc2a2323c4eaa81e7390c5d9f530 func MinMaxLocWithMask(src, mask GpuMat) (minVal, maxVal float64, minLoc, maxLoc image.Point, err error) { var cMin, cMax C.double var minLocX, minLocY, maxLocX, maxLocY C.int e := OpenCVResult(C.GpuMinMaxLoc(src.p, mask.p, &cMin, &cMax, &minLocX, &minLocY, &maxLocX, &maxLocY)) return float64(cMin), float64(cMax), image.Pt(int(minLocX), int(minLocY)), image.Pt(int(maxLocX), int(maxLocY)), e } // Normalize scales and shifts array elements so that they cover a certain range. // For further details, see: // https://docs.opencv.org/4.x/d5/de6/group__cudaarithm__reduce.html#ga4da4738b9956a5baaa2f5f8c2fba438a func Normalize(src GpuMat, dst *GpuMat, alpha, beta float64, normType gocv.NormType, dtype int) error { return OpenCVResult(C.GpuNormalize(src.p, dst.p, C.double(alpha), C.double(beta), C.int(normType), C.int(dtype), nil, nil)) } // NormalizeWithMask scales and shifts array elements so that they cover a certain range, using a mask. func NormalizeWithMask(src GpuMat, dst *GpuMat, alpha, beta float64, normType gocv.NormType, dtype int, mask GpuMat) error { return OpenCVResult(C.GpuNormalize(src.p, dst.p, C.double(alpha), C.double(beta), C.int(normType), C.int(dtype), mask.p, nil)) } // NormalizeWithStream scales and shifts array elements so that they cover a certain range, using a mask and Stream. func NormalizeWithStream(src GpuMat, dst *GpuMat, alpha, beta float64, normType gocv.NormType, dtype int, mask GpuMat, s Stream) error { return OpenCVResult(C.GpuNormalize(src.p, dst.p, C.double(alpha), C.double(beta), C.int(normType), C.int(dtype), mask.p, s.p)) } // FindMinMaxLoc finds the minimum and maximum values and their locations in a GpuMat. // For further details, see: // https://docs.opencv.org/4.x/d5/de6/group__cudaarithm__reduce.html#ga93916bc473a62d215d1130fab84d090a func FindMinMaxLoc(src GpuMat, minMaxVals, loc *GpuMat) error { return OpenCVResult(C.GpuFindMinMaxLoc(src.p, minMaxVals.p, loc.p, nil, nil)) } // FindMinMaxLocWithMask finds the minimum and maximum values and their locations in a GpuMat using a mask. func FindMinMaxLocWithMask(src GpuMat, minMaxVals, loc *GpuMat, mask GpuMat) error { return OpenCVResult(C.GpuFindMinMaxLoc(src.p, minMaxVals.p, loc.p, mask.p, nil)) } // FindMinMaxLocWithStream finds the minimum and maximum values and their locations in a GpuMat using a mask and Stream. func FindMinMaxLocWithStream(src GpuMat, minMaxVals, loc *GpuMat, mask GpuMat, s Stream) error { return OpenCVResult(C.GpuFindMinMaxLoc(src.p, minMaxVals.p, loc.p, mask.p, s.p)) } // FindMinMax finds the minimum and maximum values in a GpuMat and stores them in dst. // For further details, see: // https://docs.opencv.org/4.x/d5/de6/group__cudaarithm__reduce.html#gae7f5f2aa9f65314470a76fccdff887f2 func FindMinMax(src GpuMat, dst *GpuMat) error { return OpenCVResult(C.GpuFindMinMax(src.p, dst.p, nil, nil)) } // FindMinMaxWithMask finds the minimum and maximum values in a GpuMat using a mask and stores them in dst. func FindMinMaxWithMask(src GpuMat, dst *GpuMat, mask GpuMat) error { return OpenCVResult(C.GpuFindMinMax(src.p, dst.p, mask.p, nil)) } // FindMinMaxWithStream finds the minimum and maximum values in a GpuMat using a mask and Stream, and stores them in dst. func FindMinMaxWithStream(src GpuMat, dst *GpuMat, mask GpuMat, s Stream) error { return OpenCVResult(C.GpuFindMinMax(src.p, dst.p, mask.p, s.p)) } ================================================ FILE: cuda/arithm.h ================================================ #ifndef _OPENCV3_CUDA_ARITHM_H_ #define _OPENCV3_CUDA_ARITHM_H_ #include #include #ifdef __cplusplus #include #include extern "C" { #endif #include "cuda.h" #ifdef __cplusplus typedef cv::Ptr< cv::cuda::LookUpTable >* LookUpTable; #else typedef void* LookUpTable; #endif OpenCVResult GpuAbs(GpuMat src, GpuMat dst, Stream s); OpenCVResult GpuAbsDiff(GpuMat src1, GpuMat src2, GpuMat dst, Stream s); OpenCVResult GpuAdd(GpuMat src1, GpuMat src2, GpuMat dst, Stream s); OpenCVResult GpuBitwiseAnd(GpuMat src1, GpuMat src2, GpuMat dst, Stream s); OpenCVResult GpuBitwiseNot(GpuMat src, GpuMat dst, Stream s); OpenCVResult GpuBitwiseOr(GpuMat src1, GpuMat src2, GpuMat dst, Stream s); OpenCVResult GpuBitwiseXor(GpuMat src1, GpuMat src2, GpuMat dst, Stream s); OpenCVResult GpuDivide(GpuMat src1, GpuMat src2, GpuMat dst, Stream s); OpenCVResult GpuExp(GpuMat src, GpuMat dst, Stream s); OpenCVResult GpuLog(GpuMat src, GpuMat dst, Stream s); OpenCVResult GpuMax(GpuMat src1, GpuMat src2, GpuMat dst, Stream s); OpenCVResult GpuMin(GpuMat src1, GpuMat src2, GpuMat dst, Stream s); OpenCVResult GpuMultiply(GpuMat src1, GpuMat src2, GpuMat dst, Stream s); OpenCVResult GpuSqr(GpuMat src, GpuMat dst, Stream s); OpenCVResult GpuSqrt(GpuMat src, GpuMat dst, Stream s); OpenCVResult GpuSubtract(GpuMat src1, GpuMat src2, GpuMat dst, Stream s); OpenCVResult GpuThreshold(GpuMat src, GpuMat dst, double thresh, double maxval, int typ, Stream s); OpenCVResult GpuFlip(GpuMat src, GpuMat dst, int flipCode, Stream s); OpenCVResult GpuMerge(struct GpuMats mats, GpuMat dst, Stream s); OpenCVResult GpuTranspose(GpuMat src, GpuMat dst, Stream s); OpenCVResult GpuAddWeighted(GpuMat src1, double alpha, GpuMat src2, double beta, double gamma, GpuMat dst, int dType, Stream s); OpenCVResult GpuCopyMakeBorder(GpuMat src, GpuMat dst, int top, int bottom, int left, int right, int borderType, Scalar value, Stream s); OpenCVResult GpuCalcNorm(GpuMat src, GpuMat dst, int typ, Stream s); OpenCVResult GpuCalcNormDiff(GpuMat src1, GpuMat src2, GpuMat dst, int typ, Stream s); double GpuNorm(GpuMat src1, GpuMat src2, int typ); OpenCVResult GpuCompare(GpuMat src1, GpuMat src2, GpuMat dst, int typ, Stream s); OpenCVResult GpuLShift(GpuMat src, Scalar shift, GpuMat dst, Stream s); OpenCVResult GpuRShift(GpuMat src, Scalar shift, GpuMat dst, Stream s); OpenCVResult GpuAbsSum(GpuMat src, GpuMat mask, struct Scalar* result); OpenCVResult GpuAbsSumWithMask(GpuMat src, GpuMat mask, struct Scalar* result); OpenCVResult GpuCalcAbsSum(GpuMat src, GpuMat dst, GpuMat mask, Stream s); OpenCVResult GpuMinMax(GpuMat src, GpuMat mask, double* minVal, double* maxVal); OpenCVResult GpuMinMaxLoc(GpuMat src, GpuMat mask, double* minVal, double* maxVal, int* minLocX, int* minLocY, int* maxLocX, int* maxLocY); OpenCVResult GpuNormalize(GpuMat src, GpuMat dst, double alpha, double beta, int normType, int dtype, GpuMat mask, Stream s); OpenCVResult GpuFindMinMaxLoc(GpuMat src, GpuMat minMaxVals, GpuMat loc, GpuMat mask, Stream s); OpenCVResult GpuFindMinMax(GpuMat src, GpuMat dst, GpuMat mask, Stream s); //LookUpTable LookUpTable Cuda_Create_LookUpTable(GpuMat lut); void Cuda_LookUpTable_Close(LookUpTable lt); OpenCVResult Cuda_LookUpTable_Transform(LookUpTable lt, GpuMat src, GpuMat dst, Stream s); bool Cuda_LookUpTable_Empty(LookUpTable lut); OpenCVResult Cuda_Split(GpuMat src, GpuMats dst, Stream s); #ifdef __cplusplus } #endif #endif //_OPENCV3_CUDA_ARITHM_H_ ================================================ FILE: cuda/arithm_test.go ================================================ //go:build !gocv_specific_modules || (gocv_specific_modules && gocv_cuda_arithm) package cuda import ( "testing" "gocv.io/x/gocv" ) func TestAbs(t *testing.T) { src := gocv.IMRead("../images/gocvlogo.jpg", gocv.IMReadColor) if src.Empty() { t.Error("Invalid read of Mat in Abs test") } defer src.Close() var cimg, dimg = NewGpuMat(), NewGpuMat() defer cimg.Close() defer dimg.Close() cimg.Upload(src) dest := gocv.NewMat() defer dest.Close() Abs(cimg, &dimg) dimg.Download(&dest) if dest.Empty() || src.Rows() != dest.Rows() || src.Cols() != dest.Cols() { t.Error("Invalid Abs test") } } func TestAbsException(t *testing.T) { src := gocv.NewMat() defer src.Close() var cimg, dimg = NewGpuMat(), NewGpuMat() defer cimg.Close() defer dimg.Close() cimg.Upload(src) dest := gocv.NewMat() defer dest.Close() err := Abs(cimg, &dimg) if err == nil { t.Error("Expected exception in test") } if len(err.Error()) == 0 { t.Error("Expected exception message in test") } } func TestAbsWithStream(t *testing.T) { src := gocv.IMRead("../images/gocvlogo.jpg", gocv.IMReadColor) if src.Empty() { t.Error("Invalid read of Mat in Abs test") } defer src.Close() var cimg, dimg, s = NewGpuMat(), NewGpuMat(), NewStream() defer cimg.Close() defer dimg.Close() defer s.Close() dest := gocv.NewMat() defer dest.Close() cimg.UploadWithStream(src, s) AbsWithStream(cimg, &dimg, s) dimg.DownloadWithStream(&dest, s) s.WaitForCompletion() if dest.Empty() || src.Rows() != dest.Rows() || src.Cols() != dest.Cols() { t.Error("Invalid Abs test") } } func TestAbsDiff(t *testing.T) { src1 := gocv.IMRead("../images/gocvlogo.jpg", gocv.IMReadColor) if src1.Empty() { t.Error("Invalid read of Mat in AbsDiff test") } defer src1.Close() var cimg1, cimg2, dimg = NewGpuMat(), NewGpuMat(), NewGpuMat() defer cimg1.Close() defer cimg2.Close() defer dimg.Close() cimg1.Upload(src1) cimg2.Upload(src1) dest := gocv.NewMat() defer dest.Close() AbsDiff(cimg1, cimg2, &dimg) dimg.Download(&dest) if dest.Empty() || src1.Rows() != dest.Rows() || src1.Cols() != dest.Cols() { t.Error("Invalid AbsDiff test") } } func TestAdd(t *testing.T) { src1 := gocv.IMRead("../images/gocvlogo.jpg", gocv.IMReadColor) if src1.Empty() { t.Error("Invalid read of Mat in AbsDiff test") } defer src1.Close() var cimg1, cimg2, dimg = NewGpuMat(), NewGpuMat(), NewGpuMat() defer cimg1.Close() defer cimg2.Close() defer dimg.Close() cimg1.Upload(src1) cimg2.Upload(src1) dest := gocv.NewMat() defer dest.Close() Add(cimg1, cimg2, &dimg) dimg.Download(&dest) if dest.Empty() || src1.Rows() != dest.Rows() || src1.Cols() != dest.Cols() { t.Error("Invalid Add test") } } func TestBitwiseAnd(t *testing.T) { src1 := gocv.IMRead("../images/gocvlogo.jpg", gocv.IMReadColor) if src1.Empty() { t.Error("Invalid read of Mat in AbsDiff test") } defer src1.Close() var cimg1, cimg2, dimg = NewGpuMat(), NewGpuMat(), NewGpuMat() defer cimg1.Close() defer cimg2.Close() defer dimg.Close() cimg1.Upload(src1) cimg2.Upload(src1) dest := gocv.NewMat() defer dest.Close() BitwiseAnd(cimg1, cimg2, &dimg) dimg.Download(&dest) if dest.Empty() || src1.Rows() != dest.Rows() || src1.Cols() != dest.Cols() { t.Error("Invalid BitwiseAnd test") } } func TestBitwiseNot(t *testing.T) { src1 := gocv.IMRead("../images/gocvlogo.jpg", gocv.IMReadColor) if src1.Empty() { t.Error("Invalid read of Mat in AbsDiff test") } defer src1.Close() var cimg, dimg = NewGpuMat(), NewGpuMat() defer cimg.Close() defer dimg.Close() cimg.Upload(src1) dest := gocv.NewMat() defer dest.Close() BitwiseNot(cimg, &dimg) dimg.Download(&dest) if dest.Empty() || src1.Rows() != dest.Rows() || src1.Cols() != dest.Cols() { t.Error("Invalid BitwiseNot test") } } func TestBitwiseOr(t *testing.T) { src1 := gocv.IMRead("../images/gocvlogo.jpg", gocv.IMReadColor) if src1.Empty() { t.Error("Invalid read of Mat in BitwiseOr test") } defer src1.Close() var cimg1, cimg2, dimg = NewGpuMat(), NewGpuMat(), NewGpuMat() defer cimg1.Close() defer cimg2.Close() defer dimg.Close() cimg1.Upload(src1) cimg2.Upload(src1) dest := gocv.NewMat() defer dest.Close() BitwiseOr(cimg1, cimg2, &dimg) dimg.Download(&dest) if dest.Empty() || src1.Rows() != dest.Rows() || src1.Cols() != dest.Cols() { t.Error("Invalid BitwiseOr test") } } func TestBitwiseXor(t *testing.T) { src1 := gocv.IMRead("../images/gocvlogo.jpg", gocv.IMReadColor) if src1.Empty() { t.Error("Invalid read of Mat in BitwiseXor test") } defer src1.Close() var cimg1, cimg2, dimg = NewGpuMat(), NewGpuMat(), NewGpuMat() defer cimg1.Close() defer cimg2.Close() defer dimg.Close() cimg1.Upload(src1) cimg2.Upload(src1) dest := gocv.NewMat() defer dest.Close() BitwiseXor(cimg1, cimg2, &dimg) dimg.Download(&dest) if dest.Empty() || src1.Rows() != dest.Rows() || src1.Cols() != dest.Cols() { t.Error("Invalid BitwiseXor test") } } func TestDivide(t *testing.T) { src1 := gocv.IMRead("../images/gocvlogo.jpg", gocv.IMReadColor) if src1.Empty() { t.Error("Invalid read of Mat in Divide test") } defer src1.Close() var cimg1, cimg2, dimg = NewGpuMat(), NewGpuMat(), NewGpuMat() defer cimg1.Close() defer cimg2.Close() defer dimg.Close() cimg1.Upload(src1) cimg2.Upload(src1) dest := gocv.NewMat() defer dest.Close() Divide(cimg1, cimg2, &dimg) dimg.Download(&dest) if dest.Empty() || src1.Rows() != dest.Rows() || src1.Cols() != dest.Cols() { t.Error("Invalid Divide test") } } func TestDivideWithStream(t *testing.T) { src1 := gocv.IMRead("../images/gocvlogo.jpg", gocv.IMReadColor) if src1.Empty() { t.Error("Invalid read of Mat in Divide test") } defer src1.Close() var cimg1, cimg2, dimg = NewGpuMat(), NewGpuMat(), NewGpuMat() var s = NewStream() defer cimg1.Close() defer cimg2.Close() defer dimg.Close() defer s.Close() cimg1.UploadWithStream(src1, s) cimg2.UploadWithStream(src1, s) dest := gocv.NewMat() defer dest.Close() DivideWithStream(cimg1, cimg2, &dimg, s) dimg.DownloadWithStream(&dest, s) s.WaitForCompletion() if dest.Empty() || src1.Rows() != dest.Rows() || src1.Cols() != dest.Cols() { t.Error("Invalid Divide test") } } func TestExp(t *testing.T) { src1 := gocv.IMRead("../images/gocvlogo.jpg", gocv.IMReadColor) if src1.Empty() { t.Error("Invalid read of Mat in Exp test") } defer src1.Close() var cimg1, dimg = NewGpuMat(), NewGpuMat() defer cimg1.Close() defer dimg.Close() cimg1.Upload(src1) dest := gocv.NewMat() defer dest.Close() Exp(cimg1, &dimg) dimg.Download(&dest) if dest.Empty() || src1.Rows() != dest.Rows() || src1.Cols() != dest.Cols() { t.Error("Invalid Exp test") } } func TestLog(t *testing.T) { src1 := gocv.IMRead("../images/gocvlogo.jpg", gocv.IMReadColor) if src1.Empty() { t.Error("Invalid read of Mat in Log test") } defer src1.Close() var cimg1, dimg = NewGpuMat(), NewGpuMat() defer cimg1.Close() defer dimg.Close() cimg1.Upload(src1) dest := gocv.NewMat() defer dest.Close() Log(cimg1, &dimg) dimg.Download(&dest) if dest.Empty() || src1.Rows() != dest.Rows() || src1.Cols() != dest.Cols() { t.Error("Invalid Log test") } } func TestMax(t *testing.T) { src1 := gocv.IMRead("../images/gocvlogo.jpg", gocv.IMReadColor) if src1.Empty() { t.Error("Invalid read of Mat in Max test") } defer src1.Close() var cimg1, cimg2, dimg = NewGpuMat(), NewGpuMat(), NewGpuMat() defer cimg1.Close() defer cimg2.Close() defer dimg.Close() cimg1.Upload(src1) cimg2.Upload(src1) dest := gocv.NewMat() defer dest.Close() Max(cimg1, cimg2, &dimg) dimg.Download(&dest) if dest.Empty() || src1.Rows() != dest.Rows() || src1.Cols() != dest.Cols() { t.Error("Invalid Max test") } } func TestMin(t *testing.T) { src1 := gocv.IMRead("../images/gocvlogo.jpg", gocv.IMReadColor) if src1.Empty() { t.Error("Invalid read of Mat in Min test") } defer src1.Close() var cimg1, cimg2, dimg = NewGpuMat(), NewGpuMat(), NewGpuMat() defer cimg1.Close() defer cimg2.Close() defer dimg.Close() cimg1.Upload(src1) cimg2.Upload(src1) dest := gocv.NewMat() defer dest.Close() Min(cimg1, cimg2, &dimg) dimg.Download(&dest) if dest.Empty() || src1.Rows() != dest.Rows() || src1.Cols() != dest.Cols() { t.Error("Invalid Min test") } } func TestMultiply(t *testing.T) { src1 := gocv.IMRead("../images/gocvlogo.jpg", gocv.IMReadColor) if src1.Empty() { t.Error("Invalid read of Mat in Multiply test") } defer src1.Close() var cimg1, cimg2, dimg = NewGpuMat(), NewGpuMat(), NewGpuMat() defer cimg1.Close() defer cimg2.Close() defer dimg.Close() cimg1.Upload(src1) cimg2.Upload(src1) dest := gocv.NewMat() defer dest.Close() Multiply(cimg1, cimg2, &dimg) dimg.Download(&dest) if dest.Empty() || src1.Rows() != dest.Rows() || src1.Cols() != dest.Cols() { t.Error("Invalid Multiply test") } } func TestMultiplyWithStream(t *testing.T) { src1 := gocv.IMRead("../images/gocvlogo.jpg", gocv.IMReadColor) if src1.Empty() { t.Error("Invalid read of Mat in Multiply test") } defer src1.Close() var cimg1, cimg2, dimg = NewGpuMat(), NewGpuMat(), NewGpuMat() var s = NewStream() defer cimg1.Close() defer cimg2.Close() defer dimg.Close() defer s.Close() cimg1.UploadWithStream(src1, s) cimg2.UploadWithStream(src1, s) dest := gocv.NewMat() defer dest.Close() MultiplyWithStream(cimg1, cimg2, &dimg, s) dimg.DownloadWithStream(&dest, s) s.WaitForCompletion() if dest.Empty() || src1.Rows() != dest.Rows() || src1.Cols() != dest.Cols() { t.Error("Invalid Multiply test") } } func TestThreshold(t *testing.T) { src := gocv.IMRead("../images/gocvlogo.jpg", gocv.IMReadColor) if src.Empty() { t.Error("Invalid read of Mat in Threshold test") } defer src.Close() var cimg, dimg = NewGpuMat(), NewGpuMat() defer cimg.Close() defer dimg.Close() cimg.Upload(src) dest := gocv.NewMat() defer dest.Close() Threshold(cimg, &dimg, 25, 255, gocv.ThresholdBinary) dimg.Download(&dest) if dest.Empty() || src.Rows() != dest.Rows() || src.Cols() != dest.Cols() { t.Error("Invalid Threshold test") } } func TestThresholdWithStream(t *testing.T) { src := gocv.IMRead("../images/gocvlogo.jpg", gocv.IMReadColor) if src.Empty() { t.Error("Invalid read of Mat in Threshold test") } defer src.Close() var cimg, dimg, s = NewGpuMat(), NewGpuMat(), NewStream() defer cimg.Close() defer dimg.Close() defer s.Close() dest := gocv.NewMat() defer dest.Close() cimg.UploadWithStream(src, s) ThresholdWithStream(cimg, &dimg, 25, 255, gocv.ThresholdBinary, s) dimg.DownloadWithStream(&dest, s) s.WaitForCompletion() if dest.Empty() || src.Rows() != dest.Rows() || src.Cols() != dest.Cols() { t.Error("Invalid Threshold test") } } func TestFlip(t *testing.T) { src := gocv.IMRead("../images/gocvlogo.jpg", gocv.IMReadColor) if src.Empty() { t.Error("Invalid read of Mat in Flip test") } defer src.Close() var cimg, dimg = NewGpuMat(), NewGpuMat() defer cimg.Close() defer dimg.Close() cimg.Upload(src) dest := gocv.NewMat() defer dest.Close() Flip(cimg, &dimg, 0) dimg.Download(&dest) if dest.Empty() || src.Rows() != dest.Rows() || src.Cols() != dest.Cols() { t.Error("Invalid Flip test") } } func TestFlipWithStream(t *testing.T) { src := gocv.IMRead("../images/gocvlogo.jpg", gocv.IMReadColor) if src.Empty() { t.Error("Invalid read of Mat in Flip test") } defer src.Close() var cimg, dimg, s = NewGpuMat(), NewGpuMat(), NewStream() defer cimg.Close() defer dimg.Close() defer s.Close() dest := gocv.NewMat() defer dest.Close() cimg.UploadWithStream(src, s) FlipWithStream(cimg, &dimg, 0, s) dimg.DownloadWithStream(&dest, s) s.WaitForCompletion() if dest.Empty() || src.Rows() != dest.Rows() || src.Cols() != dest.Cols() { t.Error("Invalid Flip test") } } func TestMerge(t *testing.T) { src := NewGpuMatWithSize(101, 102, gocv.MatTypeCV8U) defer src.Close() src2 := NewGpuMatWithSize(101, 102, gocv.MatTypeCV8U) defer src2.Close() src3 := NewGpuMatWithSize(101, 102, gocv.MatTypeCV8U) defer src3.Close() dstGPU := NewGpuMat() defer dstGPU.Close() Merge([]GpuMat{src, src2, src3}, &dstGPU) if dstGPU.Empty() { t.Error("TestMerge dst should not be empty.") } } func TestMergeWithStream(t *testing.T) { src := NewGpuMatWithSize(101, 102, gocv.MatTypeCV8U) defer src.Close() src2 := NewGpuMatWithSize(101, 102, gocv.MatTypeCV8U) defer src2.Close() src3 := NewGpuMatWithSize(101, 102, gocv.MatTypeCV8U) defer src3.Close() s := NewStream() defer s.Close() dstGPU := NewGpuMat() defer dstGPU.Close() MergeWithStream([]GpuMat{src, src2, src3}, &dstGPU, s) s.WaitForCompletion() if dstGPU.Empty() { t.Error("TestMergeWithStream dst should not be empty.") } } func TestTranspose(t *testing.T) { src := gocv.IMRead("../images/gocvlogo.jpg", gocv.IMReadGrayScale) if src.Empty() { t.Error("Invalid read of Mat in Transpose test") } defer src.Close() var cimg, dimg = NewGpuMat(), NewGpuMat() defer cimg.Close() defer dimg.Close() cimg.Upload(src) dest := gocv.NewMat() defer dest.Close() Transpose(cimg, &dimg) dimg.Download(&dest) if dest.Empty() || src.Rows() != dest.Cols() || src.Cols() != dest.Rows() { t.Error("Invalid Transpose test") } } func TestTransposeWithStream(t *testing.T) { src := gocv.IMRead("../images/gocvlogo.jpg", gocv.IMReadGrayScale) if src.Empty() { t.Error("Invalid read of Mat in TransposeWithStream test") } defer src.Close() var cimg, dimg, s = NewGpuMat(), NewGpuMat(), NewStream() defer cimg.Close() defer dimg.Close() defer s.Close() cimg.Upload(src) dest := gocv.NewMat() defer dest.Close() TransposeWithStream(cimg, &dimg, s) dimg.DownloadWithStream(&dest, s) s.WaitForCompletion() if dest.Empty() || src.Rows() != dest.Cols() || src.Cols() != dest.Rows() { t.Error("Invalid TransposeWithStream test") } } func TestAddWeighted(t *testing.T) { src1 := gocv.IMRead("../images/gocvlogo.jpg", gocv.IMReadGrayScale) if src1.Empty() { t.Error("Invalid read of Mat in AddWeighted test") } defer src1.Close() src2 := gocv.IMRead("../images/gocvlogo.jpg", gocv.IMReadGrayScale) if src2.Empty() { t.Error("Invalid read of Mat in AddWeighted test") } defer src2.Close() var cimg1, cimg2, dimg = NewGpuMat(), NewGpuMat(), NewGpuMat() defer cimg1.Close() defer cimg2.Close() defer dimg.Close() cimg1.Upload(src1) cimg2.Upload(src2) dest := gocv.NewMat() defer dest.Close() alpha, beta, gamma := 0.5, 0.5, 0.0 AddWeighted(cimg1, alpha, cimg2, beta, gamma, &dimg, -1) dimg.Download(&dest) if dest.Empty() { t.Error("Invalid AddWeighted test") } } func TestAddWeightedWithStream(t *testing.T) { src1 := gocv.IMRead("../images/gocvlogo.jpg", gocv.IMReadGrayScale) if src1.Empty() { t.Error("Invalid read of Mat in AddWeighted test") } defer src1.Close() src2 := gocv.IMRead("../images/gocvlogo.jpg", gocv.IMReadGrayScale) if src2.Empty() { t.Error("Invalid read of Mat in AddWeighted test") } defer src2.Close() var cimg1, cimg2, dimg, s = NewGpuMat(), NewGpuMat(), NewGpuMat(), NewStream() defer cimg1.Close() defer cimg2.Close() defer dimg.Close() defer s.Close() cimg1.UploadWithStream(src1, s) cimg2.UploadWithStream(src2, s) dest := gocv.NewMat() defer dest.Close() alpha, beta, gamma := 0.5, 0.5, 0.0 AddWeightedWithStream(cimg1, alpha, cimg2, beta, gamma, &dimg, -1, s) dimg.DownloadWithStream(&dest, s) s.WaitForCompletion() if dest.Empty() { t.Error("Invalid AddWeightedWithStream test") } } func TestCopyMakeBorder(t *testing.T) { src := gocv.IMRead("../images/gocvlogo.jpg", gocv.IMReadGrayScale) if src.Empty() { t.Error("Invalid read of Mat in CopyMakeBorder test") } defer src.Close() var cimg, dimg = NewGpuMat(), NewGpuMat() defer cimg.Close() defer dimg.Close() cimg.Upload(src) dest := gocv.NewMat() defer dest.Close() CopyMakeBorder(cimg, &dimg, 10, 10, 10, 10, gocv.BorderReflect, gocv.NewScalar(0, 0, 0, 0)) dimg.Download(&dest) if dest.Empty() { t.Error("Invalid CopyMakeBorder test") } } func TestCopyMakeBorderWithStream(t *testing.T) { src := gocv.IMRead("../images/gocvlogo.jpg", gocv.IMReadGrayScale) if src.Empty() { t.Error("Invalid read of Mat in CopyMakeBorder test") } defer src.Close() var cimg, dimg, s = NewGpuMat(), NewGpuMat(), NewStream() defer cimg.Close() defer dimg.Close() defer s.Close() cimg.UploadWithStream(src, s) dest := gocv.NewMat() defer dest.Close() CopyMakeBorderWithStream(cimg, &dimg, 10, 10, 10, 10, gocv.BorderReflect, gocv.NewScalar(0, 0, 0, 0), s) dimg.DownloadWithStream(&dest, s) s.WaitForCompletion() if dest.Empty() { t.Error("Invalid CopyMakeBorderWithStream test") } } func TestNewLookUpTable(t *testing.T) { m := NewGpuMatWithSize(1, 256, gocv.MatTypeCV8U) defer m.Close() lt := NewLookUpTable(m) defer lt.Close() } func TestLookUpTableEmpty(t *testing.T) { m := NewGpuMatWithSize(1, 256, gocv.MatTypeCV8U) defer m.Close() lt := NewLookUpTable(m) defer lt.Close() lt.Empty() } func TestTransform(t *testing.T) { src := NewGpuMatWithSize(256, 256, gocv.MatTypeCV8UC3) defer src.Close() dst := NewGpuMatWithSize(256, 256, gocv.MatTypeCV8UC3) defer dst.Close() m := NewGpuMatWithSize(1, 256, gocv.MatTypeCV8U) defer m.Close() lt := NewLookUpTable(m) defer lt.Close() lt.Transform(src, &dst) } func TestTransformWithStream(t *testing.T) { src := NewGpuMatWithSize(256, 256, gocv.MatTypeCV8UC3) defer src.Close() dst := NewGpuMatWithSize(256, 256, gocv.MatTypeCV8UC3) defer dst.Close() m := NewGpuMatWithSize(1, 256, gocv.MatTypeCV8U) defer m.Close() lt := NewLookUpTable(m) defer lt.Close() s := NewStream() defer s.Close() lt.TransformWithStream(src, &dst, s) s.WaitForCompletion() } func TestSplit(t *testing.T) { m := NewGpuMatWithSize(256, 256, gocv.MatTypeCV8UC2) defer m.Close() m0 := NewGpuMatWithSize(256, 256, gocv.MatTypeCV8UC1) defer m0.Close() m1 := NewGpuMatWithSize(256, 256, gocv.MatTypeCV8UC1) defer m1.Close() mats := []GpuMat{m0, m1} Split(m, mats) } func TestSplitWithStream(t *testing.T) { m := NewGpuMatWithSize(256, 256, gocv.MatTypeCV8UC2) defer m.Close() m0 := NewGpuMatWithSize(256, 256, gocv.MatTypeCV8UC1) defer m0.Close() m1 := NewGpuMatWithSize(256, 256, gocv.MatTypeCV8UC1) defer m1.Close() mats := []GpuMat{m0, m1} s := NewStream() defer s.Close() SplitWithStream(m, mats, s) s.WaitForCompletion() } func TestCalcNorm(t *testing.T) { src := gocv.IMRead("../images/chessboard_4x6_distort_correct.png", gocv.IMReadGrayScale) if src.Empty() { t.Error("Invalid read of Mat in CalcNorm test") } defer src.Close() var cimg, dimg = NewGpuMat(), NewGpuMat() defer cimg.Close() defer dimg.Close() dest := gocv.NewMat() defer dest.Close() cimg.Upload(src) CalcNorm(cimg, dimg, gocv.NormL2) dimg.Download(&dest) if dest.Empty() { t.Error("Invalid CalcNorm test") } } func TestCalcNormWithStream(t *testing.T) { src := gocv.IMRead("../images/chessboard_4x6_distort_correct.png", gocv.IMReadGrayScale) if src.Empty() { t.Error("Invalid read of Mat in CalcNorm test") } defer src.Close() var cimg, dimg, s = NewGpuMat(), NewGpuMat(), NewStream() defer cimg.Close() defer dimg.Close() defer s.Close() dest := gocv.NewMat() defer dest.Close() cimg.UploadWithStream(src, s) CalcNormWithStream(cimg, dimg, gocv.NormL2, s) dimg.DownloadWithStream(&dest, s) s.WaitForCompletion() if dest.Empty() { t.Error("Invalid CalcNormWithStream test") } } func TestCalcNormDiff(t *testing.T) { src1 := gocv.IMRead("../images/chessboard_4x6_distort_correct.png", gocv.IMReadGrayScale) if src1.Empty() { t.Error("Invalid read of Mat in CalcNormDiff test") } defer src1.Close() src2 := gocv.IMRead("../images/chessboard_4x6_distort.png", gocv.IMReadGrayScale) if src2.Empty() { t.Error("Invalid read of Mat in CalcNormDiff test") } defer src2.Close() var cimg1, cimg2, dimg = NewGpuMat(), NewGpuMat(), NewGpuMat() defer cimg1.Close() defer cimg2.Close() defer dimg.Close() dest := gocv.NewMat() defer dest.Close() cimg1.Upload(src1) cimg2.Upload(src2) CalcNormDiff(cimg1, cimg2, dimg, gocv.NormL2) dimg.Download(&dest) if dest.Empty() { t.Error("Invalid CalcNormDiff test") } } func TestCalcNormDiffWithStream(t *testing.T) { src1 := gocv.IMRead("../images/chessboard_4x6_distort_correct.png", gocv.IMReadGrayScale) if src1.Empty() { t.Error("Invalid read of Mat in CalcNormDiff test") } defer src1.Close() src2 := gocv.IMRead("../images/chessboard_4x6_distort.png", gocv.IMReadGrayScale) if src2.Empty() { t.Error("Invalid read of Mat in CalcNormDiff test") } defer src2.Close() var cimg1, cimg2, dimg, s = NewGpuMat(), NewGpuMat(), NewGpuMat(), NewStream() defer cimg1.Close() defer cimg2.Close() defer dimg.Close() defer s.Close() dest := gocv.NewMat() defer dest.Close() cimg1.UploadWithStream(src1, s) cimg2.UploadWithStream(src2, s) CalcNormDiffWithStream(cimg1, cimg2, dimg, gocv.NormL2, s) dimg.DownloadWithStream(&dest, s) s.WaitForCompletion() if dest.Empty() { t.Error("Invalid CalcNormWithStream test") } } func TestNorm(t *testing.T) { src1 := gocv.IMRead("../images/chessboard_4x6_distort_correct.png", gocv.IMReadGrayScale) if src1.Empty() { t.Error("Invalid read of Mat in Norm test") } defer src1.Close() src2 := gocv.IMRead("../images/chessboard_4x6_distort.png", gocv.IMReadGrayScale) if src2.Empty() { t.Error("Invalid read of Mat in Norm test") } defer src2.Close() var cimg1, cimg2 = NewGpuMat(), NewGpuMat() defer cimg1.Close() defer cimg2.Close() cimg1.Upload(src1) cimg2.Upload(src2) result := Norm(cimg1, cimg2, gocv.NormL2) if result == 0 { t.Error("Invalid Norm test") } } func TestCompareDiff(t *testing.T) { src1 := gocv.IMRead("../images/chessboard_4x6_distort_correct.png", gocv.IMReadGrayScale) if src1.Empty() { t.Error("Invalid read of Mat in Compare test") } defer src1.Close() src2 := gocv.IMRead("../images/chessboard_4x6_distort.png", gocv.IMReadGrayScale) if src2.Empty() { t.Error("Invalid read of Mat in Compare test") } defer src2.Close() var cimg1, cimg2, dimg = NewGpuMat(), NewGpuMat(), NewGpuMat() defer cimg1.Close() defer cimg2.Close() defer dimg.Close() dest := gocv.NewMat() defer dest.Close() cimg1.Upload(src1) cimg2.Upload(src2) Compare(cimg1, cimg2, dimg, gocv.CompareNE) dimg.Download(&dest) if dest.Empty() { t.Error("Invalid CalcNormDiff test") } } func TestLShift(t *testing.T) { src := gocv.IMRead("../images/gocvlogo.jpg", gocv.IMReadGrayScale) if src.Empty() { t.Error("Invalid read of Mat in LShift test") } defer src.Close() cimg := NewGpuMat() defer cimg.Close() cimg.Upload(src) dst := NewGpuMat() defer dst.Close() err := LShift(cimg, gocv.NewScalar(128, 128, 128, 128), &dst) if err != nil { t.Errorf("LShift error: %v", err) } if dst.Empty() { t.Error("LShift result should not be empty") } } func TestLShiftWithStream(t *testing.T) { src := gocv.IMRead("../images/gocvlogo.jpg", gocv.IMReadGrayScale) if src.Empty() { t.Error("Invalid read of Mat in LShiftWithStream test") } defer src.Close() cimg := NewGpuMat() defer cimg.Close() cimg.Upload(src) dst := NewGpuMat() defer dst.Close() s := NewStream() defer s.Close() err := LShiftWithStream(cimg, gocv.NewScalar(128, 128, 128, 128), &dst, s) if err != nil { t.Errorf("LShiftWithStream error: %v", err) } s.WaitForCompletion() if dst.Empty() { t.Error("LShiftWithStream result should not be empty") } } func TestRShift(t *testing.T) { src := gocv.IMRead("../images/gocvlogo.jpg", gocv.IMReadGrayScale) if src.Empty() { t.Error("Invalid read of Mat in RShift test") } defer src.Close() cimg := NewGpuMat() defer cimg.Close() cimg.Upload(src) dst := NewGpuMat() defer dst.Close() err := RShift(cimg, gocv.NewScalar(2, 2, 2, 2), &dst) if err != nil { t.Errorf("RShift error: %v", err) } if dst.Empty() { t.Error("RShift result should not be empty") } } func TestRShiftWithStream(t *testing.T) { src := gocv.IMRead("../images/gocvlogo.jpg", gocv.IMReadGrayScale) if src.Empty() { t.Error("Invalid read of Mat in RShiftWithStream test") } defer src.Close() cimg := NewGpuMat() defer cimg.Close() cimg.Upload(src) dst := NewGpuMat() defer dst.Close() s := NewStream() defer s.Close() err := RShiftWithStream(cimg, gocv.NewScalar(2, 2, 2, 2), &dst, s) if err != nil { t.Errorf("RShiftWithStream error: %v", err) } s.WaitForCompletion() if dst.Empty() { t.Error("RShiftWithStream result should not be empty") } } func TestAbsSum(t *testing.T) { src := gocv.IMRead("../images/gocvlogo.jpg", gocv.IMReadColor) if src.Empty() { t.Error("Invalid read of Mat in AbsSum test") } defer src.Close() cimg := NewGpuMat() defer cimg.Close() cimg.Upload(src) sum, err := AbsSum(cimg) if err != nil { t.Errorf("AbsSum error: %v", err) } if sum.Val1 == 0 && sum.Val2 == 0 && sum.Val3 == 0 && sum.Val4 == 0 { t.Error("AbsSum result should not be all zeros") } } func TestCalcAbsSum(t *testing.T) { src := gocv.IMRead("../images/gocvlogo.jpg", gocv.IMReadColor) if src.Empty() { t.Error("Invalid read of Mat in CalcAbsSum test") } defer src.Close() cimg := NewGpuMat() defer cimg.Close() cimg.Upload(src) dst := NewGpuMat() defer dst.Close() err := CalcAbsSum(cimg, &dst) if err != nil { t.Errorf("CalcAbsSum error: %v", err) } if dst.Empty() { t.Error("CalcAbsSum result should not be empty") } } func TestMinMax(t *testing.T) { src := gocv.IMRead("../images/gocvlogo.jpg", gocv.IMReadGrayScale) if src.Empty() { t.Error("Invalid read of Mat in MinMax test") } defer src.Close() cimg := NewGpuMat() defer cimg.Close() cimg.Upload(src) minVal, maxVal, err := MinMax(cimg) if err != nil { t.Errorf("MinMax error: %v", err) } if minVal >= maxVal { t.Errorf("MinMax result invalid: min=%v max=%v", minVal, maxVal) } } func TestMinMaxLoc(t *testing.T) { src := gocv.IMRead("../images/gocvlogo.jpg", gocv.IMReadGrayScale) if src.Empty() { t.Error("Invalid read of Mat in MinMaxLoc test") } defer src.Close() cimg := NewGpuMat() defer cimg.Close() cimg.Upload(src) minVal, maxVal, minLoc, maxLoc, err := MinMaxLoc(cimg) if err != nil { t.Errorf("MinMaxLoc error: %v", err) } if minVal >= maxVal { t.Errorf("MinMaxLoc result invalid: min=%v max=%v", minVal, maxVal) } if minLoc == maxLoc { t.Errorf("MinMaxLoc locations should not be equal: minLoc=%v maxLoc=%v", minLoc, maxLoc) } } func TestNormalize(t *testing.T) { src := gocv.IMRead("../images/gocvlogo.jpg", gocv.IMReadGrayScale) if src.Empty() { t.Error("Invalid read of Mat in Normalize test") } defer src.Close() cimg := NewGpuMat() defer cimg.Close() cimg.Upload(src) dst := NewGpuMat() defer dst.Close() err := Normalize(cimg, &dst, 0, 255, gocv.NormMinMax, -1) if err != nil { t.Errorf("Normalize error: %v", err) } if dst.Empty() { t.Error("Normalize result should not be empty") } } func TestFindMinMaxLoc(t *testing.T) { src := gocv.IMRead("../images/gocvlogo.jpg", gocv.IMReadGrayScale) if src.Empty() { t.Error("Invalid read of Mat in FindMinMaxLoc test") } defer src.Close() cimg := NewGpuMat() defer cimg.Close() cimg.Upload(src) minMaxVals := NewGpuMat() defer minMaxVals.Close() loc := NewGpuMat() defer loc.Close() err := FindMinMaxLoc(cimg, &minMaxVals, &loc) if err != nil { t.Errorf("FindMinMaxLoc error: %v", err) } if minMaxVals.Empty() || loc.Empty() { t.Error("FindMinMaxLoc result should not be empty") } } func TestFindMinMax(t *testing.T) { src := gocv.IMRead("../images/gocvlogo.jpg", gocv.IMReadGrayScale) if src.Empty() { t.Error("Invalid read of Mat in FindMinMax test") } defer src.Close() cimg := NewGpuMat() defer cimg.Close() cimg.Upload(src) dst := NewGpuMat() defer dst.Close() err := FindMinMax(cimg, &dst) if err != nil { t.Errorf("FindMinMax error: %v", err) } if dst.Empty() { t.Error("FindMinMax result should not be empty") } } ================================================ FILE: cuda/bgsegm.cpp ================================================ //go:build !gocv_specific_modules || (gocv_specific_modules && gocv_cuda_bgsegm) #include "bgsegm.h" CudaBackgroundSubtractorMOG2 CudaBackgroundSubtractorMOG2_Create() { try { return new cv::Ptr(cv::cuda::createBackgroundSubtractorMOG2()); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } void CudaBackgroundSubtractorMOG2_Close(CudaBackgroundSubtractorMOG2 b) { delete b; } OpenCVResult CudaBackgroundSubtractorMOG2_Apply(CudaBackgroundSubtractorMOG2 b, GpuMat src, GpuMat dst, Stream s) { try { if (s == NULL) { (*b)->apply(*src, *dst); } else { (*b)->apply(*src, *dst, -1.0, *s); } return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } CudaBackgroundSubtractorMOG CudaBackgroundSubtractorMOG_Create() { try { return new cv::Ptr(cv::cuda::createBackgroundSubtractorMOG()); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } void CudaBackgroundSubtractorMOG_Close(CudaBackgroundSubtractorMOG b) { delete b; } OpenCVResult CudaBackgroundSubtractorMOG_Apply(CudaBackgroundSubtractorMOG b, GpuMat src, GpuMat dst, Stream s) { try { if (s == NULL) { (*b)->apply(*src, *dst); } else { (*b)->apply(*src, *dst, -1.0, *s); } return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } ================================================ FILE: cuda/bgsegm.go ================================================ //go:build !gocv_specific_modules || (gocv_specific_modules && gocv_cuda_bgsegm) package cuda /* #include #include "bgsegm.h" */ import "C" import "unsafe" // BackgroundSubtractorMOG2 is a wrapper around the cv::cuda::BackgroundSubtractorMOG2. type BackgroundSubtractorMOG2 struct { // C.BackgroundSubtractorMOG2 p unsafe.Pointer } // BackgroundSubtractorMOG is a wrapper around the cv::cuda::BackgroundSubtractorMOG. type BackgroundSubtractorMOG struct { // C.BackgroundSubtractorMOG p unsafe.Pointer } // NewBackgroundSubtractorMOG2 returns a new BackgroundSubtractor algorithm // of type MOG2. MOG2 is a Gaussian Mixture-based Background/Foreground // Segmentation Algorithm. // // For further details, please see: // https://docs.opencv.org/master/dc/d3d/cudabgsegm_8hpp.html func NewBackgroundSubtractorMOG2() BackgroundSubtractorMOG2 { return BackgroundSubtractorMOG2{p: unsafe.Pointer(C.CudaBackgroundSubtractorMOG2_Create())} } // Close BackgroundSubtractorMOG2. func (b *BackgroundSubtractorMOG2) Close() error { C.CudaBackgroundSubtractorMOG2_Close((C.CudaBackgroundSubtractorMOG2)(b.p)) b.p = nil return nil } // Apply computes a foreground mask using the current BackgroundSubtractorMOG2. // // For further details, please see: // https://docs.opencv.org/master/df/d23/classcv_1_1cuda_1_1BackgroundSubtractorMOG2.html#a92408f07bf1268c1b778cb186b3113b0 func (b *BackgroundSubtractorMOG2) Apply(src GpuMat, dst *GpuMat) error { return OpenCVResult(C.CudaBackgroundSubtractorMOG2_Apply((C.CudaBackgroundSubtractorMOG2)(b.p), src.p, dst.p, nil)) } // ApplyWithStream computes a foreground mask using the current BackgroundSubtractorMOG2 // using a Stream for concurrency. // // For further details, please see: // https://docs.opencv.org/master/df/d23/classcv_1_1cuda_1_1BackgroundSubtractorMOG2.html#a92408f07bf1268c1b778cb186b3113b0 func (b *BackgroundSubtractorMOG2) ApplyWithStream(src GpuMat, dst *GpuMat, s Stream) error { return OpenCVResult(C.CudaBackgroundSubtractorMOG2_Apply((C.CudaBackgroundSubtractorMOG2)(b.p), src.p, dst.p, s.p)) } // NewBackgroundSubtractorMOG returns a new BackgroundSubtractor algorithm // of type MOG. MOG is a Gaussian Mixture-based Background/Foreground // Segmentation Algorithm. // // For further details, please see: // https://docs.opencv.org/master/dc/d3d/cudabgsegm_8hpp.html func NewBackgroundSubtractorMOG() BackgroundSubtractorMOG { return BackgroundSubtractorMOG{p: unsafe.Pointer(C.CudaBackgroundSubtractorMOG_Create())} } // Close BackgroundSubtractorMOG. func (b *BackgroundSubtractorMOG) Close() error { C.CudaBackgroundSubtractorMOG_Close((C.CudaBackgroundSubtractorMOG)(b.p)) b.p = nil return nil } // Apply computes a foreground mask using the current BackgroundSubtractorMOG. // // For further details, please see: // https://docs.opencv.org/master/d1/dfe/classcv_1_1cuda_1_1BackgroundSubtractorMOG.html#a8f52d2f7abd1c77c84243efc53972cbf func (b *BackgroundSubtractorMOG) Apply(src GpuMat, dst *GpuMat) error { return OpenCVResult(C.CudaBackgroundSubtractorMOG_Apply((C.CudaBackgroundSubtractorMOG)(b.p), src.p, dst.p, nil)) } // ApplyWithStream computes a foreground mask using the current BackgroundSubtractorMOG // using a Stream for concurrency. // // For further details, please see: // https://docs.opencv.org/master/d1/dfe/classcv_1_1cuda_1_1BackgroundSubtractorMOG.html#a8f52d2f7abd1c77c84243efc53972cbf func (b *BackgroundSubtractorMOG) ApplyWithStream(src GpuMat, dst *GpuMat, s Stream) error { return OpenCVResult(C.CudaBackgroundSubtractorMOG_Apply((C.CudaBackgroundSubtractorMOG)(b.p), src.p, dst.p, s.p)) } ================================================ FILE: cuda/bgsegm.h ================================================ #ifndef _OPENCV3_CUDABGSEGM_H_ #define _OPENCV3_CUDABGSEGM_H_ #ifdef __cplusplus #include #include extern "C" { #endif #include "../core.h" #include "cuda.h" #ifdef __cplusplus typedef cv::Ptr* CudaBackgroundSubtractorMOG2; typedef cv::Ptr* CudaBackgroundSubtractorMOG; #else typedef void* CudaBackgroundSubtractorMOG2; typedef void* CudaBackgroundSubtractorMOG; #endif CudaBackgroundSubtractorMOG2 CudaBackgroundSubtractorMOG2_Create(); void CudaBackgroundSubtractorMOG2_Close(CudaBackgroundSubtractorMOG2 b); OpenCVResult CudaBackgroundSubtractorMOG2_Apply(CudaBackgroundSubtractorMOG2 b, GpuMat src, GpuMat dst, Stream s); CudaBackgroundSubtractorMOG CudaBackgroundSubtractorMOG_Create(); void CudaBackgroundSubtractorMOG_Close(CudaBackgroundSubtractorMOG b); OpenCVResult CudaBackgroundSubtractorMOG_Apply(CudaBackgroundSubtractorMOG b, GpuMat src, GpuMat dst, Stream s); #ifdef __cplusplus } #endif #endif //_OPENCV3_CUDABGSEGM_H_ ================================================ FILE: cuda/bgsegm_test.go ================================================ //go:build !gocv_specific_modules || (gocv_specific_modules && gocv_cuda_bgsegm) package cuda import ( "testing" "gocv.io/x/gocv" ) func TestCudaMOG2(t *testing.T) { img := gocv.IMRead("../images/face.jpg", gocv.IMReadColor) if img.Empty() { t.Error("Invalid Mat in CudaMOG2 test") } defer img.Close() var cimg, dimg = NewGpuMat(), NewGpuMat() defer cimg.Close() defer dimg.Close() cimg.Upload(img) dst := gocv.NewMat() defer dst.Close() mog2 := NewBackgroundSubtractorMOG2() defer mog2.Close() mog2.Apply(cimg, &dimg) dimg.Download(&dst) if dst.Empty() { t.Error("Error in TestCudaMOG2 test") } } func TestCudaMOG2WithStream(t *testing.T) { img := gocv.IMRead("../images/face.jpg", gocv.IMReadColor) if img.Empty() { t.Error("Invalid Mat in CudaMOG2 test") } defer img.Close() var cimg, dimg, s = NewGpuMat(), NewGpuMat(), NewStream() defer cimg.Close() defer dimg.Close() defer s.Close() dst := gocv.NewMat() defer dst.Close() mog2 := NewBackgroundSubtractorMOG2() defer mog2.Close() cimg.UploadWithStream(img, s) mog2.ApplyWithStream(cimg, &dimg, s) dimg.DownloadWithStream(&dst, s) s.WaitForCompletion() if dst.Empty() { t.Error("Error in TestCudaMOG2 test") } } func TestCudaMOG(t *testing.T) { img := gocv.IMRead("../images/face.jpg", gocv.IMReadColor) if img.Empty() { t.Error("Invalid Mat in CudaMOG test") } defer img.Close() var cimg, dimg = NewGpuMat(), NewGpuMat() defer cimg.Close() defer dimg.Close() cimg.Upload(img) dst := gocv.NewMat() defer dst.Close() mog2 := NewBackgroundSubtractorMOG() defer mog2.Close() mog2.Apply(cimg, &dimg) dimg.Download(&dst) if dst.Empty() { t.Error("Error in TestCudaMOG test") } } func TestCudaMOGWithStream(t *testing.T) { img := gocv.IMRead("../images/face.jpg", gocv.IMReadColor) if img.Empty() { t.Error("Invalid Mat in CudaMOG test") } defer img.Close() var cimg, dimg, s = NewGpuMat(), NewGpuMat(), NewStream() defer cimg.Close() defer dimg.Close() defer s.Close() dst := gocv.NewMat() defer dst.Close() mog2 := NewBackgroundSubtractorMOG() defer mog2.Close() cimg.UploadWithStream(img, s) mog2.ApplyWithStream(cimg, &dimg, s) dimg.DownloadWithStream(&dst, s) s.WaitForCompletion() if dst.Empty() { t.Error("Error in TestCudaMOG test") } } ================================================ FILE: cuda/cgo.go ================================================ //go:build !customenv && !opencvstatic package cuda // Changes here should be mirrored in gocv/cgo.go and contrib/cgo.go. /* #cgo !windows pkg-config: opencv4 #cgo CXXFLAGS: --std=c++11 -DNDEBUG #cgo windows CPPFLAGS: -IC:/opencv/build/install/include #cgo windows LDFLAGS: -LC:/opencv/build/install/x64/mingw/lib -lopencv_core4120 -lopencv_face4120 -lopencv_videoio4120 -lopencv_imgproc4120 -lopencv_highgui4120 -lopencv_imgcodecs4120 -lopencv_objdetect4120 -lopencv_features2d4120 -lopencv_video4120 -lopencv_dnn4120 -lopencv_xfeatures2d4120 -lopencv_plot4120 -lopencv_tracking4120 -lopencv_img_hash4120 -lopencv_calib3d4120 -lopencv_bgsegm4120 -lopencv_aruco4120 -lopencv_wechat_qrcode4120 -lopencv_ximgproc4120 -lopencv_xobjdetect4120 -lopencv_mcc4120 */ import "C" ================================================ FILE: cuda/cgo_static.go ================================================ //go:build !customenv && opencvstatic && linux package gocv // Changes here should be mirrored in contrib/cgo_static.go and cuda/cgo_static.go. /* #cgo CXXFLAGS: --std=c++11 -DNDEBUG #cgo CPPFLAGS: -I/usr/local/include -I/usr/local/include/opencv4 #cgo amd64 LDFLAGS: -O2 -g -static -L/usr/local/lib -L/usr/local/lib/opencv4/3rdparty -lopencv_gapi -lopencv_stitching -lopencv_aruco -lopencv_bgsegm -lopencv_bioinspired -lopencv_ccalib -lopencv_dnn_objdetect -lopencv_dnn_superres -lopencv_dpm -lopencv_face -lopencv_freetype -lopencv_fuzzy -lopencv_hfs -lopencv_img_hash -lopencv_intensity_transform -lopencv_line_descriptor -lopencv_mcc -lopencv_quality -lopencv_rapid -lopencv_reg -lopencv_rgbd -lopencv_saliency -lopencv_signal -lopencv_stereo -lopencv_structured_light -lopencv_phase_unwrapping -lopencv_superres -lopencv_optflow -lopencv_surface_matching -lopencv_tracking -lopencv_highgui -lopencv_datasets -lopencv_text -lopencv_plot -lopencv_videostab -lopencv_videoio -lopencv_wechat_qrcode -lopencv_xfeatures2d -lopencv_shape -lopencv_ml -lopencv_ximgproc -lopencv_video -lopencv_xobjdetect -lopencv_objdetect -lopencv_calib3d -lopencv_imgcodecs -lopencv_features2d -lopencv_dnn -lopencv_flann -lopencv_xphoto -lopencv_photo -lopencv_imgproc -lopencv_core -llibprotobuf -lade -ltbb -littnotify -llibjpeg-turbo -llibwebp -llibtiff -llibopenjp2 -lIlmImf -lquirc -lippiw -lippicv -lpng -lz -lgcc -lstdc++ -lfreetype -lharfbuzz -ldl -lm -lpthread -lrt -lavdevice -lm -latomic -lavfilter -pthread -lm -latomic -lswscale -lm -latomic -lpostproc -lm -latomic -lavformat -lm -latomic -lz -lavcodec -lvpx -lm -lvpx -lm -lvpx -lm -lvpx -lm -pthread -lm -latomic -lz -lx264 -lswresample -lm -latomic -lavutil -pthread -lm -latomic #cgo arm64 LDFLAGS: -O2 -g -static -L/usr/local/lib -L/usr/local/lib/opencv4/3rdparty -lopencv_gapi -lopencv_stitching -lopencv_aruco -lopencv_bgsegm -lopencv_bioinspired -lopencv_ccalib -lopencv_dnn_objdetect -lopencv_dnn_superres -lopencv_dpm -lopencv_face -lopencv_freetype -lopencv_fuzzy -lopencv_hfs -lopencv_img_hash -lopencv_intensity_transform -lopencv_line_descriptor -lopencv_mcc -lopencv_quality -lopencv_rapid -lopencv_reg -lopencv_rgbd -lopencv_saliency -lopencv_signal -lopencv_stereo -lopencv_structured_light -lopencv_phase_unwrapping -lopencv_superres -lopencv_optflow -lopencv_surface_matching -lopencv_tracking -lopencv_highgui -lopencv_datasets -lopencv_text -lopencv_plot -lopencv_videostab -lopencv_videoio -lopencv_wechat_qrcode -lopencv_xfeatures2d -lopencv_shape -lopencv_ml -lopencv_ximgproc -lopencv_video -lopencv_xobjdetect -lopencv_objdetect -lopencv_calib3d -lopencv_imgcodecs -lopencv_features2d -lopencv_dnn -lopencv_flann -lopencv_xphoto -lopencv_photo -lopencv_imgproc -lopencv_core -llibprotobuf -lade -ltbb -littnotify -llibjpeg-turbo -llibwebp -llibtiff -llibopenjp2 -lIlmImf -lquirc -ltegra_hal -lpng -lz -lgcc -lstdc++ -lfreetype -lharfbuzz -ldl -lm -lpthread -lrt -lavdevice -lm -latomic -lavfilter -pthread -lm -latomic -lswscale -lm -latomic -lpostproc -lm -latomic -lavformat -lm -latomic -lz -lavcodec -lvpx -lm -lvpx -lm -lvpx -lm -lvpx -lm -pthread -lm -latomic -lz -lx264 -lswresample -lm -latomic -lavutil -pthread -lm -latomic */ import "C" ================================================ FILE: cuda/cgo_static_darwin.go ================================================ //go:build !customenv && opencvstatic && darwin package gocv // Changes here should be mirrored in contrib/cgo_static_darwin.go and cuda/cgo_static_darwin.go. /* #cgo CXXFLAGS: --std=c++11 -DNDEBUG #cgo pkg-config: --static opencv4 */ import "C" ================================================ FILE: cuda/cgo_static_windows.go ================================================ //go:build !customenv && opencvstatic && windows package gocv // Changes here should be mirrored in contrib/cgo_static_windows.go and cuda/cgo_static_windows.go. /* #cgo CXXFLAGS: --std=c++11 -DNDEBUG #cgo CPPFLAGS: -IC:/opencv/build/install/include #cgo LDFLAGS: -LC:/opencv/build/install/x64/mingw/staticlib -lopencv_stereo4120 -lopencv_tracking4120 -lopencv_superres4120 -lopencv_stitching4120 -lopencv_optflow4120 -lopencv_gapi4120 -lopencv_face4120 -lopencv_dpm4120 -lopencv_dnn_objdetect4120 -lopencv_ccalib4120 -lopencv_bioinspired4120 -lopencv_bgsegm4120 -lopencv_aruco4120 -lopencv_xobjdetect4120 -lopencv_ximgproc4120 -lopencv_xfeatures2d4120 -lopencv_videostab4120 -lopencv_video4120 -lopencv_structured_light4120 -lopencv_shape4120 -lopencv_rgbd4120 -lopencv_rapid4120 -lopencv_objdetect4120 -lopencv_mcc4120 -lopencv_highgui4120 -lopencv_datasets4120 -lopencv_calib3d4120 -lopencv_videoio4120 -lopencv_text4120 -lopencv_line_descriptor4120 -lopencv_imgcodecs4120 -lopencv_img_hash4120 -lopencv_hfs4120 -lopencv_fuzzy4120 -lopencv_features2d4120 -lopencv_dnn_superres4120 -lopencv_dnn4120 -lopencv_xphoto4120 -lopencv_wechat_qrcode4120 -lopencv_surface_matching4120 -lopencv_reg4120 -lopencv_quality4120 -lopencv_plot4120 -lopencv_photo4120 -lopencv_phase_unwrapping4120 -lopencv_ml4120 -lopencv_intensity_transform4120 -lopencv_imgproc4120 -lopencv_flann4120 -lopencv_core4120 -lade -lquirc -llibprotobuf -lIlmImf -llibpng -llibopenjp2 -llibwebp -llibtiff -llibjpeg-turbo -lzlib -lkernel32 -lgdi32 -lwinspool -lshell32 -lole32 -loleaut32 -luuid -lcomdlg32 -ladvapi32 -luser32 */ import "C" ================================================ FILE: cuda/core.cpp ================================================ #include "../core.h" #include "core.h" #include void GpuRects_Close(struct Rects rs) { delete[] rs.rects; } ================================================ FILE: cuda/core.go ================================================ package cuda /* #include #include "../core.h" #include "core.h" */ import "C" import ( "image" "reflect" "unsafe" ) func toRectangles(ret C.Rects) []image.Rectangle { cArray := ret.rects length := int(ret.length) hdr := reflect.SliceHeader{ Data: uintptr(unsafe.Pointer(cArray)), Len: length, Cap: length, } s := *(*[]C.Rect)(unsafe.Pointer(&hdr)) rects := make([]image.Rectangle, length) for i, r := range s { rects[i] = image.Rect(int(r.x), int(r.y), int(r.x+r.width), int(r.y+r.height)) } return rects } ================================================ FILE: cuda/core.h ================================================ #ifndef _OPENCV3_CUDA_CORE_H_ #define _OPENCV3_CUDA_CORE_H_ #include #include #ifdef __cplusplus #include extern "C" { #endif void GpuRects_Close(struct Rects rs); #ifdef __cplusplus } #endif #endif //_OPENCV3_CUDA_CORE_H_ ================================================ FILE: cuda/cuda.cpp ================================================ #include "cuda.h" GpuMat GpuMat_New() { try { return new cv::cuda::GpuMat(); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } GpuMat GpuMat_NewFromMat(Mat mat) { try { return new cv::cuda::GpuMat(*mat); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } GpuMat GpuMat_NewWithSize(int rows, int cols, int type) { try { return new cv::cuda::GpuMat(rows, cols, type); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } void GpuMat_Upload(GpuMat m, Mat data, Stream s){ try { if (s == NULL) { m->upload(*data); return; } m->upload(*data, *s); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); } } void GpuMat_Download(GpuMat m, Mat dst, Stream s){ try { if (s == NULL) { m->download(*dst); return; } m->download(*dst, *s); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); } } int GpuMat_Empty(GpuMat m){ try { return m->empty(); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return true; } } void GpuMat_Close(GpuMat m){ delete m; } void PrintCudaDeviceInfo(int device){ try { cv::cuda::printCudaDeviceInfo(device); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); } } void PrintShortCudaDeviceInfo(int device){ try { cv::cuda::printShortCudaDeviceInfo(device); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); } } int GetCudaEnabledDeviceCount(){ try { return cv::cuda::getCudaEnabledDeviceCount(); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return 0; } } int GetCudaDevice() { try { return cv::cuda::getDevice(); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return -1; } } void SetCudaDevice(int device) { try { cv::cuda::setDevice(device); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); } } void ResetCudaDevice(){ try { cv::cuda::resetDevice(); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); } } bool CudaDeviceSupports(int features) { try { return cv::cuda::deviceSupports(cv::cuda::FeatureSet(features)); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return false; } } void GpuMat_ConvertTo(GpuMat m, GpuMat dst, int type, Stream s) { try { if (s == NULL) { m->convertTo(*dst, type); return; } m->convertTo(*dst, type, *s); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); } } void GpuMat_ConvertFp16(GpuMat m, GpuMat dst) { try { cv::cuda::convertFp16(*m, *dst); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); } } void GpuMat_CopyTo(GpuMat m, GpuMat dst, Stream s) { try { if (s == NULL) { m->copyTo(*dst); return; } m->copyTo(*dst, *s); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); } } GpuMat GpuMat_Reshape(GpuMat m, int cn, int rows) { try { return new cv::cuda::GpuMat(m->reshape(cn, rows)); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } int GpuMat_Cols(GpuMat m) { return m->cols; } int GpuMat_Rows(GpuMat m) { return m->rows; } int GpuMat_Channels(GpuMat m) { return m->channels(); } int GpuMat_Type(GpuMat m) { return m->type(); } Stream Stream_New() { try { return new cv::cuda::Stream(); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } void Stream_Close(Stream s){ delete s; } bool Stream_QueryIfComplete(Stream s) { try { return s->queryIfComplete(); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return false; } } void Stream_WaitForCompletion(Stream s) { try { s->waitForCompletion(); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); } } ================================================ FILE: cuda/cuda.go ================================================ // Package cuda is the GoCV wrapper around OpenCV cuda. // // For further details, please see: // https://github.com/opencv/opencv // // import "gocv.io/x/gocv/cuda" package cuda /* #include #include "cuda.h" */ import "C" import "gocv.io/x/gocv" type FeatureSet int const ( FeatureSetCompute10 FeatureSet = 10 FeatureSetCompute11 FeatureSet = 11 FeatureSetCompute12 FeatureSet = 12 FeatureSetCompute13 FeatureSet = 13 FeatureSetCompute20 FeatureSet = 20 FeatureSetCompute21 FeatureSet = 21 FeatureSetCompute30 FeatureSet = 30 FeatureSetCompute32 FeatureSet = 32 FeatureSetCompute35 FeatureSet = 35 FeatureSetCompute50 FeatureSet = 50 FeatureSetGlobalAtomics = FeatureSetCompute11 FeatureSetSharedAtomics = FeatureSetCompute12 FeatureSetNativeDouble = FeatureSetCompute13 FeatureSetWarpShuffleFunctions = FeatureSetCompute30 FeatureSetDynamicParallelism = FeatureSetCompute35 ) // GpuMat is the GPU version of a Mat // // For further details, please see: // https://docs.opencv.org/master/d0/d60/classcv_1_1cuda_1_1GpuMat.html type GpuMat struct { p C.GpuMat } // Upload performs data upload to GpuMat (Blocking call) // // For further details, please see: // https://docs.opencv.org/master/d0/d60/classcv_1_1cuda_1_1GpuMat.html#a00ef5bfe18d14623dcf578a35e40a46b func (g *GpuMat) Upload(data gocv.Mat) { C.GpuMat_Upload(g.p, C.Mat(data.Ptr()), nil) } // UploadWithStream performs data upload to GpuMat (non-blocking call) // // For further details, please see: // https://docs.opencv.org/master/d0/d60/classcv_1_1cuda_1_1GpuMat.html#a00ef5bfe18d14623dcf578a35e40a46b func (g *GpuMat) UploadWithStream(data gocv.Mat, s Stream) { C.GpuMat_Upload(g.p, C.Mat(data.Ptr()), s.p) } // Download performs data download from GpuMat (Blocking call) // // For further details, please see: // https://docs.opencv.org/master/d0/d60/classcv_1_1cuda_1_1GpuMat.html#a027e74e4364ddfd9687b58aa5db8d4e8 func (g *GpuMat) Download(dst *gocv.Mat) { C.GpuMat_Download(g.p, C.Mat(dst.Ptr()), nil) } // DownloadWithStream performs data download from GpuMat (non-blocking call) // // For further details, please see: // https://docs.opencv.org/master/d0/d60/classcv_1_1cuda_1_1GpuMat.html#a027e74e4364ddfd9687b58aa5db8d4e8 func (g *GpuMat) DownloadWithStream(dst *gocv.Mat, s Stream) { C.GpuMat_Download(g.p, C.Mat(dst.Ptr()), s.p) } // Empty returns true if GpuMat is empty func (g *GpuMat) Empty() bool { return C.GpuMat_Empty(g.p) != 0 } // Close the GpuMat object func (g *GpuMat) Close() error { C.GpuMat_Close(g.p) g.p = nil return nil } // Closed determines if the GpuMat is closed or not. func (g *GpuMat) Closed() bool { return g.p == nil } // NewGpuMat returns a new empty GpuMat func NewGpuMat() GpuMat { return newGpuMat(C.GpuMat_New()) } // NewGpuMatFromMat returns a new GpuMat based on a Mat func NewGpuMatFromMat(mat gocv.Mat) GpuMat { return newGpuMat(C.GpuMat_NewFromMat(C.Mat(mat.Ptr()))) } // NewGpuMatWithSize returns a new GpuMat with a specific size and type. func NewGpuMatWithSize(rows int, cols int, mt gocv.MatType) GpuMat { return newGpuMat(C.GpuMat_NewWithSize(C.int(rows), C.int(cols), C.int(mt))) } func newGpuMat(p C.GpuMat) GpuMat { return GpuMat{p: p} } // PrintCudaDeviceInfo prints extensive cuda device information func PrintCudaDeviceInfo(device int) { C.PrintCudaDeviceInfo(C.int(device)) } // PrintShortCudaDeviceInfo prints a small amount of cuda device information func PrintShortCudaDeviceInfo(device int) { C.PrintShortCudaDeviceInfo(C.int(device)) } // GetCudaEnabledDeviceCount returns the number of cuda enabled devices on the // system func GetCudaEnabledDeviceCount() int { return int(C.GetCudaEnabledDeviceCount()) } // GetDevice returns the current device index. // // For further details, please see: // https://docs.opencv.org/master/d8/d40/group__cudacore__init.html#ga6ded4ed8e4fc483a9863d31f34ec9c0e func GetDevice() int { return int(C.GetCudaDevice()) } // SetDevice sets a device and initializes it for the current thread. // // For further details, please see: // https://docs.opencv.org/master/d8/d40/group__cudacore__init.html#gaefa34186b185de47851836dba537828b func SetDevice(device int) { C.SetCudaDevice(C.int(device)) } // ResetDevice explicitly destroys and cleans up all resources associated // with the current device in the current process. // // Any subsequent API call to this device will reinitialize the device. // // For further details, please see: // https://docs.opencv.org/master/d8/d40/group__cudacore__init.html#ga6153b6f461101374e655a54fc77e725e func ResetDevice() { C.ResetCudaDevice() } // DeviceSupports checks whether current device supports the given feature. // // For further details, please see: // https://docs.opencv.org/4.x/d8/d40/group__cudacore__init.html#ga170b10cc9af4aa8cce8c0afdb4b1d08c func DeviceSupports(feature FeatureSet) bool { return bool(C.CudaDeviceSupports(C.int(feature))) } // ConvertTo converts GpuMat into destination GpuMat. // // For further details, please see: // https://docs.opencv.org/master/d0/d60/classcv_1_1cuda_1_1GpuMat.html#a3a1b076e54d8a8503014e27a5440d98a func (m *GpuMat) ConvertTo(dst *GpuMat, mt gocv.MatType) { C.GpuMat_ConvertTo(m.p, dst.p, C.int(mt), nil) return } // ConvertToWithStream converts GpuMat into destination GpuMat. // // For further details, please see: // https://docs.opencv.org/master/d0/d60/classcv_1_1cuda_1_1GpuMat.html#a3a1b076e54d8a8503014e27a5440d98a func (m *GpuMat) ConvertToWithStream(dst *GpuMat, mt gocv.MatType, s Stream) { C.GpuMat_ConvertTo(m.p, dst.p, C.int(mt), s.p) return } // ConvertFp16 converts an array to half precision floating number. // // For further details, please see: // https://docs.opencv.org/4.x/d8/d40/group__cudacore__init.html#gaa1c52258763197958eb9e6681917f723 func (m *GpuMat) ConvertFp16(dst *GpuMat) { C.GpuMat_ConvertFp16(m.p, dst.p) return } // CopyTo copies GpuMat into destination GpuMat. // // For further details, please see: // https://docs.opencv.org/master/d0/d60/classcv_1_1cuda_1_1GpuMat.html#a948c562ee340c0678a44884bde1f5a3e func (m *GpuMat) CopyTo(dst *GpuMat) { C.GpuMat_CopyTo(m.p, dst.p, nil) return } // CopyToWithStream copies GpuMat into destination GpuMat. // // For further details, please see: // https://docs.opencv.org/master/d0/d60/classcv_1_1cuda_1_1GpuMat.html#a948c562ee340c0678a44884bde1f5a3e func (m *GpuMat) CopyToWithStream(dst *GpuMat, s Stream) { C.GpuMat_CopyTo(m.p, dst.p, s.p) return } // Rows returns the number of rows for this GpuMat. func (m *GpuMat) Rows() int { return int(C.GpuMat_Rows(m.p)) } // Cols returns the number of columns for this GpuMat. func (m *GpuMat) Cols() int { return int(C.GpuMat_Cols(m.p)) } // Channels returns the number of channels for this GpuMat. func (m *GpuMat) Channels() int { return int(C.GpuMat_Channels(m.p)) } // Type returns the type for this GpuMat. func (m *GpuMat) Type() gocv.MatType { return gocv.MatType(C.GpuMat_Type(m.p)) } // Ptr returns the GpuMat's underlying object pointer. func (m *GpuMat) Ptr() C.GpuMat { return m.p } // Reshape creates a new GpuMat with the same data // but with a different number of channels and/or different number of rows. // // For further details, please see: // https://docs.opencv.org/master/d0/d60/classcv_1_1cuda_1_1GpuMat.html#a408e22ed824d1ddf59f58bda895017a8 func (m *GpuMat) Reshape(cn int, rows int) GpuMat { return newGpuMat(C.GpuMat_Reshape(m.p, C.int(cn), C.int(rows))) } // Stream asynchronous stream used for CUDA operations. // // For further details, please see: // https://docs.opencv.org/master/d9/df3/classcv_1_1cuda_1_1Stream.html#aa6434e2f5f29bd81406732b39951c246 type Stream struct { p C.Stream } // NewStream returns a new empty Stream. func NewStream() Stream { return Stream{p: C.Stream_New()} } // Close the Stream. func (s *Stream) Close() error { C.Stream_Close(s.p) s.p = nil return nil } // QueryIfComplete returns true if the current stream queue is finished // // For further details, please see: // https://docs.opencv.org/master/d9/df3/classcv_1_1cuda_1_1Stream.html#a9fab618395d42fa31987506e42fab1b4 func (s *Stream) QueryIfComplete() bool { return bool(C.Stream_QueryIfComplete(s.p)) } // WaitForCompletion blocks the current CPU thread until all operations in the stream are complete. // // For further details, please see: // https://docs.opencv.org/master/d9/df3/classcv_1_1cuda_1_1Stream.html#a0e1d939503e8faad741ab584b720bca6 func (s *Stream) WaitForCompletion() { C.Stream_WaitForCompletion(s.p) } ================================================ FILE: cuda/cuda.h ================================================ #ifndef _OPENCV3_CUDA_H_ #define _OPENCV3_CUDA_H_ #ifdef __cplusplus #include #include extern "C" { #endif #include "../core.h" #ifdef __cplusplus typedef cv::cuda::GpuMat* GpuMat; typedef cv::cuda::Stream* Stream; #else typedef void* GpuMat; typedef void* Stream; #endif // Wrapper for the vector of GpuMat aka std::vector typedef struct GpuMats { GpuMat* mats; int length; } GpuMats; GpuMat GpuMat_New(); GpuMat GpuMat_NewFromMat(Mat mat); GpuMat GpuMat_NewWithSize(int rows, int cols, int type); void GpuMat_Upload(GpuMat m, Mat data, Stream s); void GpuMat_Download(GpuMat m, Mat dst, Stream s); void GpuMat_Close(GpuMat m); int GpuMat_Empty(GpuMat m); void GpuMat_ConvertTo(GpuMat m, GpuMat dst, int type, Stream s); void GpuMat_ConvertFp16(GpuMat m, GpuMat dst); void GpuMat_CopyTo(GpuMat m, GpuMat dst, Stream s); GpuMat GpuMat_Reshape(GpuMat m, int cn, int rows); int GpuMat_Cols(GpuMat m); int GpuMat_Rows(GpuMat m); int GpuMat_Channels(GpuMat m); int GpuMat_Type(GpuMat m); void PrintCudaDeviceInfo(int device); void PrintShortCudaDeviceInfo(int device); int GetCudaEnabledDeviceCount(); int GetCudaDevice(); void SetCudaDevice(int device); void ResetCudaDevice(); bool CudaDeviceSupports(int features); Stream Stream_New(); void Stream_Close(Stream s); bool Stream_QueryIfComplete(Stream s); void Stream_WaitForCompletion(Stream s); #ifdef __cplusplus } #endif #endif //_OPENCV3_CUDA_H_ ================================================ FILE: cuda/cuda_test.go ================================================ package cuda import ( "testing" "gocv.io/x/gocv" ) func TestNewGpuMat(t *testing.T) { mat := NewGpuMat() defer mat.Close() if !mat.Empty() { t.Error("New GpuMat should be empty") } } func TestGpuMatClosed(t *testing.T) { mat := NewGpuMat() mat.Close() if !mat.Closed() { t.Error("Closed GpuMat should be closed") } } func TestNewGpuMatFromMat(t *testing.T) { mat := gocv.NewMat() defer mat.Close() gpumat := NewGpuMatFromMat(mat) defer gpumat.Close() if !gpumat.Empty() { t.Error("New GpuMat should be empty") } } func TestNewGpuMatFromMatWithSize(t *testing.T) { mat := gocv.NewMatWithSize(100, 200, gocv.MatTypeCV32FC4) defer mat.Close() gpumat := NewGpuMatFromMat(mat) defer gpumat.Close() if gpumat.Empty() { t.Error("New GpuMat should be not empty") } if gpumat.Rows() != 100 { t.Error("incorrect number of rows for GpuMat") } if gpumat.Cols() != 200 { t.Error("incorrect number of cols for GpuMat") } if gpumat.Type() != gocv.MatTypeCV32FC4 { t.Error("incorrect type for GpuMat") } } func TestNewGpuMatWithSize(t *testing.T) { gpumat := NewGpuMatWithSize(100, 200, gocv.MatTypeCV32FC4) defer gpumat.Close() if gpumat.Empty() { t.Error("New GpuMat should be not empty") } if gpumat.Rows() != 100 { t.Error("incorrect number of rows for GpuMat") } if gpumat.Cols() != 200 { t.Error("incorrect number of cols for GpuMat") } if gpumat.Type() != gocv.MatTypeCV32FC4 { t.Error("incorrect type for GpuMat") } } func TestGetCudaEnabledDeviceCount(t *testing.T) { if GetCudaEnabledDeviceCount() < 1 { t.Fatal("expected atleast one cuda enabled device") } } func TestConvertFp16(t *testing.T) { gpumat := NewGpuMatWithSize(100, 200, gocv.MatTypeCV32FC4) defer gpumat.Close() fp16mat := NewGpuMatWithSize(100, 200, gocv.MatTypeCV32FC4) defer fp16mat.Close() gpumat.ConvertFp16(&fp16mat) if fp16mat.Empty() { t.Error("New fp16mat should be not empty") } if fp16mat.Rows() != 100 { t.Error("incorrect number of rows for fp16mat") } if fp16mat.Cols() != 200 { t.Error("incorrect number of cols for fp16mat") } if fp16mat.Type() != gocv.MatTypeCV16SC4 { t.Error("incorrect type for fp16mat", fp16mat.Type()) } } func TestCudaDeviceSupports(t *testing.T) { if !DeviceSupports(FeatureSetCompute10) { t.Fatal("expected FeatureSetCompute10 on cuda enabled device") } } ================================================ FILE: cuda/errors.go ================================================ package cuda /* #include "../core.h" */ import "C" import "errors" // Converts a OpenCVResult struct to an error. func OpenCVResult(result C.OpenCVResult) error { if result.Code == 0 { return nil } return errors.New(C.GoString(result.Message)) } ================================================ FILE: cuda/filters.cpp ================================================ //go:build !gocv_specific_modules || (gocv_specific_modules && gocv_cuda_filters) #include "../core.h" #include "filters.h" #include GaussianFilter CreateGaussianFilter(int srcType, int dstType, Size ksize, double sigma1) { try { cv::Size sz(ksize.width, ksize.height); return new cv::Ptr(cv::cuda::createGaussianFilter(srcType, dstType, sz, sigma1)); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } GaussianFilter CreateGaussianFilterWithParams(int srcType, int dstType, Size ksize, double sigma1, double sigma2, int rowBorderMode, int columnBorderMode) { try { cv::Size sz(ksize.width, ksize.height); return new cv::Ptr(cv::cuda::createGaussianFilter(srcType, dstType, sz, sigma1, sigma2, rowBorderMode, columnBorderMode)); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } void GaussianFilter_Close(GaussianFilter gf) { delete gf; } OpenCVResult GaussianFilter_Apply(GaussianFilter gf, GpuMat img, GpuMat dst, Stream s) { try { if (s == NULL) { (*gf)->apply(*img, *dst); } else { (*gf)->apply(*img, *dst, *s); } return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } MorphologyFilter CreateMorphologyFilter(int op, int srcType, Mat kernel) { try { return new cv::Ptr(cv::cuda::createMorphologyFilter(op, srcType, *kernel)); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } MorphologyFilter CreateMorphologyFilterWithParams(int op, int srcType, Mat kernel, Point anchor, int iterations) { try { cv::Point pt(anchor.x, anchor.y); return new cv::Ptr(cv::cuda::createMorphologyFilter(op, srcType, *kernel, pt, iterations)); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } void MorphologyFilter_Close(MorphologyFilter mf) { delete mf; } OpenCVResult MorphologyFilter_Apply(MorphologyFilter mf, GpuMat img, GpuMat dst, Stream s) { try { if (s == NULL) { (*mf)->apply(*img, *dst); } else { (*mf)->apply(*img, *dst, *s); } return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } SobelFilter CreateSobelFilter(int srcType, int dstType, int dx, int dy) { try { return new cv::Ptr(cv::cuda::createSobelFilter(srcType, dstType, dx, dy)); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } SobelFilter CreateSobelFilterWithParams(int srcType, int dstType, int dx, int dy, int ksize, double scale, int rowBorderMode, int columnBorderMode) { try { return new cv::Ptr(cv::cuda::createSobelFilter(srcType, dstType, dx, dy, ksize, rowBorderMode, columnBorderMode)); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } void SobelFilter_Close(SobelFilter sf) { delete sf; } OpenCVResult SobelFilter_Apply(SobelFilter sf, GpuMat img, GpuMat dst, Stream s) { try { if (s == NULL) { (*sf)->apply(*img, *dst); } else { (*sf)->apply(*img, *dst, *s); } return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } ================================================ FILE: cuda/filters.go ================================================ //go:build !gocv_specific_modules || (gocv_specific_modules && gocv_cuda_filters) package cuda /* #include #include "../core.h" #include "core.h" #include "filters.h" */ import "C" import ( "image" "unsafe" "gocv.io/x/gocv" ) // GaussianFilter // // For further details, please see: // https://docs.opencv.org/master/dc/d66/group__cudafilters.html#gaa4df286369114cfd4b144ae211f6a6c8 type GaussianFilter struct { p unsafe.Pointer } // NewGaussianFilter returns a new GaussianFilter. func NewGaussianFilter(srcType gocv.MatType, dstType gocv.MatType, ksize image.Point, sigma1 float64) GaussianFilter { pSize := C.struct_Size{ width: C.int(ksize.X), height: C.int(ksize.Y), } return GaussianFilter{p: unsafe.Pointer(C.CreateGaussianFilter(C.int(srcType), C.int(dstType), pSize, C.double(sigma1)))} } // Close GaussianFilter func (gf *GaussianFilter) Close() error { C.GaussianFilter_Close((C.GaussianFilter)(gf.p)) gf.p = nil return nil } // Apply applies the Gaussian filter. // // For further details, please see: // https://docs.opencv.org/master/dc/d2b/classcv_1_1cuda_1_1Filter.html#a20b58d13871027473b4c39cc698cf80f func (gf *GaussianFilter) Apply(img GpuMat, dst *GpuMat) error { return OpenCVResult(C.GaussianFilter_Apply(C.GaussianFilter(gf.p), img.p, dst.p, nil)) } // ApplyWithStream applies the Gaussian filter // using a Stream for concurrency. // // For further details, please see: // https://docs.opencv.org/master/dc/d2b/classcv_1_1cuda_1_1Filter.html#a20b58d13871027473b4c39cc698cf80f func (gf *GaussianFilter) ApplyWithStream(img GpuMat, dst *GpuMat, s Stream) error { return OpenCVResult(C.GaussianFilter_Apply(C.GaussianFilter(gf.p), img.p, dst.p, s.p)) } // MorphologyFilter // // For further details, please see: // https://docs.opencv.org/4.x/dc/d66/group__cudafilters.html#gae58694e07be6bdbae126f36c75c08ee6 type MorphologyFilter struct { p unsafe.Pointer } // NewMorphologyFilter returns a new MorphologyFilter. func NewMorphologyFilter(op gocv.MorphType, srcType gocv.MatType, kernel gocv.Mat) MorphologyFilter { return MorphologyFilter{p: unsafe.Pointer(C.CreateMorphologyFilter(C.int(op), C.int(srcType), C.Mat(kernel.Ptr())))} } // NewMorphologyFilterWithParams returns a new MorphologyFilter. func NewMorphologyFilterWithParams(op gocv.MorphType, srcType gocv.MatType, kernel gocv.Mat, anchor image.Point, iterations int) MorphologyFilter { pt := C.struct_Point{ x: C.int(anchor.X), y: C.int(anchor.Y), } return MorphologyFilter{p: unsafe.Pointer(C.CreateMorphologyFilterWithParams(C.int(op), C.int(srcType), C.Mat(kernel.Ptr()), pt, C.int(iterations)))} } // Close MorphologyFilter func (mf *MorphologyFilter) Close() error { C.MorphologyFilter_Close((C.MorphologyFilter)(mf.p)) mf.p = nil return nil } // Apply applies the Morphology filter. // // For further details, please see: // https://docs.opencv.org/master/dc/d2b/classcv_1_1cuda_1_1Filter.html#a20b58d13871027473b4c39cc698cf80f func (mf *MorphologyFilter) Apply(img GpuMat, dst *GpuMat) error { return OpenCVResult(C.MorphologyFilter_Apply(C.MorphologyFilter(mf.p), img.p, dst.p, nil)) } // ApplyWithStream applies the Morphology filter // using a Stream for concurrency. // // For further details, please see: // https://docs.opencv.org/master/dc/d2b/classcv_1_1cuda_1_1Filter.html#a20b58d13871027473b4c39cc698cf80f func (mf *MorphologyFilter) ApplyWithStream(img GpuMat, dst *GpuMat, s Stream) error { return OpenCVResult(C.MorphologyFilter_Apply(C.MorphologyFilter(mf.p), img.p, dst.p, s.p)) } // SobelFilter // // For further details, please see: // https://docs.opencv.org/master/dc/d66/group__cudafilters.html#gabf85fe61958bb21e93211a6fcc7c5c3b type SobelFilter struct { p unsafe.Pointer } // NewSobelFilter returns a new SobelFilter. func NewSobelFilter(srcType gocv.MatType, dstType gocv.MatType, dx int, dy int) SobelFilter { return SobelFilter{p: unsafe.Pointer(C.CreateSobelFilter(C.int(srcType), C.int(dstType), C.int(dx), C.int(dy)))} } // NewSobelFilterWithParams returns a new SobelFilter. func NewSobelFilterWithParams(srcType gocv.MatType, dstType gocv.MatType, dx int, dy int, ksize int, scale float64, rowBorderMode int, columnBorderMode int) SobelFilter { return SobelFilter{p: unsafe.Pointer(C.CreateSobelFilterWithParams(C.int(srcType), C.int(dstType), C.int(dx), C.int(dy), C.int(ksize), C.double(scale), C.int(rowBorderMode), C.int(columnBorderMode)))} } // Close SobelFilter func (sf *SobelFilter) Close() error { C.SobelFilter_Close((C.SobelFilter)(sf.p)) sf.p = nil return nil } // Apply applies the Sobel filter. // // For further details, please see: // https://docs.opencv.org/master/dc/d2b/classcv_1_1cuda_1_1Filter.html#a20b58d13871027473b4c39cc698cf80f func (sf *SobelFilter) Apply(img GpuMat, dst *GpuMat) error { return OpenCVResult(C.SobelFilter_Apply(C.SobelFilter(sf.p), img.p, dst.p, nil)) } // ApplyWithStream applies the Sobel filter // using a Stream for concurrency. // // For further details, please see: // https://docs.opencv.org/master/dc/d2b/classcv_1_1cuda_1_1Filter.html#a20b58d13871027473b4c39cc698cf80f func (sf *SobelFilter) ApplyWithStream(img GpuMat, dst *GpuMat, s Stream) error { return OpenCVResult(C.SobelFilter_Apply(C.SobelFilter(sf.p), img.p, dst.p, s.p)) } ================================================ FILE: cuda/filters.h ================================================ #ifndef _GOCV_CUDA_FILTERS_H_ #define _GOCV_CUDA_FILTERS_H_ #include #include #ifdef __cplusplus #include #include extern "C" { #endif #include "cuda.h" #ifdef __cplusplus typedef cv::Ptr* GaussianFilter; typedef cv::Ptr* MorphologyFilter; typedef cv::Ptr* SobelFilter; #else typedef void* GaussianFilter; typedef void* MorphologyFilter; typedef void* SobelFilter; #endif // GaussianFilter GaussianFilter CreateGaussianFilter(int srcType, int dstType, Size ksize, double sigma1); GaussianFilter CreateGaussianFilterWithParams(int srcType, int dstType, Size ksize, double sigma1, double sigma2, int rowBorderMode, int columnBorderMode); void GaussianFilter_Close(GaussianFilter gf); OpenCVResult GaussianFilter_Apply(GaussianFilter gf, GpuMat img, GpuMat dst, Stream s); // MorphologyFilter MorphologyFilter CreateMorphologyFilter(int op, int srcType, Mat kernel); MorphologyFilter CreateMorphologyFilterWithParams(int op, int srcType, Mat kernel, Point anchor, int iterations); void MorphologyFilter_Close(MorphologyFilter mf); OpenCVResult MorphologyFilter_Apply(MorphologyFilter mf, GpuMat img, GpuMat dst, Stream s); // SobelFilter SobelFilter CreateSobelFilter(int srcType, int dstType, int dx, int dy); SobelFilter CreateSobelFilterWithParams(int srcType, int dstType, int dx, int dy, int ksize, double scale, int rowBorderMode, int columnBorderMode); void SobelFilter_Close(SobelFilter sf); OpenCVResult SobelFilter_Apply(SobelFilter sf, GpuMat img, GpuMat dst, Stream s); #ifdef __cplusplus } #endif #endif //_GOCV_CUDA_FILTERS_H_ ================================================ FILE: cuda/filters_test.go ================================================ //go:build !gocv_specific_modules || (gocv_specific_modules && gocv_cuda_filters) package cuda import ( "image" "testing" "gocv.io/x/gocv" ) func TestGaussianFilter_Apply(t *testing.T) { src := gocv.IMRead("../images/face-detect.jpg", gocv.IMReadColor) if src.Empty() { t.Error("Invalid read of Mat in GaussianFilter test") } defer src.Close() cimg, dimg := NewGpuMat(), NewGpuMat() defer cimg.Close() defer dimg.Close() cimg.Upload(src) filter := NewGaussianFilter(src.Type(), src.Type(), image.Pt(23, 23), 30) defer filter.Close() filter.Apply(cimg, &dimg) dest := gocv.NewMat() defer dest.Close() dimg.Download(&dest) if dest.Empty() { t.Error("Empty GaussianFilter test") } if src.Rows() != dest.Rows() { t.Error("Invalid GaussianFilter test rows") } if src.Cols() != dest.Cols() { t.Error("Invalid GaussianFilter test cols") } } func TestGaussianFilter_ApplyWithStream(t *testing.T) { src := gocv.IMRead("../images/face-detect.jpg", gocv.IMReadColor) if src.Empty() { t.Error("Invalid read of Mat in GaussianFilter test") } defer src.Close() cimg, dimg := NewGpuMat(), NewGpuMat() defer cimg.Close() defer dimg.Close() filter := NewGaussianFilter(src.Type(), src.Type(), image.Pt(23, 23), 30) defer filter.Close() stream := NewStream() defer stream.Close() dest := gocv.NewMat() defer dest.Close() cimg.UploadWithStream(src, stream) filter.ApplyWithStream(cimg, &dimg, stream) dimg.DownloadWithStream(&dest, stream) stream.WaitForCompletion() if dest.Empty() { t.Error("Empty GaussianFilter test") } if src.Rows() != dest.Rows() { t.Error("Invalid GaussianFilter test rows") } if src.Cols() != dest.Cols() { t.Error("Invalid GaussianFilter test cols") } } func TestMorphologyFilter_Apply(t *testing.T) { src := gocv.IMRead("../images/face-detect.jpg", gocv.IMReadGrayScale) if src.Empty() { t.Error("Invalid read of Mat in MorphologyFilter test") } defer src.Close() cimg, dimg := NewGpuMat(), NewGpuMat() defer cimg.Close() defer dimg.Close() kernel := gocv.GetStructuringElement(gocv.MorphRect, image.Pt(1, 1)) defer kernel.Close() filter := NewMorphologyFilter(gocv.MorphDilate, src.Type(), kernel) defer filter.Close() dest := gocv.NewMat() defer dest.Close() cimg.Upload(src) filter.Apply(cimg, &dimg) dimg.Download(&dest) if dest.Empty() { t.Error("Empty MorphologyFilter test") } if src.Rows() != dest.Rows() { t.Error("Invalid MorphologyFilter test rows") } if src.Cols() != dest.Cols() { t.Error("Invalid MorphologyFilter test cols") } } func TestMorphologyFilter_ApplyWithStream(t *testing.T) { src := gocv.IMRead("../images/face-detect.jpg", gocv.IMReadGrayScale) if src.Empty() { t.Error("Invalid read of Mat in MorphologyFilter test") } defer src.Close() cimg, dimg := NewGpuMat(), NewGpuMat() defer cimg.Close() defer dimg.Close() kernel := gocv.GetStructuringElement(gocv.MorphRect, image.Pt(1, 1)) defer kernel.Close() filter := NewMorphologyFilter(gocv.MorphDilate, src.Type(), kernel) defer filter.Close() stream := NewStream() defer stream.Close() dest := gocv.NewMat() defer dest.Close() cimg.UploadWithStream(src, stream) filter.ApplyWithStream(cimg, &dimg, stream) dimg.DownloadWithStream(&dest, stream) stream.WaitForCompletion() if dest.Empty() { t.Error("Empty MorphologyFilter test") } if src.Rows() != dest.Rows() { t.Error("Invalid MorphologyFilter test rows") } if src.Cols() != dest.Cols() { t.Error("Invalid MorphologyFilter test cols") } } func TestSobelFilter_Apply(t *testing.T) { src := gocv.IMRead("../images/face-detect.jpg", gocv.IMReadGrayScale) if src.Empty() { t.Error("Invalid read of Mat in SobelFilter test") } defer src.Close() cimg, dimg := NewGpuMat(), NewGpuMat() defer cimg.Close() defer dimg.Close() filter := NewSobelFilter(src.Type(), src.Type(), 0, 1) defer filter.Close() dest := gocv.NewMat() defer dest.Close() cimg.Upload(src) filter.Apply(cimg, &dimg) dimg.Download(&dest) if dest.Empty() { t.Error("Empty SobelFilter test") } if src.Rows() != dest.Rows() { t.Error("Invalid SobelFilter test rows") } if src.Cols() != dest.Cols() { t.Error("Invalid SobelFilter test cols") } } func TestSobelFilter_ApplyWithStream(t *testing.T) { src := gocv.IMRead("../images/face-detect.jpg", gocv.IMReadGrayScale) if src.Empty() { t.Error("Invalid read of Mat in SobelFilter test") } defer src.Close() cimg, dimg := NewGpuMat(), NewGpuMat() defer cimg.Close() defer dimg.Close() filter := NewSobelFilter(src.Type(), src.Type(), 0, 1) defer filter.Close() stream := NewStream() defer stream.Close() dest := gocv.NewMat() defer dest.Close() cimg.UploadWithStream(src, stream) filter.ApplyWithStream(cimg, &dimg, stream) dimg.DownloadWithStream(&dest, stream) stream.WaitForCompletion() if dest.Empty() { t.Error("Empty SobelFilter test") } if src.Rows() != dest.Rows() { t.Error("Invalid SobelFilter test rows") } if src.Cols() != dest.Cols() { t.Error("Invalid SobelFilter test cols") } } ================================================ FILE: cuda/helpers_test.go ================================================ package cuda import "math" var eps = 0.00000001 func floatEquals(a, b float32) bool { if math.Abs(float64(a-b)) < eps { return true } return false } // round helper from https://stackoverflow.com/questions/39544571/golang-round-to-nearest-0-05 func round(x, unit float32) float32 { return float32(int32(x/unit+0.5)) * unit } ================================================ FILE: cuda/imgproc.cpp ================================================ #include "../core.h" #include "imgproc.h" #include OpenCVResult GpuCvtColor(GpuMat src, GpuMat dst, int code, Stream s) { try { if (s == NULL) { cv::cuda::cvtColor(*src, *dst, code); } else { cv::cuda::cvtColor(*src, *dst, code, 0, *s); } return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult GpuDemosaicing(GpuMat src, GpuMat dst, int code, Stream s) { try { if (s == NULL) { cv::cuda::demosaicing(*src, *dst, code); } else { cv::cuda::demosaicing(*src, *dst, code, -1, *s); } return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } CannyEdgeDetector CreateCannyEdgeDetector(double lowThresh, double highThresh) { try { return new cv::Ptr(cv::cuda::createCannyEdgeDetector(lowThresh, highThresh)); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } CannyEdgeDetector CreateCannyEdgeDetectorWithParams(double lowThresh, double highThresh, int appertureSize, bool L2gradient) { try { return new cv::Ptr(cv::cuda::createCannyEdgeDetector(lowThresh, highThresh, appertureSize, L2gradient)); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } void CannyEdgeDetector_Close(CannyEdgeDetector det) { delete det; } OpenCVResult CannyEdgeDetector_Detect(CannyEdgeDetector det, GpuMat img, GpuMat dst, Stream s) { try { if (s == NULL) { (*det)->detect(*img, *dst); } else { (*det)->detect(*img, *dst, *s); } return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } int CannyEdgeDetector_GetAppertureSize(CannyEdgeDetector det) { try { return int((*det)->getAppertureSize()); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return 0; } } double CannyEdgeDetector_GetHighThreshold(CannyEdgeDetector det) { try { return double((*det)->getHighThreshold()); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return 0.0; } } bool CannyEdgeDetector_GetL2Gradient(CannyEdgeDetector det) { try { return bool((*det)->getL2Gradient()); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return false; } } double CannyEdgeDetector_GetLowThreshold(CannyEdgeDetector det) { try { return double((*det)->getLowThreshold()); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return 0.0; } } void CannyEdgeDetector_SetAppertureSize(CannyEdgeDetector det, int appertureSize) { try { (*det)->setAppertureSize(appertureSize); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); } } void CannyEdgeDetector_SetHighThreshold(CannyEdgeDetector det, double highThresh) { try { (*det)->setHighThreshold(highThresh); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); } } void CannyEdgeDetector_SetL2Gradient(CannyEdgeDetector det, bool L2gradient) { try { (*det)->setL2Gradient(L2gradient); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); } } void CannyEdgeDetector_SetLowThreshold(CannyEdgeDetector det, double lowThresh) { try { (*det)->setLowThreshold(lowThresh); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); } } HoughLinesDetector HoughLinesDetector_Create(double rho, double theta, int threshold) { try { return new cv::Ptr(cv::cuda::createHoughLinesDetector(rho, theta, threshold)); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } HoughLinesDetector HoughLinesDetector_CreateWithParams(double rho, double theta, int threshold, bool sort, int maxlines) { try { return new cv::Ptr(cv::cuda::createHoughLinesDetector(rho, theta, threshold, sort, maxlines)); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } void HoughLinesDetector_Close(HoughLinesDetector hld) { delete hld; } OpenCVResult HoughLinesDetector_Detect(HoughLinesDetector hld, GpuMat img, GpuMat dst, Stream s) { try { if (s == NULL) { (*hld)->detect(*img, *dst); } else { (*hld)->detect(*img, *dst, *s); } return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } HoughSegmentDetector HoughSegmentDetector_Create(double rho, double theta, int minLineLength, int maxLineGap) { try { return new cv::Ptr(cv::cuda::createHoughSegmentDetector(rho, theta, minLineLength, maxLineGap)); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } void HoughSegmentDetector_Close(HoughSegmentDetector hsd) { delete hsd; } OpenCVResult HoughSegmentDetector_Detect(HoughSegmentDetector hsd, GpuMat img, GpuMat dst, Stream s) { try { if (s == NULL) { (*hsd)->detect(*img, *dst); } else { (*hsd)->detect(*img, *dst, *s); } return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } TemplateMatching TemplateMatching_Create(int srcType, int method) { try { return new cv::Ptr(cv::cuda::createTemplateMatching(srcType, method)); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } void TemplateMatching_Close(TemplateMatching tm) { delete tm; } OpenCVResult TemplateMatching_Match(TemplateMatching tm, GpuMat img, GpuMat tmpl, GpuMat dst, Stream s) { try { if (s == NULL) { (*tm)->match(*img, *tmpl, *dst); } else { (*tm)->match(*img, *tmpl, *dst, *s); } return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult AlphaComp(GpuMat img1, GpuMat img2, GpuMat dst, int alpha_op, Stream s) { try { if(s == NULL) { cv::cuda::alphaComp(*img1, *img2, *dst, alpha_op); } else { cv::cuda::alphaComp(*img1, *img2, *dst, alpha_op, *s); } return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult GammaCorrection(GpuMat src, GpuMat dst, bool forward, Stream s) { try { if(s == NULL) { cv::cuda::gammaCorrection(*src, *dst, forward); } else { cv::cuda::gammaCorrection(*src, *dst, forward, *s); } return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult SwapChannels(GpuMat image, int dstOrder[4], Stream s) { try { if(s == NULL) { cv::cuda::swapChannels(*image, dstOrder); } else { cv::cuda::swapChannels(*image, dstOrder, *s); } return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Cuda_CalcHist(GpuMat src, GpuMat dst, Stream s) { try { if(s == NULL) { cv::cuda::calcHist(*src, *dst); } else { cv::cuda::calcHist(*src, *dst, *s); } return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Cuda_CalcHist_WithParams(GpuMat src, GpuMat mask, GpuMat dst, Stream s) { try { if(s == NULL) { cv::cuda::calcHist(*src, *mask, *dst); } else { cv::cuda::calcHist(*src, *mask, *dst, *s); } return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Cuda_EqualizeHist(GpuMat src, GpuMat dst, Stream s) { try { if(s == NULL) { cv::cuda::equalizeHist(*src, *dst); } else { cv::cuda::equalizeHist(*src, *dst, *s); } return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Cuda_EvenLevels(GpuMat levels, int nLevels, int lowerLevel, int upperLevel, Stream s) { try { if(s == NULL) { cv::cuda::evenLevels(*levels, nLevels, lowerLevel, upperLevel); } else { cv::cuda::evenLevels(*levels, nLevels, lowerLevel, upperLevel, *s); } return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Cuda_HistEven(GpuMat src, GpuMat hist, int histSize, int lowerLevel, int upperLevel, Stream s) { try { if(s == NULL) { cv::cuda::histEven(*src, *hist, histSize, lowerLevel, upperLevel); } else { cv::cuda::histEven(*src, *hist, histSize, lowerLevel, upperLevel, *s); } return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Cuda_HistRange(GpuMat src, GpuMat hist, GpuMat levels, Stream s){ try { if(s == NULL) { cv::cuda::histRange(*src, *hist, *levels); } else { cv::cuda::histRange(*src, *hist, *levels, *s); } return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Cuda_BilateralFilter(GpuMat src, GpuMat dst, int kernel_size, float sigma_color, float sigma_spatial, int borderMode, Stream s) { try { if(s == NULL) { cv::cuda::bilateralFilter(*src, *dst, kernel_size, sigma_color, sigma_spatial, borderMode); } else { cv::cuda::bilateralFilter(*src, *dst, kernel_size, sigma_color, sigma_spatial, borderMode, *s); } return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Cuda_BlendLinear(GpuMat img1, GpuMat img2, GpuMat weights1, GpuMat weights2, GpuMat result, Stream s) { try { if(s == NULL) { cv::cuda::blendLinear(*img1, *img2, *weights1, *weights2, *result); } else { cv::cuda::blendLinear(*img1, *img2, *weights1, *weights2, *result, *s); } return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Cuda_MeanShiftFiltering(GpuMat src, GpuMat dst, int sp, int sr, TermCriteria criteria, Stream s) { try { if(s == NULL) { cv::cuda::meanShiftFiltering(*src, *dst, sp, sr, *criteria); } else { cv::cuda::meanShiftFiltering(*src, *dst, sp, sr, *criteria, *s); } return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Cuda_MeanShiftProc(GpuMat src, GpuMat dstr, GpuMat dstsp, int sp, int sr, TermCriteria criteria, Stream s) { try { if(s == NULL) { cv::cuda::meanShiftProc(*src, *dstr, *dstsp, sp, sr, *criteria); } else { cv::cuda::meanShiftProc(*src, *dstr, *dstsp, sp, sr, *criteria, *s); } return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Cuda_MeanShiftSegmentation(GpuMat src, GpuMat dst, int sp, int sr, int minSize, TermCriteria criteria, Stream s) { try { if(s == NULL) { cv::cuda::meanShiftSegmentation(*src, *dst, sp, sr, minSize, *criteria); } else { cv::cuda::meanShiftSegmentation(*src, *dst, sp, sr, minSize, *criteria, *s); } return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } ================================================ FILE: cuda/imgproc.go ================================================ package cuda /* #include #include "../core.h" #include "core.h" #include "imgproc.h" */ import "C" import ( "unsafe" "gocv.io/x/gocv" ) // CannyEdgeDetector // // For further details, please see: // https://docs.opencv.org/master/d0/d43/classcv_1_1cuda_1_1CannyEdgeDetector.html type CannyEdgeDetector struct { p unsafe.Pointer } // NewCannyEdgeDetector returns a new CannyEdgeDetector. func NewCannyEdgeDetector(lowThresh, highThresh float64) CannyEdgeDetector { return CannyEdgeDetector{p: unsafe.Pointer(C.CreateCannyEdgeDetector(C.double(lowThresh), C.double(highThresh)))} } // NewCannyEdgeDetectorWithParams returns a new CannyEdgeDetector. func NewCannyEdgeDetectorWithParams(lowThresh, highThresh float64, appertureSize int, L2gradient bool) CannyEdgeDetector { return CannyEdgeDetector{p: unsafe.Pointer(C.CreateCannyEdgeDetectorWithParams(C.double(lowThresh), C.double(highThresh), C.int(appertureSize), C.bool(L2gradient)))} } // Close CannyEdgeDetector func (h *CannyEdgeDetector) Close() error { C.CannyEdgeDetector_Close((C.CannyEdgeDetector)(h.p)) h.p = nil return nil } // Detect finds edges in an image using the Canny algorithm. // // For further details, please see: // https://docs.opencv.org/master/d0/d43/classcv_1_1cuda_1_1CannyEdgeDetector.html#a6438cf8453f2dfd6703ceb50056de309 func (h *CannyEdgeDetector) Detect(img GpuMat, dst *GpuMat) error { return OpenCVResult(C.CannyEdgeDetector_Detect(C.CannyEdgeDetector(h.p), img.p, dst.p, nil)) } // DetectWithStream finds edges in an image using the Canny algorithm // using a Stream for concurrency. // // For further details, please see: // https://docs.opencv.org/master/d0/d43/classcv_1_1cuda_1_1CannyEdgeDetector.html#a6438cf8453f2dfd6703ceb50056de309 func (h *CannyEdgeDetector) DetectWithStream(img GpuMat, dst *GpuMat, s Stream) error { return OpenCVResult(C.CannyEdgeDetector_Detect(C.CannyEdgeDetector(h.p), img.p, dst.p, s.p)) } // GetAppertureSize // // For further details, please see: // https://docs.opencv.org/master/d0/d43/classcv_1_1cuda_1_1CannyEdgeDetector.html#a19c2963ff255b0c18387594a704439d3 func (h *CannyEdgeDetector) GetAppertureSize() int { return int(C.CannyEdgeDetector_GetAppertureSize(C.CannyEdgeDetector(h.p))) } // GetHighThreshold // // For further details, please see: // https://docs.opencv.org/master/d0/d43/classcv_1_1cuda_1_1CannyEdgeDetector.html#a8366296a57059487dcfd7b30f4a9e3b1 func (h *CannyEdgeDetector) GetHighThreshold() float64 { return float64(C.CannyEdgeDetector_GetHighThreshold(C.CannyEdgeDetector(h.p))) } // GetL2Gradient // // For further details, please see: // https://docs.opencv.org/master/d0/d43/classcv_1_1cuda_1_1CannyEdgeDetector.html#a8fe4ed887c226b12ab44084789b4c6dd func (h *CannyEdgeDetector) GetL2Gradient() bool { return bool(C.CannyEdgeDetector_GetL2Gradient(C.CannyEdgeDetector(h.p))) } // GetLowThreshold // // For further details, please see: // https://docs.opencv.org/master/d0/d43/classcv_1_1cuda_1_1CannyEdgeDetector.html#aaf5a8944a8ac11093cf7a093b45cd3a8 func (h *CannyEdgeDetector) GetLowThreshold() float64 { return float64(C.CannyEdgeDetector_GetLowThreshold(C.CannyEdgeDetector(h.p))) } // SetAppertureSize // // For further details, please see: // https://docs.opencv.org/master/d0/d43/classcv_1_1cuda_1_1CannyEdgeDetector.html#aac7d0602338e1a2a783811a929967714 func (h *CannyEdgeDetector) SetAppertureSize(appertureSize int) { C.CannyEdgeDetector_SetAppertureSize(C.CannyEdgeDetector(h.p), C.int(appertureSize)) } // SetHighThreshold // // For further details, please see: // https://docs.opencv.org/master/d0/d43/classcv_1_1cuda_1_1CannyEdgeDetector.html#a63d352fe7f3bad640e63f4e394619235 func (h *CannyEdgeDetector) SetHighThreshold(highThresh float64) { C.CannyEdgeDetector_SetHighThreshold(C.CannyEdgeDetector(h.p), C.double(highThresh)) } // SetL2Gradient // // For further details, please see: // https://docs.opencv.org/master/d0/d43/classcv_1_1cuda_1_1CannyEdgeDetector.html#ac2e8a675cc30cb3e621ac684e22f89d1 func (h *CannyEdgeDetector) SetL2Gradient(L2gradient bool) { C.CannyEdgeDetector_SetL2Gradient(C.CannyEdgeDetector(h.p), C.bool(L2gradient)) } // SetLowThreshold // // For further details, please see: // https://docs.opencv.org/master/d0/d43/classcv_1_1cuda_1_1CannyEdgeDetector.html#a6bdc1479c1557288a69c6314c61d1548 func (h *CannyEdgeDetector) SetLowThreshold(lowThresh float64) { C.CannyEdgeDetector_SetLowThreshold(C.CannyEdgeDetector(h.p), C.double(lowThresh)) } // CvtColor converts an image from one color space to another. // It converts the src Mat image to the dst Mat using the // code param containing the desired ColorConversionCode color space. // // For further details, please see: // https://docs.opencv.org/master/db/d8c/group__cudaimgproc__color.html#ga48d0f208181d5ca370d8ff6b62cbe826 func CvtColor(src GpuMat, dst *GpuMat, code gocv.ColorConversionCode) error { return OpenCVResult(C.GpuCvtColor(src.p, dst.p, C.int(code), nil)) } // CvtColorWithStream converts an image from one color space to another // using a Stream for concurrency. // It converts the src Mat image to the dst Mat using the // code param containing the desired ColorConversionCode color space. // // For further details, please see: // https://docs.opencv.org/master/db/d8c/group__cudaimgproc__color.html#ga48d0f208181d5ca370d8ff6b62cbe826 func CvtColorWithStream(src GpuMat, dst *GpuMat, code gocv.ColorConversionCode, s Stream) error { return OpenCVResult(C.GpuCvtColor(src.p, dst.p, C.int(code), s.p)) } // Demosaicing converts an image from Bayer pattern to RGB or grayscale. // It converts the src Mat image to the dst Mat using the // code param containing the desired ColorConversionCode color space. // // For further details, please see: // https://docs.opencv.org/master/db/d8c/group__cudaimgproc__color.html#ga7fb153572b573ebd2d7610fcbe64166e func Demosaicing(src GpuMat, dst *GpuMat, code gocv.ColorConversionCode) error { return OpenCVResult(C.GpuDemosaicing(src.p, dst.p, C.int(code), nil)) } // DemosaicingWithStream converts an image from Bayer pattern to RGB or grayscale // using a Stream for concurrency. // It converts the src Mat image to the dst Mat using the // code param containing the desired ColorConversionCode color space. // // For further details, please see: // https://docs.opencv.org/master/db/d8c/group__cudaimgproc__color.html#ga7fb153572b573ebd2d7610fcbe64166e func DemosaicingWithStream(src GpuMat, dst *GpuMat, code gocv.ColorConversionCode, s Stream) error { return OpenCVResult(C.GpuDemosaicing(src.p, dst.p, C.int(code), s.p)) } // HoughLinesDetector // // For further details, please see: // https://docs.opencv.org/master/d2/dcd/classcv_1_1cuda_1_1HoughLinesDetector.html type HoughLinesDetector struct { p unsafe.Pointer } // NewHoughLinesDetector returns a new HoughLinesDetector. func NewHoughLinesDetector(rho float32, theta float32, threshold int) HoughLinesDetector { return HoughLinesDetector{p: unsafe.Pointer(C.HoughLinesDetector_Create(C.double(rho), C.double(theta), C.int(threshold)))} } // NewHoughLinesDetectorWithParams returns a new HoughLinesDetector. func NewHoughLinesDetectorWithParams(rho float32, theta float32, threshold int, sort bool, maxlines int) HoughLinesDetector { return HoughLinesDetector{p: unsafe.Pointer(C.HoughLinesDetector_CreateWithParams(C.double(rho), C.double(theta), C.int(threshold), C.bool(sort), C.int(maxlines)))} } // Close HoughLinesDetector func (h *HoughLinesDetector) Close() error { C.HoughLinesDetector_Close((C.HoughLinesDetector)(h.p)) h.p = nil return nil } // Detect finds lines in a binary image using the classical Hough transform. // // For further details, please see: // https://docs.opencv.org/master/d2/dcd/classcv_1_1cuda_1_1HoughLinesDetector.html#a18ff6d0886833ac6215054e191ae2520 func (h *HoughLinesDetector) Detect(img GpuMat, dst *GpuMat) error { return OpenCVResult(C.HoughLinesDetector_Detect(C.HoughLinesDetector(h.p), img.p, dst.p, nil)) } // DetectWithStream finds lines in a binary image using the classical Hough transform // using a Stream for concurrency. // // For further details, please see: // https://docs.opencv.org/master/d2/dcd/classcv_1_1cuda_1_1HoughLinesDetector.html#a18ff6d0886833ac6215054e191ae2520 func (h *HoughLinesDetector) DetectWithStream(img GpuMat, dst *GpuMat, s Stream) error { return OpenCVResult(C.HoughLinesDetector_Detect(C.HoughLinesDetector(h.p), img.p, dst.p, s.p)) } // HoughSegmentDetector // // For further details, please see: // https://docs.opencv.org/master/d6/df9/classcv_1_1cuda_1_1HoughSegmentDetector.html type HoughSegmentDetector struct { p unsafe.Pointer } // NewHoughSegmentDetector returns a new HoughSegmentDetector. func NewHoughSegmentDetector(rho float32, theta float32, minLineLength int, maxLineGap int) HoughSegmentDetector { return HoughSegmentDetector{p: unsafe.Pointer(C.HoughSegmentDetector_Create(C.double(rho), C.double(theta), C.int(minLineLength), C.int(maxLineGap)))} } // Close HoughSegmentDetector func (h *HoughSegmentDetector) Close() error { C.HoughSegmentDetector_Close((C.HoughSegmentDetector)(h.p)) h.p = nil return nil } // Detect finds lines in a binary image using the Hough probabilistic transform. // For further details, please see: // https://docs.opencv.org/master/d6/df9/classcv_1_1cuda_1_1HoughSegmentDetector.html#a739bf84825ca455966d69dd75ca0ea6e func (h *HoughSegmentDetector) Detect(img GpuMat, dst *GpuMat) error { return OpenCVResult(C.HoughSegmentDetector_Detect(C.HoughSegmentDetector(h.p), img.p, dst.p, nil)) } // DetectWithStream finds lines in a binary image using the Hough probabilistic transform // using a Stream for concurrency. // // For further details, please see: // https://docs.opencv.org/master/d6/df9/classcv_1_1cuda_1_1HoughSegmentDetector.html#a739bf84825ca455966d69dd75ca0ea6e func (h *HoughSegmentDetector) DetectWithStream(img GpuMat, dst *GpuMat, s Stream) error { return OpenCVResult(C.HoughSegmentDetector_Detect(C.HoughSegmentDetector(h.p), img.p, dst.p, s.p)) } // TemplateMatching // // For further details, please see: // https://docs.opencv.org/4.6.0/d2/d58/classcv_1_1cuda_1_1TemplateMatching.html type TemplateMatching struct { p unsafe.Pointer } // NewTemplateMatching returns a new TemplateMatching. func NewTemplateMatching(srcType gocv.MatType, method gocv.TemplateMatchMode) TemplateMatching { return TemplateMatching{p: unsafe.Pointer(C.TemplateMatching_Create(C.int(srcType), C.int(method)))} } // Close TemplateMatching func (tm *TemplateMatching) Close() error { C.TemplateMatching_Close((C.TemplateMatching)(tm.p)) tm.p = nil return nil } // Match computes a proximity map for a raster template and an image where the template is searched for. // For further details, please see: // https://docs.opencv.org/4.6.0/d2/d58/classcv_1_1cuda_1_1TemplateMatching.html#a05a565a53461c916b3b10737cbe43a01 func (tm *TemplateMatching) Match(img GpuMat, tmpl GpuMat, dst *GpuMat) error { return OpenCVResult(C.TemplateMatching_Match(C.TemplateMatching(tm.p), img.p, tmpl.p, dst.p, nil)) } // MatchWithStream computes a proximity map for a raster template and an image where the template is searched for // using a Stream for concurrency. // // For further details, please see: // https://docs.opencv.org/4.6.0/d2/d58/classcv_1_1cuda_1_1TemplateMatching.html#a05a565a53461c916b3b10737cbe43a01 func (tm *TemplateMatching) MatchWithStream(img GpuMat, tmpl GpuMat, dst *GpuMat, s Stream) error { return OpenCVResult(C.TemplateMatching_Match(C.TemplateMatching(tm.p), img.p, tmpl.p, dst.p, s.p)) } // AlphaComp Composites two images using alpha opacity values contained in each image. // // img1: First image. Supports CV_8UC4 , CV_16UC4 , CV_32SC4 and CV_32FC4 types. // // img2: Second image. Must have the same size and the same type as img1. // // dst: Destination image. // // alpha_op: Flag specifying the alpha-blending operation // // For further details, please see: // https://docs.opencv.org/4.x/db/d8c/group__cudaimgproc__color.html#ga08a698700458d9311390997b57fbf8dc func AlphaComp(img1 GpuMat, img2 GpuMat, dst *GpuMat, alphaOp AlphaCompTypes) error { return OpenCVResult(C.AlphaComp(img1.p, img2.p, dst.p, C.int(alphaOp), nil)) } // AlphaCompWithStream Composites two images using alpha opacity values contained in each image. // // img1: First image. Supports CV_8UC4 , CV_16UC4 , CV_32SC4 and CV_32FC4 types. // // img2: Second image. Must have the same size and the same type as img1. // // dst: Destination image. // // alpha_op: Flag specifying the alpha-blending operation // // stream: Stream for the asynchronous version. // // For further details, please see: // https://docs.opencv.org/4.x/db/d8c/group__cudaimgproc__color.html#ga08a698700458d9311390997b57fbf8dc func AlphaCompWithStream(img1 GpuMat, img2 GpuMat, dst *GpuMat, alphaOp AlphaCompTypes, s Stream) error { return OpenCVResult(C.AlphaComp(img1.p, img2.p, dst.p, C.int(alphaOp), s.p)) } // GammaCorrection Routines for correcting image color gamma. // // src: Source image (3- or 4-channel 8 bit). // // dst: Destination image. // // forward: true for forward gamma correction or false for inverse gamma correction. // // For further details, please see: // https://docs.opencv.org/4.x/db/d8c/group__cudaimgproc__color.html#gaf4195a8409c3b8fbfa37295c2b2c4729 func GammaCorrection(src GpuMat, dst *GpuMat, forward bool) error { return OpenCVResult(C.GammaCorrection(src.p, dst.p, C.bool(forward), nil)) } // GammaCorrectionWithStream Routines for correcting image color gamma. // // src: Source image (3- or 4-channel 8 bit). // // dst: Destination image. // // forward: true for forward gamma correction or false for inverse gamma correction. // // stream: Stream for the asynchronous version. // // For further details, please see: // https://docs.opencv.org/4.x/db/d8c/group__cudaimgproc__color.html#gaf4195a8409c3b8fbfa37295c2b2c4729 func GammaCorrectionWithStream(src GpuMat, dst *GpuMat, forward bool, s Stream) error { return OpenCVResult(C.GammaCorrection(src.p, dst.p, C.bool(forward), s.p)) } // SwapChannels Exchanges the color channels of an image in-place. // // image: Source image. Supports only CV_8UC4 type. // // dstOrder: Integer array describing how channel values are permutated. The n-th entry of the array // contains the number of the channel that is stored in the n-th channel of the output image. // E.g. Given an RGBA image, aDstOrder = [3,2,1,0] converts this to ABGR channel order. // // supports arbitrary permutations of the original channels, including replication. // // For further details, please see: // https://docs.opencv.org/4.x/db/d8c/group__cudaimgproc__color.html#ga75a29cc4a97cde0d43ea066b01de927e func SwapChannels(image *GpuMat, dstOrder []int) error { return OpenCVResult(C.SwapChannels(image.p, (*C.int)(unsafe.Pointer(&dstOrder[0])), nil)) } // SwapChannelsWithStream Exchanges the color channels of an image in-place. // // image: Source image. Supports only CV_8UC4 type. // // dstOrder: Integer array describing how channel values are permutated. The n-th entry of the array // contains the number of the channel that is stored in the n-th channel of the output image. // E.g. Given an RGBA image, aDstOrder = [3,2,1,0] converts this to ABGR channel order. // // stream: Stream for the asynchronous version. // // supports arbitrary permutations of the original channels, including replication. // // For further details, please see: // https://docs.opencv.org/4.x/db/d8c/group__cudaimgproc__color.html#ga75a29cc4a97cde0d43ea066b01de927e func SwapChannelsWithStream(image *GpuMat, dstOrder []int, s Stream) error { return OpenCVResult(C.SwapChannels(image.p, (*C.int)(unsafe.Pointer(&dstOrder[0])), s.p)) } // CalcHist Calculates histogram for one channel 8-bit image. // // src: Source image with CV_8UC1 type. // // hist: Destination histogram with one row, 256 columns, and the CV_32SC1 type. // // For further details, please see: // https://docs.opencv.org/4.x/d8/d0e/group__cudaimgproc__hist.html#gaaf3944106890947020bb4522a7619c26 func CalcHist(src GpuMat, dst *GpuMat) error { return OpenCVResult(C.Cuda_CalcHist(src.p, dst.p, nil)) } // CalcHistWithStream Calculates histogram for one channel 8-bit image. // // src: Source image with CV_8UC1 type. // // hist: Destination histogram with one row, 256 columns, and the CV_32SC1 type. // // stream: Stream for the asynchronous version. // // For further details, please see: // https://docs.opencv.org/4.x/d8/d0e/group__cudaimgproc__hist.html#gaaf3944106890947020bb4522a7619c26 func CalcHistWithStream(src GpuMat, dst *GpuMat, s Stream) error { return OpenCVResult(C.Cuda_CalcHist(src.p, dst.p, s.p)) } // CalcHistWithParams Calculates histogram for one channel 8-bit image confined in given mask. // // src: Source image with CV_8UC1 type. // // mask: A mask image same size as src and of type CV_8UC1. // // hist: Destination histogram with one row, 256 columns, and the CV_32SC1 type. // // stream: Stream for the asynchronous version. // // For further details, please see: // https://docs.opencv.org/4.x/d8/d0e/group__cudaimgproc__hist.html#ga2d55b444ce776c8bbd3087cc90c47f32 func CalcHistWithParams(src GpuMat, mask GpuMat, dst *GpuMat, s Stream) error { return OpenCVResult(C.Cuda_CalcHist_WithParams(src.p, mask.p, dst.p, s.p)) } // EqualizeHist Equalizes the histogram of a grayscale image. // // src: Source image with CV_8UC1 type. // // dst: Destination image. // // For further details, please see: // https://docs.opencv.org/4.x/d8/d0e/group__cudaimgproc__hist.html#ga2384be74bd2feba7e6c46815513f0060 func EqualizeHist(src GpuMat, dst *GpuMat) error { return OpenCVResult(C.Cuda_EqualizeHist(src.p, dst.p, nil)) } // EqualizeHistWithStream Equalizes the histogram of a grayscale image. // // src: Source image with CV_8UC1 type. // // dst: Destination image. // // stream: Stream for the asynchronous version. // // For further details, please see: // https://docs.opencv.org/4.x/d8/d0e/group__cudaimgproc__hist.html#ga2384be74bd2feba7e6c46815513f0060 func EqualizeHistWithStream(src GpuMat, dst *GpuMat, s Stream) error { return OpenCVResult(C.Cuda_EqualizeHist(src.p, dst.p, s.p)) } // EvenLevels Computes levels with even distribution. // // levels: Destination array. levels has 1 row, nLevels columns, and the CV_32SC1 type. // // nLevels: Number of computed levels. nLevels must be at least 2. // // lowerLevel: Lower boundary value of the lowest level. // // upperLevel: Upper boundary value of the greatest level. // // For further details, please see: // https://docs.opencv.org/4.x/d8/d0e/group__cudaimgproc__hist.html#ga2f2cbd21dc6d7367a7c4ee1a826f389dFor further details, please see: func EvenLevels(levels *GpuMat, nLevels int, lowerLevel int, upperLevel int) error { return OpenCVResult(C.Cuda_EvenLevels(levels.p, C.int(nLevels), C.int(lowerLevel), C.int(upperLevel), nil)) } // EvenLevelsWithStream Computes levels with even distribution. // // levels: Destination array. levels has 1 row, nLevels columns, and the CV_32SC1 type. // // nLevels: Number of computed levels. nLevels must be at least 2. // // lowerLevel: Lower boundary value of the lowest level. // // upperLevel: Upper boundary value of the greatest level. // // stream: Stream for the asynchronous version. // // For further details, please see: // https://docs.opencv.org/4.x/d8/d0e/group__cudaimgproc__hist.html#ga2f2cbd21dc6d7367a7c4ee1a826f389dFor further details, please see: func EvenLevelsWithStream(levels *GpuMat, nLevels int, lowerLevel int, upperLevel int, s Stream) error { return OpenCVResult(C.Cuda_EvenLevels(levels.p, C.int(nLevels), C.int(lowerLevel), C.int(upperLevel), s.p)) } // HistEven Calculates a histogram with evenly distributed bins. // // src: Source image. CV_8U, CV_16U, or CV_16S depth and 1 or 4 channels are supported. // For a four-channel image, all channels are processed separately. // // hist: Destination histogram with one row, histSize columns, and the CV_32S type. // // histSize: Size of the histogram. // // lowerLevel: Lower boundary of lowest-level bin. // // upperLevel: Upper boundary of highest-level bin. // // For further details, please see: // https://docs.opencv.org/4.x/d8/d0e/group__cudaimgproc__hist.html#gacd3b14279fb77a57a510cb8c89a1856f func HistEven(src GpuMat, hist *GpuMat, histSize int, lowerLevel int, upperLevel int) error { return OpenCVResult(C.Cuda_HistEven(src.p, hist.p, C.int(histSize), C.int(lowerLevel), C.int(upperLevel), nil)) } // HistEvenWithStream Calculates a histogram with evenly distributed bins. // // src: Source image. CV_8U, CV_16U, or CV_16S depth and 1 or 4 channels are supported. // For a four-channel image, all channels are processed separately. // // hist: Destination histogram with one row, histSize columns, and the CV_32S type. // // histSize: Size of the histogram. // // lowerLevel: Lower boundary of lowest-level bin. // // upperLevel: Upper boundary of highest-level bin. // // stream: Stream for the asynchronous version. // // For further details, please see: // https://docs.opencv.org/4.x/d8/d0e/group__cudaimgproc__hist.html#gacd3b14279fb77a57a510cb8c89a1856f func HistEvenWithStream(src GpuMat, hist *GpuMat, histSize int, lowerLevel int, upperLevel int, s Stream) error { return OpenCVResult(C.Cuda_HistEven(src.p, hist.p, C.int(histSize), C.int(lowerLevel), C.int(upperLevel), s.p)) } // HistRange Calculates a histogram with bins determined by the levels array. // // src: Source image. CV_8U , CV_16U , or CV_16S depth and 1 or 4 channels are supported. // For a four-channel image, all channels are processed separately. // // hist: Destination histogram with one row, (levels.cols-1) columns, and the CV_32SC1 type. // // levels: Number of levels in the histogram. // // For further details, please see: // https://docs.opencv.org/4.x/d8/d0e/group__cudaimgproc__hist.html#ga87819085c1059186d9cdeacd92cea783 func HistRange(src GpuMat, hist *GpuMat, levels GpuMat) error { return OpenCVResult(C.Cuda_HistRange(src.p, hist.p, levels.p, nil)) } // HistRangeWithStream Calculates a histogram with bins determined by the levels array. // // src: Source image. CV_8U , CV_16U , or CV_16S depth and 1 or 4 channels are supported. // For a four-channel image, all channels are processed separately. // // hist: Destination histogram with one row, (levels.cols-1) columns, and the CV_32SC1 type. // // levels: Number of levels in the histogram. // // stream: Stream for the asynchronous version. // // For further details, please see: // https://docs.opencv.org/4.x/d8/d0e/group__cudaimgproc__hist.html#ga87819085c1059186d9cdeacd92cea783 func HistRangeWithStream(src GpuMat, hist *GpuMat, levels GpuMat, s Stream) error { return OpenCVResult(C.Cuda_HistRange(src.p, hist.p, levels.p, s.p)) } // BilateralFilter Performs bilateral filtering of passed image. // // src: Source image. Supports only (channels != 2 && depth() != CV_8S && depth() != CV_32S && depth() != CV_64F). // // dst: Destination imagwe. // // kernelSize: Kernel window size. // // sigmaColor: Filter sigma in the color space. // // sigmaSpatial: Filter sigma in the coordinate space. // // borderMode: Border type. See borderInterpolate for details. // BorderReflect101 , BorderReplicate , BorderConstant , BorderReflect and BorderWrap are supported for now. // // For further details, please see: // https://docs.opencv.org/4.x/d0/d05/group__cudaimgproc.html#ga6abeaecdd4e7edc0bd1393a04f4f20bd func BilateralFilter(src GpuMat, dst *GpuMat, kernelSize int, sigmaColor float32, sigmaSpatial float32, borderMode BorderType) error { return OpenCVResult(C.Cuda_BilateralFilter(src.p, dst.p, C.int(kernelSize), C.float(sigmaColor), C.float(sigmaSpatial), C.int(borderMode), nil)) } // BilateralFilterWithStream Performs bilateral filtering of passed image. // // src: Source image. Supports only (channels != 2 && depth() != CV_8S && depth() != CV_32S && depth() != CV_64F). // // dst: Destination imagwe. // // kernelSize: Kernel window size. // // sigmaColor: Filter sigma in the color space. // // sigmaSpatial: Filter sigma in the coordinate space. // // borderMode: Border type. See borderInterpolate for details. // BorderReflect101 , BorderReplicate , BorderConstant , BorderReflect and BorderWrap are supported for now. // // stream: Stream for the asynchronous version. // // For further details, please see: // https://docs.opencv.org/4.x/d0/d05/group__cudaimgproc.html#ga6abeaecdd4e7edc0bd1393a04f4f20bd func BilateralFilterWithStream(src GpuMat, dst *GpuMat, kernelSize int, sigmaColor float32, sigmaSpatial float32, borderMode BorderType, s Stream) error { return OpenCVResult(C.Cuda_BilateralFilter(src.p, dst.p, C.int(kernelSize), C.float(sigmaColor), C.float(sigmaSpatial), C.int(borderMode), s.p)) } // BlendLinear Performs linear blending of two images. // // img1: First image. Supports only CV_8U and CV_32F depth. // // img2: Second image. Must have the same size and the same type as img1 . // // weights1: Weights for first image. Must have tha same size as img1 . Supports only CV_32F type. // // weights2: Weights for second image. Must have tha same size as img2 . Supports only CV_32F type. // // result: Destination image. // // For further details, please see: // https://docs.opencv.org/4.x/d0/d05/group__cudaimgproc.html#ga4793607e5729bcc15b27ea33d9fe335e func BlendLinear(img1 GpuMat, img2 GpuMat, weights1 GpuMat, weights2 GpuMat, result *GpuMat) error { return OpenCVResult(C.Cuda_BlendLinear(img1.p, img2.p, weights1.p, weights2.p, result.p, nil)) } // BlendLinearWithStream Performs linear blending of two images. // // img1: First image. Supports only CV_8U and CV_32F depth. // // img2: Second image. Must have the same size and the same type as img1 . // // weights1: Weights for first image. Must have tha same size as img1 . Supports only CV_32F type. // // weights2: Weights for second image. Must have tha same size as img2 . Supports only CV_32F type. // // result: Destination image. // // stream: Stream for the asynchronous version. // // For further details, please see: // https://docs.opencv.org/4.x/d0/d05/group__cudaimgproc.html#ga4793607e5729bcc15b27ea33d9fe335e func BlendLinearWithStream(img1 GpuMat, img2 GpuMat, weights1 GpuMat, weights2 GpuMat, result *GpuMat, s Stream) error { return OpenCVResult(C.Cuda_BlendLinear(img1.p, img2.p, weights1.p, weights2.p, result.p, s.p)) } // MeanShiftFiltering Performs mean-shift filtering for each point of the source image. // It maps each point of the source image into another point. // As a result, you have a new color and new position of each point. // // src: Source image. Only CV_8UC4 images are supported for now. // // dst: Destination image containing the color of mapped points. It has the same size and type as src . // // sp: Spatial window radius. // // sr: Color window radius. // // criteria: Termination criteria. See TermCriteria. // // For further details, please see: // https://docs.opencv.org/4.x/d0/d05/group__cudaimgproc.html#gae13b3035bc6df0e512d876dbb8c00555 func MeanShiftFiltering(src GpuMat, dst *GpuMat, sp int, sr int, criteria gocv.TermCriteria) error { return OpenCVResult(C.Cuda_MeanShiftFiltering(src.p, dst.p, C.int(sp), C.int(sr), C.TermCriteria(criteria.Ptr()), nil)) } // MeanShiftFilteringWithStream Performs mean-shift filtering for each point of the source image. // It maps each point of the source image into another point. // As a result, you have a new color and new position of each point. // // src: Source image. Only CV_8UC4 images are supported for now. // // dst: Destination image containing the color of mapped points. It has the same size and type as src . // // sp: Spatial window radius. // // sr: Color window radius. // // criteria: Termination criteria. See TermCriteria. // // stream: Stream for the asynchronous version. // // For further details, please see: // https://docs.opencv.org/4.x/d0/d05/group__cudaimgproc.html#gae13b3035bc6df0e512d876dbb8c00555 func MeanShiftFilteringWithStream(src GpuMat, dst *GpuMat, sp int, sr int, criteria gocv.TermCriteria, s Stream) error { return OpenCVResult(C.Cuda_MeanShiftFiltering(src.p, dst.p, C.int(sp), C.int(sr), C.TermCriteria(criteria.Ptr()), s.p)) } // MeanShiftProc Performs a mean-shift procedure and stores information // about processed points (their colors and positions) in two images. // // src: Source image. Only CV_8UC4 images are supported for now. // // dstr: Destination image containing the color of mapped points. The size and type is the same as src . // // dstsp: Destination image containing the position of mapped points. The size is the same as src size. The type is CV_16SC2 . // // sp: Spatial window radius. // // sr: Color window radius. // // criteria: Termination criteria. See TermCriteria. // // For further details, please see: // https://docs.opencv.org/4.x/d0/d05/group__cudaimgproc.html#ga6039dc8ecbe2f912bc83fcc9b3bcca39 func MeanShiftProc(src GpuMat, dstr *GpuMat, dstsp *GpuMat, sp int, sr int, criteria gocv.TermCriteria) error { return OpenCVResult(C.Cuda_MeanShiftProc(src.p, dstr.p, dstsp.p, C.int(sp), C.int(sr), C.TermCriteria(criteria.Ptr()), nil)) } // MeanShiftProcWithStream Performs a mean-shift procedure and stores information // about processed points (their colors and positions) in two images. // // src: Source image. Only CV_8UC4 images are supported for now. // // dstr: Destination image containing the color of mapped points. The size and type is the same as src . // // dstsp: Destination image containing the position of mapped points. The size is the same as src size. The type is CV_16SC2 . // // sp: Spatial window radius. // // sr: Color window radius. // // criteria: Termination criteria. See TermCriteria. // // stream: Stream for the asynchronous version. // // For further details, please see: // https://docs.opencv.org/4.x/d0/d05/group__cudaimgproc.html#ga6039dc8ecbe2f912bc83fcc9b3bcca39 func MeanShiftProcWithStream(src GpuMat, dstr *GpuMat, dstsp *GpuMat, sp int, sr int, criteria gocv.TermCriteria, s Stream) error { return OpenCVResult(C.Cuda_MeanShiftProc(src.p, dstr.p, dstsp.p, C.int(sp), C.int(sr), C.TermCriteria(criteria.Ptr()), s.p)) } // MeanShiftSegmentation Performs a mean-shift segmentation of the source image and eliminates small segments. // // src: Source image. Only CV_8UC4 images are supported for now. // // dst: Segmented image with the same size and type as src. // // sp: Spatial window radius. // // sr: Color window radius. // // minsize: Minimum segment size. Smaller segments are merged. // // criteria: Termination criteria. See TermCriteria. // // For further details, please see: // https://docs.opencv.org/4.x/d0/d05/group__cudaimgproc.html#ga70ed80533a448829dc48cf22b1845c16 func MeanShiftSegmentation(src GpuMat, dst *GpuMat, sp int, sr int, minSize int, criteria gocv.TermCriteria) error { return OpenCVResult(C.Cuda_MeanShiftSegmentation(src.p, dst.p, C.int(sp), C.int(sr), C.int(minSize), C.TermCriteria(criteria.Ptr()), nil)) } // MeanShiftSegmentationWithStream Performs a mean-shift segmentation of the source image and eliminates small segments. // // src: Source image. Only CV_8UC4 images are supported for now. // // dst: Segmented image with the same size and type as src. // // sp: Spatial window radius. // // sr: Color window radius. // // minsize: Minimum segment size. Smaller segments are merged. // // criteria: Termination criteria. See TermCriteria. // // stream: Stream for the asynchronous version. // // For further details, please see: // https://docs.opencv.org/4.x/d0/d05/group__cudaimgproc.html#ga70ed80533a448829dc48cf22b1845c16 func MeanShiftSegmentationWithStream(src GpuMat, dst *GpuMat, sp int, sr int, minSize int, criteria gocv.TermCriteria, s Stream) error { return OpenCVResult(C.Cuda_MeanShiftSegmentation(src.p, dst.p, C.int(sp), C.int(sr), C.int(minSize), C.TermCriteria(criteria.Ptr()), s.p)) } ================================================ FILE: cuda/imgproc.h ================================================ #ifndef _OPENCV3_CUDA_IMGPROC_H_ #define _OPENCV3_CUDA_IMGPROC_H_ #include #include #ifdef __cplusplus #include #include #include extern "C" { #endif #include "cuda.h" #ifdef __cplusplus typedef cv::Ptr* CannyEdgeDetector; typedef cv::Ptr* HoughLinesDetector; typedef cv::Ptr* HoughSegmentDetector; typedef cv::Ptr* TemplateMatching; #else typedef void* CannyEdgeDetector; typedef void* HoughLinesDetector; typedef void* HoughSegmentDetector; typedef void* TemplateMatching; #endif // standalone functions OpenCVResult GpuCvtColor(GpuMat src, GpuMat dst, int code, Stream s); OpenCVResult GpuDemosaicing(GpuMat src, GpuMat dst, int code, Stream s); OpenCVResult AlphaComp(GpuMat img1, GpuMat img2, GpuMat dst, int alpha_op, Stream s); OpenCVResult GammaCorrection(GpuMat src, GpuMat dst, bool forward, Stream s); OpenCVResult SwapChannels(GpuMat image, int dstOrder[4], Stream s); OpenCVResult Cuda_CalcHist(GpuMat src, GpuMat dst, Stream s); OpenCVResult Cuda_CalcHist_WithParams(GpuMat src, GpuMat mask, GpuMat dst, Stream s); OpenCVResult Cuda_EqualizeHist(GpuMat src, GpuMat dst, Stream s); OpenCVResult Cuda_EvenLevels(GpuMat levels, int nLevels, int lowerLevel, int upperLevel, Stream s); OpenCVResult Cuda_HistEven(GpuMat src, GpuMat hist, int histSize, int lowerLevel, int upperLevel, Stream s); OpenCVResult Cuda_HistRange(GpuMat src, GpuMat hist, GpuMat levels, Stream s); OpenCVResult Cuda_BilateralFilter(GpuMat src, GpuMat dst, int kernel_size, float sigma_color, float sigma_spatial, int borderMode, Stream s); OpenCVResult Cuda_BlendLinear(GpuMat img1, GpuMat img2, GpuMat weights1, GpuMat weights2, GpuMat result, Stream s); OpenCVResult Cuda_MeanShiftFiltering(GpuMat src, GpuMat dst, int sp, int sr, TermCriteria criteria, Stream s); OpenCVResult Cuda_MeanShiftProc(GpuMat src, GpuMat dstr, GpuMat dstsp, int sp, int sr, TermCriteria criteria, Stream s); OpenCVResult Cuda_MeanShiftSegmentation(GpuMat src, GpuMat dst, int sp, int sr, int minSize, TermCriteria criteria, Stream s); // CannyEdgeDetector CannyEdgeDetector CreateCannyEdgeDetector(double lowThresh, double highThresh); CannyEdgeDetector CreateCannyEdgeDetectorWithParams(double lowThresh, double highThresh, int appertureSize, bool L2gradient); void CannyEdgeDetector_Close(CannyEdgeDetector det); OpenCVResult CannyEdgeDetector_Detect(CannyEdgeDetector det, GpuMat img, GpuMat dst, Stream s); int CannyEdgeDetector_GetAppertureSize(CannyEdgeDetector det); double CannyEdgeDetector_GetHighThreshold(CannyEdgeDetector det); bool CannyEdgeDetector_GetL2Gradient(CannyEdgeDetector det); double CannyEdgeDetector_GetLowThreshold(CannyEdgeDetector det); void CannyEdgeDetector_SetAppertureSize(CannyEdgeDetector det, int appertureSize); void CannyEdgeDetector_SetHighThreshold(CannyEdgeDetector det, double highThresh); void CannyEdgeDetector_SetL2Gradient(CannyEdgeDetector det, bool L2gradient); void CannyEdgeDetector_SetLowThreshold(CannyEdgeDetector det, double lowThresh); // HoughLinesDetector HoughLinesDetector HoughLinesDetector_Create(double rho, double theta, int threshold); HoughLinesDetector HoughLinesDetector_CreateWithParams(double rho, double theta, int threshold, bool sort, int maxlines); void HoughLinesDetector_Close(HoughLinesDetector hld); OpenCVResult HoughLinesDetector_Detect(HoughLinesDetector hld, GpuMat img, GpuMat dst, Stream s); // HoughSegmentDetector HoughSegmentDetector HoughSegmentDetector_Create(double rho, double theta, int minLineLength, int maxLineGap); void HoughSegmentDetector_Close(HoughSegmentDetector hsd); OpenCVResult HoughSegmentDetector_Detect(HoughSegmentDetector hsd, GpuMat img, GpuMat dst, Stream s); // TemplateMatching TemplateMatching TemplateMatching_Create(int srcType, int method); void TemplateMatching_Close(TemplateMatching tm); OpenCVResult TemplateMatching_Match(TemplateMatching tm, GpuMat img, GpuMat tmpl, GpuMat dst, Stream s); #ifdef __cplusplus } #endif #endif //_OPENCV3_CUDA_IMGPROC_H_ ================================================ FILE: cuda/imgproc_alphacomptypes.go ================================================ package cuda type AlphaCompTypes int const ( AlphaCompTypeOver AlphaCompTypes = iota AlphaCompTypeIn AlphaCompTypeOut AlphaCompTypeAtop AlphaCompTypeXor AlphaCompTypePlus AlphaCompTypeOverPremul AlphaCompTypeInPremul AlphaCompTypeOutPremul AlphaCompTypeAtopPremul AlphaCompTypeXorPremul AlphaCompTypePlusPremul AlphaCompTypePremul ) ================================================ FILE: cuda/imgproc_test.go ================================================ package cuda import ( "fmt" "math" "strconv" "testing" "github.com/pascaldekloe/goe/verify" "gocv.io/x/gocv" ) func TestCanny_Detect(t *testing.T) { src := gocv.IMRead("../images/face-detect.jpg", gocv.IMReadGrayScale) if src.Empty() { t.Error("Invalid read of Mat in Canny test") } defer src.Close() cimg, dimg := NewGpuMat(), NewGpuMat() defer cimg.Close() defer dimg.Close() dest := gocv.NewMat() defer dest.Close() detector := NewCannyEdgeDetector(50, 100) defer detector.Close() cimg.Upload(src) detector.Detect(cimg, &dimg) dimg.Download(&dest) if dest.Empty() { t.Error("Empty Canny test") } if src.Rows() != dest.Rows() { t.Error("Invalid Canny test rows") } if src.Cols() != dest.Cols() { t.Error("Invalid Canny test cols") } } func TestHoughLines_Calc(t *testing.T) { src := gocv.IMRead("../images/face-detect.jpg", gocv.IMReadGrayScale) if src.Empty() { t.Error("Invalid read of Mat in HoughLines test") } defer src.Close() cimg, mimg, dimg := NewGpuMat(), NewGpuMat(), NewGpuMat() defer cimg.Close() defer mimg.Close() defer dimg.Close() canny := NewCannyEdgeDetector(100, 200) defer canny.Close() detector := NewHoughLinesDetectorWithParams(1, math.Pi/180, 50, true, 4096) defer detector.Close() dest := gocv.NewMat() defer dest.Close() cimg.Upload(src) canny.Detect(cimg, &mimg) detector.Detect(mimg, &dimg) dimg.Download(&dest) if dest.Empty() { t.Error("Empty HoughLines test") } if dest.Rows() != 2 { t.Errorf("Invalid HoughLines test rows: %v", dest.Rows()) } expected := map[float32]float32{ 21: 1.5707964, 337: 0.034906585, 85: 1.5707964, 276: 0, 329: 0.034906585, } actual := make(map[float32]float32) for i := 0; i < dest.Cols(); i += 2 { actual[dest.GetFloatAt(0, i)] = dest.GetFloatAt(0, i+1) } for k, v := range expected { s32 := strconv.FormatFloat(float64(k), 'f', -1, 32) verify.Values(t, s32, actual[k], v) } } func TestHoughLines_CalcWithStream(t *testing.T) { src := gocv.IMRead("../images/face-detect.jpg", gocv.IMReadGrayScale) if src.Empty() { t.Error("Invalid read of Mat in HoughLines test") } defer src.Close() cimg, mimg, dimg := NewGpuMat(), NewGpuMat(), NewGpuMat() defer cimg.Close() defer mimg.Close() defer dimg.Close() stream := NewStream() defer stream.Close() canny := NewCannyEdgeDetector(100, 200) defer canny.Close() detector := NewHoughLinesDetectorWithParams(1, math.Pi/180, 50, true, 4096) defer detector.Close() dest := gocv.NewMat() defer dest.Close() cimg.UploadWithStream(src, stream) canny.DetectWithStream(cimg, &mimg, stream) detector.DetectWithStream(mimg, &dimg, stream) dimg.DownloadWithStream(&dest, stream) stream.WaitForCompletion() if dest.Empty() { t.Error("Empty HoughLines test") } if dest.Rows() != 2 { t.Errorf("Invalid HoughLines test rows: %v", dest.Rows()) } expected := map[float32]float32{ 21: 1.5707964, 337: 0.034906585, 85: 1.5707964, 276: 0, 329: 0.034906585, } actual := make(map[float32]float32) for i := 0; i < dest.Cols(); i += 2 { actual[dest.GetFloatAt(0, i)] = dest.GetFloatAt(0, i+1) } for k, v := range expected { s32 := strconv.FormatFloat(float64(k), 'f', -1, 32) verify.Values(t, s32, actual[k], v) } } func TestHoughSegment_Calc(t *testing.T) { src := gocv.IMRead("../images/face-detect.jpg", gocv.IMReadGrayScale) if src.Empty() { t.Error("Invalid read of Mat in HoughSegment test") } defer src.Close() cimg, mimg, dimg := NewGpuMat(), NewGpuMat(), NewGpuMat() defer cimg.Close() defer mimg.Close() defer dimg.Close() canny := NewCannyEdgeDetector(50, 100) defer canny.Close() detector := NewHoughSegmentDetector(1, math.Pi/180, 150, 50) defer detector.Close() dest := gocv.NewMat() defer dest.Close() cimg.Upload(src) canny.Detect(cimg, &mimg) detector.Detect(mimg, &dimg) fimg := dimg.Reshape(0, dimg.Cols()) defer fimg.Close() fimg.Download(&dest) if dest.Empty() { t.Error("Empty HoughSegment test") } if dest.Rows() != 5 { t.Errorf("Invalid HoughSegment test rows: %v", dest.Rows()) } if dest.Cols() != 1 { t.Errorf("Invalid HoughSegment test cols: %v", dest.Cols()) } type point struct { X, Y int32 } expected := map[point]point{ {1, 21}: {398, 21}, {304, 21}: {10, 315}, } actual := make(map[point]point) for i := 0; i < dest.Rows(); i += 4 { actual[point{dest.GetVeciAt(i, 0)[0], dest.GetVeciAt(i, 0)[1]}] = point{dest.GetVeciAt(i, 0)[2], dest.GetVeciAt(i, 0)[3]} } for k, v := range expected { verify.Values(t, fmt.Sprintf("%d %d", k.X, k.Y), actual[k], v) } } func TestHoughSegment_CalcWithStream(t *testing.T) { src := gocv.IMRead("../images/face-detect.jpg", gocv.IMReadGrayScale) if src.Empty() { t.Error("Invalid read of Mat in HoughSegment test") } defer src.Close() cimg, mimg, dimg := NewGpuMat(), NewGpuMat(), NewGpuMat() defer cimg.Close() defer mimg.Close() defer dimg.Close() stream := NewStream() defer stream.Close() canny := NewCannyEdgeDetector(50, 100) defer canny.Close() detector := NewHoughSegmentDetector(1, math.Pi/180, 150, 50) defer detector.Close() dest := gocv.NewMat() defer dest.Close() cimg.UploadWithStream(src, stream) canny.DetectWithStream(cimg, &mimg, stream) detector.DetectWithStream(mimg, &dimg, stream) fimg := dimg.Reshape(0, dimg.Cols()) defer fimg.Close() fimg.DownloadWithStream(&dest, stream) stream.WaitForCompletion() if dest.Empty() { t.Error("Empty HoughSegment test") } if dest.Rows() != 5 { t.Errorf("Invalid HoughSegment test rows: %v", dest.Rows()) } if dest.Cols() != 1 { t.Errorf("Invalid HoughSegment test cols: %v", dest.Cols()) } type point struct { X, Y int32 } expected := map[point]point{ {1, 21}: {398, 21}, {304, 21}: {10, 315}, } actual := make(map[point]point) for i := 0; i < dest.Rows(); i += 4 { actual[point{dest.GetVeciAt(i, 0)[0], dest.GetVeciAt(i, 0)[1]}] = point{dest.GetVeciAt(i, 0)[2], dest.GetVeciAt(i, 0)[3]} } for k, v := range expected { verify.Values(t, fmt.Sprintf("%d %d", k.X, k.Y), actual[k], v) } } func TestTemplateMatching_Match(t *testing.T) { imgScene := gocv.IMRead("../images/face.jpg", gocv.IMReadGrayScale) if imgScene.Empty() { t.Error("Invalid read of face.jpg in MatchTemplate test") } defer imgScene.Close() imgTemplate := gocv.IMRead("../images/toy.jpg", gocv.IMReadGrayScale) if imgTemplate.Empty() { t.Error("Invalid read of toy.jpg in MatchTemplate test") } defer imgTemplate.Close() cimg, timg, dimg := NewGpuMat(), NewGpuMat(), NewGpuMat() defer cimg.Close() defer timg.Close() defer dimg.Close() dest := gocv.NewMat() defer dest.Close() matcher := NewTemplateMatching(gocv.MatTypeCV8U, gocv.TmSqdiff) defer matcher.Close() cimg.Upload(imgScene) timg.Upload(imgTemplate) matcher.Match(cimg, timg, &dimg) dimg.Download(&dest) _, maxConfidence, _, _ := gocv.MinMaxLoc(dest) if maxConfidence < 0.95 { t.Errorf("Max confidence of %f is too low. MatchTemplate could not find template in scene.", maxConfidence) } } func TestDemosaicing(t *testing.T) { img := gocv.IMRead("../images/face.jpg", gocv.IMReadColor) if img.Empty() { t.Error("Invalid read of Mat in Demosaicing test") } defer img.Close() patterns := map[string]gocv.ColorConversionCode{ "bg": gocv.ColorBayerBGToBGR, "gb": gocv.ColorBayerGBToBGR, "rg": gocv.ColorBayerRGToBGR, "gr": gocv.ColorBayerGRToBGR, } for pattern, code := range patterns { bayerImg, err := NewBayerFromMat(img, pattern) if bayerImg.Empty() { t.Error("Invalid conversion from Mat to Bayer in Demosaicing test") } if err != nil { t.Error(err) } cimg, dimg := NewGpuMat(), NewGpuMat() cimg.Upload(bayerImg) dest := gocv.NewMat() Demosaicing(cimg, &dimg, code) dimg.Download(&dest) if dest.Empty() || bayerImg.Rows() != dest.Rows() || bayerImg.Cols() != dest.Cols() { t.Error("Invalid convert in Demosaicing test") } bayerImg.Close() cimg.Close() dimg.Close() dest.Close() } } func TestDemosaicing_WithStream(t *testing.T) { img := gocv.IMRead("../images/face.jpg", gocv.IMReadColor) if img.Empty() { t.Error("Invalid read of Mat in Demosaicing test") } defer img.Close() patterns := map[string]gocv.ColorConversionCode{ "bg": gocv.ColorBayerBGToBGR, "gb": gocv.ColorBayerGBToBGR, "rg": gocv.ColorBayerRGToBGR, "gr": gocv.ColorBayerGRToBGR, } for pattern, code := range patterns { stream := NewStream() bayerImg, err := NewBayerFromMat(img, pattern) if bayerImg.Empty() { t.Error("Invalid conversion from Mat to Bayer in DemosaicingWithStream test") } if err != nil { t.Error(err) } cimg, dimg := NewGpuMat(), NewGpuMat() dest := gocv.NewMat() cimg.UploadWithStream(bayerImg, stream) DemosaicingWithStream(cimg, &dimg, code, stream) dimg.DownloadWithStream(&dest, stream) stream.WaitForCompletion() if dest.Empty() || bayerImg.Rows() != dest.Rows() || bayerImg.Cols() != dest.Cols() { t.Error("Invalid convert in DemosaicingWithStream test") } bayerImg.Close() cimg.Close() dimg.Close() dest.Close() stream.Close() } } func NewBayerFromMat(src gocv.Mat, pattern string) (gocv.Mat, error) { dest := gocv.NewMatWithSize(src.Rows(), src.Cols(), gocv.MatTypeCV8UC1) switch pattern { case "bg": for y := 0; y < src.Rows(); y++ { for x := 0; x < src.Cols(); x++ { if (x+y)%2 != 0 { dest.SetUCharAt(y, x, src.GetVecbAt(y, x)[1]) } else if (x % 2) != 0 { dest.SetUCharAt(y, x, src.GetVecbAt(y, x)[0]) } else { dest.SetUCharAt(y, x, src.GetVecbAt(y, x)[2]) } } } case "gb": for y := 0; y < src.Rows(); y++ { for x := 0; x < src.Cols(); x++ { if (x+y)%2 == 0 { dest.SetUCharAt(y, x, src.GetVecbAt(y, x)[1]) } else if (x % 2) == 0 { dest.SetUCharAt(y, x, src.GetVecbAt(y, x)[0]) } else { dest.SetUCharAt(y, x, src.GetVecbAt(y, x)[2]) } } } case "rg": for y := 0; y < src.Rows(); y++ { for x := 0; x < src.Cols(); x++ { if (x+y)%2 != 0 { dest.SetUCharAt(y, x, src.GetVecbAt(y, x)[1]) } else if (x % 2) == 0 { dest.SetUCharAt(y, x, src.GetVecbAt(y, x)[0]) } else { dest.SetUCharAt(y, x, src.GetVecbAt(y, x)[2]) } } } case "gr": for y := 0; y < src.Rows(); y++ { for x := 0; x < src.Cols(); x++ { if (x+y)%2 == 0 { dest.SetUCharAt(y, x, src.GetVecbAt(y, x)[1]) } else if (x % 2) != 0 { dest.SetUCharAt(y, x, src.GetVecbAt(y, x)[0]) } else { dest.SetUCharAt(y, x, src.GetVecbAt(y, x)[2]) } } } default: dest.Close() return gocv.Mat{}, fmt.Errorf("invalid pattern: %s", pattern) } return dest, nil } func TestAlphaComp(t *testing.T) { img := gocv.IMRead("../images/box.png", gocv.IMReadUnchanged) defer img.Close() converted := gocv.NewMat() defer converted.Close() gocv.CvtColor(img, &converted, gocv.ColorRGBAToBGRA) m1 := NewGpuMatFromMat(converted) defer m1.Close() m2 := NewGpuMatFromMat(converted) defer m2.Close() dst := NewGpuMat() defer dst.Close() AlphaComp(m1, m2, &dst, AlphaCompTypeOver) } func TestAlphaCompWithStream(t *testing.T) { img := gocv.IMRead("../images/box.png", gocv.IMReadUnchanged) defer img.Close() converted := gocv.NewMat() defer converted.Close() gocv.CvtColor(img, &converted, gocv.ColorRGBAToBGRA) m1 := NewGpuMatFromMat(converted) defer m1.Close() m2 := NewGpuMatFromMat(converted) defer m2.Close() dst := NewGpuMat() defer dst.Close() s := NewStream() defer s.Close() AlphaCompWithStream(m1, m2, &dst, AlphaCompTypeOver, s) s.WaitForCompletion() } func TestGammaCorrection(t *testing.T) { img := gocv.IMRead("../images/box.png", gocv.IMReadUnchanged) defer img.Close() converted := gocv.NewMat() defer converted.Close() gocv.CvtColor(img, &converted, gocv.ColorRGBAToBGRA) m1 := NewGpuMatFromMat(converted) defer m1.Close() dst := NewGpuMat() defer dst.Close() GammaCorrection(m1, &dst, true) } func TestGammaCorrectionWithStream(t *testing.T) { img := gocv.IMRead("../images/box.png", gocv.IMReadUnchanged) defer img.Close() converted := gocv.NewMat() defer converted.Close() gocv.CvtColor(img, &converted, gocv.ColorRGBAToBGRA) m1 := NewGpuMatFromMat(converted) defer m1.Close() dst := NewGpuMat() defer dst.Close() s := NewStream() defer s.Close() GammaCorrectionWithStream(m1, &dst, true, s) s.WaitForCompletion() } func TestSwapChannels(t *testing.T) { img := gocv.IMRead("../images/box.png", gocv.IMReadUnchanged) defer img.Close() converted := gocv.NewMat() defer converted.Close() gocv.CvtColor(img, &converted, gocv.ColorRGBAToBGRA) m1 := NewGpuMatFromMat(converted) defer m1.Close() SwapChannels(&m1, []int{3, 2, 1, 0}) } func TestSwapChannelsWithStream(t *testing.T) { img := gocv.IMRead("../images/box.png", gocv.IMReadUnchanged) defer img.Close() converted := gocv.NewMat() defer converted.Close() gocv.CvtColor(img, &converted, gocv.ColorRGBAToBGRA) m1 := NewGpuMatFromMat(converted) defer m1.Close() s := NewStream() defer s.Close() SwapChannelsWithStream(&m1, []int{3, 2, 1, 0}, s) s.WaitForCompletion() } func TestCalcHist(t *testing.T) { m1 := NewGpuMatWithSize(256, 256, gocv.MatTypeCV8UC1) defer m1.Close() m2 := NewGpuMatWithSize(1, 256, gocv.MatTypeCV32SC1) defer m2.Close() CalcHist(m1, &m2) CalcHistWithParams(m1, m1, &m2, Stream{}) } func TestCalcHistWithStream(t *testing.T) { m1 := NewGpuMatWithSize(256, 256, gocv.MatTypeCV8UC1) defer m1.Close() m2 := NewGpuMatWithSize(1, 256, gocv.MatTypeCV32SC1) defer m2.Close() s := NewStream() defer s.Close() s1 := NewStream() defer s1.Close() CalcHistWithStream(m1, &m2, s) CalcHistWithParams(m1, m1, &m2, s1) s.WaitForCompletion() s1.WaitForCompletion() } func TestEqualizeHist(t *testing.T) { m1 := NewGpuMatWithSize(256, 256, gocv.MatTypeCV8UC1) defer m1.Close() m2 := NewGpuMatWithSize(1, 256, gocv.MatTypeCV32SC1) defer m2.Close() EqualizeHist(m1, &m2) } func TestEqualizeHistWithStream(t *testing.T) { m1 := NewGpuMatWithSize(256, 256, gocv.MatTypeCV8UC1) defer m1.Close() m2 := NewGpuMatWithSize(1, 256, gocv.MatTypeCV32SC1) defer m2.Close() s := NewStream() defer s.Close() EqualizeHistWithStream(m1, &m2, s) s.WaitForCompletion() } func TestEvenLevels(t *testing.T) { m1 := NewGpuMatWithSize(256, 256, gocv.MatTypeCV8UC1) defer m1.Close() EvenLevels(&m1, 2, 1, 2) } func TestEvenLevelsWithStream(t *testing.T) { m1 := NewGpuMatWithSize(256, 256, gocv.MatTypeCV8UC1) defer m1.Close() s := NewStream() defer s.Close() EvenLevelsWithStream(&m1, 2, 1, 2, s) s.WaitForCompletion() } func TestHistEven(t *testing.T) { m1 := NewGpuMatWithSize(256, 256, gocv.MatTypeCV8UC1) defer m1.Close() m2 := NewGpuMatWithSize(1, 256, gocv.MatTypeCV32SC1) defer m2.Close() HistEven(m1, &m2, 256, 1, 2) } func TestHistEvenWithStream(t *testing.T) { m1 := NewGpuMatWithSize(256, 256, gocv.MatTypeCV8UC1) defer m1.Close() m2 := NewGpuMatWithSize(1, 256, gocv.MatTypeCV32SC1) defer m2.Close() s := NewStream() defer s.Close() HistEvenWithStream(m1, &m2, 256, 1, 2, s) s.WaitForCompletion() } func TestHistRange(t *testing.T) { src := NewGpuMatWithSize(256, 256, gocv.MatTypeCV8UC1) defer src.Close() levels := NewGpuMatWithSize(1, 256, gocv.MatTypeCV32SC1) defer levels.Close() hist := NewGpuMatWithSize(1, 256, gocv.MatTypeCV32SC1) defer hist.Close() HistRange(src, &hist, levels) } func TestHistRangeWithStream(t *testing.T) { src := NewGpuMatWithSize(256, 256, gocv.MatTypeCV8UC1) defer src.Close() levels := NewGpuMatWithSize(1, 256, gocv.MatTypeCV32SC1) defer levels.Close() hist := NewGpuMatWithSize(1, 256, gocv.MatTypeCV32SC1) defer hist.Close() s := NewStream() defer s.Close() HistRangeWithStream(src, &hist, levels, s) s.WaitForCompletion() } func TestBilateralFilter(t *testing.T) { src := NewGpuMatWithSize(256, 256, gocv.MatTypeCV8UC1) defer src.Close() dst := NewGpuMatWithSize(256, 256, gocv.MatTypeCV32SC1) defer dst.Close() BilateralFilter(src, &dst, 1, 2.2, 3.3, BorderDefault) } func TestBilateralFilterWithStream(t *testing.T) { src := NewGpuMatWithSize(256, 256, gocv.MatTypeCV8UC1) defer src.Close() dst := NewGpuMatWithSize(256, 256, gocv.MatTypeCV32SC1) defer dst.Close() s := NewStream() defer s.Close() BilateralFilterWithStream(src, &dst, 1, 2.2, 3.3, BorderDefault, s) s.WaitForCompletion() } func TestBlendLinear(t *testing.T) { img1 := NewGpuMatWithSize(256, 256, gocv.MatTypeCV8UC1) defer img1.Close() img2 := NewGpuMatWithSize(256, 256, gocv.MatTypeCV8UC1) defer img2.Close() result := NewGpuMatWithSize(256, 256, gocv.MatTypeCV8UC1) defer result.Close() weights1 := NewGpuMatWithSize(256, 256, gocv.MatTypeCV32FC1) defer weights1.Close() weights2 := NewGpuMatWithSize(256, 256, gocv.MatTypeCV32FC1) defer weights2.Close() BlendLinear(img1, img2, weights1, weights2, &result) } func TestBlendLinearWithStream(t *testing.T) { img1 := NewGpuMatWithSize(256, 256, gocv.MatTypeCV8UC1) defer img1.Close() img2 := NewGpuMatWithSize(256, 256, gocv.MatTypeCV8UC1) defer img2.Close() result := NewGpuMatWithSize(256, 256, gocv.MatTypeCV8UC1) defer result.Close() weights1 := NewGpuMatWithSize(256, 256, gocv.MatTypeCV32FC1) defer weights1.Close() weights2 := NewGpuMatWithSize(256, 256, gocv.MatTypeCV32FC1) defer weights2.Close() s := NewStream() defer s.Close() BlendLinearWithStream(img1, img2, weights1, weights2, &result, s) s.WaitForCompletion() } func TestMeanShiftFiltering(t *testing.T) { src := NewGpuMatWithSize(256, 256, gocv.MatTypeCV8UC4) defer src.Close() dst := NewGpuMatWithSize(256, 256, gocv.MatTypeCV8UC4) defer dst.Close() criteria := gocv.NewTermCriteria(gocv.Count, 1, 2.2) MeanShiftFiltering(src, &dst, 1, 2, criteria) } func TestMeanShiftFilteringWithStream(t *testing.T) { src := NewGpuMatWithSize(256, 256, gocv.MatTypeCV8UC4) defer src.Close() dst := NewGpuMatWithSize(256, 256, gocv.MatTypeCV8UC4) defer dst.Close() criteria := gocv.NewTermCriteria(gocv.Count, 1, 2.2) s := NewStream() defer s.Close() MeanShiftFilteringWithStream(src, &dst, 1, 2, criteria, s) s.WaitForCompletion() } func TestMeanShiftProc(t *testing.T) { src := NewGpuMatWithSize(256, 256, gocv.MatTypeCV8UC4) defer src.Close() dstr := NewGpuMatWithSize(256, 256, gocv.MatTypeCV8UC4) defer dstr.Close() dstsp := NewGpuMatWithSize(256, 256, gocv.MatTypeCV16SC2) defer dstsp.Close() criteria := gocv.NewTermCriteria(gocv.Count, 1, 2.2) MeanShiftProc(src, &dstr, &dstsp, 1, 2, criteria) } func TestMeanShiftProcWithStream(t *testing.T) { src := NewGpuMatWithSize(256, 256, gocv.MatTypeCV8UC4) defer src.Close() dstr := NewGpuMatWithSize(256, 256, gocv.MatTypeCV8UC4) defer dstr.Close() dstsp := NewGpuMatWithSize(256, 256, gocv.MatTypeCV16SC2) defer dstsp.Close() criteria := gocv.NewTermCriteria(gocv.Count, 1, 2.2) s := NewStream() defer s.Close() MeanShiftProcWithStream(src, &dstr, &dstsp, 1, 2, criteria, s) s.WaitForCompletion() } func TestMeanShiftSegmentation(t *testing.T) { src := NewGpuMatWithSize(256, 256, gocv.MatTypeCV8UC4) defer src.Close() dst := NewGpuMatWithSize(256, 256, gocv.MatTypeCV8UC4) defer dst.Close() criteria := gocv.NewTermCriteria(gocv.Count, 1, 2.2) MeanShiftSegmentation(src, &dst, 1, 2, 3, criteria) } func TestMeanShiftSegmentationWithStream(t *testing.T) { src := NewGpuMatWithSize(256, 256, gocv.MatTypeCV8UC4) defer src.Close() dst := NewGpuMatWithSize(256, 256, gocv.MatTypeCV8UC4) defer dst.Close() criteria := gocv.NewTermCriteria(gocv.Count, 1, 2.2) s := NewStream() defer s.Close() MeanShiftSegmentationWithStream(src, &dst, 1, 2, 3, criteria, s) s.WaitForCompletion() } ================================================ FILE: cuda/objdetect.cpp ================================================ //go:build !gocv_specific_modules || (gocv_specific_modules && gocv_cuda_objdetect) #include "../core.h" #include "cuda.h" #include "objdetect.h" // CascadeClassifier_GPU CascadeClassifier_GPU CascadeClassifier_GPU_Create(const char* cascade_name) { try { return new cv::Ptr(cv::cuda::CascadeClassifier::create(cascade_name)); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } struct Rects CascadeClassifier_GPU_DetectMultiScale(CascadeClassifier_GPU cs, GpuMat img) { try { std::vector detected; cv::cuda::GpuMat objbuf; (*cs)->detectMultiScale(*img, objbuf); // uses all default parameters (*cs)->convert(objbuf, detected); Rect* rects = new Rect[detected.size()]; for (size_t i = 0; i < detected.size(); ++i) { Rect r = {detected[i].x, detected[i].y, detected[i].width, detected[i].height}; rects[i] = r; } Rects ret = {rects, (int)detected.size()}; return ret; } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); Rects ret = {NULL, 0}; return ret; } } // HOG HOG HOG_Create() { try { return new cv::Ptr(cv::cuda::HOG::create()); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } HOG HOG_CreateWithParams(Size winSize, Size blockSize, Size blockStride, Size cellSize, int nbins) { try { cv::Size winSz(winSize.width, winSize.height); cv::Size blockSz(blockSize.width, blockSize.height); cv::Size blockSt(blockStride.width, blockStride.height); cv::Size cellSz(cellSize.width, cellSize.height); return new cv::Ptr(cv::cuda::HOG::create(winSz, blockSz, blockSt, cellSz, nbins)); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } struct Rects HOG_DetectMultiScale(HOG hog, GpuMat img) { try { std::vector detected; (*hog)->detectMultiScale(*img, detected); Rect* rects = new Rect[detected.size()]; for (size_t i = 0; i < detected.size(); ++i) { Rect r = {detected[i].x, detected[i].y, detected[i].width, detected[i].height}; rects[i] = r; } Rects ret = {rects, (int)detected.size()}; return ret; } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); Rects ret = {NULL, 0}; return ret; } } GpuMat HOG_Compute(HOG hog, GpuMat img) { try { GpuMat dst = new cv::cuda::GpuMat(); (*hog)->compute(*img, *dst); return dst; } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } Mat HOG_GetPeopleDetector(HOG hog) { try { return new cv::Mat((*hog)->getDefaultPeopleDetector()); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return new cv::Mat(); } } void HOG_SetSVMDetector(HOG hog, Mat det) { try { (*hog)->setSVMDetector(*det); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); } } int HOG_GetDescriptorFormat(HOG hog) { try { return int((*hog)->getDescriptorFormat()); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return 0; } } size_t HOG_GetBlockHistogramSize(HOG hog) { try { return size_t((*hog)->getBlockHistogramSize()); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return 0; } } size_t HOG_GetDescriptorSize(HOG hog) { try { return size_t((*hog)->getDescriptorSize()); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return 0; } } bool HOG_GetGammaCorrection(HOG hog) { try { return bool((*hog)->getGammaCorrection()); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return false; } } int HOG_GetGroupThreshold(HOG hog) { try { return int((*hog)->getGroupThreshold()); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return 0; } } double HOG_GetHitThreshold(HOG hog) { try { return double((*hog)->getHitThreshold()); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return 0.0; } } double HOG_GetL2HysThreshold(HOG hog) { try { return double((*hog)->getL2HysThreshold()); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return 0.0; } } int HOG_GetNumLevels(HOG hog) { try { return int((*hog)->getNumLevels()); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return 0; } } double HOG_GetScaleFactor(HOG hog) { try { return double((*hog)->getScaleFactor()); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return 0.0; } } double HOG_GetWinSigma(HOG hog) { try { return double((*hog)->getWinSigma()); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return 0.0; } } struct Size HOG_GetWinStride(HOG hog) { try { cv::Size sz = (*hog)->getWinStride(); Size size = {sz.width, sz.height}; return size; } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); Size size = {0, 0}; return size; } } void HOG_SetDescriptorFormat(HOG hog, int descrFormat) { try { auto df = static_cast(descrFormat); (*hog)->setDescriptorFormat(df); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); } } void HOG_SetGammaCorrection(HOG hog, bool gammaCorrection) { try { (*hog)->setGammaCorrection(gammaCorrection); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); } } void HOG_SetGroupThreshold(HOG hog, int groupThreshold) { try { (*hog)->setGroupThreshold(groupThreshold); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); } } void HOG_SetHitThreshold(HOG hog, double hitThreshold) { try { (*hog)->setHitThreshold(hitThreshold); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); } } void HOG_SetL2HysThreshold(HOG hog, double thresholdL2hys) { try { (*hog)->setL2HysThreshold(thresholdL2hys); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); } } void HOG_SetNumLevels(HOG hog, int nlevels) { try { (*hog)->setNumLevels(nlevels); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); } } void HOG_SetScaleFactor(HOG hog, double scale0) { try { (*hog)->setScaleFactor(scale0); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); } } void HOG_SetWinSigma(HOG hog, double winSigma) { try { (*hog)->setWinSigma(winSigma); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); } } void HOG_SetWinStride(HOG hog, Size dsize) { try { cv::Size sz(dsize.width, dsize.height); (*hog)->setWinStride(sz); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); } } ================================================ FILE: cuda/objdetect.go ================================================ //go:build !gocv_specific_modules || (gocv_specific_modules && gocv_cuda_objdetect) // Package cuda is the GoCV wrapper around OpenCV cuda. // // For further details, please see: // https://github.com/opencv/c // // import "gocv.io/x/gocv/cuda" package cuda /* #include #include "../core.h" #include "objdetect.h" #include "core.h" */ import "C" import ( "image" "unsafe" ) type DescriptorStorageFormat int const ( DESCR_FORMAT_COL_BY_COL DescriptorStorageFormat = 0 DESCR_FORMAT_COL_BY_ROW DescriptorStorageFormat = 1 ) // CascadeClassifier_GPU is a cascade classifier class for object detection. // // For further details, please see: // https://docs.opencv.org/master/d9/d80/classcv_1_1cuda_1_1CascadeClassifier.html type CascadeClassifier struct { p unsafe.Pointer } // NewCascadeClassifier_GPU returns a new CascadeClassifier. func NewCascadeClassifier(name string) CascadeClassifier { cName := C.CString(name) defer C.free(unsafe.Pointer(cName)) return CascadeClassifier{p: unsafe.Pointer(C.CascadeClassifier_GPU_Create(cName))} } // DetectMultiScale detects objects of different sizes in the input Mat image. // The detected objects are returned as a slice of image.Rectangle structs. // // For further details, please see: // https://docs.opencv.org/master/d9/d80/classcv_1_1cuda_1_1CascadeClassifier.html#a182656b878046eb3f0e9c0f0ee327f08 func (c *CascadeClassifier) DetectMultiScale(img GpuMat) []image.Rectangle { ret := C.CascadeClassifier_GPU_DetectMultiScale(C.CascadeClassifier_GPU(c.p), img.p) defer C.GpuRects_Close(ret) return toRectangles(ret) } // HOG is a Histogram Of Gradiants (HOG) for object detection. // // For further details, please see: // https://docs.opencv.org/master/d5/d33/structcv_1_1HOG.html#a723b95b709cfd3f95cf9e616de988fc8 type HOG struct { p unsafe.Pointer } // NewHOG returns a new HOG. func CreateHOG() HOG { return HOG{p: unsafe.Pointer(C.HOG_Create())} } func CreateHOGWithParams(winSize, blockSize, blockStride, cellSize image.Point, nbins int) HOG { wSz := C.struct_Size{ width: C.int(winSize.X), height: C.int(winSize.Y), } bSz := C.struct_Size{ width: C.int(blockSize.X), height: C.int(blockSize.Y), } bSt := C.struct_Size{ width: C.int(blockStride.X), height: C.int(blockStride.Y), } cSz := C.struct_Size{ width: C.int(cellSize.X), height: C.int(cellSize.Y), } return HOG{p: unsafe.Pointer(C.HOG_CreateWithParams(wSz, bSz, bSt, cSz, C.int(nbins)))} } // Compute returns block descriptors computed for the whole image. // // For further details, please see: // https://docs.opencv.org/master/de/da6/classcv_1_1cuda_1_1HOG.html#ab4287267081959ec77c01269dbfcd373 func (h *HOG) Compute(img GpuMat) GpuMat { return newGpuMat(C.HOG_Compute(C.HOG(h.p), img.p)) } // DetectMultiScale detects objects in the input Mat image. // The detected objects are returned as a slice of image.Rectangle structs. // // For further details, please see: // https://docs.opencv.org/master/d5/d33/structcv_1_1HOG.html#a660e5cd036fd5ddf0f5767b352acd948 func (h *HOG) DetectMultiScale(img GpuMat) []image.Rectangle { ret := C.HOG_DetectMultiScale(C.HOG(h.p), img.p) defer C.GpuRects_Close(ret) return toRectangles(ret) } // GetDefaultPeopleDetector returns a new Mat with the HOG DefaultPeopleDetector. // // For further details, please see: // https://docs.opencv.org/master/de/da6/classcv_1_1cuda_1_1HOG.html#a016f9ffced8b2f4b20bdd06a775017d1 func (h *HOG) GetDefaultPeopleDetector() C.Mat { return C.Mat(C.HOG_GetPeopleDetector(C.HOG(h.p))) } // SetSVMDetector sets the data for the HOG. // // For further details, please see: // https://docs.opencv.org/master/de/da6/classcv_1_1cuda_1_1HOG.html#a5d12db2277b7c3c849d75258eec8d1d4 func (h *HOG) SetSVMDetector(det C.Mat) error { C.HOG_SetSVMDetector(C.HOG(h.p), det) return nil } // GetDescriptorFormat // // For further details, please see: // https://docs.opencv.org/master/de/da6/classcv_1_1cuda_1_1HOG.html#adad29ed960a953aa13dc59c410683620 func (h *HOG) GetDescriptorFormat() DescriptorStorageFormat { return DescriptorStorageFormat(C.HOG_GetDescriptorFormat(C.HOG(h.p))) } // GetBlockHistogramSize returns the block histogram size. // // For further details, please see: // https://docs.opencv.org/master/de/da6/classcv_1_1cuda_1_1HOG.html#a016f9ffced8b2f4b20bdd06a775017d1 func (h *HOG) GetBlockHistogramSize() int { return int(C.HOG_GetBlockHistogramSize(C.HOG(h.p))) } // GetDescriptorFormat returns the number of coefficients required for the classification. // // For further details, please see: // https://docs.opencv.org/master/de/da6/classcv_1_1cuda_1_1HOG.html#adb8c714cba1a025b8869d5a0e152f824 func (h *HOG) GetDescriptorSize() int { return int(C.HOG_GetDescriptorSize(C.HOG(h.p))) } // GetGammaCorrection // // For further details, please see: // https://docs.opencv.org/master/de/da6/classcv_1_1cuda_1_1HOG.html#a7032eed27cf7a004b727a6e522c2404e func (h *HOG) GetGammaCorrection() bool { return bool(C.HOG_GetGammaCorrection(C.HOG(h.p))) } // GetGroupThreshold // // For further details, please see: // https://docs.opencv.org/master/de/da6/classcv_1_1cuda_1_1HOG.html#a7032eed27cf7a004b727a6e522c2404e func (h *HOG) GetGroupThreshold() int { return int(C.HOG_GetGroupThreshold(C.HOG(h.p))) } // GetHitThreshold // // For further details, please see: // https://docs.opencv.org/master/de/da6/classcv_1_1cuda_1_1HOG.html#ae0de149980ea47fbd39b7766df565b27 func (h *HOG) GetHitThreshold() float64 { return float64(C.HOG_GetHitThreshold(C.HOG(h.p))) } // GetL2HysThreshold // // For further details, please see: // https://docs.opencv.org/master/de/da6/classcv_1_1cuda_1_1HOG.html#a6853c9a66889fed996678f7972df9660 func (h *HOG) GetL2HysThreshold() float64 { return float64(C.HOG_GetL2HysThreshold(C.HOG(h.p))) } // GetNumLevels // // For further details, please see: // https://docs.opencv.org/master/de/da6/classcv_1_1cuda_1_1HOG.html#a15238eb6f52a1ddeedd015773c46efd8 func (h *HOG) GetNumLevels() int { return int(C.HOG_GetNumLevels(C.HOG(h.p))) } // GetScaleFactor // // For further details, please see: // https://docs.opencv.org/master/de/da6/classcv_1_1cuda_1_1HOG.html#a89c59564625bb2c691af8c2cf49aab9e func (h *HOG) GetScaleFactor() float64 { return float64(C.HOG_GetScaleFactor(C.HOG(h.p))) } // GetWinSigma // // For further details, please see: // https://docs.opencv.org/master/de/da6/classcv_1_1cuda_1_1HOG.html#a22d03fa05b251b4f19cfa1fab36e754e func (h *HOG) GetWinSigma() float64 { return float64(C.HOG_GetWinSigma(C.HOG(h.p))) } // GetWinStride // // For further details, please see: // https://docs.opencv.org/master/de/da6/classcv_1_1cuda_1_1HOG.html#a6c63504790b51963ca33496a0b039b48 func (h *HOG) GetWinStride() image.Point { sz := C.HOG_GetWinStride(C.HOG(h.p)) return image.Pt(int(sz.width), int(sz.height)) } // SetDescriptorFormat // // For further details, please see: // https://docs.opencv.org/master/de/da6/classcv_1_1cuda_1_1HOG.html#a6e3e1075a567268f2dfb2151b1c99cb6 func (h *HOG) SetDescriptorFormat(descrFormat DescriptorStorageFormat) { C.HOG_SetDescriptorFormat(C.HOG(h.p), C.int(descrFormat)) } // SetGammaCorrection // // For further details, please see: // https://docs.opencv.org/master/de/da6/classcv_1_1cuda_1_1HOG.html#a0eb2f1ecf59ccc599bffac3a0a55562f func (h *HOG) SetGammaCorrection(gammaCorrection bool) { C.HOG_SetGammaCorrection(C.HOG(h.p), C.bool(gammaCorrection)) } // SetGroupThreshold // // For further details, please see: // https://docs.opencv.org/master/de/da6/classcv_1_1cuda_1_1HOG.html#adad9af4e4ed0e0a045a70cd44520eefd func (h *HOG) SetGroupThreshold(groupThreshold int) { C.HOG_SetGroupThreshold(C.HOG(h.p), C.int(groupThreshold)) } // SetHitThreshold // // For further details, please see: // https://docs.opencv.org/master/de/da6/classcv_1_1cuda_1_1HOG.html#a8b623393c11d18b89fa373269b97aea4 func (h *HOG) SetHitThreshold(hitThreshold float64) { C.HOG_SetHitThreshold(C.HOG(h.p), C.double(hitThreshold)) } // SetL2HysThreshold // // For further details, please see: // https://docs.opencv.org/master/de/da6/classcv_1_1cuda_1_1HOG.html#a30e5c88864fff774f403313993947d62 func (h *HOG) SetL2HysThreshold(thresholdL2hys float64) { C.HOG_SetL2HysThreshold(C.HOG(h.p), C.double(thresholdL2hys)) } // SetNumLevels // // For further details, please see: // https://docs.opencv.org/master/de/da6/classcv_1_1cuda_1_1HOG.html#a7602088f3e792de196f8f7efcd9bd448 func (h *HOG) SetNumLevels(nlevels int) { C.HOG_SetNumLevels(C.HOG(h.p), C.int(nlevels)) } // SetScaleFactor // // For further details, please see: // https://docs.opencv.org/master/de/da6/classcv_1_1cuda_1_1HOG.html#a21dc5e3dc6272030694d52e83352b337 func (h *HOG) SetScaleFactor(scale0 float64) { C.HOG_SetScaleFactor(C.HOG(h.p), C.double(scale0)) } // SetWinSigma // // For further details, please see: // https://docs.opencv.org/master/de/da6/classcv_1_1cuda_1_1HOG.html#ab291779ff8ac649174b102f64c5f9012 func (h *HOG) SetWinSigma(winSigma float64) { C.HOG_SetWinSigma(C.HOG(h.p), C.double(winSigma)) } // SetWinStride // // For further details, please see: // https://docs.opencv.org/master/de/da6/classcv_1_1cuda_1_1HOG.html#a5e74646651209ae13f1b3dd18179773f func (h *HOG) SetWinStride(sz image.Point) { pSize := C.struct_Size{ width: C.int(sz.X), height: C.int(sz.Y), } C.HOG_SetWinStride(C.HOG(h.p), pSize) return } ================================================ FILE: cuda/objdetect.h ================================================ #ifndef _OPENCV3_GPU_H_ #define _OPENCV3_GPU_H_ #include #ifdef __cplusplus #include #include #include extern "C" { #endif #include "../core.h" #include "cuda.h" #ifdef __cplusplus typedef cv::Ptr* CascadeClassifier_GPU; typedef cv::Ptr* HOG; #else typedef void* CascadeClassifier_GPU; typedef void* HOG; #endif // CascadeClassifier CascadeClassifier_GPU CascadeClassifier_GPU_Create(const char* cascade_name); struct Rects CascadeClassifier_GPU_DetectMultiScale(CascadeClassifier_GPU cs, GpuMat img); // HOG HOG HOG_Create(); HOG HOG_CreateWithParams(Size winSize, Size blockSize, Size blockStride, Size cellSize, int nbins); struct Rects HOG_DetectMultiScale(HOG hog, GpuMat img); GpuMat HOG_Compute(HOG hog, GpuMat img); Mat HOG_GetPeopleDetector(HOG hog); void HOG_SetSVMDetector(HOG hog, Mat det); int HOG_GetDescriptorFormat(HOG hog); size_t HOG_GetBlockHistogramSize(HOG hog); size_t HOG_GetDescriptorSize(HOG hog); bool HOG_GetGammaCorrection(HOG hog); int HOG_GetGroupThreshold(HOG hog); double HOG_GetHitThreshold(HOG hog); double HOG_GetL2HysThreshold(HOG hog); int HOG_GetNumLevels(HOG hog); double HOG_GetScaleFactor(HOG hog); double HOG_GetWinSigma(HOG hog); struct Size HOG_GetWinStride(HOG hog); void HOG_SetDescriptorFormat(HOG hog, int descrFormat); void HOG_SetGammaCorrection(HOG hog, bool gammaCorrection); void HOG_SetGroupThreshold(HOG hog, int groupThreshold); void HOG_SetHitThreshold(HOG hog, double hitThreshold); void HOG_SetL2HysThreshold(HOG hog, double thresholdL2hys); void HOG_SetNumLevels(HOG hog, int nlevels); void HOG_SetScaleFactor(HOG hog, double scale0); void HOG_SetWinSigma(HOG hog, double winSigma); void HOG_SetWinStride(HOG hog, Size dsize); #ifdef __cplusplus } #endif #endif //_OPENCV3_GPU_H_ ================================================ FILE: cuda/optflow.cpp ================================================ //go:build !gocv_specific_modules || (gocv_specific_modules && gocv_cuda_optflow) #include "optflow.h" CudaSparsePyrLKOpticalFlow CudaSparsePyrLKOpticalFlow_Create() { try { return new cv::Ptr(cv::cuda::SparsePyrLKOpticalFlow::create()); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } OpenCVResult CudaSparsePyrLKOpticalFlow_Calc(CudaSparsePyrLKOpticalFlow p, GpuMat prevImg, GpuMat nextImg, GpuMat prevPts, GpuMat nextPts, GpuMat status){ try { (*p)->calc(*prevImg,*nextImg,*prevPts,*nextPts,*status); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } ================================================ FILE: cuda/optflow.go ================================================ //go:build !gocv_specific_modules || (gocv_specific_modules && gocv_cuda_optflow) package cuda /* #include #include "cuda.h" #include "optflow.h" */ import "C" import "unsafe" // SparsePyrLKOpticalFlow is a wrapper around the cv::cuda::SparsePyrLKOpticalFlow. type SparsePyrLKOpticalFlow struct { // C.SparsePyrLKOpticalFlow p unsafe.Pointer } // NewSparsePyrLKOpticalFlow returns a new SparsePyrLKOpticalFlow // // For further details, please see: // https://docs.opencv.org/master/d7/d05/classcv_1_1cuda_1_1SparsePyrLKOpticalFlow.html#a6bcd2d457532d7db76c3e7f11b60063b func NewSparsePyrLKOpticalFlow() SparsePyrLKOpticalFlow { return SparsePyrLKOpticalFlow{p: unsafe.Pointer(C.CudaSparsePyrLKOpticalFlow_Create())} } // Calc calculates a sparse optical flow. // // For further details, please see: // https://docs.opencv.org/master/d5/dcf/classcv_1_1cuda_1_1SparseOpticalFlow.html#a80d5efbb7788e3dc4c49e6226ba34347 func (s SparsePyrLKOpticalFlow) Calc(prevImg, nextImg, prevPts, nextPts, status GpuMat) error { return OpenCVResult(C.CudaSparsePyrLKOpticalFlow_Calc(C.CudaSparsePyrLKOpticalFlow(s.p), prevImg.p, nextImg.p, prevPts.p, nextPts.p, status.p)) } ================================================ FILE: cuda/optflow.h ================================================ #ifndef _OPENCV_CUDAOPTFLOW_HPP_ #define _OPENCV_CUDAOPTFLOW_HPP_ #ifdef __cplusplus #include #include #include extern "C" { #endif #include "../core.h" #include "cuda.h" #ifdef __cplusplus typedef cv::Ptr* CudaSparsePyrLKOpticalFlow; #else typedef void* CudaSparsePyrLKOpticalFlow; #endif CudaSparsePyrLKOpticalFlow CudaSparsePyrLKOpticalFlow_Create(); OpenCVResult CudaSparsePyrLKOpticalFlow_Calc(CudaSparsePyrLKOpticalFlow p, GpuMat prevImg, GpuMat nextImg, GpuMat prevPts, GpuMat nextPts, GpuMat status); #ifdef __cplusplus } #endif #endif // _OPENCV_CUDAOPTFLOW_HPP_ ================================================ FILE: cuda/optflow_test.go ================================================ //go:build !gocv_specific_modules || (gocv_specific_modules && gocv_cuda_optflow) package cuda import "testing" func TestSparsePyrLKOpticalFlow_Calc(t *testing.T) { prevImg := NewGpuMat() defer prevImg.Close() nextImg := NewGpuMat() defer nextImg.Close() prevPts := NewGpuMat() defer prevPts.Close() nextPts := NewGpuMat() defer nextPts.Close() status := NewGpuMat() defer status.Close() pyrLk := NewSparsePyrLKOpticalFlow() pyrLk.Calc(prevImg, nextImg, prevPts, nextPts, status) } ================================================ FILE: cuda/warping.cpp ================================================ //go:build !gocv_specific_modules || (gocv_specific_modules && gocv_cuda_warping) #include "warping.h" OpenCVResult CudaResize(GpuMat src, GpuMat dst, Size dsize, double fx, double fy, int interp, Stream s) { try { cv::Size sz(dsize.width, dsize.height); if (s == NULL) { cv::cuda::resize(*src, *dst, sz, fx, fy, interp); } else { cv::cuda::resize(*src, *dst, sz, fx, fy, interp, *s); } return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult CudaPyrDown(GpuMat src, GpuMat dst, Stream s) { try { if (s == NULL) { cv::cuda::pyrDown(*src, *dst); } else { cv::cuda::pyrDown(*src, *dst, *s); } return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult CudaPyrUp(GpuMat src, GpuMat dst, Stream s) { try { if (s == NULL) { cv::cuda::pyrUp(*src, *dst); } else { cv::cuda::pyrUp(*src, *dst, *s); } return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult CudaBuildWarpAffineMaps(GpuMat M, bool inverse, Size dsize, GpuMat xmap, GpuMat ymap, Stream s) { try { cv::Size sz(dsize.width, dsize.height); if (s == NULL) { cv::cuda::buildWarpAffineMaps(*M, inverse, sz, *xmap, *ymap); } else { cv::cuda::buildWarpAffineMaps(*M, inverse, sz, *xmap, *ymap, *s); } return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult CudaBuildWarpPerspectiveMaps(GpuMat M, bool inverse, Size dsize, GpuMat xmap, GpuMat ymap, Stream s) { try { cv::Size sz(dsize.width, dsize.height); if (s == NULL) { cv::cuda::buildWarpPerspectiveMaps(*M, inverse, sz, *xmap, *ymap); } else { cv::cuda::buildWarpPerspectiveMaps(*M, inverse, sz, *xmap, *ymap, *s); } return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult CudaRemap(GpuMat src, GpuMat dst, GpuMat xmap, GpuMat ymap, int interp, int borderMode, Scalar borderValue, Stream s) { try { cv::Scalar c = cv::Scalar(borderValue.val1, borderValue.val2, borderValue.val3, borderValue.val4); if (s == NULL) { cv::cuda::remap(*src, *dst, *xmap, *ymap, interp, borderMode, c); } else { cv::cuda::remap(*src, *dst, *xmap, *ymap, interp, borderMode, c, *s); } return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult CudaRotate(GpuMat src, GpuMat dst, Size dsize, double angle, double xShift, double yShift, int interp, Stream s) { try { cv::Size sz(dsize.width, dsize.height); if (s == NULL) { cv::cuda::rotate(*src, *dst, sz, angle, xShift, yShift, interp); } else { cv::cuda::rotate(*src, *dst, sz, angle, xShift, yShift, interp, *s); } return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult CudaWarpAffine(GpuMat src, GpuMat dst, GpuMat M, Size dsize, int flags, int borderMode, Scalar borderValue, Stream s) { try { cv::Scalar c = cv::Scalar(borderValue.val1, borderValue.val2, borderValue.val3, borderValue.val4); cv::Size sz(dsize.width, dsize.height); if (s == NULL) { cv::cuda::warpAffine(*src, *dst, *M, sz, flags, borderMode, c); } else { cv::cuda::warpAffine(*src, *dst, *M, sz, flags, borderMode, c, *s); } return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult CudaWarpPerspective(GpuMat src, GpuMat dst, GpuMat M, Size dsize, int flags, int borderMode, Scalar borderValue, Stream s) { try { cv::Scalar c = cv::Scalar(borderValue.val1, borderValue.val2, borderValue.val3, borderValue.val4); cv::Size sz(dsize.width, dsize.height); if (s == NULL) { cv::cuda::warpPerspective(*src, *dst, *M, sz, flags, borderMode, c); } else { cv::cuda::warpPerspective(*src, *dst, *M, sz, flags, borderMode, c, *s); } return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } ================================================ FILE: cuda/warping.go ================================================ //go:build !gocv_specific_modules || (gocv_specific_modules && gocv_cuda_warping) package cuda /* #include #include "warping.h" */ import "C" import ( "image" "image/color" ) // InterpolationFlags are bit flags that control the interpolation algorithm // that is used. type InterpolationFlags int const ( // InterpolationNearestNeighbor is nearest neighbor. (fast but low quality) InterpolationNearestNeighbor InterpolationFlags = 0 // InterpolationLinear is bilinear interpolation. InterpolationLinear InterpolationFlags = 1 // InterpolationCubic is bicube interpolation. InterpolationCubic InterpolationFlags = 2 // InterpolationArea uses pixel area relation. It is preferred for image // decimation as it gives moire-free results. InterpolationArea InterpolationFlags = 3 // InterpolationLanczos4 is Lanczos interpolation over 8x8 neighborhood. InterpolationLanczos4 InterpolationFlags = 4 // InterpolationDefault is an alias for InterpolationLinear. InterpolationDefault = InterpolationLinear // InterpolationMax indicates use maximum interpolation. InterpolationMax InterpolationFlags = 7 ) // BorderType type of border. type BorderType int const ( // BorderConstant border type BorderConstant BorderType = 0 // BorderReplicate border type BorderReplicate BorderType = 1 // BorderReflect border type BorderReflect BorderType = 2 // BorderWrap border type BorderWrap BorderType = 3 // BorderReflect101 border type BorderReflect101 BorderType = 4 // BorderTransparent border type BorderTransparent BorderType = 5 // BorderDefault border type BorderDefault = BorderReflect101 // BorderIsolated border type BorderIsolated BorderType = 16 ) // Resize resizes an image. // // For further details, please see: // https://docs.opencv.org/master/db/d29/group__cudawarping.html#ga4f5fa0770d1c9efbadb9be1b92a6452a func Resize(src GpuMat, dst *GpuMat, sz image.Point, fx, fy float64, interp InterpolationFlags) error { pSize := C.struct_Size{ width: C.int(sz.X), height: C.int(sz.Y), } return OpenCVResult(C.CudaResize(src.p, dst.p, pSize, C.double(fx), C.double(fy), C.int(interp), nil)) } // ResizeWithStream resizes an image // using a Stream for concurrency. // // For further details, please see: // https://docs.opencv.org/master/db/d29/group__cudawarping.html#ga4f5fa0770d1c9efbadb9be1b92a6452a func ResizeWithStream(src GpuMat, dst *GpuMat, sz image.Point, fx, fy float64, interp InterpolationFlags, s Stream) error { pSize := C.struct_Size{ width: C.int(sz.X), height: C.int(sz.Y), } return OpenCVResult(C.CudaResize(src.p, dst.p, pSize, C.double(fx), C.double(fy), C.int(interp), s.p)) } // Rotate rotates an image around the origin (0,0) and then shifts it. // // For further details, please see: // https://docs.opencv.org/master/db/d29/group__cudawarping.html#ga55d958eceb0f871e04b1be0adc6ef1b5 func Rotate(src GpuMat, dst *GpuMat, sz image.Point, angle, xShift, yShift float64, interp InterpolationFlags) error { pSize := C.struct_Size{ width: C.int(sz.X), height: C.int(sz.Y), } return OpenCVResult(C.CudaRotate(src.p, dst.p, pSize, C.double(angle), C.double(xShift), C.double(yShift), C.int(interp), nil)) } // RotateWithStream rotates an image around the origin (0,0) and then shifts it // using a Stream for concurrency. // // For further details, please see: // https://docs.opencv.org/master/db/d29/group__cudawarping.html#ga55d958eceb0f871e04b1be0adc6ef1b5 func RotateWithStream(src GpuMat, dst *GpuMat, sz image.Point, angle, xShift, yShift float64, interp InterpolationFlags, s Stream) error { pSize := C.struct_Size{ width: C.int(sz.X), height: C.int(sz.Y), } return OpenCVResult(C.CudaRotate(src.p, dst.p, pSize, C.double(angle), C.double(xShift), C.double(yShift), C.int(interp), s.p)) } // Remap applies a generic geometrical transformation to an image. // // For further details, please see: // https://docs.opencv.org/master/db/d29/group__cudawarping.html#ga0ece6c76e8efa3171adb8432d842beb0 func Remap(src GpuMat, dst, xmap, ymap *GpuMat, interpolation InterpolationFlags, borderMode BorderType, borderValue color.RGBA) error { bv := C.struct_Scalar{ val1: C.double(borderValue.B), val2: C.double(borderValue.G), val3: C.double(borderValue.R), val4: C.double(borderValue.A), } return OpenCVResult(C.CudaRemap(src.p, dst.p, xmap.p, ymap.p, C.int(interpolation), C.int(borderMode), bv, nil)) } // RemapWithStream applies a generic geometrical transformation to an image // using a Stream for concurrency. // // For further details, please see: // https://docs.opencv.org/master/db/d29/group__cudawarping.html#ga0ece6c76e8efa3171adb8432d842beb0 func RemapWithStream(src GpuMat, dst, xmap, ymap *GpuMat, interpolation InterpolationFlags, borderMode BorderType, borderValue color.RGBA, s Stream) error { bv := C.struct_Scalar{ val1: C.double(borderValue.B), val2: C.double(borderValue.G), val3: C.double(borderValue.R), val4: C.double(borderValue.A), } return OpenCVResult(C.CudaRemap(src.p, dst.p, xmap.p, ymap.p, C.int(interpolation), C.int(borderMode), bv, s.p)) } // PyrDown blurs an image and downsamples it. // // For further details, please see: // https://docs.opencv.org/master/db/d29/group__cudawarping.html#ga9c8456de9792d96431e065f407c7a91b func PyrDown(src GpuMat, dst *GpuMat) error { return OpenCVResult(C.CudaPyrDown(src.p, dst.p, nil)) } // PyrDownWithStream blurs an image and downsamples it // using a Stream for concurrency. // // For further details, please see: // https://docs.opencv.org/master/db/d29/group__cudawarping.html#ga9c8456de9792d96431e065f407c7a91b func PyrDownWithStream(src GpuMat, dst *GpuMat, s Stream) error { return OpenCVResult(C.CudaPyrDown(src.p, dst.p, s.p)) } // PyrUp upsamples an image and then blurs it. // // For further details, please see: // https://docs.opencv.org/master/db/d29/group__cudawarping.html#ga2048da0dfdb9e4a726232c5cef7e5747 func PyrUp(src GpuMat, dst *GpuMat) error { return OpenCVResult(C.CudaPyrUp(src.p, dst.p, nil)) } // PyrUpWithStream upsamples an image and then blurs it // using a Stream for concurrency. // // For further details, please see: // https://docs.opencv.org/master/db/d29/group__cudawarping.html#ga2048da0dfdb9e4a726232c5cef7e5747 func PyrUpWithStream(src GpuMat, dst *GpuMat, s Stream) error { return OpenCVResult(C.CudaPyrUp(src.p, dst.p, s.p)) } // WarpPerspective applies a perspective transformation to an image. // // For further details, please see: // https://docs.opencv.org/master/db/d29/group__cudawarping.html#ga7a6cf95065536712de6b155f3440ccff func WarpPerspective(src GpuMat, dst *GpuMat, m GpuMat, sz image.Point, flags InterpolationFlags, borderType BorderType, borderValue color.RGBA) error { pSize := C.struct_Size{ width: C.int(sz.X), height: C.int(sz.Y), } bv := C.struct_Scalar{ val1: C.double(borderValue.B), val2: C.double(borderValue.G), val3: C.double(borderValue.R), val4: C.double(borderValue.A), } return OpenCVResult(C.CudaWarpPerspective(src.p, dst.p, m.p, pSize, C.int(flags), C.int(borderType), bv, nil)) } // WarpPerspectiveWithStream applies a perspective transformation to an image // using a Stream for concurrency. // // For further details, please see: // https://docs.opencv.org/master/db/d29/group__cudawarping.html#ga7a6cf95065536712de6b155f3440ccff func WarpPerspectiveWithStream(src GpuMat, dst *GpuMat, m GpuMat, sz image.Point, flags InterpolationFlags, borderType BorderType, borderValue color.RGBA, s Stream) error { pSize := C.struct_Size{ width: C.int(sz.X), height: C.int(sz.Y), } bv := C.struct_Scalar{ val1: C.double(borderValue.B), val2: C.double(borderValue.G), val3: C.double(borderValue.R), val4: C.double(borderValue.A), } return OpenCVResult(C.CudaWarpPerspective(src.p, dst.p, m.p, pSize, C.int(flags), C.int(borderType), bv, s.p)) } // WarpAffine applies an affine transformation to an image. For more parameters please check WarpAffineWithParams // // For further details, please see: // https://docs.opencv.org/master/db/d29/group__cudawarping.html#ga9e8dd9e73b96bdc8e27d85c0e83f1130 func WarpAffine(src GpuMat, dst *GpuMat, m GpuMat, sz image.Point, flags InterpolationFlags, borderType BorderType, borderValue color.RGBA) error { pSize := C.struct_Size{ width: C.int(sz.X), height: C.int(sz.Y), } bv := C.struct_Scalar{ val1: C.double(borderValue.B), val2: C.double(borderValue.G), val3: C.double(borderValue.R), val4: C.double(borderValue.A), } return OpenCVResult(C.CudaWarpAffine(src.p, dst.p, m.p, pSize, C.int(flags), C.int(borderType), bv, nil)) } // WarpAffineWithStream applies an affine transformation to an image // using a Stream for concurrency. // // # For more parameters please check WarpAffineWithParams // // For further details, please see: // https://docs.opencv.org/master/db/d29/group__cudawarping.html#ga9e8dd9e73b96bdc8e27d85c0e83f1130 func WarpAffineWithStream(src GpuMat, dst *GpuMat, m GpuMat, sz image.Point, flags InterpolationFlags, borderType BorderType, borderValue color.RGBA, s Stream) error { pSize := C.struct_Size{ width: C.int(sz.X), height: C.int(sz.Y), } bv := C.struct_Scalar{ val1: C.double(borderValue.B), val2: C.double(borderValue.G), val3: C.double(borderValue.R), val4: C.double(borderValue.A), } return OpenCVResult(C.CudaWarpAffine(src.p, dst.p, m.p, pSize, C.int(flags), C.int(borderType), bv, s.p)) } // BuildWarpAffineMaps builds transformation maps for affine transformation. // // For further details. please see: // https://docs.opencv.org/master/db/d29/group__cudawarping.html#ga63504590a96e4cc702d994281d17bc1c func BuildWarpAffineMaps(M GpuMat, inverse bool, sz image.Point, xmap, ymap *GpuMat) error { pSize := C.struct_Size{ width: C.int(sz.X), height: C.int(sz.Y), } return OpenCVResult(C.CudaBuildWarpAffineMaps(M.p, C.bool(inverse), pSize, xmap.p, ymap.p, nil)) } // BuildWarpAffineMapsWithStream builds transformation maps for affine transformation // using a Stream for concurrency. // // For further details. please see: // https://docs.opencv.org/master/db/d29/group__cudawarping.html#ga63504590a96e4cc702d994281d17bc1c func BuildWarpAffineMapsWithStream(M GpuMat, inverse bool, sz image.Point, xmap, ymap *GpuMat, s Stream) error { pSize := C.struct_Size{ width: C.int(sz.X), height: C.int(sz.Y), } return OpenCVResult(C.CudaBuildWarpAffineMaps(M.p, C.bool(inverse), pSize, xmap.p, ymap.p, s.p)) } // BuildWarpPerspectiveMaps builds transformation maps for perspective transformation. // // For further details, please see: // https://docs.opencv.org/master/db/d29/group__cudawarping.html#ga8d16e3003703bd3b89cca98c913ef864 func BuildWarpPerspectiveMaps(M GpuMat, inverse bool, sz image.Point, xmap, ymap *GpuMat) error { pSize := C.struct_Size{ width: C.int(sz.X), height: C.int(sz.Y), } return OpenCVResult(C.CudaBuildWarpPerspectiveMaps(M.p, C.bool(inverse), pSize, xmap.p, ymap.p, nil)) } // BuildWarpPerspectiveMapsWithStream builds transformation maps for perspective transformation // using a Stream for concurrency. // // For further details, please see: // https://docs.opencv.org/master/db/d29/group__cudawarping.html#ga8d16e3003703bd3b89cca98c913ef864 func BuildWarpPerspectiveMapsWithStream(M GpuMat, inverse bool, sz image.Point, xmap, ymap *GpuMat, s Stream) error { pSize := C.struct_Size{ width: C.int(sz.X), height: C.int(sz.Y), } return OpenCVResult(C.CudaBuildWarpPerspectiveMaps(M.p, C.bool(inverse), pSize, xmap.p, ymap.p, s.p)) } ================================================ FILE: cuda/warping.h ================================================ #ifndef _OPENCV3_CUDAWARPING_H_ #define _OPENCV3_CUDAWARPING_H_ #ifdef __cplusplus #include #include extern "C" { #endif #include "../core.h" #include "cuda.h" OpenCVResult CudaResize(GpuMat src, GpuMat dst, Size dsize, double fx, double fy, int interp, Stream s); OpenCVResult CudaPyrDown(GpuMat src, GpuMat dst, Stream s); OpenCVResult CudaPyrUp(GpuMat src, GpuMat dst, Stream s); OpenCVResult CudaBuildWarpAffineMaps(GpuMat M, bool inverse, Size dsize, GpuMat xmap, GpuMat ymap, Stream s); OpenCVResult CudaBuildWarpPerspectiveMaps(GpuMat M, bool inverse, Size dsize, GpuMat xmap, GpuMat ymap, Stream s); OpenCVResult CudaRemap(GpuMat src, GpuMat dst, GpuMat xmap, GpuMat ymap, int interp, int borderMode, Scalar borderValue, Stream s); OpenCVResult CudaRotate(GpuMat src, GpuMat dst, Size dsize, double angle, double xShift, double yShift, int interp, Stream s); OpenCVResult CudaWarpAffine(GpuMat src, GpuMat dst, GpuMat M, Size dsize, int flags, int borderMode, Scalar borderValue, Stream s); OpenCVResult CudaWarpPerspective(GpuMat src, GpuMat dst, GpuMat M, Size dsize, int flags, int borderMode, Scalar borderValue, Stream s); #ifdef __cplusplus } #endif #endif //_OPENCV3_CUDAWARPING_H_ ================================================ FILE: cuda/warping_string.go ================================================ //go:build !gocv_specific_modules || (gocv_specific_modules && gocv_cuda_warping) package cuda func (c InterpolationFlags) String() string { switch c { case InterpolationNearestNeighbor: return "interpolation-nearest-neighbor" case InterpolationLinear: return "interpolation-linear" case InterpolationCubic: return "interpolation-cubic" case InterpolationArea: return "interpolation-area" case InterpolationLanczos4: return "interpolation-lanczos4" case InterpolationMax: return "interpolation-max" } return "" } func (c BorderType) String() string { switch c { case BorderConstant: return "border-constant" case BorderReplicate: return "border-replicate" case BorderWrap: return "border-wrap" case BorderReflect101: return "border-reflect101" case BorderTransparent: return "border-transparent" case BorderIsolated: return "border-isolated" } return "" } ================================================ FILE: cuda/warping_test.go ================================================ //go:build !gocv_specific_modules || (gocv_specific_modules && gocv_cuda_warping) package cuda import ( "image" "image/color" "math" "testing" "gocv.io/x/gocv" ) func TestResize(t *testing.T) { src := gocv.IMRead("../images/gocvlogo.jpg", gocv.IMReadColor) if src.Empty() { t.Error("Invalid read of Mat in Resize test") } defer src.Close() var cimg, dimg = NewGpuMat(), NewGpuMat() defer cimg.Close() defer dimg.Close() cimg.Upload(src) dst := gocv.NewMat() defer dst.Close() Resize(cimg, &dimg, image.Point{}, 0.5, 0.5, InterpolationDefault) dimg.Download(&dst) if dst.Cols() != 200 || dst.Rows() != 172 { t.Errorf("Expected dst size of 200x172 got %dx%d", dst.Cols(), dst.Rows()) } Resize(cimg, &dimg, image.Pt(440, 377), 0, 0, InterpolationCubic) dimg.Download(&dst) if dst.Cols() != 440 || dst.Rows() != 377 { t.Errorf("Expected dst size of 440x377 got %dx%d", dst.Cols(), dst.Rows()) } } func TestResizeWithStream(t *testing.T) { src := gocv.IMRead("../images/gocvlogo.jpg", gocv.IMReadColor) if src.Empty() { t.Error("Invalid read of Mat in Resize test") } defer src.Close() var cimg, dimg = NewGpuMat(), NewGpuMat() defer cimg.Close() defer dimg.Close() cimg.Upload(src) dst := gocv.NewMat() defer dst.Close() stream := NewStream() defer stream.Close() ResizeWithStream(cimg, &dimg, image.Point{}, 0.5, 0.5, InterpolationDefault, stream) dimg.Download(&dst) if dst.Cols() != 200 || dst.Rows() != 172 { t.Errorf("Expected dst size of 200x172 got %dx%d", dst.Cols(), dst.Rows()) } ResizeWithStream(cimg, &dimg, image.Pt(440, 377), 0, 0, InterpolationCubic, stream) dimg.Download(&dst) if dst.Cols() != 440 || dst.Rows() != 377 { t.Errorf("Expected dst size of 440x377 got %dx%d", dst.Cols(), dst.Rows()) } } func TestPyrDown(t *testing.T) { src := gocv.IMRead("../images/face-detect.jpg", gocv.IMReadColor) if src.Empty() { t.Error("Invalid read of Mat in PyrDown test") } defer src.Close() var gsrc, gdst = NewGpuMat(), NewGpuMat() defer gsrc.Close() defer gdst.Close() gsrc.Upload(src) dst := gocv.NewMat() defer dst.Close() PyrDown(gsrc, &gdst) gdst.Download(&dst) if dst.Empty() && math.Abs(float64(src.Cols()-2*dst.Cols())) < 2.0 && math.Abs(float64(src.Rows()-2*dst.Rows())) < 2.0 { t.Error("Invalid PyrDown test") } } func TestPyrDownWithStream(t *testing.T) { src := gocv.IMRead("../images/face-detect.jpg", gocv.IMReadColor) if src.Empty() { t.Error("Invalid read of Mat in PyrDown test") } defer src.Close() var gsrc, gdst = NewGpuMat(), NewGpuMat() defer gsrc.Close() defer gdst.Close() gsrc.Upload(src) dst := gocv.NewMat() defer dst.Close() stream := NewStream() defer stream.Close() PyrDownWithStream(gsrc, &gdst, stream) gdst.Download(&dst) if dst.Empty() && math.Abs(float64(src.Cols()-2*dst.Cols())) < 2.0 && math.Abs(float64(src.Rows()-2*dst.Rows())) < 2.0 { t.Error("Invalid PyrDown test") } } func TestPyrUp(t *testing.T) { src := gocv.IMRead("../images/face-detect.jpg", gocv.IMReadColor) if src.Empty() { t.Error("Invalid read of Mat in PyrUp test") } defer src.Close() var gsrc, gdst = NewGpuMat(), NewGpuMat() defer gsrc.Close() defer gdst.Close() gsrc.Upload(src) dst := gocv.NewMat() defer dst.Close() PyrDown(gsrc, &gdst) if dst.Empty() && math.Abs(float64(2*src.Cols()-dst.Cols())) < 2.0 && math.Abs(float64(2*src.Rows()-dst.Rows())) < 2.0 { t.Error("Invalid PyrUp test") } } func TestPyrUpWithStream(t *testing.T) { src := gocv.IMRead("../images/face-detect.jpg", gocv.IMReadColor) if src.Empty() { t.Error("Invalid read of Mat in PyrUp test") } defer src.Close() var gsrc, gdst = NewGpuMat(), NewGpuMat() defer gsrc.Close() defer gdst.Close() gsrc.Upload(src) dst := gocv.NewMat() defer dst.Close() stream := NewStream() defer stream.Close() PyrDownWithStream(gsrc, &gdst, stream) if dst.Empty() && math.Abs(float64(2*src.Cols()-dst.Cols())) < 2.0 && math.Abs(float64(2*src.Rows()-dst.Rows())) < 2.0 { t.Error("Invalid PyrUp test") } } func TestRemap(t *testing.T) { src := gocv.IMRead("../images/gocvlogo.jpg", gocv.IMReadUnchanged) defer src.Close() dst := gocv.NewMat() defer dst.Close() map1 := gocv.NewMatWithSize(256, 256, gocv.MatTypeCV32F) defer map1.Close() map1.SetFloatAt(50, 50, 25.4) map2 := gocv.NewMatWithSize(256, 256, gocv.MatTypeCV32F) defer map2.Close() gsrc, gdst, gmap1, gmap2 := NewGpuMat(), NewGpuMat(), NewGpuMat(), NewGpuMat() gsrc.Upload(src) gmap1.Upload(map1) gmap2.Upload(map2) Remap(gsrc, &gdst, &gmap1, &gmap2, InterpolationDefault, BorderConstant, color.RGBA{0, 0, 0, 0}) gdst.Download(&dst) if ok := dst.Empty(); ok { t.Errorf("Remap(): dst is empty") } } func TestRemapWithStream(t *testing.T) { src := gocv.IMRead("../images/gocvlogo.jpg", gocv.IMReadUnchanged) defer src.Close() dst := gocv.NewMat() defer dst.Close() map1 := gocv.NewMatWithSize(256, 256, gocv.MatTypeCV32F) defer map1.Close() map1.SetFloatAt(50, 50, 25.4) map2 := gocv.NewMatWithSize(256, 256, gocv.MatTypeCV32F) defer map2.Close() gsrc, gdst, gmap1, gmap2 := NewGpuMat(), NewGpuMat(), NewGpuMat(), NewGpuMat() gsrc.Upload(src) gmap1.Upload(map1) gmap2.Upload(map2) stream := NewStream() defer stream.Close() RemapWithStream(gsrc, &gdst, &gmap1, &gmap2, InterpolationDefault, BorderConstant, color.RGBA{0, 0, 0, 0}, stream) gdst.Download(&dst) if ok := dst.Empty(); ok { t.Errorf("Remap(): dst is empty") } } ================================================ FILE: data/haarcascade_frontalface_default.xml ================================================ BOOST HAAR 24 24 211 0 25 <_> 9 -5.0425500869750977e+00 <_> 0 -1 0 -3.1511999666690826e-02 2.0875380039215088e+00 -2.2172100543975830e+00 <_> 0 -1 1 1.2396000325679779e-02 -1.8633940219879150e+00 1.3272049427032471e+00 <_> 0 -1 2 2.1927999332547188e-02 -1.5105249881744385e+00 1.0625729560852051e+00 <_> 0 -1 3 5.7529998011887074e-03 -8.7463897466659546e-01 1.1760339736938477e+00 <_> 0 -1 4 1.5014000236988068e-02 -7.7945697307586670e-01 1.2608419656753540e+00 <_> 0 -1 5 9.9371001124382019e-02 5.5751299858093262e-01 -1.8743000030517578e+00 <_> 0 -1 6 2.7340000960975885e-03 -1.6911929845809937e+00 4.4009700417518616e-01 <_> 0 -1 7 -1.8859000876545906e-02 -1.4769539833068848e+00 4.4350099563598633e-01 <_> 0 -1 8 5.9739998541772366e-03 -8.5909199714660645e-01 8.5255599021911621e-01 <_> 16 -4.9842400550842285e+00 <_> 0 -1 9 -2.1110000088810921e-02 1.2435649633407593e+00 -1.5713009834289551e+00 <_> 0 -1 10 2.0355999469757080e-02 -1.6204780340194702e+00 1.1817760467529297e+00 <_> 0 -1 11 2.1308999508619308e-02 -1.9415930509567261e+00 7.0069098472595215e-01 <_> 0 -1 12 9.1660000383853912e-02 -5.5670100450515747e-01 1.7284419536590576e+00 <_> 0 -1 13 3.6288000643253326e-02 2.6763799786567688e-01 -2.1831810474395752e+00 <_> 0 -1 14 -1.9109999760985374e-02 -2.6730210781097412e+00 4.5670801401138306e-01 <_> 0 -1 15 8.2539999857544899e-03 -1.0852910280227661e+00 5.3564202785491943e-01 <_> 0 -1 16 1.8355000764131546e-02 -3.5200199484825134e-01 9.3339198827743530e-01 <_> 0 -1 17 -7.0569999516010284e-03 9.2782098054885864e-01 -6.6349899768829346e-01 <_> 0 -1 18 -9.8770000040531158e-03 1.1577470302581787e+00 -2.9774799942970276e-01 <_> 0 -1 19 1.5814000740647316e-02 -4.1960600018501282e-01 1.3576040267944336e+00 <_> 0 -1 20 -2.0700000226497650e-02 1.4590020179748535e+00 -1.9739399850368500e-01 <_> 0 -1 21 -1.3760800659656525e-01 1.1186759471893311e+00 -5.2915501594543457e-01 <_> 0 -1 22 1.4318999834358692e-02 -3.5127198696136475e-01 1.1440860033035278e+00 <_> 0 -1 23 1.0253000073134899e-02 -6.0850602388381958e-01 7.7098500728607178e-01 <_> 0 -1 24 9.1508001089096069e-02 3.8817799091339111e-01 -1.5122940540313721e+00 <_> 27 -4.6551899909973145e+00 <_> 0 -1 25 6.9747000932693481e-02 -1.0130879878997803e+00 1.4687349796295166e+00 <_> 0 -1 26 3.1502999365329742e-02 -1.6463639736175537e+00 1.0000629425048828e+00 <_> 0 -1 27 1.4260999858379364e-02 4.6480301022529602e-01 -1.5959889888763428e+00 <_> 0 -1 28 1.4453000389039516e-02 -6.5511900186538696e-01 8.3021801710128784e-01 <_> 0 -1 29 -3.0509999487549067e-03 -1.3982310295104980e+00 4.2550599575042725e-01 <_> 0 -1 30 3.2722998410463333e-02 -5.0702601671218872e-01 1.0526109933853149e+00 <_> 0 -1 31 -7.2960001416504383e-03 3.6356899142265320e-01 -1.3464889526367188e+00 <_> 0 -1 32 5.0425000488758087e-02 -3.0461400747299194e-01 1.4504129886627197e+00 <_> 0 -1 33 4.6879000961780548e-02 -4.0286201238632202e-01 1.2145609855651855e+00 <_> 0 -1 34 -6.9358997046947479e-02 1.0539360046386719e+00 -4.5719701051712036e-01 <_> 0 -1 35 -4.9033999443054199e-02 -1.6253089904785156e+00 1.5378999710083008e-01 <_> 0 -1 36 8.4827996790409088e-02 2.8402999043464661e-01 -1.5662059783935547e+00 <_> 0 -1 37 -1.7229999648407102e-03 -1.0147459506988525e+00 2.3294800519943237e-01 <_> 0 -1 38 1.1562199890613556e-01 -1.6732899844646454e-01 1.2804069519042969e+00 <_> 0 -1 39 -5.1279999315738678e-02 1.5162390470504761e+00 -3.0271100997924805e-01 <_> 0 -1 40 -4.2706999927759171e-02 1.7631920576095581e+00 -5.1832001656293869e-02 <_> 0 -1 41 3.7178099155426025e-01 -3.1389200687408447e-01 1.5357979536056519e+00 <_> 0 -1 42 1.9412999972701073e-02 -1.0017599910497665e-01 9.3655401468276978e-01 <_> 0 -1 43 1.7439000308513641e-02 -4.0379899740219116e-01 9.6293002367019653e-01 <_> 0 -1 44 3.9638999849557877e-02 1.7039099335670471e-01 -2.9602990150451660e+00 <_> 0 -1 45 -9.1469995677471161e-03 8.8786798715591431e-01 -4.3818700313568115e-01 <_> 0 -1 46 1.7219999572262168e-03 -3.7218600511550903e-01 4.0018901228904724e-01 <_> 0 -1 47 3.0231000855565071e-02 6.5924003720283508e-02 -2.6469180583953857e+00 <_> 0 -1 48 -7.8795999288558960e-02 -1.7491459846496582e+00 2.8475299477577209e-01 <_> 0 -1 49 2.1110000088810921e-03 -9.3908101320266724e-01 2.3205199837684631e-01 <_> 0 -1 50 2.7091000229120255e-02 -5.2664000540971756e-02 1.0756820440292358e+00 <_> 0 -1 51 -4.4964998960494995e-02 -1.8294479846954346e+00 9.9561996757984161e-02 <_> 32 -4.4531588554382324e+00 <_> 0 -1 52 -6.5701000392436981e-02 1.1558510065078735e+00 -1.0716359615325928e+00 <_> 0 -1 53 1.5839999541640282e-02 -1.5634720325469971e+00 7.6877099275588989e-01 <_> 0 -1 54 1.4570899307727814e-01 -5.7450097799301147e-01 1.3808720111846924e+00 <_> 0 -1 55 6.1389999464154243e-03 -1.4570560455322266e+00 5.1610302925109863e-01 <_> 0 -1 56 6.7179999314248562e-03 -8.3533602952957153e-01 5.8522200584411621e-01 <_> 0 -1 57 1.8518000841140747e-02 -3.1312099099159241e-01 1.1696679592132568e+00 <_> 0 -1 58 1.9958000630140305e-02 -4.3442600965499878e-01 9.5446902513504028e-01 <_> 0 -1 59 -2.7755001187324524e-01 1.4906179904937744e+00 -1.3815900683403015e-01 <_> 0 -1 60 9.1859996318817139e-03 -9.6361500024795532e-01 2.7665498852729797e-01 <_> 0 -1 61 -3.7737999111413956e-02 -2.4464108943939209e+00 2.3619599640369415e-01 <_> 0 -1 62 1.8463000655174255e-02 1.7539200186729431e-01 -1.3423130512237549e+00 <_> 0 -1 63 -1.1114999651908875e-02 4.8710799217224121e-01 -8.9851897954940796e-01 <_> 0 -1 64 3.3927999436855316e-02 1.7874200642108917e-01 -1.6342279911041260e+00 <_> 0 -1 65 -3.5649001598358154e-02 -1.9607399702072144e+00 1.8102499842643738e-01 <_> 0 -1 66 -1.1438000015914440e-02 9.9010699987411499e-01 -3.8103199005126953e-01 <_> 0 -1 67 -6.5236002206802368e-02 -2.5794160366058350e+00 2.4753600358963013e-01 <_> 0 -1 68 -4.2272001504898071e-02 1.4411840438842773e+00 -2.9508298635482788e-01 <_> 0 -1 69 1.9219999667257071e-03 -4.9608600139617920e-01 6.3173598051071167e-01 <_> 0 -1 70 -1.2921799719333649e-01 -2.3314270973205566e+00 5.4496999830007553e-02 <_> 0 -1 71 2.2931000217795372e-02 -8.4447097778320312e-01 3.8738098740577698e-01 <_> 0 -1 72 -3.4120000898838043e-02 -1.4431500434875488e+00 9.8422996699810028e-02 <_> 0 -1 73 2.6223000138998032e-02 1.8223099410533905e-01 -1.2586519718170166e+00 <_> 0 -1 74 2.2236999124288559e-02 6.9807998836040497e-02 -2.3820950984954834e+00 <_> 0 -1 75 -5.8240001089870930e-03 3.9332500100135803e-01 -2.7542799711227417e-01 <_> 0 -1 76 4.3653000146150589e-02 1.4832699298858643e-01 -1.1368780136108398e+00 <_> 0 -1 77 5.7266999036073685e-02 2.4628099799156189e-01 -1.2687400579452515e+00 <_> 0 -1 78 2.3409998975694180e-03 -7.5448900461196899e-01 2.7163800597190857e-01 <_> 0 -1 79 1.2996000237762928e-02 -3.6394900083541870e-01 7.0959198474884033e-01 <_> 0 -1 80 -2.6517000049352646e-02 -2.3221859931945801e+00 3.5744000226259232e-02 <_> 0 -1 81 -5.8400002308189869e-03 4.2194300889968872e-01 -4.8184998333454132e-02 <_> 0 -1 82 -1.6568999737501144e-02 1.1099940538406372e+00 -3.4849700331687927e-01 <_> 0 -1 83 -6.8157002329826355e-02 -3.3269989490509033e+00 2.1299000084400177e-01 <_> 52 -4.3864588737487793e+00 <_> 0 -1 84 3.9974000304937363e-02 -1.2173449993133545e+00 1.0826710462570190e+00 <_> 0 -1 85 1.8819500505924225e-01 -4.8289400339126587e-01 1.4045250415802002e+00 <_> 0 -1 86 7.8027002513408661e-02 -1.0782150030136108e+00 7.4040299654006958e-01 <_> 0 -1 87 1.1899999663000926e-04 -1.2019979953765869e+00 3.7749201059341431e-01 <_> 0 -1 88 8.5056997835636139e-02 -4.3939098715782166e-01 1.2647340297698975e+00 <_> 0 -1 89 8.9720003306865692e-03 -1.8440499901771545e-01 4.5726400613784790e-01 <_> 0 -1 90 8.8120000436902046e-03 3.0396699905395508e-01 -9.5991098880767822e-01 <_> 0 -1 91 -2.3507999256253242e-02 1.2487529516220093e+00 4.6227999031543732e-02 <_> 0 -1 92 7.0039997808635235e-03 -5.9442102909088135e-01 5.3963297605514526e-01 <_> 0 -1 93 3.3851999789476395e-02 2.8496098518371582e-01 -1.4895249605178833e+00 <_> 0 -1 94 -3.2530000898987055e-03 4.8120799660682678e-01 -5.2712398767471313e-01 <_> 0 -1 95 2.9097000136971474e-02 2.6743900775909424e-01 -1.6007850170135498e+00 <_> 0 -1 96 -8.4790000692009926e-03 -1.3107639551162720e+00 1.5243099629878998e-01 <_> 0 -1 97 -1.0795000009238720e-02 4.5613598823547363e-01 -7.2050899267196655e-01 <_> 0 -1 98 -2.4620000272989273e-02 -1.7320619821548462e+00 6.8363003432750702e-02 <_> 0 -1 99 3.7380000576376915e-03 -1.9303299486637115e-01 6.8243497610092163e-01 <_> 0 -1 100 -1.2264000251889229e-02 -1.6095290184020996e+00 7.5268000364303589e-02 <_> 0 -1 101 -4.8670000396668911e-03 7.4286502599716187e-01 -2.1510200202465057e-01 <_> 0 -1 102 7.6725997030735016e-02 -2.6835098862648010e-01 1.3094140291213989e+00 <_> 0 -1 103 2.8578000143170357e-02 -5.8793000876903534e-02 1.2196329832077026e+00 <_> 0 -1 104 1.9694000482559204e-02 -3.5142898559570312e-01 8.4926998615264893e-01 <_> 0 -1 105 -2.9093999415636063e-02 -1.0507299900054932e+00 2.9806300997734070e-01 <_> 0 -1 106 -2.9144000262022018e-02 8.2547801733016968e-01 -3.2687199115753174e-01 <_> 0 -1 107 1.9741000607609749e-02 2.0452600717544556e-01 -8.3760201930999756e-01 <_> 0 -1 108 4.3299999088048935e-03 2.0577900111675262e-01 -6.6829800605773926e-01 <_> 0 -1 109 -3.5500999540090561e-02 -1.2969900369644165e+00 1.3897499442100525e-01 <_> 0 -1 110 -1.6172999516129494e-02 -1.3110569715499878e+00 7.5751997530460358e-02 <_> 0 -1 111 -2.2151000797748566e-02 -1.0524389743804932e+00 1.9241100549697876e-01 <_> 0 -1 112 -2.2707000374794006e-02 -1.3735309839248657e+00 6.6780999302864075e-02 <_> 0 -1 113 1.6607999801635742e-02 -3.7135999649763107e-02 7.7846401929855347e-01 <_> 0 -1 114 -1.3309000059962273e-02 -9.9850702285766602e-01 1.2248100340366364e-01 <_> 0 -1 115 -3.3732000738382339e-02 1.4461359977722168e+00 1.3151999562978745e-02 <_> 0 -1 116 1.6935000196099281e-02 -3.7121298909187317e-01 5.2842199802398682e-01 <_> 0 -1 117 3.3259999472647905e-03 -5.7568502426147461e-01 3.9261901378631592e-01 <_> 0 -1 118 8.3644002676010132e-02 1.6116000711917877e-02 -2.1173279285430908e+00 <_> 0 -1 119 2.5785198807716370e-01 -8.1609003245830536e-02 9.8782497644424438e-01 <_> 0 -1 120 -3.6566998809576035e-02 -1.1512110233306885e+00 9.6459001302719116e-02 <_> 0 -1 121 -1.6445999965071678e-02 3.7315499782562256e-01 -1.4585399627685547e-01 <_> 0 -1 122 -3.7519999314099550e-03 2.6179298758506775e-01 -5.8156698942184448e-01 <_> 0 -1 123 -6.3660000450909138e-03 7.5477397441864014e-01 -1.7055200040340424e-01 <_> 0 -1 124 -3.8499999791383743e-03 2.2653999924659729e-01 -6.3876402378082275e-01 <_> 0 -1 125 -4.5494001358747482e-02 -1.2640299797058105e+00 2.5260698795318604e-01 <_> 0 -1 126 -2.3941000923514366e-02 8.7068402767181396e-01 -2.7104699611663818e-01 <_> 0 -1 127 -7.7558003365993500e-02 -1.3901610374450684e+00 2.3612299561500549e-01 <_> 0 -1 128 2.3614000529050827e-02 6.6140003502368927e-02 -1.2645419836044312e+00 <_> 0 -1 129 -2.5750000495463610e-03 -5.3841698169708252e-01 3.0379098653793335e-01 <_> 0 -1 130 1.2010800093412399e-01 -3.5343000292778015e-01 5.2866202592849731e-01 <_> 0 -1 131 2.2899999748915434e-03 -5.8701997995376587e-01 2.4061000347137451e-01 <_> 0 -1 132 6.9716997444629669e-02 -3.3348900079727173e-01 5.1916301250457764e-01 <_> 0 -1 133 -4.6670001000165939e-02 6.9795399904251099e-01 -1.4895999804139137e-02 <_> 0 -1 134 -5.0129000097513199e-02 8.6146199703216553e-01 -2.5986000895500183e-01 <_> 0 -1 135 3.0147999525070190e-02 1.9332799315452576e-01 -5.9131097793579102e-01 <_> 53 -4.1299300193786621e+00 <_> 0 -1 136 9.1085001826286316e-02 -8.9233100414276123e-01 1.0434230566024780e+00 <_> 0 -1 137 1.2818999588489532e-02 -1.2597670555114746e+00 5.5317097902297974e-01 <_> 0 -1 138 1.5931999310851097e-02 -8.6254400014877319e-01 6.3731801509857178e-01 <_> 0 -1 139 2.2780001163482666e-03 -7.4639201164245605e-01 5.3155601024627686e-01 <_> 0 -1 140 3.1840998679399490e-02 -1.2650489807128906e+00 3.6153900623321533e-01 <_> 0 -1 141 2.6960000395774841e-03 -9.8290401697158813e-01 3.6013001203536987e-01 <_> 0 -1 142 -1.2055000290274620e-02 6.4068400859832764e-01 -5.0125002861022949e-01 <_> 0 -1 143 2.1324999630451202e-02 -2.4034999310970306e-01 8.5448002815246582e-01 <_> 0 -1 144 3.0486000701785088e-02 -3.4273600578308105e-01 1.1428849697113037e+00 <_> 0 -1 145 -4.5079998672008514e-02 1.0976949930191040e+00 -1.7974600195884705e-01 <_> 0 -1 146 -7.1700997650623322e-02 1.5735000371932983e+00 -3.1433498859405518e-01 <_> 0 -1 147 5.9218000620603561e-02 -2.7582401037216187e-01 1.0448570251464844e+00 <_> 0 -1 148 6.7010000348091125e-03 -1.0974019765853882e+00 1.9801199436187744e-01 <_> 0 -1 149 4.1046999394893646e-02 3.0547699332237244e-01 -1.3287999629974365e+00 <_> 0 -1 150 -8.5499999113380909e-04 2.5807100534439087e-01 -7.0052897930145264e-01 <_> 0 -1 151 -3.0360000208020210e-02 -1.2306419610977173e+00 2.2609399259090424e-01 <_> 0 -1 152 -1.2930000200867653e-02 4.0758600831031799e-01 -5.1234501600265503e-01 <_> 0 -1 153 3.7367999553680420e-02 -9.4755001366138458e-02 6.1765098571777344e-01 <_> 0 -1 154 2.4434000253677368e-02 -4.1100600361824036e-01 4.7630500793457031e-01 <_> 0 -1 155 5.7007998228073120e-02 2.5249299407005310e-01 -6.8669801950454712e-01 <_> 0 -1 156 -1.6313999891281128e-02 -9.3928402662277222e-01 1.1448100209236145e-01 <_> 0 -1 157 -1.7648899555206299e-01 1.2451089620590210e+00 -5.6519001722335815e-02 <_> 0 -1 158 1.7614600062370300e-01 -3.2528200745582581e-01 8.2791501283645630e-01 <_> 0 -1 159 -7.3910001665353775e-03 3.4783700108528137e-01 -1.7929099500179291e-01 <_> 0 -1 160 6.0890998691320419e-02 5.5098000913858414e-02 -1.5480779409408569e+00 <_> 0 -1 161 -2.9123000800609589e-02 -1.0255639553070068e+00 2.4106900393962860e-01 <_> 0 -1 162 -4.5648999512195587e-02 1.0301599502563477e+00 -3.1672099232673645e-01 <_> 0 -1 163 3.7333000451326370e-02 2.1620599925518036e-01 -8.2589900493621826e-01 <_> 0 -1 164 -2.4411000311374664e-02 -1.5957959890365601e+00 5.1139000803232193e-02 <_> 0 -1 165 -5.9806998819112778e-02 -1.0312290191650391e+00 1.3092300295829773e-01 <_> 0 -1 166 -3.0106000602245331e-02 -1.4781630039215088e+00 3.7211999297142029e-02 <_> 0 -1 167 7.4209999293088913e-03 -2.4024100601673126e-01 4.9333998560905457e-01 <_> 0 -1 168 -2.1909999195486307e-03 2.8941500186920166e-01 -5.7259601354598999e-01 <_> 0 -1 169 2.0860999822616577e-02 -2.3148399591445923e-01 6.3765901327133179e-01 <_> 0 -1 170 -6.6990000195801258e-03 -1.2107750177383423e+00 6.4018003642559052e-02 <_> 0 -1 171 1.8758000805974007e-02 2.4461300671100616e-01 -9.9786698818206787e-01 <_> 0 -1 172 -4.4323001056909561e-02 -1.3699189424514771e+00 3.6051999777555466e-02 <_> 0 -1 173 2.2859999909996986e-02 2.1288399398326874e-01 -1.0397620201110840e+00 <_> 0 -1 174 -9.8600005730986595e-04 3.2443600893020630e-01 -5.4291802644729614e-01 <_> 0 -1 175 1.7239000648260117e-02 -2.8323900699615479e-01 4.4468200206756592e-01 <_> 0 -1 176 -3.4531001001596451e-02 -2.3107020854949951e+00 -3.1399999279528856e-03 <_> 0 -1 177 6.7006997764110565e-02 2.8715699911117554e-01 -6.4481002092361450e-01 <_> 0 -1 178 2.3776899278163910e-01 -2.7174800634384155e-01 8.0219101905822754e-01 <_> 0 -1 179 -1.2903000228106976e-02 -1.5317620038986206e+00 2.1423600614070892e-01 <_> 0 -1 180 1.0514999739825726e-02 7.7037997543811798e-02 -1.0581140518188477e+00 <_> 0 -1 181 1.6969000920653343e-02 1.4306700229644775e-01 -8.5828399658203125e-01 <_> 0 -1 182 -7.2460002265870571e-03 -1.1020129919052124e+00 6.4906999468803406e-02 <_> 0 -1 183 1.0556999593973160e-02 1.3964000158011913e-02 6.3601499795913696e-01 <_> 0 -1 184 6.1380001716315746e-03 -3.4545901417732239e-01 5.6296801567077637e-01 <_> 0 -1 185 1.3158000074326992e-02 1.9927300512790680e-01 -1.5040320158004761e+00 <_> 0 -1 186 3.1310000922530890e-03 -4.0903699398040771e-01 3.7796398997306824e-01 <_> 0 -1 187 -1.0920699685811996e-01 -2.2227079868316650e+00 1.2178199738264084e-01 <_> 0 -1 188 8.1820003688335419e-03 -2.8652000427246094e-01 6.7890799045562744e-01 <_> 62 -4.0218091011047363e+00 <_> 0 -1 189 3.1346999108791351e-02 -8.8884598016738892e-01 9.4936800003051758e-01 <_> 0 -1 190 3.1918000429868698e-02 -1.1146880388259888e+00 4.8888999223709106e-01 <_> 0 -1 191 6.5939999185502529e-03 -1.0097689628601074e+00 4.9723801016807556e-01 <_> 0 -1 192 2.6148000732064247e-02 2.5991299748420715e-01 -1.2537480592727661e+00 <_> 0 -1 193 1.2845000252127647e-02 -5.7138597965240479e-01 5.9659498929977417e-01 <_> 0 -1 194 2.6344999670982361e-02 -5.5203199386596680e-01 3.0217400193214417e-01 <_> 0 -1 195 -1.5083000063896179e-02 -1.2871240377426147e+00 2.2354200482368469e-01 <_> 0 -1 196 -3.8887001574039459e-02 1.7425049543380737e+00 -9.9747002124786377e-02 <_> 0 -1 197 -5.7029998861253262e-03 -1.0523240566253662e+00 1.8362599611282349e-01 <_> 0 -1 198 -1.4860000228509307e-03 5.6784200668334961e-01 -4.6742001175880432e-01 <_> 0 -1 199 -2.8486000373959541e-02 1.3082909584045410e+00 -2.6460900902748108e-01 <_> 0 -1 200 6.6224999725818634e-02 -4.6210700273513794e-01 4.1749599575996399e-01 <_> 0 -1 201 8.8569996878504753e-03 -4.1474899649620056e-01 5.9204798936843872e-01 <_> 0 -1 202 1.1355999857187271e-02 3.6103099584579468e-01 -4.5781201124191284e-01 <_> 0 -1 203 -2.7679998893290758e-03 -8.9238899946212769e-01 1.4199000597000122e-01 <_> 0 -1 204 1.1246999725699425e-02 2.9353401064872742e-01 -9.7330600023269653e-01 <_> 0 -1 205 7.1970000863075256e-03 -7.9334902763366699e-01 1.8313400447368622e-01 <_> 0 -1 206 3.1768999993801117e-02 1.5523099899291992e-01 -1.3245639801025391e+00 <_> 0 -1 207 2.5173999369144440e-02 3.4214999526739120e-02 -2.0948131084442139e+00 <_> 0 -1 208 7.5360001064836979e-03 -3.9450600743293762e-01 5.1333999633789062e-01 <_> 0 -1 209 3.2873000949621201e-02 8.8372997939586639e-02 -1.2814120054244995e+00 <_> 0 -1 210 -2.7379998937249184e-03 5.5286502838134766e-01 -4.6384999155998230e-01 <_> 0 -1 211 -3.8075000047683716e-02 -1.8497270345687866e+00 4.5944001525640488e-02 <_> 0 -1 212 -3.8984000682830811e-02 -4.8223701119422913e-01 3.4760600328445435e-01 <_> 0 -1 213 2.8029999230057001e-03 -4.5154699683189392e-01 4.2806300520896912e-01 <_> 0 -1 214 -5.4145999252796173e-02 -8.4520798921585083e-01 1.6674900054931641e-01 <_> 0 -1 215 -8.3280000835657120e-03 3.5348299145698547e-01 -4.7163200378417969e-01 <_> 0 -1 216 3.3778000622987747e-02 1.8463100492954254e-01 -1.6686669588088989e+00 <_> 0 -1 217 -1.1238099634647369e-01 -1.2521569728851318e+00 3.5992000252008438e-02 <_> 0 -1 218 -1.0408000089228153e-02 -8.1620401144027710e-01 2.3428599536418915e-01 <_> 0 -1 219 -4.9439999274909496e-03 -9.2584699392318726e-01 1.0034800320863724e-01 <_> 0 -1 220 -9.3029998242855072e-03 5.6499302387237549e-01 -1.8881900608539581e-01 <_> 0 -1 221 -1.1749999597668648e-02 8.0302399396896362e-01 -3.8277000188827515e-01 <_> 0 -1 222 -2.3217000067234039e-02 -8.4926998615264893e-01 1.9671200215816498e-01 <_> 0 -1 223 1.6866000369191170e-02 -4.0591898560523987e-01 5.0695300102233887e-01 <_> 0 -1 224 -2.4031000211834908e-02 -1.5297520160675049e+00 2.3344999551773071e-01 <_> 0 -1 225 -3.6945998668670654e-02 6.3007700443267822e-01 -3.1780400872230530e-01 <_> 0 -1 226 -6.1563998460769653e-02 5.8627897500991821e-01 -1.2107999995350838e-02 <_> 0 -1 227 2.1661000326275826e-02 -2.5623700022697449e-01 1.0409849882125854e+00 <_> 0 -1 228 -3.6710000131279230e-03 2.9171100258827209e-01 -8.3287298679351807e-01 <_> 0 -1 229 4.4849000871181488e-02 -3.9633199572563171e-01 4.5662000775337219e-01 <_> 0 -1 230 5.7195000350475311e-02 2.1023899316787720e-01 -1.5004800558090210e+00 <_> 0 -1 231 -1.1342000216245651e-02 4.4071298837661743e-01 -3.8653799891471863e-01 <_> 0 -1 232 -1.2004000134766102e-02 9.3954598903656006e-01 -1.0589499771595001e-01 <_> 0 -1 233 2.2515999153256416e-02 9.4480002298951149e-03 -1.6799509525299072e+00 <_> 0 -1 234 -1.9809000194072723e-02 -1.0133639574050903e+00 2.4146600067615509e-01 <_> 0 -1 235 1.5891000628471375e-02 -3.7507599592208862e-01 4.6614098548889160e-01 <_> 0 -1 236 -9.1420002281665802e-03 -8.0484098196029663e-01 1.7816999554634094e-01 <_> 0 -1 237 -4.4740000739693642e-03 -1.0562069416046143e+00 7.3305003345012665e-02 <_> 0 -1 238 1.2742500007152557e-01 2.0165599882602692e-01 -1.5467929840087891e+00 <_> 0 -1 239 4.7703001648187637e-02 -3.7937799096107483e-01 3.7885999679565430e-01 <_> 0 -1 240 5.3608000278472900e-02 2.1220499277114868e-01 -1.2399710416793823e+00 <_> 0 -1 241 -3.9680998772382736e-02 -1.0257550477981567e+00 5.1282998174428940e-02 <_> 0 -1 242 -6.7327000200748444e-02 -1.0304750204086304e+00 2.3005299270153046e-01 <_> 0 -1 243 1.3337600231170654e-01 -2.0869000256061554e-01 1.2272510528564453e+00 <_> 0 -1 244 -2.0919300615787506e-01 8.7929898500442505e-01 -4.4254999607801437e-02 <_> 0 -1 245 -6.5589003264904022e-02 1.0443429946899414e+00 -2.1682099997997284e-01 <_> 0 -1 246 6.1882998794317245e-02 1.3798199594020844e-01 -1.9009059667587280e+00 <_> 0 -1 247 -2.5578999891877174e-02 -1.6607600450515747e+00 5.8439997956156731e-03 <_> 0 -1 248 -3.4827001392841339e-02 7.9940402507781982e-01 -8.2406997680664062e-02 <_> 0 -1 249 -1.8209999427199364e-02 -9.6073997020721436e-01 6.6320002079010010e-02 <_> 0 -1 250 1.5070999972522259e-02 1.9899399578571320e-01 -7.6433002948760986e-01 <_> 72 -3.8832089900970459e+00 <_> 0 -1 251 4.6324998140335083e-02 -1.0362670421600342e+00 8.2201498746871948e-01 <_> 0 -1 252 1.5406999737024307e-02 -1.2327589988708496e+00 2.9647698998451233e-01 <_> 0 -1 253 1.2808999978005886e-02 -7.5852298736572266e-01 5.7985502481460571e-01 <_> 0 -1 254 4.9150999635457993e-02 -3.8983899354934692e-01 8.9680302143096924e-01 <_> 0 -1 255 1.2621000409126282e-02 -7.1799302101135254e-01 5.0440901517868042e-01 <_> 0 -1 256 -1.8768999725580215e-02 5.5147600173950195e-01 -7.0555400848388672e-01 <_> 0 -1 257 4.1965000331401825e-02 -4.4782099127769470e-01 7.0985502004623413e-01 <_> 0 -1 258 -5.1401998847723007e-02 -1.0932120084762573e+00 2.6701900362968445e-01 <_> 0 -1 259 -7.0960998535156250e-02 8.3618402481079102e-01 -3.8318100571632385e-01 <_> 0 -1 260 1.6745999455451965e-02 -2.5733101367950439e-01 2.5966501235961914e-01 <_> 0 -1 261 -6.2400000169873238e-03 3.1631499528884888e-01 -5.8796900510787964e-01 <_> 0 -1 262 -3.9397999644279480e-02 -1.0491210222244263e+00 1.6822400689125061e-01 <_> 0 -1 263 0. 1.6144199669361115e-01 -8.7876898050308228e-01 <_> 0 -1 264 -2.2307999432086945e-02 -6.9053500890731812e-01 2.3607000708580017e-01 <_> 0 -1 265 1.8919999711215496e-03 2.4989199638366699e-01 -5.6583297252655029e-01 <_> 0 -1 266 1.0730000212788582e-03 -5.0415802001953125e-01 3.8374501466751099e-01 <_> 0 -1 267 3.9230998605489731e-02 4.2619001120328903e-02 -1.3875889778137207e+00 <_> 0 -1 268 6.2238000333309174e-02 1.4119400084018707e-01 -1.0688860416412354e+00 <_> 0 -1 269 2.1399999968707561e-03 -8.9622402191162109e-01 1.9796399772167206e-01 <_> 0 -1 270 9.1800000518560410e-04 -4.5337298512458801e-01 4.3532699346542358e-01 <_> 0 -1 271 -6.9169998168945312e-03 3.3822798728942871e-01 -4.4793000817298889e-01 <_> 0 -1 272 -2.3866999894380569e-02 -7.8908598423004150e-01 2.2511799633502960e-01 <_> 0 -1 273 -1.0262800008058548e-01 -2.2831439971923828e+00 -5.3960001096129417e-03 <_> 0 -1 274 -9.5239998772740364e-03 3.9346700906753540e-01 -5.2242201566696167e-01 <_> 0 -1 275 3.9877001196146011e-02 3.2799001783132553e-02 -1.5079489946365356e+00 <_> 0 -1 276 -1.3144999742507935e-02 -1.0839990377426147e+00 1.8482400476932526e-01 <_> 0 -1 277 -5.0590999424457550e-02 -1.8822289705276489e+00 -2.2199999075382948e-03 <_> 0 -1 278 2.4917000904679298e-02 1.4593400061130524e-01 -2.2196519374847412e+00 <_> 0 -1 279 -7.6370001770555973e-03 -1.0164569616317749e+00 5.8797001838684082e-02 <_> 0 -1 280 4.2911998927593231e-02 1.5443000197410583e-01 -1.1843889951705933e+00 <_> 0 -1 281 2.3000000510364771e-04 -7.7305799722671509e-01 1.2189900130033493e-01 <_> 0 -1 282 9.0929996222257614e-03 -1.1450099945068359e-01 7.1091300249099731e-01 <_> 0 -1 283 1.1145000346004963e-02 7.0000998675823212e-02 -1.0534820556640625e+00 <_> 0 -1 284 -5.2453000098466873e-02 -1.7594360113143921e+00 1.9523799419403076e-01 <_> 0 -1 285 -2.3020699620246887e-01 9.5840299129486084e-01 -2.5045698881149292e-01 <_> 0 -1 286 -1.6365999355912209e-02 4.6731901168823242e-01 -2.1108399331569672e-01 <_> 0 -1 287 -1.7208000645041466e-02 7.0835697650909424e-01 -2.8018298745155334e-01 <_> 0 -1 288 -3.6648001521825790e-02 -1.1013339757919312e+00 2.4341100454330444e-01 <_> 0 -1 289 -1.0304999537765980e-02 -1.0933129787445068e+00 5.6258998811244965e-02 <_> 0 -1 290 -1.3713000342249870e-02 -2.6438099145889282e-01 1.9821000099182129e-01 <_> 0 -1 291 2.9308000579476357e-02 -2.2142399847507477e-01 1.0525950193405151e+00 <_> 0 -1 292 2.4077000096440315e-02 1.8485699594020844e-01 -1.7203969955444336e+00 <_> 0 -1 293 6.1280000954866409e-03 -9.2721498012542725e-01 5.8752998709678650e-02 <_> 0 -1 294 -2.2377999499440193e-02 1.9646559953689575e+00 2.7785999700427055e-02 <_> 0 -1 295 -7.0440000854432583e-03 2.1427600085735321e-01 -4.8407599329948425e-01 <_> 0 -1 296 -4.0603000670671463e-02 -1.1754349470138550e+00 1.6061200201511383e-01 <_> 0 -1 297 -2.4466000497341156e-02 -1.1239900588989258e+00 4.1110001504421234e-02 <_> 0 -1 298 2.5309999473392963e-03 -1.7169700562953949e-01 3.2178801298141479e-01 <_> 0 -1 299 -1.9588999450206757e-02 8.2720202207565308e-01 -2.6376700401306152e-01 <_> 0 -1 300 -2.9635999351739883e-02 -1.1524770259857178e+00 1.4999300241470337e-01 <_> 0 -1 301 -1.5030000358819962e-02 -1.0491830110549927e+00 4.0160998702049255e-02 <_> 0 -1 302 -6.0715001076459885e-02 -1.0903840065002441e+00 1.5330800414085388e-01 <_> 0 -1 303 -1.2790000066161156e-02 4.2248600721359253e-01 -4.2399200797080994e-01 <_> 0 -1 304 -2.0247999578714371e-02 -9.1866999864578247e-01 1.8485699594020844e-01 <_> 0 -1 305 -3.0683999881148338e-02 -1.5958670377731323e+00 2.5760000571608543e-03 <_> 0 -1 306 -2.0718000829219818e-02 -6.6299998760223389e-01 3.1037199497222900e-01 <_> 0 -1 307 -1.7290000105276704e-03 1.9183400273323059e-01 -6.5084999799728394e-01 <_> 0 -1 308 -3.1394001096487045e-02 -6.3643002510070801e-01 1.5408399701118469e-01 <_> 0 -1 309 1.9003000110387802e-02 -1.8919399380683899e-01 1.5294510126113892e+00 <_> 0 -1 310 6.1769997701048851e-03 -1.0597900301218033e-01 6.4859598875045776e-01 <_> 0 -1 311 -1.0165999643504620e-02 -1.0802700519561768e+00 3.7176001816987991e-02 <_> 0 -1 312 -1.4169999631121755e-03 3.4157499670982361e-01 -9.7737997770309448e-02 <_> 0 -1 313 -4.0799998678267002e-03 4.7624599933624268e-01 -3.4366300702095032e-01 <_> 0 -1 314 -4.4096998870372772e-02 9.7634297609329224e-01 -1.9173000007867813e-02 <_> 0 -1 315 -6.0669999569654465e-02 -2.1752851009368896e+00 -2.8925999999046326e-02 <_> 0 -1 316 -3.2931998372077942e-02 -6.4383101463317871e-01 1.6494099795818329e-01 <_> 0 -1 317 -1.4722800254821777e-01 -1.4745830297470093e+00 2.5839998852461576e-03 <_> 0 -1 318 -1.1930000036954880e-02 4.2441400885581970e-01 -1.7712600529193878e-01 <_> 0 -1 319 1.4517900347709656e-01 2.5444999337196350e-02 -1.2779400348663330e+00 <_> 0 -1 320 5.1447998732328415e-02 1.5678399801254272e-01 -1.5188430547714233e+00 <_> 0 -1 321 3.1479999888688326e-03 -4.0424400568008423e-01 3.2429701089859009e-01 <_> 0 -1 322 -4.3600000441074371e-02 -1.9932260513305664e+00 1.5018600225448608e-01 <_> 83 -3.8424909114837646e+00 <_> 0 -1 323 1.2899599969387054e-01 -6.2161999940872192e-01 1.1116520166397095e+00 <_> 0 -1 324 -9.1261997818946838e-02 1.0143059492111206e+00 -6.1335200071334839e-01 <_> 0 -1 325 1.4271999709308147e-02 -1.0261659622192383e+00 3.9779999852180481e-01 <_> 0 -1 326 3.2889999449253082e-02 -1.1386079788208008e+00 2.8690800070762634e-01 <_> 0 -1 327 1.2590000405907631e-02 -5.6645601987838745e-01 4.5172399282455444e-01 <_> 0 -1 328 1.4661000110208988e-02 3.0505999922752380e-01 -6.8129599094390869e-01 <_> 0 -1 329 -3.3555999398231506e-02 -1.7208939790725708e+00 6.1439000070095062e-02 <_> 0 -1 330 1.4252699911594391e-01 2.3192200064659119e-01 -1.7297149896621704e+00 <_> 0 -1 331 -6.2079997733235359e-03 -1.2163300514221191e+00 1.2160199880599976e-01 <_> 0 -1 332 1.8178999423980713e-02 3.2553699612617493e-01 -8.1003999710083008e-01 <_> 0 -1 333 2.5036999955773354e-02 -3.1698799133300781e-01 6.7361402511596680e-01 <_> 0 -1 334 4.6560999006032944e-02 -1.1089800298213959e-01 8.4082502126693726e-01 <_> 0 -1 335 -8.9999996125698090e-03 3.9574500918388367e-01 -4.7624599933624268e-01 <_> 0 -1 336 4.0805999189615250e-02 -1.8000000272877514e-04 9.4570702314376831e-01 <_> 0 -1 337 -3.4221999347209930e-02 7.5206297636032104e-01 -3.1531500816345215e-01 <_> 0 -1 338 -3.9716001600027084e-02 -8.3139598369598389e-01 1.7744399607181549e-01 <_> 0 -1 339 2.5170000735670328e-03 -5.9377998113632202e-01 2.4657000601291656e-01 <_> 0 -1 340 2.7428999543190002e-02 1.5998399257659912e-01 -4.2781999707221985e-01 <_> 0 -1 341 3.4986000508069992e-02 3.5055998712778091e-02 -1.5988600254058838e+00 <_> 0 -1 342 4.4970000162720680e-03 -5.2034300565719604e-01 3.7828299403190613e-01 <_> 0 -1 343 2.7699999045580626e-03 -5.3182601928710938e-01 2.4951000511646271e-01 <_> 0 -1 344 3.5174001008272171e-02 1.9983400404453278e-01 -1.4446129798889160e+00 <_> 0 -1 345 2.5970999151468277e-02 4.4426999986171722e-02 -1.3622980117797852e+00 <_> 0 -1 346 -1.5783999115228653e-02 -9.1020399332046509e-01 2.7190300822257996e-01 <_> 0 -1 347 -7.5880000367760658e-03 9.2064999043941498e-02 -8.1628900766372681e-01 <_> 0 -1 348 2.0754000172019005e-02 2.1185700595378876e-01 -7.4729001522064209e-01 <_> 0 -1 349 5.9829000383615494e-02 -2.7301099896430969e-01 8.0923300981521606e-01 <_> 0 -1 350 3.9039000868797302e-02 -1.0432299971580505e-01 8.6226201057434082e-01 <_> 0 -1 351 2.1665999665856361e-02 6.2709003686904907e-02 -9.8894298076629639e-01 <_> 0 -1 352 -2.7496999129652977e-02 -9.2690998315811157e-01 1.5586300194263458e-01 <_> 0 -1 353 1.0462000034749508e-02 1.3418099284172058e-01 -7.0386397838592529e-01 <_> 0 -1 354 2.4870999157428741e-02 1.9706700742244720e-01 -4.0263301134109497e-01 <_> 0 -1 355 -1.6036000102758408e-02 -1.1409829854965210e+00 7.3997996747493744e-02 <_> 0 -1 356 4.8627000302076340e-02 1.6990399360656738e-01 -7.2152197360992432e-01 <_> 0 -1 357 1.2619999470189214e-03 -4.7389799356460571e-01 2.6254999637603760e-01 <_> 0 -1 358 -8.8035002350807190e-02 -2.1606519222259521e+00 1.4554800093173981e-01 <_> 0 -1 359 1.8356999382376671e-02 4.4750999659299850e-02 -1.0766370296478271e+00 <_> 0 -1 360 3.5275001078844070e-02 -3.2919000834226608e-02 1.2153890132904053e+00 <_> 0 -1 361 -2.0392900705337524e-01 -1.3187999725341797e+00 1.5503999777138233e-02 <_> 0 -1 362 -1.6619000583887100e-02 3.6850199103355408e-01 -1.5283699333667755e-01 <_> 0 -1 363 3.7739001214504242e-02 -2.5727799534797668e-01 7.0655298233032227e-01 <_> 0 -1 364 2.2720000706613064e-03 -7.7602997422218323e-02 3.3367800712585449e-01 <_> 0 -1 365 -1.4802999794483185e-02 -7.8524798154830933e-01 7.6934002339839935e-02 <_> 0 -1 366 -4.8319000750780106e-02 1.7022320032119751e+00 4.9722000956535339e-02 <_> 0 -1 367 -2.9539000242948532e-02 7.7670699357986450e-01 -2.4534299969673157e-01 <_> 0 -1 368 -4.6169001609086990e-02 -1.4922779798507690e+00 1.2340000271797180e-01 <_> 0 -1 369 -2.8064999729394913e-02 -2.1345369815826416e+00 -2.5797000154852867e-02 <_> 0 -1 370 -5.7339998893439770e-03 5.6982600688934326e-01 -1.2056600302457809e-01 <_> 0 -1 371 -1.0111000388860703e-02 6.7911398410797119e-01 -2.6638001203536987e-01 <_> 0 -1 372 1.1359999887645245e-02 2.4789799749851227e-01 -6.4493000507354736e-01 <_> 0 -1 373 5.1809001713991165e-02 1.4716000296175480e-02 -1.2395579814910889e+00 <_> 0 -1 374 3.3291999250650406e-02 -8.2559995353221893e-03 1.0168470144271851e+00 <_> 0 -1 375 -1.4494000002741814e-02 4.5066800713539124e-01 -3.6250999569892883e-01 <_> 0 -1 376 -3.4221999347209930e-02 -9.5292502641677856e-01 2.0684599876403809e-01 <_> 0 -1 377 -8.0654002726078033e-02 -2.0139501094818115e+00 -2.3084999993443489e-02 <_> 0 -1 378 -8.9399999706074595e-04 3.9572000503540039e-01 -2.9351300001144409e-01 <_> 0 -1 379 9.7162000834941864e-02 -2.4980300664901733e-01 1.0859220027923584e+00 <_> 0 -1 380 3.6614000797271729e-02 -5.7844001799821854e-02 1.2162159681320190e+00 <_> 0 -1 381 5.1693998277187347e-02 4.3062999844551086e-02 -1.0636160373687744e+00 <_> 0 -1 382 -2.4557000026106834e-02 -4.8946800827980042e-01 1.7182900011539459e-01 <_> 0 -1 383 3.2736799120903015e-01 -2.9688599705696106e-01 5.1798301935195923e-01 <_> 0 -1 384 7.6959999278187752e-03 -5.9805899858474731e-01 2.4803200364112854e-01 <_> 0 -1 385 1.6172200441360474e-01 -2.9613999649882317e-02 -2.3162529468536377e+00 <_> 0 -1 386 -4.7889999113976955e-03 3.7457901239395142e-01 -3.2779198884963989e-01 <_> 0 -1 387 -1.8402999266982079e-02 -9.9692702293395996e-01 7.2948001325130463e-02 <_> 0 -1 388 7.7665001153945923e-02 1.4175699651241302e-01 -1.7238730192184448e+00 <_> 0 -1 389 1.8921000882983208e-02 -2.1273100376129150e-01 1.0165189504623413e+00 <_> 0 -1 390 -7.9397998750209808e-02 -1.3164349794387817e+00 1.4981999993324280e-01 <_> 0 -1 391 -6.8037003278732300e-02 4.9421998858451843e-01 -2.9091000556945801e-01 <_> 0 -1 392 -6.1010001227259636e-03 4.2430499196052551e-01 -3.3899301290512085e-01 <_> 0 -1 393 3.1927000731229782e-02 -3.1046999618411064e-02 -2.3459999561309814e+00 <_> 0 -1 394 -2.9843999072909355e-02 -7.8989601135253906e-01 1.5417699515819550e-01 <_> 0 -1 395 -8.0541998147964478e-02 -2.2509229183197021e+00 -3.0906999483704567e-02 <_> 0 -1 396 3.8109999150037766e-03 -2.5577300786972046e-01 2.3785500228404999e-01 <_> 0 -1 397 3.3647000789642334e-02 -2.2541399300098419e-01 9.2307400703430176e-01 <_> 0 -1 398 8.2809999585151672e-03 -2.8896200656890869e-01 3.1046199798583984e-01 <_> 0 -1 399 1.0104399919509888e-01 -3.4864000976085663e-02 -2.7102620601654053e+00 <_> 0 -1 400 -1.0009000077843666e-02 5.9715402126312256e-01 -3.3831000328063965e-02 <_> 0 -1 401 7.1919998154044151e-03 -4.7738000750541687e-01 2.2686000168323517e-01 <_> 0 -1 402 2.4969000369310379e-02 2.2877700626850128e-01 -1.0435529947280884e+00 <_> 0 -1 403 2.7908000349998474e-01 -2.5818100571632385e-01 7.6780498027801514e-01 <_> 0 -1 404 -4.4213000684976578e-02 -5.9798002243041992e-01 2.8039899468421936e-01 <_> 0 -1 405 -1.4136999845504761e-02 7.0987302064895630e-01 -2.5645199418067932e-01 <_> 91 -3.6478610038757324e+00 <_> 0 -1 406 1.3771200180053711e-01 -5.5870598554611206e-01 1.0953769683837891e+00 <_> 0 -1 407 3.4460999071598053e-02 -7.1171897649765015e-01 5.2899599075317383e-01 <_> 0 -1 408 1.8580000847578049e-02 -1.1157519817352295e+00 4.0593999624252319e-01 <_> 0 -1 409 2.5041999295353889e-02 -4.0892499685287476e-01 7.4129998683929443e-01 <_> 0 -1 410 5.7179000228643417e-02 -3.8054299354553223e-01 7.3647701740264893e-01 <_> 0 -1 411 1.4932000078260899e-02 -6.9945502281188965e-01 3.7950998544692993e-01 <_> 0 -1 412 8.8900001719594002e-03 -5.4558598995208740e-01 3.6332499980926514e-01 <_> 0 -1 413 3.0435999855399132e-02 -1.0124599933624268e-01 7.9585897922515869e-01 <_> 0 -1 414 -4.4160000979900360e-02 8.4410899877548218e-01 -3.2976400852203369e-01 <_> 0 -1 415 1.8461000174283981e-02 2.6326599717140198e-01 -9.6736502647399902e-01 <_> 0 -1 416 1.0614999569952488e-02 1.5251900255680084e-01 -1.0589870214462280e+00 <_> 0 -1 417 -4.5974001288414001e-02 -1.9918340444564819e+00 1.3629099726676941e-01 <_> 0 -1 418 8.2900002598762512e-02 -3.2037198543548584e-01 6.0304200649261475e-01 <_> 0 -1 419 -8.9130001142621040e-03 5.9586602449417114e-01 -2.1139599382877350e-01 <_> 0 -1 420 4.2814001441001892e-02 2.2925000637769699e-02 -1.4679330587387085e+00 <_> 0 -1 421 -8.7139997631311417e-03 -4.3989500403404236e-01 2.0439699292182922e-01 <_> 0 -1 422 -4.3390002101659775e-03 -8.9066797494888306e-01 1.0469999909400940e-01 <_> 0 -1 423 8.0749997869133949e-03 2.1164199709892273e-01 -4.0231600403785706e-01 <_> 0 -1 424 9.6739001572132111e-02 1.3319999910891056e-02 -1.6085360050201416e+00 <_> 0 -1 425 -3.0536999925971031e-02 1.0063740015029907e+00 -1.3413299620151520e-01 <_> 0 -1 426 -6.0855999588966370e-02 -1.4689979553222656e+00 9.4240000471472740e-03 <_> 0 -1 427 -3.8162000477313995e-02 -8.1636399030685425e-01 2.6171201467514038e-01 <_> 0 -1 428 -9.6960002556443214e-03 1.1561699956655502e-01 -7.1693199872970581e-01 <_> 0 -1 429 4.8902999609708786e-02 1.3050499558448792e-01 -1.6448370218276978e+00 <_> 0 -1 430 -4.1611999273300171e-02 -1.1795840263366699e+00 2.5017000734806061e-02 <_> 0 -1 431 -2.0188000053167343e-02 6.3188201189041138e-01 -1.0490400344133377e-01 <_> 0 -1 432 -9.7900000400841236e-04 1.8507799506187439e-01 -5.3565901517868042e-01 <_> 0 -1 433 -3.3622000366449356e-02 -9.3127602338790894e-01 2.0071500539779663e-01 <_> 0 -1 434 1.9455999135971069e-02 3.8029000163078308e-02 -1.0112210512161255e+00 <_> 0 -1 435 -3.1800000579096377e-04 3.6457699537277222e-01 -2.7610900998115540e-01 <_> 0 -1 436 -3.8899999344721437e-04 1.9665899872779846e-01 -5.3410500288009644e-01 <_> 0 -1 437 -9.3496002256870270e-02 -1.6772350072860718e+00 2.0727099478244781e-01 <_> 0 -1 438 -7.7877998352050781e-02 -3.0760629177093506e+00 -3.5803999751806259e-02 <_> 0 -1 439 1.6947999596595764e-02 2.1447399258613586e-01 -7.1376299858093262e-01 <_> 0 -1 440 -2.1459000185132027e-02 -1.1468060016632080e+00 1.5855999663472176e-02 <_> 0 -1 441 -1.2865999713540077e-02 8.3812397718429565e-01 -6.5944001078605652e-02 <_> 0 -1 442 7.8220004215836525e-03 -2.8026801347732544e-01 7.9376900196075439e-01 <_> 0 -1 443 1.0294400155544281e-01 1.7832300066947937e-01 -6.8412202596664429e-01 <_> 0 -1 444 -3.7487998604774475e-02 9.6189999580383301e-01 -2.1735599637031555e-01 <_> 0 -1 445 2.5505999103188515e-02 1.0103999637067318e-02 1.2461110353469849e+00 <_> 0 -1 446 6.6700001480057836e-04 -5.3488200902938843e-01 1.4746299386024475e-01 <_> 0 -1 447 -2.8867900371551514e-01 8.2172799110412598e-01 -1.4948000200092793e-02 <_> 0 -1 448 9.1294996440410614e-02 -1.9605399668216705e-01 1.0803170204162598e+00 <_> 0 -1 449 1.2056600302457809e-01 -2.3848999291658401e-02 1.1392610073089600e+00 <_> 0 -1 450 -7.3775000870227814e-02 -1.3583840131759644e+00 -4.2039998807013035e-03 <_> 0 -1 451 -3.3128000795841217e-02 -6.4483201503753662e-01 2.4142199754714966e-01 <_> 0 -1 452 -4.3937001377344131e-02 8.4285402297973633e-01 -2.0624800026416779e-01 <_> 0 -1 453 1.8110199272632599e-01 1.9212099909782410e-01 -1.2222139835357666e+00 <_> 0 -1 454 -1.1850999668240547e-02 -7.2677397727966309e-01 5.2687998861074448e-02 <_> 0 -1 455 4.5920000411570072e-03 -3.6305201053619385e-01 2.9223799705505371e-01 <_> 0 -1 456 7.0620002225041389e-03 5.8116000145673752e-02 -6.7161601781845093e-01 <_> 0 -1 457 -2.3715000599622726e-02 4.7142100334167480e-01 1.8580000847578049e-02 <_> 0 -1 458 -6.7171998322010040e-02 -1.1331889629364014e+00 2.3780999705195427e-02 <_> 0 -1 459 -6.5310001373291016e-02 9.8253500461578369e-01 2.8362000361084938e-02 <_> 0 -1 460 2.2791000083088875e-02 -2.8213700652122498e-01 5.8993399143218994e-01 <_> 0 -1 461 -1.9037999212741852e-02 -6.3711500167846680e-01 2.6514598727226257e-01 <_> 0 -1 462 -6.8689999170601368e-03 3.7487301230430603e-01 -3.3232098817825317e-01 <_> 0 -1 463 -4.0146000683307648e-02 -1.3048729896545410e+00 1.5724299848079681e-01 <_> 0 -1 464 -4.0530998259782791e-02 -2.0458049774169922e+00 -2.6925999671220779e-02 <_> 0 -1 465 -1.2253999710083008e-02 7.7649402618408203e-01 -4.2971000075340271e-02 <_> 0 -1 466 -2.7219999581575394e-02 1.7424400150775909e-01 -4.4600901007652283e-01 <_> 0 -1 467 -8.8366001844406128e-02 -1.5036419630050659e+00 1.4289900660514832e-01 <_> 0 -1 468 -7.9159997403621674e-03 2.8666698932647705e-01 -3.7923699617385864e-01 <_> 0 -1 469 -4.1960000991821289e-02 1.3846950531005859e+00 6.5026998519897461e-02 <_> 0 -1 470 4.5662999153137207e-02 -2.2452299296855927e-01 7.9521000385284424e-01 <_> 0 -1 471 -1.4090600609779358e-01 -1.5879319906234741e+00 1.1359000205993652e-01 <_> 0 -1 472 -5.9216000139713287e-02 -1.1945960521697998e+00 -7.1640000678598881e-03 <_> 0 -1 473 4.3390002101659775e-03 -1.5528699755668640e-01 4.0664499998092651e-01 <_> 0 -1 474 -2.0369999110698700e-03 2.5927901268005371e-01 -3.8368299603462219e-01 <_> 0 -1 475 2.7516499161720276e-01 -8.8497996330261230e-02 7.6787501573562622e-01 <_> 0 -1 476 -2.6601999998092651e-02 7.5024497509002686e-01 -2.2621999680995941e-01 <_> 0 -1 477 4.0906000882387161e-02 1.2158600240945816e-01 -1.4566910266876221e+00 <_> 0 -1 478 5.5320002138614655e-03 -3.6611500382423401e-01 2.5968599319458008e-01 <_> 0 -1 479 3.1879000365734100e-02 -7.5019001960754395e-02 4.8484799265861511e-01 <_> 0 -1 480 -4.1482001543045044e-02 7.8220397233963013e-01 -2.1992200613021851e-01 <_> 0 -1 481 -9.6130996942520142e-02 -8.9456301927566528e-01 1.4680700004100800e-01 <_> 0 -1 482 -1.1568999849259853e-02 8.2714098691940308e-01 -2.0275600254535675e-01 <_> 0 -1 483 1.8312999978661537e-02 1.6367999836802483e-02 2.7306801080703735e-01 <_> 0 -1 484 -3.4166000783443451e-02 1.1307320594787598e+00 -1.8810899555683136e-01 <_> 0 -1 485 -2.4476999416947365e-02 -5.7791298627853394e-01 1.5812499821186066e-01 <_> 0 -1 486 4.8957001417875290e-02 -2.2564999759197235e-02 -1.6373280286788940e+00 <_> 0 -1 487 -2.0702999085187912e-02 -5.4512101411819458e-01 2.4086999893188477e-01 <_> 0 -1 488 -2.3002000525593758e-02 -1.2236540317535400e+00 -7.3440000414848328e-03 <_> 0 -1 489 6.4585000276565552e-02 1.4695599675178528e-01 -4.4967499375343323e-01 <_> 0 -1 490 1.2666000053286552e-02 -2.7873900532722473e-01 4.3876600265502930e-01 <_> 0 -1 491 -1.2002999894320965e-02 -2.4289099872112274e-01 2.5350099802017212e-01 <_> 0 -1 492 -2.6443999260663986e-02 -8.5864800214767456e-01 2.6025999337434769e-02 <_> 0 -1 493 -2.5547999888658524e-02 6.9287902116775513e-01 -2.1160000469535589e-03 <_> 0 -1 494 3.9115000516176224e-02 -1.6589100658893585e-01 1.5209139585494995e+00 <_> 0 -1 495 -6.0330000706017017e-03 4.3856900930404663e-01 -2.1613700687885284e-01 <_> 0 -1 496 -3.3936999738216400e-02 -9.7998398542404175e-01 2.2133000195026398e-02 <_> 99 -3.8700489997863770e+00 <_> 0 -1 497 4.0672998875379562e-02 -9.0474700927734375e-01 6.4410597085952759e-01 <_> 0 -1 498 2.5609999895095825e-02 -7.9216998815536499e-01 5.7489997148513794e-01 <_> 0 -1 499 1.9959500432014465e-01 -3.0099600553512573e-01 1.3143850564956665e+00 <_> 0 -1 500 1.2404999695718288e-02 -8.9882999658584595e-01 2.9205799102783203e-01 <_> 0 -1 501 3.9207998663187027e-02 -4.1955199837684631e-01 5.3463298082351685e-01 <_> 0 -1 502 -3.0843999236822128e-02 4.5793399214744568e-01 -4.4629099965095520e-01 <_> 0 -1 503 -3.5523001104593277e-02 9.1310501098632812e-01 -2.7373200654983521e-01 <_> 0 -1 504 -6.1650000512599945e-02 -1.4697799682617188e+00 2.0364099740982056e-01 <_> 0 -1 505 -1.1739999987185001e-02 -1.0482879877090454e+00 6.7801997065544128e-02 <_> 0 -1 506 6.6933996975421906e-02 2.9274499416351318e-01 -5.2282899618148804e-01 <_> 0 -1 507 -2.0631000399589539e-02 -1.2855139970779419e+00 4.4550999999046326e-02 <_> 0 -1 508 -2.2357000038027763e-02 -8.5753798484802246e-01 1.8434000015258789e-01 <_> 0 -1 509 1.1500000255182385e-03 1.6405500471591949e-01 -6.9125002622604370e-01 <_> 0 -1 510 3.5872999578714371e-02 1.5756499767303467e-01 -8.4262597560882568e-01 <_> 0 -1 511 3.0659999698400497e-02 2.1637000143527985e-02 -1.3634690046310425e+00 <_> 0 -1 512 5.5559999309480190e-03 -1.6737000644207001e-01 2.5888401269912720e-01 <_> 0 -1 513 -6.1160000041127205e-03 -9.7271800041198730e-01 6.6100001335144043e-02 <_> 0 -1 514 -3.0316999182105064e-02 9.8474198579788208e-01 -1.6448000445961952e-02 <_> 0 -1 515 -9.7200004383921623e-03 4.7604700922966003e-01 -3.2516700029373169e-01 <_> 0 -1 516 -5.7126998901367188e-02 -9.5920699834823608e-01 1.9938200712203979e-01 <_> 0 -1 517 4.0059997700154781e-03 -5.2612501382827759e-01 2.2428700327873230e-01 <_> 0 -1 518 3.3734001219272614e-02 1.7070099711418152e-01 -1.0737580060958862e+00 <_> 0 -1 519 -3.4641999751329422e-02 -1.1343129873275757e+00 3.6540001630783081e-02 <_> 0 -1 520 4.6923000365495682e-02 2.5832301378250122e-01 -7.1535801887512207e-01 <_> 0 -1 521 -8.7660001590847969e-03 1.9640900194644928e-01 -5.3355097770690918e-01 <_> 0 -1 522 6.5627999603748322e-02 -5.1194999366998672e-02 9.7610700130462646e-01 <_> 0 -1 523 -4.4165000319480896e-02 1.0631920099258423e+00 -2.3462599515914917e-01 <_> 0 -1 524 1.7304999753832817e-02 -1.8582899868488312e-01 4.5889899134635925e-01 <_> 0 -1 525 3.3135998994112015e-02 -2.9381999745965004e-02 -2.6651329994201660e+00 <_> 0 -1 526 -2.1029999479651451e-02 9.9979901313781738e-01 2.4937000125646591e-02 <_> 0 -1 527 2.9783999547362328e-02 -2.9605999588966370e-02 -2.1695868968963623e+00 <_> 0 -1 528 5.5291999131441116e-02 -7.5599999399855733e-04 7.4651998281478882e-01 <_> 0 -1 529 -3.3597998321056366e-02 -1.5274159908294678e+00 1.1060000397264957e-02 <_> 0 -1 530 1.9602999091148376e-02 3.3574998378753662e-02 9.9526202678680420e-01 <_> 0 -1 531 -2.0787000656127930e-02 7.6612901687622070e-01 -2.4670800566673279e-01 <_> 0 -1 532 3.2536000013351440e-02 1.6263400018215179e-01 -6.1134302616119385e-01 <_> 0 -1 533 -1.0788000188767910e-02 -9.7839701175689697e-01 2.8969999402761459e-02 <_> 0 -1 534 -9.9560003727674484e-03 4.6145799756050110e-01 -1.3510499894618988e-01 <_> 0 -1 535 -3.7489999085664749e-03 2.5458198785781860e-01 -5.1955598592758179e-01 <_> 0 -1 536 -4.1779998689889908e-02 -8.0565100908279419e-01 1.5208500623703003e-01 <_> 0 -1 537 -3.4221000969409943e-02 -1.3137799501419067e+00 -3.5800000187009573e-03 <_> 0 -1 538 1.0130000300705433e-02 2.0175799727439880e-01 -6.1339598894119263e-01 <_> 0 -1 539 -8.9849002659320831e-02 9.7632801532745361e-01 -2.0884799957275391e-01 <_> 0 -1 540 2.6097999885678291e-02 -1.8807999789714813e-01 4.7705799341201782e-01 <_> 0 -1 541 -3.7539999466389418e-03 -6.7980402708053589e-01 1.1288800090551376e-01 <_> 0 -1 542 3.1973000615835190e-02 1.8951700627803802e-01 -1.4967479705810547e+00 <_> 0 -1 543 1.9332999363541603e-02 -2.3609900474548340e-01 8.1320500373840332e-01 <_> 0 -1 544 1.9490000559017062e-03 2.4830399453639984e-01 -6.9211997091770172e-02 <_> 0 -1 545 -4.4146999716758728e-02 -1.0418920516967773e+00 4.8053000122308731e-02 <_> 0 -1 546 -4.4681999832391739e-02 5.1346302032470703e-01 -7.3799998499453068e-03 <_> 0 -1 547 -1.0757499933242798e-01 1.6202019453048706e+00 -1.8667599558830261e-01 <_> 0 -1 548 -1.2846800684928894e-01 2.9869480133056641e+00 9.5427997410297394e-02 <_> 0 -1 549 -4.4757999479770660e-02 6.0405302047729492e-01 -2.7058699727058411e-01 <_> 0 -1 550 -4.3990999460220337e-02 -6.1790502071380615e-01 1.5997199714183807e-01 <_> 0 -1 551 -1.2268999963998795e-01 6.6327202320098877e-01 -2.3636999726295471e-01 <_> 0 -1 552 -1.9982999190688133e-02 -1.1228660345077515e+00 1.9616700708866119e-01 <_> 0 -1 553 -1.5527999959886074e-02 -1.0770269632339478e+00 2.0693000406026840e-02 <_> 0 -1 554 -4.8971001058816910e-02 8.1168299913406372e-01 -1.7252000048756599e-02 <_> 0 -1 555 5.5975999683141708e-02 -2.2529000416398048e-02 -1.7356760501861572e+00 <_> 0 -1 556 -9.8580000922083855e-03 6.7881399393081665e-01 -5.8180000633001328e-02 <_> 0 -1 557 1.3481000438332558e-02 5.7847999036312103e-02 -7.7255302667617798e-01 <_> 0 -1 558 6.5609999001026154e-03 -1.3146899640560150e-01 6.7055797576904297e-01 <_> 0 -1 559 7.1149999275803566e-03 -3.7880599498748779e-01 3.0978998541831970e-01 <_> 0 -1 560 4.8159998841583729e-03 -5.8470398187637329e-01 2.5602099299430847e-01 <_> 0 -1 561 9.5319999381899834e-03 -3.0217000842094421e-01 4.1253298521041870e-01 <_> 0 -1 562 -2.7474999427795410e-02 5.9154701232910156e-01 1.7963999882340431e-02 <_> 0 -1 563 -3.9519999176263809e-02 9.6913498640060425e-01 -2.1020300686359406e-01 <_> 0 -1 564 -3.0658999457955360e-02 9.1155898571014404e-01 4.0550000965595245e-02 <_> 0 -1 565 -1.4680000022053719e-03 -6.0489797592163086e-01 1.6960899531841278e-01 <_> 0 -1 566 1.9077600538730621e-01 4.3515000492334366e-02 8.1892901659011841e-01 <_> 0 -1 567 5.1790000870823860e-03 -9.3617302179336548e-01 2.4937000125646591e-02 <_> 0 -1 568 2.4126000702381134e-02 1.8175500631332397e-01 -3.4185901284217834e-01 <_> 0 -1 569 -2.6383999735116959e-02 -1.2912579774856567e+00 -3.4280000254511833e-03 <_> 0 -1 570 5.4139997810125351e-03 -4.6291999518871307e-02 2.5269600749015808e-01 <_> 0 -1 571 5.4216001182794571e-02 -1.2848000042140484e-02 -1.4304540157318115e+00 <_> 0 -1 572 2.3799999326001853e-04 -2.6676699519157410e-01 3.3588299155235291e-01 <_> 0 -1 573 1.5216999687254429e-02 -5.1367300748825073e-01 1.3005100190639496e-01 <_> 0 -1 574 1.7007999122142792e-02 4.1575899720191956e-01 -3.1241199374198914e-01 <_> 0 -1 575 3.0496999621391296e-02 -2.4820999801158905e-01 7.0828497409820557e-01 <_> 0 -1 576 6.5430002287030220e-03 -2.2637000679969788e-01 1.9184599816799164e-01 <_> 0 -1 577 1.4163999259471893e-01 6.5227001905441284e-02 -8.8809502124786377e-01 <_> 0 -1 578 1.9338000565767288e-02 1.8891200423240662e-01 -2.7397701144218445e-01 <_> 0 -1 579 -1.7324000597000122e-02 -9.4866698980331421e-01 2.4196999147534370e-02 <_> 0 -1 580 -6.2069999985396862e-03 3.6938399076461792e-01 -1.7494900524616241e-01 <_> 0 -1 581 -1.6109000891447067e-02 9.6159499883651733e-01 -2.0005300641059875e-01 <_> 0 -1 582 -1.0122500360012054e-01 -3.0699110031127930e+00 1.1363799870014191e-01 <_> 0 -1 583 -7.5509999878704548e-03 2.2921000421047211e-01 -4.5645099878311157e-01 <_> 0 -1 584 4.4247999787330627e-02 -3.1599999056197703e-04 3.9225301146507263e-01 <_> 0 -1 585 -1.1636000126600266e-01 9.5233702659606934e-01 -2.0201599597930908e-01 <_> 0 -1 586 4.7360002063214779e-03 -9.9177002906799316e-02 2.0370499789714813e-01 <_> 0 -1 587 2.2459000349044800e-02 8.7280003353953362e-03 -1.0217070579528809e+00 <_> 0 -1 588 -1.2109000235795975e-02 6.4812600612640381e-01 -9.0149000287055969e-02 <_> 0 -1 589 5.6120000779628754e-02 -3.6759998649358749e-02 -1.9275590181350708e+00 <_> 0 -1 590 -8.7379999458789825e-03 6.9261300563812256e-01 -6.8374998867511749e-02 <_> 0 -1 591 6.6399998031556606e-03 -4.0569800138473511e-01 1.8625700473785400e-01 <_> 0 -1 592 -1.8131999298930168e-02 -6.4518201351165771e-01 2.1976399421691895e-01 <_> 0 -1 593 -2.2718999534845352e-02 9.7776198387145996e-01 -1.8654300272464752e-01 <_> 0 -1 594 1.2705000117421150e-02 -1.0546600073575974e-01 3.7404099106788635e-01 <_> 0 -1 595 -1.3682999648153782e-02 6.1064100265502930e-01 -2.6881098747253418e-01 <_> 115 -3.7160909175872803e+00 <_> 0 -1 596 3.1357999891042709e-02 -1.0183910131454468e+00 5.7528597116470337e-01 <_> 0 -1 597 9.3050003051757812e-02 -4.1297501325607300e-01 1.0091199874877930e+00 <_> 0 -1 598 2.5949999690055847e-02 -5.8587902784347534e-01 5.6606197357177734e-01 <_> 0 -1 599 1.6472000628709793e-02 -9.2857497930526733e-01 3.0924499034881592e-01 <_> 0 -1 600 -1.8779999809339643e-03 1.1951000243425369e-01 -1.1180130243301392e+00 <_> 0 -1 601 -9.0129999443888664e-03 -5.7849502563476562e-01 3.3154401183128357e-01 <_> 0 -1 602 2.2547999396920204e-02 -3.8325101137161255e-01 5.2462202310562134e-01 <_> 0 -1 603 -3.7780001759529114e-02 1.1790670156478882e+00 -3.4166999161243439e-02 <_> 0 -1 604 -5.3799999877810478e-03 -8.6265897750854492e-01 1.1867900192737579e-01 <_> 0 -1 605 -2.3893000558018684e-02 -7.4950599670410156e-01 2.1011400222778320e-01 <_> 0 -1 606 -2.6521999388933182e-02 9.2128598690032959e-01 -2.8252801299095154e-01 <_> 0 -1 607 1.2280000373721123e-02 2.6662799715995789e-01 -7.0013600587844849e-01 <_> 0 -1 608 9.6594996750354767e-02 -2.8453999757766724e-01 7.3168998956680298e-01 <_> 0 -1 609 -2.7414999902248383e-02 -6.1492699384689331e-01 1.5576200187206268e-01 <_> 0 -1 610 -1.5767000615596771e-02 5.7551199197769165e-01 -3.4362199902534485e-01 <_> 0 -1 611 -2.1100000012665987e-03 3.2599699497222900e-01 -1.3008299469947815e-01 <_> 0 -1 612 1.2006999924778938e-02 8.9322999119758606e-02 -9.6025598049163818e-01 <_> 0 -1 613 -1.5421999618411064e-02 3.4449499845504761e-01 -4.6711999177932739e-01 <_> 0 -1 614 -4.1579999960958958e-03 2.3696300387382507e-01 -5.2563297748565674e-01 <_> 0 -1 615 -2.1185999736189842e-02 -7.4267697334289551e-01 2.1702000498771667e-01 <_> 0 -1 616 -1.7077000811696053e-02 -9.0471798181533813e-01 6.6012002527713776e-02 <_> 0 -1 617 -4.0849998593330383e-02 -3.4446600079536438e-01 2.1503700315952301e-01 <_> 0 -1 618 -8.1930002197623253e-03 -9.3388599157333374e-01 5.0471000373363495e-02 <_> 0 -1 619 -1.9238000735640526e-02 -5.3203701972961426e-01 1.7240600287914276e-01 <_> 0 -1 620 -4.4192001223564148e-02 9.2075002193450928e-01 -2.2148500382900238e-01 <_> 0 -1 621 -6.2392000108957291e-02 -7.1053802967071533e-01 1.8323899805545807e-01 <_> 0 -1 622 -1.0079999919980764e-03 -8.7063097953796387e-01 5.5330000817775726e-02 <_> 0 -1 623 2.3870000615715981e-02 -2.2854200005531311e-01 5.2415597438812256e-01 <_> 0 -1 624 2.1391000598669052e-02 -3.0325898528099060e-01 5.5860602855682373e-01 <_> 0 -1 625 2.0254999399185181e-02 2.6901501417160034e-01 -7.0261800289154053e-01 <_> 0 -1 626 -2.8772000223398209e-02 -1.1835030317306519e+00 4.6512000262737274e-02 <_> 0 -1 627 3.4199999645352364e-03 -5.4652100801467896e-01 2.5962498784065247e-01 <_> 0 -1 628 5.6983001530170441e-02 -2.6982900500297546e-01 5.8170700073242188e-01 <_> 0 -1 629 -9.3892000615596771e-02 -9.1046398878097534e-01 1.9677700102329254e-01 <_> 0 -1 630 1.7699999734759331e-02 -4.4003298878669739e-01 2.1349500119686127e-01 <_> 0 -1 631 2.2844199836254120e-01 2.3605000227689743e-02 7.7171599864959717e-01 <_> 0 -1 632 -1.8287500739097595e-01 7.9228597879409790e-01 -2.4644799530506134e-01 <_> 0 -1 633 -6.9891996681690216e-02 8.0267798900604248e-01 -3.6072000861167908e-02 <_> 0 -1 634 1.5297000296413898e-02 -2.0072300732135773e-01 1.1030600070953369e+00 <_> 0 -1 635 6.7500001750886440e-03 -4.5967999845743179e-02 7.2094500064849854e-01 <_> 0 -1 636 -1.5983000397682190e-02 -9.0357202291488647e-01 4.4987998902797699e-02 <_> 0 -1 637 1.3088000006973743e-02 3.5297098755836487e-01 -3.7710601091384888e-01 <_> 0 -1 638 1.3061000034213066e-02 -1.9583599269390106e-01 1.1198940277099609e+00 <_> 0 -1 639 -3.9907000958919525e-02 -1.3998429775238037e+00 1.9145099818706512e-01 <_> 0 -1 640 1.5026999637484550e-02 2.3600000422447920e-03 -1.1611249446868896e+00 <_> 0 -1 641 -2.0517999306321144e-02 -4.8908099532127380e-01 1.6743400692939758e-01 <_> 0 -1 642 -2.2359000518918037e-02 -1.2202980518341064e+00 -1.1975999921560287e-02 <_> 0 -1 643 -7.9150004312396049e-03 3.7228098511695862e-01 -8.5063003003597260e-02 <_> 0 -1 644 1.5258000232279301e-02 -2.9412600398063660e-01 5.9406399726867676e-01 <_> 0 -1 645 -3.1665999442338943e-02 -1.4395569562911987e+00 1.3578799366950989e-01 <_> 0 -1 646 -3.0773999169468880e-02 -2.2545371055603027e+00 -3.3971000462770462e-02 <_> 0 -1 647 -1.5483000315725803e-02 3.7700700759887695e-01 1.5847999602556229e-02 <_> 0 -1 648 3.5167001187801361e-02 -2.9446101188659668e-01 5.3159099817276001e-01 <_> 0 -1 649 -1.7906000837683678e-02 -9.9788200855255127e-01 1.6235999763011932e-01 <_> 0 -1 650 -3.1799999997019768e-03 4.7657001763582230e-02 -7.5249898433685303e-01 <_> 0 -1 651 1.5720000490546227e-02 1.4873799681663513e-01 -6.5375399589538574e-01 <_> 0 -1 652 2.9864000156521797e-02 -1.4952000230550766e-02 -1.2275190353393555e+00 <_> 0 -1 653 2.9899999499320984e-03 -1.4263699948787689e-01 4.3272799253463745e-01 <_> 0 -1 654 8.4749996662139893e-02 -1.9280999898910522e-02 -1.1946409940719604e+00 <_> 0 -1 655 -5.8724999427795410e-02 -1.7328219413757324e+00 1.4374700188636780e-01 <_> 0 -1 656 4.4755998998880386e-02 -2.4140599370002747e-01 5.4019999504089355e-01 <_> 0 -1 657 4.0369000285863876e-02 5.7680001482367516e-03 5.6578099727630615e-01 <_> 0 -1 658 3.7735998630523682e-02 3.8180999457836151e-02 -7.9370397329330444e-01 <_> 0 -1 659 6.0752999037504196e-02 7.6453000307083130e-02 1.4813209772109985e+00 <_> 0 -1 660 -1.9832000136375427e-02 -1.6971720457077026e+00 -2.7370000258088112e-02 <_> 0 -1 661 -1.6592699289321899e-01 6.2976002693176270e-01 3.1762998551130295e-02 <_> 0 -1 662 6.9014996290206909e-02 -3.3463200926780701e-01 3.0076700448989868e-01 <_> 0 -1 663 1.1358000338077545e-02 2.2741499543190002e-01 -3.8224700093269348e-01 <_> 0 -1 664 1.7000000225380063e-03 1.9223800301551819e-01 -5.2735102176666260e-01 <_> 0 -1 665 7.9769000411033630e-02 9.1491997241973877e-02 2.1049048900604248e+00 <_> 0 -1 666 -5.7144001126289368e-02 -1.7452130317687988e+00 -4.0910001844167709e-02 <_> 0 -1 667 7.3830001056194305e-03 -2.4214799702167511e-01 3.5577800869941711e-01 <_> 0 -1 668 -1.8040999770164490e-02 1.1779999732971191e+00 -1.7676700651645660e-01 <_> 0 -1 669 9.4503000378608704e-02 1.3936099410057068e-01 -1.2993700504302979e+00 <_> 0 -1 670 5.4210000671446323e-03 -5.4608601331710815e-01 1.3916400074958801e-01 <_> 0 -1 671 7.0290002040565014e-03 -2.1597200632095337e-01 3.9258098602294922e-01 <_> 0 -1 672 3.4515999257564545e-02 6.3188999891281128e-02 -7.2108101844787598e-01 <_> 0 -1 673 -5.1924999803304672e-02 6.8667602539062500e-01 6.3272997736930847e-02 <_> 0 -1 674 -6.9162003695964813e-02 1.7411810159683228e+00 -1.6619299352169037e-01 <_> 0 -1 675 -5.5229999125003815e-03 3.0694699287414551e-01 -1.6662900149822235e-01 <_> 0 -1 676 6.8599998950958252e-02 -2.1405400335788727e-01 7.3185002803802490e-01 <_> 0 -1 677 -6.7038998007774353e-02 -7.9360598325729370e-01 2.0525799691677094e-01 <_> 0 -1 678 -2.1005000919103622e-02 3.7344399094581604e-01 -2.9618600010871887e-01 <_> 0 -1 679 2.0278999581933022e-02 -1.5200000256299973e-02 4.0555301308631897e-01 <_> 0 -1 680 -4.7107998281717300e-02 1.2116849422454834e+00 -1.7464299499988556e-01 <_> 0 -1 681 1.8768499791622162e-01 -2.2909000515937805e-02 6.9645798206329346e-01 <_> 0 -1 682 -4.3228998780250549e-02 -1.0602480173110962e+00 -5.5599998449906707e-04 <_> 0 -1 683 2.0004000514745712e-02 -3.2751001417636871e-02 5.3805100917816162e-01 <_> 0 -1 684 8.0880001187324524e-03 3.7548001855611801e-02 -7.4768900871276855e-01 <_> 0 -1 685 2.7101000770926476e-02 -8.1790000200271606e-02 3.3387100696563721e-01 <_> 0 -1 686 -9.1746002435684204e-02 -1.9213509559631348e+00 -3.8952998816967010e-02 <_> 0 -1 687 -1.2454999610781670e-02 4.8360601067543030e-01 1.8168000504374504e-02 <_> 0 -1 688 1.4649000018835068e-02 -1.9906699657440186e-01 7.2815400362014771e-01 <_> 0 -1 689 2.9101999476552010e-02 1.9871099293231964e-01 -4.9216800928115845e-01 <_> 0 -1 690 8.7799998000264168e-03 -1.9499599933624268e-01 7.7317398786544800e-01 <_> 0 -1 691 -5.4740000516176224e-02 1.8087190389633179e+00 6.8323001265525818e-02 <_> 0 -1 692 -1.4798000454902649e-02 7.8064900636672974e-01 -1.8709599971771240e-01 <_> 0 -1 693 2.5012999773025513e-02 1.5285299718379974e-01 -1.6021020412445068e+00 <_> 0 -1 694 4.6548001468181610e-02 -1.6738200187683105e-01 1.1902060508728027e+00 <_> 0 -1 695 1.7624000087380409e-02 -1.0285499691963196e-01 3.9175900816917419e-01 <_> 0 -1 696 1.6319599747657776e-01 -3.5624001175165176e-02 -1.6098170280456543e+00 <_> 0 -1 697 1.3137999922037125e-02 -5.6359000504016876e-02 5.4158902168273926e-01 <_> 0 -1 698 -1.5665000304579735e-02 2.8063100576400757e-01 -3.1708601117134094e-01 <_> 0 -1 699 8.0554001033306122e-02 1.2640400230884552e-01 -1.0297529697418213e+00 <_> 0 -1 700 3.5363998264074326e-02 2.0752999931573868e-02 -7.9105597734451294e-01 <_> 0 -1 701 3.2986998558044434e-02 1.9057099521160126e-01 -8.3839899301528931e-01 <_> 0 -1 702 1.2195000424981117e-02 7.3729000985622406e-02 -6.2780702114105225e-01 <_> 0 -1 703 4.3065998703241348e-02 4.7384999692440033e-02 1.5712939500808716e+00 <_> 0 -1 704 3.0326999723911285e-02 -2.7314600348472595e-01 3.8572001457214355e-01 <_> 0 -1 705 3.5493001341819763e-02 5.4593998938798904e-02 5.2583402395248413e-01 <_> 0 -1 706 -1.4596999622881413e-02 3.8152599334716797e-01 -2.8332400321960449e-01 <_> 0 -1 707 1.2606999836862087e-02 1.5455099940299988e-01 -3.0501499772071838e-01 <_> 0 -1 708 1.0172000154852867e-02 2.3637000471353531e-02 -8.7217897176742554e-01 <_> 0 -1 709 2.8843000531196594e-02 1.6090999543666840e-01 -2.0277599990367889e-01 <_> 0 -1 710 5.5100000463426113e-04 -6.1545401811599731e-01 8.0935999751091003e-02 <_> 127 -3.5645289421081543e+00 <_> 0 -1 711 4.8344001173973083e-02 -8.4904599189758301e-01 5.6974399089813232e-01 <_> 0 -1 712 3.2460000365972519e-02 -8.1417298316955566e-01 4.4781699776649475e-01 <_> 0 -1 713 3.3339999616146088e-02 -3.6423799395561218e-01 6.7937397956848145e-01 <_> 0 -1 714 6.4019998535513878e-03 -1.1885459423065186e+00 1.9238699972629547e-01 <_> 0 -1 715 -5.6889997795224190e-03 3.3085298538208008e-01 -7.1334099769592285e-01 <_> 0 -1 716 1.2698000296950340e-02 -5.0990802049636841e-01 1.1376299709081650e-01 <_> 0 -1 717 6.0549997724592686e-03 -1.0470550060272217e+00 2.0222599804401398e-01 <_> 0 -1 718 2.6420000940561295e-03 -5.0559401512145996e-01 3.6441200971603394e-01 <_> 0 -1 719 -1.6925999894738197e-02 -9.9541902542114258e-01 1.2602199614048004e-01 <_> 0 -1 720 2.8235999867320061e-02 -9.4137996435165405e-02 5.7780402898788452e-01 <_> 0 -1 721 1.0428999550640583e-02 2.3272900283336639e-01 -5.2569699287414551e-01 <_> 0 -1 722 9.8860003054141998e-03 -1.0316299647092819e-01 4.7657600045204163e-01 <_> 0 -1 723 2.6015000417828560e-02 -1.0920000495389104e-03 -1.5581729412078857e+00 <_> 0 -1 724 -2.5537999346852303e-02 -6.5451401472091675e-01 1.8843199312686920e-01 <_> 0 -1 725 -3.5310001112520695e-03 2.8140598535537720e-01 -4.4575300812721252e-01 <_> 0 -1 726 9.2449998483061790e-03 1.5612000226974487e-01 -2.1370999515056610e-01 <_> 0 -1 727 2.1030999720096588e-02 -2.9170298576354980e-01 5.2234101295471191e-01 <_> 0 -1 728 -5.1063001155853271e-02 1.3661290407180786e+00 3.0465999618172646e-02 <_> 0 -1 729 -6.2330000102519989e-02 1.2207020521163940e+00 -2.2434400022029877e-01 <_> 0 -1 730 -3.2963000237941742e-02 -8.2016801834106445e-01 1.4531899988651276e-01 <_> 0 -1 731 -3.7418000400066376e-02 -1.2218099832534790e+00 1.9448999315500259e-02 <_> 0 -1 732 1.2402799725532532e-01 1.2082300335168839e-01 -9.8729300498962402e-01 <_> 0 -1 733 -8.9229997247457504e-03 -1.1688489913940430e+00 2.1105000749230385e-02 <_> 0 -1 734 -5.9879999607801437e-02 -1.0689330101013184e+00 1.9860200583934784e-01 <_> 0 -1 735 6.2620001845061779e-03 -3.6229598522186279e-01 3.8000801205635071e-01 <_> 0 -1 736 -1.7673000693321228e-02 4.9094098806381226e-01 -1.4606699347496033e-01 <_> 0 -1 737 1.7579000443220139e-02 5.8728098869323730e-01 -2.7774399518966675e-01 <_> 0 -1 738 5.1560001447796822e-03 -7.5194999575614929e-02 6.0193097591400146e-01 <_> 0 -1 739 -1.0599999688565731e-02 2.7637401223182678e-01 -3.7794300913810730e-01 <_> 0 -1 740 2.0884099602699280e-01 -5.3599998354911804e-03 1.0317809581756592e+00 <_> 0 -1 741 -2.6412999257445335e-02 8.2336401939392090e-01 -2.2480599582195282e-01 <_> 0 -1 742 5.8892000466585159e-02 1.3098299503326416e-01 -1.1853699684143066e+00 <_> 0 -1 743 -1.1579000391066074e-02 -9.0667802095413208e-01 4.4126998633146286e-02 <_> 0 -1 744 4.5988000929355621e-02 1.0143999941647053e-02 1.0740900039672852e+00 <_> 0 -1 745 -2.2838000208139420e-02 1.7791990041732788e+00 -1.7315499484539032e-01 <_> 0 -1 746 -8.1709995865821838e-03 5.7386302947998047e-01 -7.4106000363826752e-02 <_> 0 -1 747 3.5359999164938927e-03 -3.2072898745536804e-01 4.0182501077651978e-01 <_> 0 -1 748 4.9444999545812607e-02 1.9288000464439392e-01 -1.2166700363159180e+00 <_> 0 -1 749 3.5139999818056822e-03 6.9568000733852386e-02 -7.1323698759078979e-01 <_> 0 -1 750 -3.0996000394225121e-02 -3.8862198591232300e-01 1.8098799884319305e-01 <_> 0 -1 751 8.6452998220920563e-02 -2.5792999193072319e-02 -1.5453219413757324e+00 <_> 0 -1 752 -1.3652600347995758e-01 -1.9199420213699341e+00 1.6613300144672394e-01 <_> 0 -1 753 -5.7689999230206013e-03 -1.2822589874267578e+00 -1.5907999128103256e-02 <_> 0 -1 754 -1.7899999395012856e-02 -4.0409898757934570e-01 2.3591600358486176e-01 <_> 0 -1 755 -1.9969999790191650e-02 -7.2891902923583984e-01 5.6235000491142273e-02 <_> 0 -1 756 -5.7493001222610474e-02 5.7830798625946045e-01 -1.5796000137925148e-02 <_> 0 -1 757 -8.3056002855300903e-02 9.1511601209640503e-01 -2.1121400594711304e-01 <_> 0 -1 758 -5.3771000355482101e-02 -5.1931297779083252e-01 1.8576000630855560e-01 <_> 0 -1 759 -8.3670001477003098e-03 2.4109700322151184e-01 -3.9648601412773132e-01 <_> 0 -1 760 5.5406998842954636e-02 1.6771200299263000e-01 -2.5664970874786377e+00 <_> 0 -1 761 -6.7180998623371124e-02 -1.3658570051193237e+00 -1.4232000336050987e-02 <_> 0 -1 762 -2.3900000378489494e-02 -1.7084569931030273e+00 1.6507799923419952e-01 <_> 0 -1 763 5.5949999950826168e-03 -3.1373998522758484e-01 3.2837900519371033e-01 <_> 0 -1 764 2.1294999867677689e-02 1.4953400194644928e-01 -4.8579800128936768e-01 <_> 0 -1 765 -2.4613000452518463e-02 7.4346399307250977e-01 -2.2305199503898621e-01 <_> 0 -1 766 -1.9626000896096230e-02 -4.0918299555778503e-01 1.8893200159072876e-01 <_> 0 -1 767 -5.3266000002622604e-02 8.1381601095199585e-01 -2.0853699743747711e-01 <_> 0 -1 768 7.1290000341832638e-03 3.2996100187301636e-01 -5.9937399625778198e-01 <_> 0 -1 769 -2.2486999630928040e-02 -1.2551610469818115e+00 -2.0413000136613846e-02 <_> 0 -1 770 -8.2310996949672699e-02 1.3821430206298828e+00 5.9308998286724091e-02 <_> 0 -1 771 1.3097000122070312e-01 -3.5843998193740845e-02 -1.5396369695663452e+00 <_> 0 -1 772 1.4293000102043152e-02 -1.8475200235843658e-01 3.7455001473426819e-01 <_> 0 -1 773 6.3479999080300331e-03 -4.4901099801063538e-01 1.3876999914646149e-01 <_> 0 -1 774 -4.6055000275373459e-02 6.7832601070404053e-01 -1.7071999609470367e-02 <_> 0 -1 775 5.7693999260663986e-02 -1.1955999769270420e-02 -1.2261159420013428e+00 <_> 0 -1 776 -6.0609998181462288e-03 3.3958598971366882e-01 6.2800000887364149e-04 <_> 0 -1 777 -5.2163001149892807e-02 -1.0621069669723511e+00 -1.3779999688267708e-02 <_> 0 -1 778 4.6572998166084290e-02 1.4538800716400146e-01 -1.2384550571441650e+00 <_> 0 -1 779 7.5309998355805874e-03 -2.4467700719833374e-01 5.1377099752426147e-01 <_> 0 -1 780 2.1615000441670418e-02 1.3072599470615387e-01 -7.0996797084808350e-01 <_> 0 -1 781 -1.7864000052213669e-02 -1.0474660396575928e+00 4.9599999329075217e-04 <_> 0 -1 782 -3.7195000797510147e-02 -1.5126730203628540e+00 1.4801399409770966e-01 <_> 0 -1 783 -3.1100001069717109e-04 1.3971500098705292e-01 -4.6867498755455017e-01 <_> 0 -1 784 2.5042999535799026e-02 2.8632000088691711e-01 -4.1794699430465698e-01 <_> 0 -1 785 9.3449996784329414e-03 -2.7336201071739197e-01 4.3444699048995972e-01 <_> 0 -1 786 3.2363999634981155e-02 1.8438899517059326e-01 -9.5019298791885376e-01 <_> 0 -1 787 -6.2299999408423901e-03 3.2581999897956848e-01 -3.0815601348876953e-01 <_> 0 -1 788 5.1488999277353287e-02 1.1416000127792358e-01 -1.9795479774475098e+00 <_> 0 -1 789 -2.6449000462889671e-02 -1.1067299842834473e+00 -8.5519999265670776e-03 <_> 0 -1 790 -1.5420000068843365e-02 8.0138701200485229e-01 -3.2035000622272491e-02 <_> 0 -1 791 1.9456999376416206e-02 -2.6449498534202576e-01 3.8753899931907654e-01 <_> 0 -1 792 3.3620998263359070e-02 1.6052000224590302e-02 5.8840900659561157e-01 <_> 0 -1 793 2.8906000778079033e-02 1.5216000378131866e-02 -9.4723600149154663e-01 <_> 0 -1 794 2.0300000323913991e-04 -3.0766001343727112e-01 2.1235899627208710e-01 <_> 0 -1 795 -4.9141999334096909e-02 -1.6058609485626221e+00 -3.1094999983906746e-02 <_> 0 -1 796 7.6425999402999878e-02 7.4758999049663544e-02 1.1639410257339478e+00 <_> 0 -1 797 2.3897999897599220e-02 -6.4320000819861889e-03 -1.1150749921798706e+00 <_> 0 -1 798 3.8970001041889191e-03 -2.4105699360370636e-01 2.0858900249004364e-01 <_> 0 -1 799 -8.9445002377033234e-02 1.9157789945602417e+00 -1.5721100568771362e-01 <_> 0 -1 800 -1.5008999966084957e-02 -2.5174099206924438e-01 1.8179899454116821e-01 <_> 0 -1 801 -1.1145999655127525e-02 -6.9349497556686401e-01 4.4927999377250671e-02 <_> 0 -1 802 9.4578996300697327e-02 1.8102100491523743e-01 -7.4978601932525635e-01 <_> 0 -1 803 5.5038899183273315e-01 -3.0974000692367554e-02 -1.6746139526367188e+00 <_> 0 -1 804 4.1381001472473145e-02 6.3910000026226044e-02 7.6561200618743896e-01 <_> 0 -1 805 2.4771999567747116e-02 1.1380000039935112e-02 -8.8559401035308838e-01 <_> 0 -1 806 5.0999000668525696e-02 1.4890299737453461e-01 -2.4634211063385010e+00 <_> 0 -1 807 -1.6893999651074409e-02 3.8870999217033386e-01 -2.9880300164222717e-01 <_> 0 -1 808 -1.2162300199270248e-01 -1.5542800426483154e+00 1.6300800442695618e-01 <_> 0 -1 809 -3.6049999762326479e-03 2.1842800080776215e-01 -3.7312099337577820e-01 <_> 0 -1 810 1.1575400084257126e-01 -4.7061000019311905e-02 5.9403699636459351e-01 <_> 0 -1 811 3.6903999745845795e-02 -2.5508600473403931e-01 5.5397301912307739e-01 <_> 0 -1 812 1.1483999900519848e-02 -1.8129499256610870e-01 4.0682798624038696e-01 <_> 0 -1 813 -2.0233999937772751e-02 5.4311197996139526e-01 -2.3822399973869324e-01 <_> 0 -1 814 -2.8765000402927399e-02 -6.9172298908233643e-01 1.5943300724029541e-01 <_> 0 -1 815 -5.8320001699030399e-03 2.9447799921035767e-01 -3.4005999565124512e-01 <_> 0 -1 816 -5.5468998849391937e-02 9.2200797796249390e-01 9.4093002378940582e-02 <_> 0 -1 817 -1.4801000244915485e-02 -7.9539698362350464e-01 3.1521998345851898e-02 <_> 0 -1 818 -7.0940000005066395e-03 3.3096000552177429e-01 -5.0886999815702438e-02 <_> 0 -1 819 -4.5124001801013947e-02 -1.3719749450683594e+00 -2.1408999338746071e-02 <_> 0 -1 820 6.4377002418041229e-02 6.3901998102664948e-02 9.1478300094604492e-01 <_> 0 -1 821 -1.4727000147104263e-02 3.6050599813461304e-01 -2.8614500164985657e-01 <_> 0 -1 822 4.5007001608610153e-02 -1.5619699656963348e-01 5.3160297870635986e-01 <_> 0 -1 823 -1.1330000124871731e-03 1.3422900438308716e-01 -4.4358900189399719e-01 <_> 0 -1 824 4.9451000988483429e-02 1.0571800172328949e-01 -2.5589139461517334e+00 <_> 0 -1 825 2.9102999716997147e-02 -1.0088000446557999e-02 -1.1073939800262451e+00 <_> 0 -1 826 3.4786000847816467e-02 -2.7719999197870493e-03 5.6700998544692993e-01 <_> 0 -1 827 -6.1309998854994774e-03 -4.6889400482177734e-01 1.2636399269104004e-01 <_> 0 -1 828 1.5525000169873238e-02 -8.4279999136924744e-03 8.7469202280044556e-01 <_> 0 -1 829 2.9249999206513166e-03 -3.4434300661087036e-01 2.0851600170135498e-01 <_> 0 -1 830 -5.3571000695228577e-02 1.4982949495315552e+00 5.7328000664710999e-02 <_> 0 -1 831 -1.9217999652028084e-02 -9.9234098196029663e-01 -9.3919998034834862e-03 <_> 0 -1 832 -5.5282998830080032e-02 -5.7682299613952637e-01 1.6860599815845490e-01 <_> 0 -1 833 5.6336000561714172e-02 -3.3775001764297485e-02 -1.3889650106430054e+00 <_> 0 -1 834 -2.3824000731110573e-02 4.0182098746299744e-01 1.8360000103712082e-03 <_> 0 -1 835 1.7810000572353601e-03 1.8145999312400818e-01 -4.1743400692939758e-01 <_> 0 -1 836 -3.7689000368118286e-02 5.4683101177215576e-01 1.8219999969005585e-02 <_> 0 -1 837 -2.4144999682903290e-02 6.8352097272872925e-01 -1.9650200009346008e-01 <_> 135 -3.7025990486145020e+00 <_> 0 -1 838 2.7444999665021896e-02 -8.9984202384948730e-01 5.1876497268676758e-01 <_> 0 -1 839 1.1554100364446640e-01 -5.6524401903152466e-01 7.0551300048828125e-01 <_> 0 -1 840 -2.2297000512480736e-02 3.6079999804496765e-01 -6.6864597797393799e-01 <_> 0 -1 841 1.3325000181794167e-02 -5.5573397874832153e-01 3.5789999365806580e-01 <_> 0 -1 842 -3.8060001097619534e-03 -1.0713000297546387e+00 1.8850000202655792e-01 <_> 0 -1 843 -2.6819999329745770e-03 -7.1584302186965942e-01 2.6344498991966248e-01 <_> 0 -1 844 3.3819999080151320e-03 -4.6930798888206482e-01 2.6658400893211365e-01 <_> 0 -1 845 3.7643000483512878e-02 2.1098700165748596e-01 -1.0804339647293091e+00 <_> 0 -1 846 -1.3861999846994877e-02 6.6912001371383667e-01 -2.7942800521850586e-01 <_> 0 -1 847 -2.7350001037120819e-03 -9.5332300662994385e-01 2.4051299691200256e-01 <_> 0 -1 848 -3.8336999714374542e-02 8.1432801485061646e-01 -2.4919399619102478e-01 <_> 0 -1 849 -3.4697998315095901e-02 1.2330100536346436e+00 6.8600000813603401e-03 <_> 0 -1 850 2.3360999301075935e-02 -3.0794700980186462e-01 7.0714497566223145e-01 <_> 0 -1 851 3.5057999193668365e-02 2.1205900609493256e-01 -1.4399830102920532e+00 <_> 0 -1 852 -1.3256999664008617e-02 -9.0260702371597290e-01 4.8610001802444458e-02 <_> 0 -1 853 1.2740000151097775e-02 2.2655199468135834e-01 -4.4643801450729370e-01 <_> 0 -1 854 3.6400000099092722e-03 -3.9817899465560913e-01 3.4665399789810181e-01 <_> 0 -1 855 1.0064700245857239e-01 1.8383599817752838e-01 -1.3410769701004028e+00 <_> 0 -1 856 0. 1.5536400675773621e-01 -5.1582497358322144e-01 <_> 0 -1 857 1.1708999983966351e-02 2.1651400625705719e-01 -7.2705197334289551e-01 <_> 0 -1 858 -3.5964999347925186e-02 -1.4789500236511230e+00 -2.4317000061273575e-02 <_> 0 -1 859 -2.1236000582575798e-02 -1.6844099760055542e-01 1.9526599347591400e-01 <_> 0 -1 860 1.4874000102281570e-02 3.7335999310016632e-02 -8.7557297945022583e-01 <_> 0 -1 861 -5.1409997977316380e-03 3.3466500043869019e-01 -2.4109700322151184e-01 <_> 0 -1 862 2.3450000211596489e-02 5.5320002138614655e-03 -1.2509720325469971e+00 <_> 0 -1 863 -2.5062000378966331e-02 4.5212399959564209e-01 -8.4469996392726898e-02 <_> 0 -1 864 -7.7400001464411616e-04 1.5249900519847870e-01 -4.8486500978469849e-01 <_> 0 -1 865 -4.0483999997377396e-02 -1.3024920225143433e+00 1.7983500659465790e-01 <_> 0 -1 866 2.8170999139547348e-02 -2.4410900473594666e-01 6.2271100282669067e-01 <_> 0 -1 867 4.5692998915910721e-02 2.8122000396251678e-02 9.2394399642944336e-01 <_> 0 -1 868 3.9707001298666000e-02 -2.2332799434661865e-01 7.7674001455307007e-01 <_> 0 -1 869 5.0517000257968903e-02 2.0319999754428864e-01 -1.0895930528640747e+00 <_> 0 -1 870 -1.7266999930143356e-02 6.8598401546478271e-01 -2.3304499685764313e-01 <_> 0 -1 871 8.0186001956462860e-02 -1.0292000137269497e-02 6.1881101131439209e-01 <_> 0 -1 872 9.7676001489162445e-02 -2.0070299506187439e-01 1.0088349580764771e+00 <_> 0 -1 873 -1.5572000294923782e-02 4.7615298628807068e-01 4.5623999089002609e-02 <_> 0 -1 874 -1.5305000357329845e-02 -1.1077369451522827e+00 4.5239999890327454e-03 <_> 0 -1 875 -1.6485000029206276e-02 1.0152939558029175e+00 1.6327999532222748e-02 <_> 0 -1 876 -2.6141999289393425e-02 4.1723299026489258e-01 -2.8645500540733337e-01 <_> 0 -1 877 8.8679995387792587e-03 2.1404999494552612e-01 -1.6772800683975220e-01 <_> 0 -1 878 -2.6886999607086182e-02 -1.1564220190048218e+00 -1.0324000380933285e-02 <_> 0 -1 879 7.7789998613297939e-03 3.5359498858451843e-01 -2.9611301422119141e-01 <_> 0 -1 880 -1.5974000096321106e-02 -1.5374109745025635e+00 -2.9958000406622887e-02 <_> 0 -1 881 2.0866999402642250e-02 2.0244100689888000e-01 -7.1270197629928589e-01 <_> 0 -1 882 8.5482001304626465e-02 -2.5932999327778816e-02 -1.5156569480895996e+00 <_> 0 -1 883 2.3872999474406242e-02 1.6803400218486786e-01 -3.8806200027465820e-01 <_> 0 -1 884 -3.9105001837015152e-02 -1.1958349943161011e+00 -2.0361000671982765e-02 <_> 0 -1 885 -7.7946998178958893e-02 -1.0898950099945068e+00 1.4530299603939056e-01 <_> 0 -1 886 -1.6876000910997391e-02 2.8049701452255249e-01 -4.1336300969123840e-01 <_> 0 -1 887 1.1875600367784500e-01 -4.3490998446941376e-02 4.1263699531555176e-01 <_> 0 -1 888 1.5624199807643890e-01 -2.6429599523544312e-01 5.5127799510955811e-01 <_> 0 -1 889 -4.5908000320196152e-02 6.0189199447631836e-01 1.8921000882983208e-02 <_> 0 -1 890 -1.0309999808669090e-02 3.8152998685836792e-01 -2.9507899284362793e-01 <_> 0 -1 891 9.5769003033638000e-02 1.3246500492095947e-01 -4.6266800165176392e-01 <_> 0 -1 892 1.3686999678611755e-02 1.1738699674606323e-01 -5.1664102077484131e-01 <_> 0 -1 893 2.3990001063793898e-03 -3.4007599949836731e-01 2.0953500270843506e-01 <_> 0 -1 894 3.3264998346567154e-02 -1.7052799463272095e-01 1.4366799592971802e+00 <_> 0 -1 895 -3.3206000924110413e-02 6.1295700073242188e-01 -4.1549999266862869e-02 <_> 0 -1 896 2.7979998849332333e-03 -4.8554301261901855e-01 1.3372699916362762e-01 <_> 0 -1 897 -6.5792001783847809e-02 -4.0257668495178223e+00 1.0876700282096863e-01 <_> 0 -1 898 2.1430000197142363e-03 -3.9179998636245728e-01 2.2427099943161011e-01 <_> 0 -1 899 2.2363999858498573e-02 -8.6429998278617859e-02 3.7785199284553528e-01 <_> 0 -1 900 -5.7410001754760742e-02 1.1454069614410400e+00 -1.9736599922180176e-01 <_> 0 -1 901 6.6550001502037048e-03 -2.1105000749230385e-02 5.8453398942947388e-01 <_> 0 -1 902 1.2326999567449093e-02 3.7817001342773438e-02 -6.6987001895904541e-01 <_> 0 -1 903 -8.1869997084140778e-03 5.6366002559661865e-01 -7.6877996325492859e-02 <_> 0 -1 904 3.6681000143289566e-02 -1.7343300580978394e-01 1.1670149564743042e+00 <_> 0 -1 905 -4.0220400691032410e-01 1.2640819549560547e+00 4.3398998677730560e-02 <_> 0 -1 906 -2.2126000374555588e-02 6.6978102922439575e-01 -2.1605299413204193e-01 <_> 0 -1 907 -1.3156999833881855e-02 -4.1198599338531494e-01 2.0215000212192535e-01 <_> 0 -1 908 -1.2860000133514404e-02 -9.1582697629928589e-01 3.9232999086380005e-02 <_> 0 -1 909 2.1627999842166901e-02 3.8719999138265848e-03 3.5668200254440308e-01 <_> 0 -1 910 1.1896000243723392e-02 -3.7303900718688965e-01 1.9235099852085114e-01 <_> 0 -1 911 -1.9548999145627022e-02 -4.2374899983406067e-01 2.4429599940776825e-01 <_> 0 -1 912 6.4444996416568756e-02 -1.6558900475502014e-01 1.2697030305862427e+00 <_> 0 -1 913 1.0898499935865402e-01 1.4894300699234009e-01 -2.1534640789031982e+00 <_> 0 -1 914 -3.4077998250722885e-02 1.3779460191726685e+00 -1.6198499500751495e-01 <_> 0 -1 915 -3.7489999085664749e-03 -3.3828601241111755e-01 2.1152900159358978e-01 <_> 0 -1 916 -1.0971999727189541e-02 7.6517897844314575e-01 -1.9692599773406982e-01 <_> 0 -1 917 -1.1485000140964985e-02 -6.9271200895309448e-01 2.1657100319862366e-01 <_> 0 -1 918 2.5984000414609909e-02 -1.1983999982476234e-02 -9.9697297811508179e-01 <_> 0 -1 919 4.2159999720752239e-03 -1.0205700248479843e-01 4.8884400725364685e-01 <_> 0 -1 920 -4.7697000205516815e-02 1.0666010379791260e+00 -1.7576299607753754e-01 <_> 0 -1 921 4.0300001273863018e-04 1.8524800240993500e-01 -7.4790000915527344e-01 <_> 0 -1 922 1.1539600044488907e-01 -2.2019700706005096e-01 5.4509997367858887e-01 <_> 0 -1 923 1.6021000221371651e-02 2.5487500429153442e-01 -5.0740098953247070e-01 <_> 0 -1 924 5.6632000952959061e-02 -1.1256000027060509e-02 -9.5968097448348999e-01 <_> 0 -1 925 -1.0726000182330608e-02 -2.8544700145721436e-01 1.6994799673557281e-01 <_> 0 -1 926 1.2420000135898590e-01 -3.6139998584985733e-02 -1.3132710456848145e+00 <_> 0 -1 927 -5.3799999877810478e-03 3.3092701435089111e-01 1.3307999819517136e-02 <_> 0 -1 928 1.1908000335097313e-02 -3.4830299019813538e-01 2.4041900038719177e-01 <_> 0 -1 929 -4.3007999658584595e-02 -1.4390469789505005e+00 1.5599599480628967e-01 <_> 0 -1 930 -3.3149998635053635e-02 -1.1805850267410278e+00 -1.2347999960184097e-02 <_> 0 -1 931 -2.1341999992728233e-02 2.2119441032409668e+00 6.2737002968788147e-02 <_> 0 -1 932 -1.2218999676406384e-02 -1.8709750175476074e+00 -4.5499999076128006e-02 <_> 0 -1 933 -1.6860999166965485e-02 -7.6912701129913330e-01 1.5330000221729279e-01 <_> 0 -1 934 -2.4999999441206455e-03 -6.2987399101257324e-01 5.1600001752376556e-02 <_> 0 -1 935 -4.5037999749183655e-02 8.5428899526596069e-01 6.2600001692771912e-03 <_> 0 -1 936 3.9057999849319458e-02 -3.2458998262882233e-02 -1.3325669765472412e+00 <_> 0 -1 937 6.6720000468194485e-03 -1.9423599541187286e-01 3.7328699231147766e-01 <_> 0 -1 938 -1.6361000016331673e-02 2.0605869293212891e+00 -1.5042699873447418e-01 <_> 0 -1 939 6.1719999648630619e-03 -1.1610999703407288e-01 2.5455400347709656e-01 <_> 0 -1 940 4.5722000300884247e-02 -1.6340000554919243e-02 -1.0449140071868896e+00 <_> 0 -1 941 4.1209999471902847e-03 -4.1997998952865601e-02 3.9680999517440796e-01 <_> 0 -1 942 -1.7800000205170363e-04 -6.6422599554061890e-01 3.3443000167608261e-02 <_> 0 -1 943 7.1109998971223831e-03 -5.8231998234987259e-02 3.7857300043106079e-01 <_> 0 -1 944 -4.9864001572132111e-02 6.1019402742385864e-01 -2.1005700528621674e-01 <_> 0 -1 945 -2.5011999532580376e-02 -5.7100099325180054e-01 1.7848399281501770e-01 <_> 0 -1 946 3.0939999967813492e-02 5.6363001465797424e-02 -6.4731001853942871e-01 <_> 0 -1 947 4.6271000057458878e-02 1.7482399940490723e-01 -9.8909401893615723e-01 <_> 0 -1 948 -3.1870000530034304e-03 -6.6804802417755127e-01 3.2267000526189804e-02 <_> 0 -1 949 -2.4351999163627625e-02 2.9444900155067444e-01 -1.3599999947473407e-03 <_> 0 -1 950 1.1974000371992588e-02 -2.8345099091529846e-01 4.7171199321746826e-01 <_> 0 -1 951 1.3070000335574150e-02 -1.0834600031375885e-01 5.7193297147750854e-01 <_> 0 -1 952 5.9163000434637070e-02 -5.0939001142978668e-02 -1.9059720039367676e+00 <_> 0 -1 953 -4.1094999760389328e-02 4.5104598999023438e-01 -9.7599998116493225e-03 <_> 0 -1 954 -8.3989001810550690e-02 -2.0349199771881104e+00 -5.1019001752138138e-02 <_> 0 -1 955 4.4619001448154449e-02 1.7041100561618805e-01 -1.2278720140457153e+00 <_> 0 -1 956 2.4419000372290611e-02 -2.1796999499201775e-02 -1.0822949409484863e+00 <_> 0 -1 957 -4.3870001100003719e-03 3.0466699600219727e-01 -3.7066599726676941e-01 <_> 0 -1 958 2.4607999250292778e-02 -3.1169500946998596e-01 2.3657299578189850e-01 <_> 0 -1 959 -8.5182003676891327e-02 -1.7982350587844849e+00 1.5254299342632294e-01 <_> 0 -1 960 2.1844999864697456e-02 -5.1888000220060349e-02 -1.9017189741134644e+00 <_> 0 -1 961 -1.6829000785946846e-02 2.1025900542736053e-01 2.1656999364495277e-02 <_> 0 -1 962 3.2547999173402786e-02 -2.0292599499225616e-01 6.0944002866744995e-01 <_> 0 -1 963 2.4709999561309814e-03 -9.5371198654174805e-01 1.8568399548530579e-01 <_> 0 -1 964 5.5415999144315720e-02 -1.4405299723148346e-01 2.1506340503692627e+00 <_> 0 -1 965 -1.0635499656200409e-01 -1.0911970138549805e+00 1.3228000700473785e-01 <_> 0 -1 966 -7.9889995977282524e-03 1.0253400355577469e-01 -5.1744902133941650e-01 <_> 0 -1 967 7.5567997992038727e-02 5.8965001255273819e-02 1.2354209423065186e+00 <_> 0 -1 968 -9.2805996537208557e-02 -1.3431650400161743e+00 -3.4462999552488327e-02 <_> 0 -1 969 4.9431998282670975e-02 4.9601998180150986e-02 1.6054730415344238e+00 <_> 0 -1 970 -1.1772999539971352e-02 -1.0261050462722778e+00 -4.1559999808669090e-03 <_> 0 -1 971 8.5886001586914062e-02 8.4642998874187469e-02 9.5220798254013062e-01 <_> 0 -1 972 8.1031002104282379e-02 -1.4687100052833557e-01 1.9359990358352661e+00 <_> 136 -3.4265899658203125e+00 <_> 0 -1 973 -3.3840999007225037e-02 6.5889501571655273e-01 -6.9755297899246216e-01 <_> 0 -1 974 1.5410000458359718e-02 -9.0728402137756348e-01 3.0478599667549133e-01 <_> 0 -1 975 5.4905999451875687e-02 -4.9774798750877380e-01 5.7132601737976074e-01 <_> 0 -1 976 2.1390000358223915e-02 -4.2565199732780457e-01 5.8096802234649658e-01 <_> 0 -1 977 7.8849997371435165e-03 -4.7905999422073364e-01 4.3016499280929565e-01 <_> 0 -1 978 -3.7544999271631241e-02 5.0861597061157227e-01 -1.9985899329185486e-01 <_> 0 -1 979 1.5925799310207367e-01 -2.3263600468635559e-01 1.0993319749832153e+00 <_> 0 -1 980 -6.8939998745918274e-02 4.0569001436233521e-01 5.6855000555515289e-02 <_> 0 -1 981 -3.3695001155138016e-02 4.5132800936698914e-01 -3.3332800865173340e-01 <_> 0 -1 982 -6.3314996659755707e-02 -8.5015702247619629e-01 2.2341699898242950e-01 <_> 0 -1 983 7.3699997738003731e-03 -9.3082201480865479e-01 5.9216998517513275e-02 <_> 0 -1 984 -9.5969997346401215e-03 -1.2794899940490723e+00 1.8447299301624298e-01 <_> 0 -1 985 -1.3067999482154846e-01 5.8426898717880249e-01 -2.6007199287414551e-01 <_> 0 -1 986 5.7402998208999634e-02 -5.3789000958204269e-02 7.1175599098205566e-01 <_> 0 -1 987 -7.2340001352131367e-03 -8.6962199211120605e-01 7.5214996933937073e-02 <_> 0 -1 988 3.1098999083042145e-02 -7.5006999075412750e-02 9.0781599283218384e-01 <_> 0 -1 989 3.5854000598192215e-02 -2.4795499444007874e-01 7.2272098064422607e-01 <_> 0 -1 990 -3.1534999608993530e-02 -1.1238329410552979e+00 2.0988300442695618e-01 <_> 0 -1 991 -1.9437000155448914e-02 -1.4499390125274658e+00 -1.5100000426173210e-02 <_> 0 -1 992 -7.2420001961290836e-03 5.3864902257919312e-01 -1.1375399678945541e-01 <_> 0 -1 993 8.1639997661113739e-03 6.6889002919197083e-02 -7.6872897148132324e-01 <_> 0 -1 994 -4.3653000146150589e-02 1.1413530111312866e+00 4.0217000991106033e-02 <_> 0 -1 995 2.6569999754428864e-02 -2.4719099700450897e-01 5.9295099973678589e-01 <_> 0 -1 996 3.2216999679803848e-02 -4.0024999529123306e-02 3.2688000798225403e-01 <_> 0 -1 997 -7.2236001491546631e-02 5.8729398250579834e-01 -2.5396001338958740e-01 <_> 0 -1 998 3.1424999237060547e-02 1.5315100550651550e-01 -5.6042098999023438e-01 <_> 0 -1 999 -4.7699999413453043e-04 1.6958899796009064e-01 -5.2626699209213257e-01 <_> 0 -1 1000 2.7189999818801880e-03 -1.4944599568843842e-01 2.9658699035644531e-01 <_> 0 -1 1001 3.2875001430511475e-02 -3.9943501353263855e-01 2.5156599283218384e-01 <_> 0 -1 1002 -1.4553000219166279e-02 2.7972599864006042e-01 -4.7203800082206726e-01 <_> 0 -1 1003 3.8017999380826950e-02 -2.9200001154094934e-03 -1.1300059556961060e+00 <_> 0 -1 1004 2.8659999370574951e-03 4.1111800074577332e-01 -2.6220801472663879e-01 <_> 0 -1 1005 -4.1606999933719635e-02 -1.4293819665908813e+00 -1.9132999703288078e-02 <_> 0 -1 1006 -2.4802999570965767e-02 -2.5013598799705505e-01 1.5978699922561646e-01 <_> 0 -1 1007 1.0098000057041645e-02 4.3738998472690582e-02 -6.9986099004745483e-01 <_> 0 -1 1008 -2.0947000011801720e-02 -9.4137799739837646e-01 2.3204000294208527e-01 <_> 0 -1 1009 2.2458000108599663e-02 -2.7185800671577454e-01 4.5319199562072754e-01 <_> 0 -1 1010 -3.7110999226570129e-02 -1.0314660072326660e+00 1.4421799778938293e-01 <_> 0 -1 1011 -1.0648000054061413e-02 6.3107001781463623e-01 -2.5520798563957214e-01 <_> 0 -1 1012 5.5422998964786530e-02 1.6206599771976471e-01 -1.7722640037536621e+00 <_> 0 -1 1013 2.1601999178528786e-02 -2.5016099214553833e-01 5.4119801521301270e-01 <_> 0 -1 1014 8.7000000348780304e-05 -2.9008901119232178e-01 3.3507999777793884e-01 <_> 0 -1 1015 1.4406000263988972e-02 -7.8840004280209541e-03 -1.1677219867706299e+00 <_> 0 -1 1016 1.0777399688959122e-01 1.1292000114917755e-01 -2.4940319061279297e+00 <_> 0 -1 1017 3.5943999886512756e-02 -1.9480599462985992e-01 9.5757502317428589e-01 <_> 0 -1 1018 -3.9510000497102737e-03 3.0927801132202148e-01 -2.5530201196670532e-01 <_> 0 -1 1019 2.0942000672221184e-02 -7.6319999061524868e-03 -1.0086350440979004e+00 <_> 0 -1 1020 -2.9877999797463417e-02 -4.6027699112892151e-01 1.9507199525833130e-01 <_> 0 -1 1021 2.5971999391913414e-02 -1.2187999673187733e-02 -1.0035500526428223e+00 <_> 0 -1 1022 1.0603000409901142e-02 -7.5969003140926361e-02 4.1669899225234985e-01 <_> 0 -1 1023 8.5819996893405914e-03 -2.6648598909378052e-01 3.9111500978469849e-01 <_> 0 -1 1024 2.1270999684929848e-02 1.8273900449275970e-01 -3.6052298545837402e-01 <_> 0 -1 1025 7.4518002569675446e-02 -1.8938399851322174e-01 9.2658001184463501e-01 <_> 0 -1 1026 4.6569998376071453e-03 -1.4506199955940247e-01 3.3294600248336792e-01 <_> 0 -1 1027 1.7119999974966049e-03 -5.2464002370834351e-01 8.9879997074604034e-02 <_> 0 -1 1028 9.8500004969537258e-04 -3.8381999731063843e-01 2.4392999708652496e-01 <_> 0 -1 1029 2.8233999386429787e-02 -5.7879998348653316e-03 -1.2617139816284180e+00 <_> 0 -1 1030 -3.2678000628948212e-02 -5.7953298091888428e-01 1.6955299675464630e-01 <_> 0 -1 1031 2.2536000236868858e-02 2.2281000390648842e-02 -8.7869602441787720e-01 <_> 0 -1 1032 -2.1657999604940414e-02 -6.5108501911163330e-01 1.2966899573802948e-01 <_> 0 -1 1033 7.6799998059868813e-03 -3.3965200185775757e-01 2.2013300657272339e-01 <_> 0 -1 1034 1.4592000283300877e-02 1.5077300369739532e-01 -5.0452399253845215e-01 <_> 0 -1 1035 2.7868000790476799e-02 -2.5045299530029297e-01 4.5741999149322510e-01 <_> 0 -1 1036 5.6940000504255295e-03 -1.0948500037193298e-01 5.5757802724838257e-01 <_> 0 -1 1037 -1.0002999566495419e-02 -9.7366297245025635e-01 1.8467999994754791e-02 <_> 0 -1 1038 -4.0719998069107533e-03 3.8222199678421021e-01 -1.6921100020408630e-01 <_> 0 -1 1039 -2.2593999281525612e-02 -1.0391089916229248e+00 5.1839998923242092e-03 <_> 0 -1 1040 -3.9579998701810837e-02 -5.5109229087829590e+00 1.1163999885320663e-01 <_> 0 -1 1041 -1.7537999898195267e-02 9.5485800504684448e-01 -1.8584500253200531e-01 <_> 0 -1 1042 9.0300003066658974e-03 1.0436000302433968e-02 8.2114797830581665e-01 <_> 0 -1 1043 -7.9539995640516281e-03 2.2632899880409241e-01 -3.4568199515342712e-01 <_> 0 -1 1044 2.7091000229120255e-02 1.6430099308490753e-01 -1.3926379680633545e+00 <_> 0 -1 1045 -2.0625999197363853e-02 -8.6366099119186401e-01 2.3880000226199627e-03 <_> 0 -1 1046 -7.1989998221397400e-02 -2.8192629814147949e+00 1.1570499837398529e-01 <_> 0 -1 1047 -2.6964999735355377e-02 -1.2946130037307739e+00 -2.4661000818014145e-02 <_> 0 -1 1048 -4.7377999871969223e-02 -8.1306397914886475e-01 1.1831399798393250e-01 <_> 0 -1 1049 -1.0895600169897079e-01 6.5937900543212891e-01 -2.0843900740146637e-01 <_> 0 -1 1050 1.3574000447988510e-02 7.4240001849830151e-03 5.3152197599411011e-01 <_> 0 -1 1051 -6.6920001991093159e-03 3.0655801296234131e-01 -3.1084299087524414e-01 <_> 0 -1 1052 -3.9070001803338528e-03 2.5576499104499817e-01 -5.2932001650333405e-02 <_> 0 -1 1053 -3.7613000720739365e-02 -1.4350049495697021e+00 -1.5448000282049179e-02 <_> 0 -1 1054 8.6329998448491096e-03 -1.6884399950504303e-01 4.2124900221824646e-01 <_> 0 -1 1055 -3.2097000628709793e-02 -6.4979398250579834e-01 4.1110001504421234e-02 <_> 0 -1 1056 5.8495998382568359e-02 -5.2963998168706894e-02 6.3368302583694458e-01 <_> 0 -1 1057 -4.0901999920606613e-02 -9.2101097106933594e-01 9.0640000998973846e-03 <_> 0 -1 1058 -1.9925000146031380e-02 5.3759998083114624e-01 -6.2996998429298401e-02 <_> 0 -1 1059 -4.6020001173019409e-03 -5.4333502054214478e-01 8.4104999899864197e-02 <_> 0 -1 1060 1.6824999824166298e-02 1.5563699603080750e-01 -4.0171200037002563e-01 <_> 0 -1 1061 9.4790002331137657e-03 -2.4245299398899078e-01 5.1509499549865723e-01 <_> 0 -1 1062 -1.9534999504685402e-02 -5.1118397712707520e-01 1.3831999897956848e-01 <_> 0 -1 1063 1.0746000334620476e-02 -2.1854999661445618e-01 6.2828701734542847e-01 <_> 0 -1 1064 3.7927001714706421e-02 1.1640299856662750e-01 -2.7301959991455078e+00 <_> 0 -1 1065 1.6390999779105186e-02 -1.4635999687016010e-02 -1.0797250270843506e+00 <_> 0 -1 1066 -1.9785000011324883e-02 1.2166420221328735e+00 3.3275000751018524e-02 <_> 0 -1 1067 1.1067000217735767e-02 -2.5388300418853760e-01 4.4038599729537964e-01 <_> 0 -1 1068 5.2479999139904976e-03 2.2496800124645233e-01 -2.4216499924659729e-01 <_> 0 -1 1069 -1.1141999624669552e-02 2.5018098950386047e-01 -3.0811500549316406e-01 <_> 0 -1 1070 -1.0666999965906143e-02 -3.2729101181030273e-01 2.6168298721313477e-01 <_> 0 -1 1071 1.0545299947261810e-01 -5.5750001221895218e-02 -1.9605729579925537e+00 <_> 0 -1 1072 5.4827999323606491e-02 -1.9519999623298645e-03 7.3866099119186401e-01 <_> 0 -1 1073 1.7760999500751495e-02 -3.0647200345993042e-01 2.6346999406814575e-01 <_> 0 -1 1074 -3.1185999512672424e-02 -2.4600900709629059e-01 1.7082199454307556e-01 <_> 0 -1 1075 -5.7296000421047211e-02 4.7033500671386719e-01 -2.6048299670219421e-01 <_> 0 -1 1076 -1.1312000453472137e-02 3.8628900051116943e-01 -2.8817000985145569e-01 <_> 0 -1 1077 3.0592000111937523e-02 -4.8826001584529877e-02 -1.7638969421386719e+00 <_> 0 -1 1078 1.8489999929443002e-03 2.1099899709224701e-01 -2.5940999388694763e-02 <_> 0 -1 1079 1.1419000104069710e-02 -1.6829599440097809e-01 1.0278660058975220e+00 <_> 0 -1 1080 8.1403002142906189e-02 1.1531999707221985e-01 -1.2482399940490723e+00 <_> 0 -1 1081 5.3495999425649643e-02 -4.6303998678922653e-02 -1.7165969610214233e+00 <_> 0 -1 1082 -2.3948000743985176e-02 -4.0246599912643433e-01 2.0562100410461426e-01 <_> 0 -1 1083 6.7690000869333744e-03 -3.3152300119400024e-01 2.0683400332927704e-01 <_> 0 -1 1084 -3.2343998551368713e-02 -7.2632801532745361e-01 2.0073500275611877e-01 <_> 0 -1 1085 3.7863001227378845e-02 -1.5631000697612762e-01 1.6697460412979126e+00 <_> 0 -1 1086 1.5440000221133232e-02 1.9487400352954865e-01 -3.5384199023246765e-01 <_> 0 -1 1087 -4.4376000761985779e-02 8.2093602418899536e-01 -1.8193599581718445e-01 <_> 0 -1 1088 -2.3102000355720520e-02 -4.3044099211692810e-01 1.2375400215387344e-01 <_> 0 -1 1089 1.9400000572204590e-02 -2.9726000502705574e-02 -1.1597590446472168e+00 <_> 0 -1 1090 1.0385700315237045e-01 1.1149899661540985e-01 -4.6835222244262695e+00 <_> 0 -1 1091 -1.8964000046253204e-02 2.1773819923400879e+00 -1.4544400572776794e-01 <_> 0 -1 1092 3.8750998675823212e-02 -4.9446001648902893e-02 3.4018298983573914e-01 <_> 0 -1 1093 2.2766999900341034e-02 -3.2802999019622803e-01 3.0531400442123413e-01 <_> 0 -1 1094 -3.1357001513242722e-02 1.1520819664001465e+00 2.7305999770760536e-02 <_> 0 -1 1095 9.6909999847412109e-03 -3.8799500465393066e-01 2.1512599289417267e-01 <_> 0 -1 1096 -4.9284998327493668e-02 -1.6774909496307373e+00 1.5774199366569519e-01 <_> 0 -1 1097 -3.9510998874902725e-02 -9.7647899389266968e-01 -1.0552000254392624e-02 <_> 0 -1 1098 4.7997999936342239e-02 2.0843900740146637e-01 -6.8992799520492554e-01 <_> 0 -1 1099 5.1422998309135437e-02 -1.6665300726890564e-01 1.2149239778518677e+00 <_> 0 -1 1100 1.4279999770224094e-02 2.3627699911594391e-01 -4.1396799683570862e-01 <_> 0 -1 1101 -9.1611996293067932e-02 -9.2830902338027954e-01 -1.8345000222325325e-02 <_> 0 -1 1102 6.5080001950263977e-03 -7.3647201061248779e-01 1.9497099518775940e-01 <_> 0 -1 1103 3.5723000764846802e-02 1.4197799563407898e-01 -4.2089301347732544e-01 <_> 0 -1 1104 5.0638001412153244e-02 1.1644000187516212e-02 7.8486597537994385e-01 <_> 0 -1 1105 -1.4613999985158443e-02 -1.1909500360488892e+00 -3.5128001123666763e-02 <_> 0 -1 1106 -3.8662999868392944e-02 2.4314730167388916e+00 6.5647996962070465e-02 <_> 0 -1 1107 -4.0346998721361160e-02 7.1755301952362061e-01 -1.9108299911022186e-01 <_> 0 -1 1108 2.3902000859379768e-02 1.5646199882030487e-01 -7.9294800758361816e-01 <_> 137 -3.5125269889831543e+00 <_> 0 -1 1109 8.5640000179409981e-03 -8.1450700759887695e-01 5.8875298500061035e-01 <_> 0 -1 1110 -1.3292600214481354e-01 9.3213397264480591e-01 -2.9367300868034363e-01 <_> 0 -1 1111 9.8400004208087921e-03 -5.6462901830673218e-01 4.1647699475288391e-01 <_> 0 -1 1112 5.0889998674392700e-03 -7.9232800006866455e-01 1.6975000500679016e-01 <_> 0 -1 1113 -6.1039000749588013e-02 -1.4169000387191772e+00 2.5020999833941460e-02 <_> 0 -1 1114 -4.6599999768659472e-04 3.7982499599456787e-01 -4.1567099094390869e-01 <_> 0 -1 1115 3.3889999613165855e-03 -4.0768599510192871e-01 3.5548499226570129e-01 <_> 0 -1 1116 2.1006999537348747e-02 -2.4080100655555725e-01 8.6112701892852783e-01 <_> 0 -1 1117 7.5559997931122780e-03 -8.7467199563980103e-01 9.8572000861167908e-02 <_> 0 -1 1118 2.4779999628663063e-02 1.5566200017929077e-01 -6.9229799509048462e-01 <_> 0 -1 1119 -3.5620000213384628e-02 -1.1472270488739014e+00 3.6359999328851700e-02 <_> 0 -1 1120 1.9810000434517860e-02 1.5516200661659241e-01 -6.9520097970962524e-01 <_> 0 -1 1121 1.5019999817013741e-02 4.1990000754594803e-02 -9.6622800827026367e-01 <_> 0 -1 1122 -2.3137999698519707e-02 4.3396899104118347e-01 2.4160000029951334e-03 <_> 0 -1 1123 -1.8743000924587250e-02 4.3481099605560303e-01 -3.2522499561309814e-01 <_> 0 -1 1124 4.5080000162124634e-01 -9.4573996961116791e-02 7.2421300411224365e-01 <_> 0 -1 1125 1.1854999698698521e-02 -3.8133099675178528e-01 3.0098399519920349e-01 <_> 0 -1 1126 -2.4830000475049019e-02 8.9300602674484253e-01 -1.0295899957418442e-01 <_> 0 -1 1127 -4.4743001461029053e-02 8.6280298233032227e-01 -2.1716499328613281e-01 <_> 0 -1 1128 -1.4600000344216824e-02 6.0069400072097778e-01 -1.5906299650669098e-01 <_> 0 -1 1129 -2.4527000263333321e-02 -1.5872869491577148e+00 -2.1817000582814217e-02 <_> 0 -1 1130 2.3024000227451324e-02 1.6853399574756622e-01 -3.8106900453567505e-01 <_> 0 -1 1131 -2.4917000904679298e-02 5.0810897350311279e-01 -2.7279898524284363e-01 <_> 0 -1 1132 1.0130000300705433e-03 -4.3138799071311951e-01 2.6438099145889282e-01 <_> 0 -1 1133 1.5603000298142433e-02 -3.1624200940132141e-01 5.5715900659561157e-01 <_> 0 -1 1134 -2.6685999706387520e-02 1.0553920269012451e+00 2.9074000194668770e-02 <_> 0 -1 1135 1.3940000208094716e-03 -7.1873801946640015e-01 6.5390996634960175e-02 <_> 0 -1 1136 -6.4799998654052615e-04 2.4884399771690369e-01 -2.0978200435638428e-01 <_> 0 -1 1137 -3.1888000667095184e-02 -6.8844497203826904e-01 6.3589997589588165e-02 <_> 0 -1 1138 -4.9290000461041927e-03 -5.9152501821517944e-01 2.7943599224090576e-01 <_> 0 -1 1139 3.1168000772595406e-02 4.5223999768495560e-02 -8.8639199733734131e-01 <_> 0 -1 1140 -3.3663000911474228e-02 -6.1590200662612915e-01 1.5749299526214600e-01 <_> 0 -1 1141 1.1966999620199203e-02 -3.0606698989868164e-01 4.2293301224708557e-01 <_> 0 -1 1142 -3.4680001437664032e-02 -1.3734940290451050e+00 1.5908700227737427e-01 <_> 0 -1 1143 9.9290004000067711e-03 -5.5860197544097900e-01 1.2119200080633163e-01 <_> 0 -1 1144 5.9574998915195465e-02 4.9720001406967640e-03 8.2055401802062988e-01 <_> 0 -1 1145 -6.5428003668785095e-02 1.5651429891586304e+00 -1.6817499697208405e-01 <_> 0 -1 1146 -9.2895999550819397e-02 -1.5794529914855957e+00 1.4661799371242523e-01 <_> 0 -1 1147 -4.1184000670909882e-02 -1.5518720149993896e+00 -2.9969999566674232e-02 <_> 0 -1 1148 2.1447999402880669e-02 1.7196300625801086e-01 -6.9343197345733643e-01 <_> 0 -1 1149 -2.5569999590516090e-02 -1.3061310052871704e+00 -2.4336999282240868e-02 <_> 0 -1 1150 -4.1200999170541763e-02 -1.3821059465408325e+00 1.4801800251007080e-01 <_> 0 -1 1151 -1.7668999731540680e-02 -7.0889997482299805e-01 3.6524001508951187e-02 <_> 0 -1 1152 9.0060001239180565e-03 -4.0913999080657959e-02 8.0373102426528931e-01 <_> 0 -1 1153 -1.1652999557554722e-02 5.7546800374984741e-01 -2.4991700053215027e-01 <_> 0 -1 1154 -7.4780001305043697e-03 -4.9280899763107300e-01 1.9810900092124939e-01 <_> 0 -1 1155 8.5499999113380909e-04 -4.8858100175857544e-01 1.3563099503517151e-01 <_> 0 -1 1156 -3.0538000166416168e-02 -6.0278397798538208e-01 1.8522000312805176e-01 <_> 0 -1 1157 -1.8846999853849411e-02 2.3565599322319031e-01 -3.5136300325393677e-01 <_> 0 -1 1158 -8.1129996106028557e-03 -8.1304997205734253e-02 2.1069599688053131e-01 <_> 0 -1 1159 -3.4830000251531601e-02 -1.2065670490264893e+00 -1.4251999557018280e-02 <_> 0 -1 1160 1.9021000713109970e-02 2.3349900543689728e-01 -4.5664900541305542e-01 <_> 0 -1 1161 -1.9004000350832939e-02 -8.1075799465179443e-01 1.3140000402927399e-02 <_> 0 -1 1162 -8.9057996869087219e-02 6.1542397737503052e-01 3.2983001321554184e-02 <_> 0 -1 1163 6.8620000965893269e-03 -2.9583099484443665e-01 2.7003699541091919e-01 <_> 0 -1 1164 -2.8240999206900597e-02 -6.1102700233459473e-01 1.7357499897480011e-01 <_> 0 -1 1165 -3.2099999953061342e-04 -5.3322899341583252e-01 6.8539001047611237e-02 <_> 0 -1 1166 -1.0829100012779236e-01 -1.2879559993743896e+00 1.1801700294017792e-01 <_> 0 -1 1167 1.5878999605774879e-02 -1.7072600126266479e-01 1.1103910207748413e+00 <_> 0 -1 1168 8.6859995499253273e-03 -1.0995099693536758e-01 4.6010500192642212e-01 <_> 0 -1 1169 -2.5234999135136604e-02 1.0220669507980347e+00 -1.8694299459457397e-01 <_> 0 -1 1170 -1.3508999720215797e-02 -7.8316599130630493e-01 1.4202600717544556e-01 <_> 0 -1 1171 -7.7149998396635056e-03 -8.8060700893402100e-01 1.1060000397264957e-02 <_> 0 -1 1172 7.1580000221729279e-02 1.1369399726390839e-01 -1.1032789945602417e+00 <_> 0 -1 1173 -1.3554000295698643e-02 -8.1096500158309937e-01 3.4080001059919596e-03 <_> 0 -1 1174 2.9450000729411840e-03 -7.2879999876022339e-02 3.4998100996017456e-01 <_> 0 -1 1175 -5.0833001732826233e-02 -1.2868590354919434e+00 -2.8842000290751457e-02 <_> 0 -1 1176 -8.7989997118711472e-03 4.7613599896430969e-01 -1.4690400660037994e-01 <_> 0 -1 1177 2.1424399316310883e-01 -5.9702001512050629e-02 -2.4802260398864746e+00 <_> 0 -1 1178 1.3962999917566776e-02 1.7420299351215363e-01 -4.3911001086235046e-01 <_> 0 -1 1179 4.2502000927925110e-02 -1.9965299963951111e-01 7.0654797554016113e-01 <_> 0 -1 1180 1.9827999174594879e-02 -6.9136001169681549e-02 6.1643397808074951e-01 <_> 0 -1 1181 -3.3560000360012054e-02 -1.2740780115127563e+00 -2.5673000141978264e-02 <_> 0 -1 1182 6.3542999327182770e-02 1.2403500080108643e-01 -1.0776289701461792e+00 <_> 0 -1 1183 2.1933000534772873e-02 1.4952000230550766e-02 -7.1023499965667725e-01 <_> 0 -1 1184 -7.8424997627735138e-02 6.2033998966217041e-01 3.3610999584197998e-02 <_> 0 -1 1185 1.4390000142157078e-02 -3.6324599385261536e-01 1.7308300733566284e-01 <_> 0 -1 1186 -6.7309997975826263e-02 5.2374100685119629e-01 1.2799999676644802e-02 <_> 0 -1 1187 1.3047499954700470e-01 -1.7122499644756317e-01 1.1235200166702271e+00 <_> 0 -1 1188 -4.6245999634265900e-02 -1.1908329725265503e+00 1.7425599694252014e-01 <_> 0 -1 1189 -2.9842000454664230e-02 8.3930599689483643e-01 -1.8064199388027191e-01 <_> 0 -1 1190 -3.8099999073892832e-04 3.5532799363136292e-01 -2.3842300474643707e-01 <_> 0 -1 1191 -2.2378999739885330e-02 -8.7943899631500244e-01 -7.8399997437372804e-04 <_> 0 -1 1192 -1.5569999814033508e-03 -1.4253300428390503e-01 2.5876200199127197e-01 <_> 0 -1 1193 1.2013000436127186e-02 -2.9015499353408813e-01 2.6051101088523865e-01 <_> 0 -1 1194 2.4384999647736549e-02 -3.1438998878002167e-02 5.8695900440216064e-01 <_> 0 -1 1195 -4.7180999070405960e-02 6.9430100917816162e-01 -2.1816100180149078e-01 <_> 0 -1 1196 -2.4893999099731445e-02 -6.4599299430847168e-01 1.5611599385738373e-01 <_> 0 -1 1197 2.1944999694824219e-02 -2.7742000296711922e-02 -1.1346880197525024e+00 <_> 0 -1 1198 1.8809899687767029e-01 -1.0076000355184078e-02 1.2429029941558838e+00 <_> 0 -1 1199 -7.7872000634670258e-02 8.5008001327514648e-01 -1.9015499949455261e-01 <_> 0 -1 1200 -4.8769000917673111e-02 -2.0763080120086670e+00 1.2179400026798248e-01 <_> 0 -1 1201 -1.7115000635385513e-02 -8.5687297582626343e-01 7.8760003671050072e-03 <_> 0 -1 1202 -2.7499999850988388e-03 3.8645499944686890e-01 -1.1391499638557434e-01 <_> 0 -1 1203 -9.8793998360633850e-02 -1.7233899831771851e+00 -5.6063000112771988e-02 <_> 0 -1 1204 -2.1936999633908272e-02 5.4749399423599243e-01 -4.2481999844312668e-02 <_> 0 -1 1205 6.1096999794244766e-02 -3.8945000618696213e-02 -1.0807880163192749e+00 <_> 0 -1 1206 -2.4563999846577644e-02 5.8311098814010620e-01 -9.7599998116493225e-04 <_> 0 -1 1207 3.3752001821994781e-02 -1.3795999810099602e-02 -8.4730297327041626e-01 <_> 0 -1 1208 3.8199000060558319e-02 1.5114299952983856e-01 -7.9473400115966797e-01 <_> 0 -1 1209 -2.0117999985814095e-02 5.1579099893569946e-01 -2.1445399522781372e-01 <_> 0 -1 1210 2.4734999984502792e-02 -2.2105000913143158e-02 4.2917698621749878e-01 <_> 0 -1 1211 -2.4357000365853310e-02 -8.6201298236846924e-01 -3.6760000512003899e-03 <_> 0 -1 1212 -2.6442000642418861e-02 -4.5397499203681946e-01 2.2462800145149231e-01 <_> 0 -1 1213 -3.4429999068379402e-03 1.3073000311851501e-01 -3.8622701168060303e-01 <_> 0 -1 1214 1.0701700299978256e-01 1.3158600032329559e-01 -7.9306900501251221e-01 <_> 0 -1 1215 4.5152999460697174e-02 -2.5296801328659058e-01 4.0672400593757629e-01 <_> 0 -1 1216 4.4349998235702515e-02 2.2613000124692917e-02 7.9618102312088013e-01 <_> 0 -1 1217 1.0839999886229634e-03 -3.9158400893211365e-01 1.1639100313186646e-01 <_> 0 -1 1218 7.1433000266551971e-02 8.2466997206211090e-02 1.2530590295791626e+00 <_> 0 -1 1219 3.5838000476360321e-02 -1.8203300237655640e-01 7.7078700065612793e-01 <_> 0 -1 1220 -2.0839000120759010e-02 -6.1744397878646851e-01 1.5891399979591370e-01 <_> 0 -1 1221 4.2525801062583923e-01 -4.8978000879287720e-02 -1.8422030210494995e+00 <_> 0 -1 1222 1.1408000253140926e-02 1.7918199300765991e-01 -1.5383499860763550e-01 <_> 0 -1 1223 -1.5364999882876873e-02 -8.4016501903533936e-01 -1.0280000278726220e-03 <_> 0 -1 1224 -1.5212000347673893e-02 -1.8995699286460876e-01 1.7130999267101288e-01 <_> 0 -1 1225 -1.8972000107169151e-02 -7.9541999101638794e-01 6.6800001077353954e-03 <_> 0 -1 1226 -3.3330000005662441e-03 -2.3530800640583038e-01 2.4730099737644196e-01 <_> 0 -1 1227 9.3248002231121063e-02 -5.4758001118898392e-02 -1.8324300050735474e+00 <_> 0 -1 1228 -1.2555000372231007e-02 2.6385200023651123e-01 -3.8526400923728943e-01 <_> 0 -1 1229 -2.7070000767707825e-02 -6.6929799318313599e-01 2.0340999588370323e-02 <_> 0 -1 1230 -2.3677000775933266e-02 6.7265301942825317e-01 -1.4344000257551670e-02 <_> 0 -1 1231 -1.4275000430643559e-02 3.0186399817466736e-01 -2.8514400124549866e-01 <_> 0 -1 1232 2.8096999973058701e-02 1.4766000211238861e-01 -1.4078520536422729e+00 <_> 0 -1 1233 5.0840001553297043e-02 -1.8613600730895996e-01 7.9953002929687500e-01 <_> 0 -1 1234 1.1505999602377415e-02 1.9118399918079376e-01 -8.5035003721714020e-02 <_> 0 -1 1235 -1.4661000110208988e-02 4.5239299535751343e-01 -2.2205199301242828e-01 <_> 0 -1 1236 2.2842499613761902e-01 1.3488399982452393e-01 -1.2894610166549683e+00 <_> 0 -1 1237 1.1106900125741959e-01 -2.0753799378871918e-01 5.4561597108840942e-01 <_> 0 -1 1238 3.2450000289827585e-03 3.2053700089454651e-01 -1.6403500735759735e-01 <_> 0 -1 1239 8.5309997200965881e-02 -2.0210500061511993e-01 5.3296798467636108e-01 <_> 0 -1 1240 2.2048000246286392e-02 1.5698599815368652e-01 -1.7014099657535553e-01 <_> 0 -1 1241 -1.5676999464631081e-02 -6.2863498926162720e-01 4.0761999785900116e-02 <_> 0 -1 1242 3.3112901449203491e-01 1.6609300673007965e-01 -1.0326379537582397e+00 <_> 0 -1 1243 8.8470000773668289e-03 -2.5076198577880859e-01 3.1660598516464233e-01 <_> 0 -1 1244 4.6080000698566437e-02 1.5352100133895874e-01 -1.6333500146865845e+00 <_> 0 -1 1245 -3.7703000009059906e-02 5.6873798370361328e-01 -2.0102599263191223e-01 <_> 159 -3.5939640998840332e+00 <_> 0 -1 1246 -8.1808999180793762e-02 5.7124799489974976e-01 -6.7438799142837524e-01 <_> 0 -1 1247 2.1761199831962585e-01 -3.8610199093818665e-01 9.0343999862670898e-01 <_> 0 -1 1248 1.4878000132739544e-02 2.2241599857807159e-01 -1.2779350280761719e+00 <_> 0 -1 1249 5.2434999495744705e-02 -2.8690400719642639e-01 7.5742298364639282e-01 <_> 0 -1 1250 9.1429995372891426e-03 -6.4880400896072388e-01 2.2268800437450409e-01 <_> 0 -1 1251 7.9169999808073044e-03 -2.9253599047660828e-01 3.1030198931694031e-01 <_> 0 -1 1252 -2.6084000244736671e-02 4.5532700419425964e-01 -3.8500601053237915e-01 <_> 0 -1 1253 -2.9400000348687172e-03 -5.1264399290084839e-01 2.7432298660278320e-01 <_> 0 -1 1254 5.7130001485347748e-02 1.5788000077009201e-02 -1.2133100032806396e+00 <_> 0 -1 1255 -6.1309998854994774e-03 3.9174601435661316e-01 -3.0866798758506775e-01 <_> 0 -1 1256 -4.0405001491308212e-02 1.1901949644088745e+00 -2.0347100496292114e-01 <_> 0 -1 1257 -2.0297000184655190e-02 -6.8239498138427734e-01 2.0458699762821198e-01 <_> 0 -1 1258 -1.7188999801874161e-02 -8.4939897060394287e-01 3.8433000445365906e-02 <_> 0 -1 1259 -2.4215999990701675e-02 -1.1039420366287231e+00 1.5975099802017212e-01 <_> 0 -1 1260 5.6869000196456909e-02 -1.9595299661159515e-01 1.1806850433349609e+00 <_> 0 -1 1261 3.6199999158270657e-04 -4.0847799181938171e-01 3.2938599586486816e-01 <_> 0 -1 1262 9.9790003150701523e-03 -2.9673001170158386e-01 4.1547900438308716e-01 <_> 0 -1 1263 -5.2625000476837158e-02 -1.3069299459457397e+00 1.7862600088119507e-01 <_> 0 -1 1264 -1.3748999685049057e-02 2.3665800690650940e-01 -4.4536599516868591e-01 <_> 0 -1 1265 -3.0517000705003738e-02 2.9018300771713257e-01 -1.1210100352764130e-01 <_> 0 -1 1266 -3.0037501454353333e-01 -2.4237680435180664e+00 -4.2830999940633774e-02 <_> 0 -1 1267 -3.5990998148918152e-02 8.8206499814987183e-01 -4.7012999653816223e-02 <_> 0 -1 1268 -5.5112000554800034e-02 8.0119001865386963e-01 -2.0490999519824982e-01 <_> 0 -1 1269 3.3762000501155853e-02 1.4617599546909332e-01 -1.1349489688873291e+00 <_> 0 -1 1270 -8.2710003480315208e-03 -8.1604897975921631e-01 1.8988000229001045e-02 <_> 0 -1 1271 -5.4399999789893627e-03 -7.0980900526046753e-01 2.2343699634075165e-01 <_> 0 -1 1272 3.1059999018907547e-03 -7.2808599472045898e-01 4.0224999189376831e-02 <_> 0 -1 1273 5.3651999682188034e-02 1.7170900106430054e-01 -1.1163710355758667e+00 <_> 0 -1 1274 -1.2541399896144867e-01 2.7680370807647705e+00 -1.4611500501632690e-01 <_> 0 -1 1275 9.2542000114917755e-02 1.1609800159931183e-01 -3.9635529518127441e+00 <_> 0 -1 1276 3.8513999432325363e-02 -7.6399999670684338e-03 -9.8780900239944458e-01 <_> 0 -1 1277 -2.0200000144541264e-03 2.3059999942779541e-01 -7.4970299005508423e-01 <_> 0 -1 1278 9.7599998116493225e-03 -3.1137999892234802e-01 3.0287799239158630e-01 <_> 0 -1 1279 2.4095000699162483e-02 -4.9529999494552612e-02 5.2690100669860840e-01 <_> 0 -1 1280 -1.7982000485062599e-02 -1.1610640287399292e+00 -5.7000000961124897e-03 <_> 0 -1 1281 -1.0555000044405460e-02 -2.7189099788665771e-01 2.3597699403762817e-01 <_> 0 -1 1282 -7.2889998555183411e-03 -5.4219102859497070e-01 8.1914000213146210e-02 <_> 0 -1 1283 2.3939000442624092e-02 1.7975799739360809e-01 -6.7049497365951538e-01 <_> 0 -1 1284 -1.8365999683737755e-02 6.2664300203323364e-01 -2.0970100164413452e-01 <_> 0 -1 1285 1.5715999528765678e-02 2.4193699657917023e-01 -1.0444309711456299e+00 <_> 0 -1 1286 -4.8804000020027161e-02 -9.4060599803924561e-01 -3.7519999314099550e-03 <_> 0 -1 1287 6.7130001261830330e-03 -7.5432002544403076e-02 6.1575299501419067e-01 <_> 0 -1 1288 9.7770001739263535e-03 3.9285000413656235e-02 -8.4810298681259155e-01 <_> 0 -1 1289 1.4744999818503857e-02 1.6968999803066254e-01 -5.0906401872634888e-01 <_> 0 -1 1290 9.7079001367092133e-02 -3.3103000372648239e-02 -1.2706379890441895e+00 <_> 0 -1 1291 4.8285998404026031e-02 9.4329997897148132e-02 2.7203190326690674e+00 <_> 0 -1 1292 9.7810002043843269e-03 -3.9533400535583496e-01 1.5363800525665283e-01 <_> 0 -1 1293 -3.9893999695777893e-02 -2.2767400741577148e-01 1.3913999497890472e-01 <_> 0 -1 1294 2.2848000749945641e-02 -2.7391999959945679e-01 3.4199500083923340e-01 <_> 0 -1 1295 6.7179999314248562e-03 -1.0874299705028534e-01 4.8125401139259338e-01 <_> 0 -1 1296 5.9599999338388443e-02 -4.9522001296281815e-02 -2.0117089748382568e+00 <_> 0 -1 1297 6.9340001791715622e-03 1.5037499368190765e-01 -1.1271899938583374e-01 <_> 0 -1 1298 1.5757000073790550e-02 -2.0885000005364418e-02 -1.1651979684829712e+00 <_> 0 -1 1299 -4.9690000712871552e-02 -8.0213499069213867e-01 1.4372299611568451e-01 <_> 0 -1 1300 5.2347000688314438e-02 -2.0836700499057770e-01 6.1677598953247070e-01 <_> 0 -1 1301 2.2430999204516411e-02 2.0305900275707245e-01 -7.5326198339462280e-01 <_> 0 -1 1302 4.1142001748085022e-02 -1.8118199706077576e-01 1.0033359527587891e+00 <_> 0 -1 1303 -2.1632000803947449e-02 4.9998998641967773e-01 -3.4662999212741852e-02 <_> 0 -1 1304 -8.2808002829551697e-02 1.1711900234222412e+00 -1.8433600664138794e-01 <_> 0 -1 1305 8.5060000419616699e-03 -6.3225001096725464e-02 2.9024899005889893e-01 <_> 0 -1 1306 7.8905001282691956e-02 -2.3274500668048859e-01 5.9695798158645630e-01 <_> 0 -1 1307 -9.0207003057003021e-02 -8.2211899757385254e-01 1.7772200703620911e-01 <_> 0 -1 1308 -2.9269000515341759e-02 6.0860699415206909e-01 -2.1468900144100189e-01 <_> 0 -1 1309 6.9499998353421688e-03 -4.2665999382734299e-02 6.0512101650238037e-01 <_> 0 -1 1310 -8.0629996955394745e-03 -1.1508270502090454e+00 -2.7286000549793243e-02 <_> 0 -1 1311 1.9595999270677567e-02 -9.1880001127719879e-03 5.6857800483703613e-01 <_> 0 -1 1312 -1.4884999953210354e-02 3.7658798694610596e-01 -2.7149501442909241e-01 <_> 0 -1 1313 2.5217000395059586e-02 -9.9991001188755035e-02 2.4664700031280518e-01 <_> 0 -1 1314 -1.5855999663472176e-02 6.6826701164245605e-01 -2.0614700019359589e-01 <_> 0 -1 1315 2.9441000893712044e-02 1.5832200646400452e-01 -7.6060897111892700e-01 <_> 0 -1 1316 -8.5279997438192368e-03 3.8212299346923828e-01 -2.5407800078392029e-01 <_> 0 -1 1317 2.4421999230980873e-02 1.5105099976062775e-01 -2.8752899169921875e-01 <_> 0 -1 1318 -3.3886998891830444e-02 -6.8002802133560181e-01 3.4327000379562378e-02 <_> 0 -1 1319 -2.0810000132769346e-03 2.5413900613784790e-01 -2.6859098672866821e-01 <_> 0 -1 1320 3.0358999967575073e-02 -3.0842000618577003e-02 -1.1476809978485107e+00 <_> 0 -1 1321 4.0210001170635223e-03 -3.5253798961639404e-01 2.9868099093437195e-01 <_> 0 -1 1322 2.7681000530719757e-02 -3.8148999214172363e-02 -1.3262039422988892e+00 <_> 0 -1 1323 7.9039996489882469e-03 -2.3737000301480293e-02 7.0503002405166626e-01 <_> 0 -1 1324 4.4031001627445221e-02 1.0674899816513062e-01 -4.5261201262474060e-01 <_> 0 -1 1325 -3.2370999455451965e-02 4.6674901247024536e-01 -6.1546999961137772e-02 <_> 0 -1 1326 2.0933000370860100e-02 -2.8447899222373962e-01 4.3845599889755249e-01 <_> 0 -1 1327 2.5227999314665794e-02 -2.2537000477313995e-02 7.0389097929000854e-01 <_> 0 -1 1328 6.5520000644028187e-03 -3.2554900646209717e-01 2.4023699760437012e-01 <_> 0 -1 1329 -5.8557998389005661e-02 -1.2227720022201538e+00 1.1668799817562103e-01 <_> 0 -1 1330 3.1899999827146530e-02 -1.9305000081658363e-02 -1.0973169803619385e+00 <_> 0 -1 1331 -3.0445000156760216e-02 6.5582501888275146e-01 7.5090996921062469e-02 <_> 0 -1 1332 1.4933000318706036e-02 -5.2155798673629761e-01 1.1523099988698959e-01 <_> 0 -1 1333 -4.9008000642061234e-02 -7.8303998708724976e-01 1.6657200455665588e-01 <_> 0 -1 1334 8.3158999681472778e-02 -2.6879999786615372e-03 -8.5282301902770996e-01 <_> 0 -1 1335 2.3902999237179756e-02 -5.1010999828577042e-02 4.1999098658561707e-01 <_> 0 -1 1336 1.6428999602794647e-02 1.9232999533414841e-02 -6.5049099922180176e-01 <_> 0 -1 1337 -1.1838000267744064e-02 -6.2409800291061401e-01 1.5411199629306793e-01 <_> 0 -1 1338 -1.6799999866634607e-04 1.7589199542999268e-01 -3.4338700771331787e-01 <_> 0 -1 1339 1.9193999469280243e-02 4.3418999761343002e-02 7.9069197177886963e-01 <_> 0 -1 1340 -1.0032000020146370e-02 4.5648899674415588e-01 -2.2494800388813019e-01 <_> 0 -1 1341 -1.4004000462591648e-02 3.3570998907089233e-01 -4.8799999058246613e-03 <_> 0 -1 1342 -1.0319899767637253e-01 -2.3378000259399414e+00 -5.8933001011610031e-02 <_> 0 -1 1343 -9.5697000622749329e-02 -6.6153901815414429e-01 2.0098599791526794e-01 <_> 0 -1 1344 -4.1480999439954758e-02 4.5939201116561890e-01 -2.2314099967479706e-01 <_> 0 -1 1345 2.4099999573081732e-03 -2.6898598670959473e-01 2.4922999739646912e-01 <_> 0 -1 1346 1.0724999755620956e-01 -1.8640199303627014e-01 7.2769802808761597e-01 <_> 0 -1 1347 3.1870000530034304e-03 -2.4608999490737915e-02 2.8643900156021118e-01 <_> 0 -1 1348 2.9167000204324722e-02 -3.4683000296354294e-02 -1.1162580251693726e+00 <_> 0 -1 1349 1.1287000030279160e-02 6.3760001212358475e-03 6.6632097959518433e-01 <_> 0 -1 1350 -1.2001000344753265e-02 4.2420101165771484e-01 -2.6279801130294800e-01 <_> 0 -1 1351 -1.2695999816060066e-02 -2.1957000717520714e-02 1.8936799466609955e-01 <_> 0 -1 1352 2.4597000330686569e-02 -3.4963998943567276e-02 -1.0989320278167725e+00 <_> 0 -1 1353 4.5953001827001572e-02 1.1109799891710281e-01 -2.9306049346923828e+00 <_> 0 -1 1354 -2.7241000905632973e-02 2.9101699590682983e-01 -2.7407899498939514e-01 <_> 0 -1 1355 4.0063999593257904e-02 1.1877900362014771e-01 -6.2801802158355713e-01 <_> 0 -1 1356 2.3055000230669975e-02 1.4813800156116486e-01 -3.7007498741149902e-01 <_> 0 -1 1357 -2.3737000301480293e-02 -5.3724801540374756e-01 1.9358199834823608e-01 <_> 0 -1 1358 7.7522002160549164e-02 -6.0194000601768494e-02 -1.9489669799804688e+00 <_> 0 -1 1359 -1.3345000334084034e-02 -4.5229598879814148e-01 1.8741500377655029e-01 <_> 0 -1 1360 -2.1719999611377716e-02 1.2144249677658081e+00 -1.5365800261497498e-01 <_> 0 -1 1361 -7.1474999189376831e-02 -2.3047130107879639e+00 1.0999900102615356e-01 <_> 0 -1 1362 -5.4999999701976776e-03 -7.1855199337005615e-01 2.0100999623537064e-02 <_> 0 -1 1363 2.6740999892354012e-02 7.3545001447200775e-02 9.8786002397537231e-01 <_> 0 -1 1364 -3.9407998323440552e-02 -1.2227380275726318e+00 -4.3506998568773270e-02 <_> 0 -1 1365 2.5888999924063683e-02 1.3409300148487091e-01 -1.1770780086517334e+00 <_> 0 -1 1366 4.8925001174211502e-02 -3.0810000374913216e-02 -9.3479502201080322e-01 <_> 0 -1 1367 3.6892998963594437e-02 1.3333700597286224e-01 -1.4998290538787842e+00 <_> 0 -1 1368 7.8929997980594635e-02 -1.4538800716400146e-01 1.5631790161132812e+00 <_> 0 -1 1369 2.9006000608205795e-02 1.9383700191974640e-01 -6.7642802000045776e-01 <_> 0 -1 1370 6.3089998438954353e-03 -3.7465399503707886e-01 1.0857500135898590e-01 <_> 0 -1 1371 -6.5830998122692108e-02 8.1059402227401733e-01 3.0201999470591545e-02 <_> 0 -1 1372 -6.8965002894401550e-02 8.3772599697113037e-01 -1.7140999436378479e-01 <_> 0 -1 1373 -1.1669100075960159e-01 -9.4647198915481567e-01 1.3123199343681335e-01 <_> 0 -1 1374 -1.3060000492259860e-03 4.6007998287677765e-02 -5.2011597156524658e-01 <_> 0 -1 1375 -4.4558998197317123e-02 -1.9423669576644897e+00 1.3200700283050537e-01 <_> 0 -1 1376 5.1033001393079758e-02 -2.1480999886989594e-01 4.8673900961875916e-01 <_> 0 -1 1377 -3.1578000634908676e-02 5.9989798069000244e-01 7.9159997403621674e-03 <_> 0 -1 1378 2.1020000800490379e-02 -2.2069500386714935e-01 5.4046201705932617e-01 <_> 0 -1 1379 -1.3824200630187988e-01 6.2957501411437988e-01 -2.1712999790906906e-02 <_> 0 -1 1380 5.2228998392820358e-02 -2.3360900580883026e-01 4.9760800600051880e-01 <_> 0 -1 1381 2.5884000584483147e-02 1.8041999638080597e-01 -2.2039200365543365e-01 <_> 0 -1 1382 -1.2138999998569489e-02 -6.9731897115707397e-01 1.5712000429630280e-02 <_> 0 -1 1383 -2.4237999692559242e-02 3.4593299031257629e-01 7.1469999849796295e-02 <_> 0 -1 1384 -2.5272000581026077e-02 -8.7583297491073608e-01 -9.8240002989768982e-03 <_> 0 -1 1385 1.2597000226378441e-02 2.3649999499320984e-01 -2.8731200098991394e-01 <_> 0 -1 1386 5.7330999523401260e-02 -6.1530999839305878e-02 -2.2326040267944336e+00 <_> 0 -1 1387 1.6671000048518181e-02 -1.9850100576877594e-01 4.0810701251029968e-01 <_> 0 -1 1388 -2.2818999364972115e-02 9.6487599611282349e-01 -2.0245699584484100e-01 <_> 0 -1 1389 3.7000001611886546e-05 -5.8908998966217041e-02 2.7055400609970093e-01 <_> 0 -1 1390 -7.6700001955032349e-03 -4.5317101478576660e-01 8.9628003537654877e-02 <_> 0 -1 1391 9.4085998833179474e-02 1.1604599654674530e-01 -1.0951169729232788e+00 <_> 0 -1 1392 -6.2267001718282700e-02 1.8096530437469482e+00 -1.4773200452327728e-01 <_> 0 -1 1393 1.7416000366210938e-02 2.3068200051784515e-01 -4.2417600750923157e-01 <_> 0 -1 1394 -2.2066000849008560e-02 4.9270299077033997e-01 -2.0630900561809540e-01 <_> 0 -1 1395 -1.0404000058770180e-02 6.0924297571182251e-01 2.8130000457167625e-02 <_> 0 -1 1396 -9.3670003116130829e-03 4.0171200037002563e-01 -2.1681700646877289e-01 <_> 0 -1 1397 -2.9039999470114708e-02 -8.4876501560211182e-01 1.4246800541877747e-01 <_> 0 -1 1398 -2.1061999723315239e-02 -7.9198300838470459e-01 -1.2595999985933304e-02 <_> 0 -1 1399 -3.7000998854637146e-02 -6.7488902807235718e-01 1.2830400466918945e-01 <_> 0 -1 1400 1.0735999792814255e-02 3.6779999732971191e-02 -6.3393002748489380e-01 <_> 0 -1 1401 1.6367599368095398e-01 1.3803899288177490e-01 -4.7189000248908997e-01 <_> 0 -1 1402 9.4917997717857361e-02 -1.3855700194835663e-01 1.9492419958114624e+00 <_> 0 -1 1403 3.5261999815702438e-02 1.3721899688243866e-01 -2.1186530590057373e+00 <_> 0 -1 1404 1.2811000458896160e-02 -2.0008100569248199e-01 4.9507799744606018e-01 <_> 155 -3.3933560848236084e+00 <_> 0 -1 1405 1.3904400169849396e-01 -4.6581199765205383e-01 7.6431602239608765e-01 <_> 0 -1 1406 1.1916999705135822e-02 -9.4398999214172363e-01 3.9726299047470093e-01 <_> 0 -1 1407 -1.0006999596953392e-02 3.2718798518180847e-01 -6.3367402553558350e-01 <_> 0 -1 1408 -6.0479999519884586e-03 2.7427899837493896e-01 -5.7446998357772827e-01 <_> 0 -1 1409 -1.2489999644458294e-03 2.3629300296306610e-01 -6.8593502044677734e-01 <_> 0 -1 1410 3.2382000237703323e-02 -5.7630199193954468e-01 2.7492699027061462e-01 <_> 0 -1 1411 -1.3957999646663666e-02 -6.1061501502990723e-01 2.4541600048542023e-01 <_> 0 -1 1412 1.1159999994561076e-03 -5.6539100408554077e-01 2.7179300785064697e-01 <_> 0 -1 1413 2.7000000045518391e-05 -8.0235999822616577e-01 1.1509100347757339e-01 <_> 0 -1 1414 -2.5700000696815550e-04 -8.1205898523330688e-01 2.3844699561595917e-01 <_> 0 -1 1415 4.0460000745952129e-03 1.3909600675106049e-01 -6.6163200139999390e-01 <_> 0 -1 1416 1.4356000348925591e-02 -1.6485199332237244e-01 4.1901698708534241e-01 <_> 0 -1 1417 -5.5374998599290848e-02 1.4425870180130005e+00 -1.8820199370384216e-01 <_> 0 -1 1418 9.3594998121261597e-02 1.3548299670219421e-01 -9.1636097431182861e-01 <_> 0 -1 1419 2.6624999940395355e-02 -3.3748298883438110e-01 3.9233601093292236e-01 <_> 0 -1 1420 3.7469998933374882e-03 -1.1615400016307831e-01 4.4399300217628479e-01 <_> 0 -1 1421 -3.1886000186204910e-02 -9.9498301744461060e-01 1.6120000509545207e-03 <_> 0 -1 1422 -2.2600000724196434e-02 -4.8067399859428406e-01 1.7007300257682800e-01 <_> 0 -1 1423 2.5202000513672829e-02 3.5580001771450043e-02 -8.0215400457382202e-01 <_> 0 -1 1424 -3.1036999076604843e-02 -1.0895340442657471e+00 1.8081900477409363e-01 <_> 0 -1 1425 -2.6475999504327774e-02 9.5671200752258301e-01 -2.1049399673938751e-01 <_> 0 -1 1426 -1.3853999786078930e-02 -1.0370320081710815e+00 2.2166700661182404e-01 <_> 0 -1 1427 -6.2925003468990326e-02 9.0199398994445801e-01 -1.9085299968719482e-01 <_> 0 -1 1428 -4.4750999659299850e-02 -1.0119110345840454e+00 1.4691199362277985e-01 <_> 0 -1 1429 -2.0428000018000603e-02 6.1624497175216675e-01 -2.3552699387073517e-01 <_> 0 -1 1430 -8.0329999327659607e-03 -8.3279997110366821e-02 2.1728700399398804e-01 <_> 0 -1 1431 8.7280003353953362e-03 6.5458998084068298e-02 -6.0318702459335327e-01 <_> 0 -1 1432 -2.7202000841498375e-02 -9.3447399139404297e-01 1.5270000696182251e-01 <_> 0 -1 1433 -1.6471000388264656e-02 -8.4177100658416748e-01 1.3332000002264977e-02 <_> 0 -1 1434 -1.3744000345468521e-02 6.0567200183868408e-01 -9.2021003365516663e-02 <_> 0 -1 1435 2.9164999723434448e-02 -2.8114000335335732e-02 -1.4014569520950317e+00 <_> 0 -1 1436 3.7457000464200974e-02 1.3080599904060364e-01 -4.9382498860359192e-01 <_> 0 -1 1437 -2.5070000439882278e-02 -1.1289390325546265e+00 -1.4600000344216824e-02 <_> 0 -1 1438 -6.3812002539634705e-02 7.5871598720550537e-01 -1.8200000049546361e-03 <_> 0 -1 1439 -9.3900002539157867e-03 2.9936400055885315e-01 -2.9487800598144531e-01 <_> 0 -1 1440 -7.6000002445653081e-04 1.9725000485777855e-02 1.9993899762630463e-01 <_> 0 -1 1441 -2.1740999072790146e-02 -8.5247898101806641e-01 4.9169998615980148e-02 <_> 0 -1 1442 -1.7869999632239342e-02 -5.9985999017953873e-02 1.5222500264644623e-01 <_> 0 -1 1443 -2.4831000715494156e-02 3.5603401064872742e-01 -2.6259899139404297e-01 <_> 0 -1 1444 1.5715500712394714e-01 1.5599999460391700e-04 1.0428730249404907e+00 <_> 0 -1 1445 6.9026999175548553e-02 -3.3006999641656876e-02 -1.1796669960021973e+00 <_> 0 -1 1446 -1.1021999642252922e-02 5.8987700939178467e-01 -5.7647999376058578e-02 <_> 0 -1 1447 -1.3834999874234200e-02 5.9502798318862915e-01 -2.4418599903583527e-01 <_> 0 -1 1448 -3.0941000208258629e-02 -1.1723799705505371e+00 1.6907000541687012e-01 <_> 0 -1 1449 2.1258000284433365e-02 -1.8900999799370766e-02 -1.0684759616851807e+00 <_> 0 -1 1450 9.3079999089241028e-02 1.6305600106716156e-01 -1.3375270366668701e+00 <_> 0 -1 1451 2.9635999351739883e-02 -2.2524799406528473e-01 4.5400100946426392e-01 <_> 0 -1 1452 -1.2199999764561653e-04 2.7409100532531738e-01 -3.7371399998664856e-01 <_> 0 -1 1453 -4.2098000645637512e-02 -7.5828802585601807e-01 1.7137000337243080e-02 <_> 0 -1 1454 -2.2505000233650208e-02 -2.2759300470352173e-01 2.3698699474334717e-01 <_> 0 -1 1455 -1.2862999923527241e-02 1.9252400100231171e-01 -3.2127100229263306e-01 <_> 0 -1 1456 2.7860000729560852e-02 1.6723699867725372e-01 -1.0209059715270996e+00 <_> 0 -1 1457 -2.7807999402284622e-02 1.2824759483337402e+00 -1.7225299775600433e-01 <_> 0 -1 1458 -6.1630001291632652e-03 -5.4072898626327515e-01 2.3885700106620789e-01 <_> 0 -1 1459 -2.0436000078916550e-02 6.3355398178100586e-01 -2.1090599894523621e-01 <_> 0 -1 1460 -1.2307999655604362e-02 -4.9778199195861816e-01 1.7402599751949310e-01 <_> 0 -1 1461 -4.0493998676538467e-02 -1.1848740577697754e+00 -3.3890999853610992e-02 <_> 0 -1 1462 2.9657000675797462e-02 2.1740999072790146e-02 1.0069919824600220e+00 <_> 0 -1 1463 6.8379999138414860e-03 2.9217999428510666e-02 -5.9906297922134399e-01 <_> 0 -1 1464 1.6164999455213547e-02 -2.1000799536705017e-01 3.7637299299240112e-01 <_> 0 -1 1465 5.0193000584840775e-02 2.5319999549537897e-03 -7.1668201684951782e-01 <_> 0 -1 1466 1.9680000841617584e-03 -2.1921400725841522e-01 3.2298699021339417e-01 <_> 0 -1 1467 2.4979999288916588e-02 -9.6840001642704010e-03 -7.7572900056838989e-01 <_> 0 -1 1468 -1.5809999778866768e-02 4.4637501239776611e-01 -6.1760000884532928e-02 <_> 0 -1 1469 3.7206999957561493e-02 -2.0495399832725525e-01 5.7722198963165283e-01 <_> 0 -1 1470 -7.9264998435974121e-02 -7.6745402812957764e-01 1.2550400197505951e-01 <_> 0 -1 1471 -1.7152000218629837e-02 -1.4121830463409424e+00 -5.1704000681638718e-02 <_> 0 -1 1472 3.2740000635385513e-02 1.9334000349044800e-01 -6.3633698225021362e-01 <_> 0 -1 1473 -1.1756999790668488e-01 8.4325402975082397e-01 -1.8018600344657898e-01 <_> 0 -1 1474 1.2057200074195862e-01 1.2530000507831573e-01 -2.1213600635528564e+00 <_> 0 -1 1475 4.2779999785125256e-03 -4.6604400873184204e-01 8.9643999934196472e-02 <_> 0 -1 1476 -7.2544999420642853e-02 5.1826500892639160e-01 1.6823999583721161e-02 <_> 0 -1 1477 1.7710599303245544e-01 -3.0910000205039978e-02 -1.1046639680862427e+00 <_> 0 -1 1478 8.4229996427893639e-03 2.4445800483226776e-01 -3.8613098859786987e-01 <_> 0 -1 1479 -1.3035000301897526e-02 9.8004400730133057e-01 -1.7016500234603882e-01 <_> 0 -1 1480 1.8912000581622124e-02 2.0248499512672424e-01 -3.8545900583267212e-01 <_> 0 -1 1481 2.1447999402880669e-02 -2.5717198848724365e-01 3.5181200504302979e-01 <_> 0 -1 1482 6.3357003033161163e-02 1.6994799673557281e-01 -9.1383802890777588e-01 <_> 0 -1 1483 -3.2435998320579529e-02 -8.5681599378585815e-01 -2.1680999547243118e-02 <_> 0 -1 1484 -2.3564999923110008e-02 5.6115597486495972e-01 -2.2400000307243317e-04 <_> 0 -1 1485 1.8789000809192657e-02 -2.5459799170494080e-01 3.4512901306152344e-01 <_> 0 -1 1486 3.1042000278830528e-02 7.5719999149441719e-03 3.4800198674201965e-01 <_> 0 -1 1487 -1.1226999573409557e-02 -6.0219800472259521e-01 4.2814999818801880e-02 <_> 0 -1 1488 -1.2845999561250210e-02 4.2020401358604431e-01 -5.3801000118255615e-02 <_> 0 -1 1489 -1.2791999615728855e-02 2.2724500298500061e-01 -3.2398000359535217e-01 <_> 0 -1 1490 6.8651996552944183e-02 9.3532003462314606e-02 10. <_> 0 -1 1491 5.2789999172091484e-03 -2.6926299929618835e-01 3.3303201198577881e-01 <_> 0 -1 1492 -3.8779001682996750e-02 -7.2365301847457886e-01 1.7806500196456909e-01 <_> 0 -1 1493 6.1820000410079956e-03 -3.5119399428367615e-01 1.6586300730705261e-01 <_> 0 -1 1494 1.7515200376510620e-01 1.1623100191354752e-01 -1.5419290065765381e+00 <_> 0 -1 1495 1.1627999693155289e-01 -9.1479998081922531e-03 -9.9842602014541626e-01 <_> 0 -1 1496 -2.2964000701904297e-02 2.0565399527549744e-01 1.5432000160217285e-02 <_> 0 -1 1497 -5.1410000771284103e-02 5.8072400093078613e-01 -2.0118400454521179e-01 <_> 0 -1 1498 2.2474199533462524e-01 1.8728999421000481e-02 1.0829299688339233e+00 <_> 0 -1 1499 9.4860000535845757e-03 -3.3171299099922180e-01 1.9902999699115753e-01 <_> 0 -1 1500 -1.1846300214529037e-01 1.3711010217666626e+00 6.8926997482776642e-02 <_> 0 -1 1501 3.7810999900102615e-02 -9.3600002583116293e-04 -8.3996999263763428e-01 <_> 0 -1 1502 2.2202000021934509e-02 -1.1963999830186367e-02 3.6673998832702637e-01 <_> 0 -1 1503 -3.6366000771522522e-02 3.7866500020027161e-01 -2.7714800834655762e-01 <_> 0 -1 1504 -1.3184699416160583e-01 -2.7481179237365723e+00 1.0666900128126144e-01 <_> 0 -1 1505 -4.1655998677015305e-02 4.7524300217628479e-01 -2.3249800503253937e-01 <_> 0 -1 1506 -3.3151999115943909e-02 -5.7929402589797974e-01 1.7434400320053101e-01 <_> 0 -1 1507 1.5769999474287033e-02 -1.1284000240266323e-02 -8.3701401948928833e-01 <_> 0 -1 1508 -3.9363000541925430e-02 3.4821599721908569e-01 -1.7455400526523590e-01 <_> 0 -1 1509 -6.7849002778530121e-02 1.4225699901580811e+00 -1.4765599370002747e-01 <_> 0 -1 1510 -2.6775000616908073e-02 2.3947000503540039e-01 1.3271999545395374e-02 <_> 0 -1 1511 3.9919000118970871e-02 -8.9999996125698090e-03 -7.5938898324966431e-01 <_> 0 -1 1512 1.0065600275993347e-01 -1.8685000017285347e-02 7.6245301961898804e-01 <_> 0 -1 1513 -8.1022001802921295e-02 -9.0439099073410034e-01 -8.5880002006888390e-03 <_> 0 -1 1514 -2.1258000284433365e-02 -2.1319599449634552e-01 2.1919700503349304e-01 <_> 0 -1 1515 -1.0630999691784382e-02 1.9598099589347839e-01 -3.5768100619316101e-01 <_> 0 -1 1516 8.1300002057105303e-04 -9.2794999480247498e-02 2.6145899295806885e-01 <_> 0 -1 1517 3.4650000743567944e-03 -5.5336099863052368e-01 2.7386000379920006e-02 <_> 0 -1 1518 1.8835999071598053e-02 1.8446099758148193e-01 -6.6934299468994141e-01 <_> 0 -1 1519 -2.5631999596953392e-02 1.9382879734039307e+00 -1.4708900451660156e-01 <_> 0 -1 1520 -4.0939999744296074e-03 -2.6451599597930908e-01 2.0733200013637543e-01 <_> 0 -1 1521 -8.9199998183175921e-04 -5.5031597614288330e-01 5.0374999642372131e-02 <_> 0 -1 1522 -4.9518000334501266e-02 -2.5615389347076416e+00 1.3141700625419617e-01 <_> 0 -1 1523 1.1680999770760536e-02 -2.4819800257682800e-01 3.9982700347900391e-01 <_> 0 -1 1524 3.4563999623060226e-02 1.6178800165653229e-01 -7.1418899297714233e-01 <_> 0 -1 1525 -8.2909995689988136e-03 2.2180099785327911e-01 -2.9181700944900513e-01 <_> 0 -1 1526 -2.2358000278472900e-02 3.1044098734855652e-01 -2.7280000504106283e-03 <_> 0 -1 1527 -3.0801000073552132e-02 -9.5672702789306641e-01 -8.3400001749396324e-03 <_> 0 -1 1528 4.3779000639915466e-02 1.2556900084018707e-01 -1.1759619712829590e+00 <_> 0 -1 1529 4.3046001344919205e-02 -5.8876998722553253e-02 -1.8568470478057861e+00 <_> 0 -1 1530 2.7188999578356743e-02 4.2858000844717026e-02 3.9036700129508972e-01 <_> 0 -1 1531 9.4149997457861900e-03 -4.3567001819610596e-02 -1.1094470024108887e+00 <_> 0 -1 1532 9.4311997294425964e-02 4.0256999433040619e-02 9.8442298173904419e-01 <_> 0 -1 1533 1.7025099694728851e-01 2.9510000720620155e-02 -6.9509297609329224e-01 <_> 0 -1 1534 -4.7148000448942184e-02 1.0338569879531860e+00 6.7602001130580902e-02 <_> 0 -1 1535 1.1186300218105316e-01 -6.8682998418807983e-02 -2.4985830783843994e+00 <_> 0 -1 1536 -1.4353999868035316e-02 -5.9481900930404663e-01 1.5001699328422546e-01 <_> 0 -1 1537 3.4024000167846680e-02 -6.4823001623153687e-02 -2.1382639408111572e+00 <_> 0 -1 1538 2.1601999178528786e-02 5.5309999734163284e-02 7.8292900323867798e-01 <_> 0 -1 1539 2.1771999076008797e-02 -7.1279997937381268e-03 -7.2148102521896362e-01 <_> 0 -1 1540 8.2416996359825134e-02 1.4609499275684357e-01 -1.3636670112609863e+00 <_> 0 -1 1541 8.4671996533870697e-02 -1.7784699797630310e-01 7.2857701778411865e-01 <_> 0 -1 1542 -5.5128000676631927e-02 -5.9402400255203247e-01 1.9357800483703613e-01 <_> 0 -1 1543 -6.4823001623153687e-02 -1.0783840417861938e+00 -4.0734000504016876e-02 <_> 0 -1 1544 -2.2769000381231308e-02 7.7900201082229614e-01 3.4960000775754452e-03 <_> 0 -1 1545 5.4756000638008118e-02 -6.5683998167514801e-02 -1.8188409805297852e+00 <_> 0 -1 1546 -8.9000001025851816e-05 -1.7891999334096909e-02 2.0768299698829651e-01 <_> 0 -1 1547 9.8361998796463013e-02 -5.5946998298168182e-02 -1.4153920412063599e+00 <_> 0 -1 1548 -7.0930002257227898e-03 3.4135299921035767e-01 -1.2089899927377701e-01 <_> 0 -1 1549 5.0278000533580780e-02 -2.6286700367927551e-01 2.5797298550605774e-01 <_> 0 -1 1550 -5.7870000600814819e-03 -1.3178600370883942e-01 1.7350199818611145e-01 <_> 0 -1 1551 1.3973999768495560e-02 2.8518000617623329e-02 -6.1152201890945435e-01 <_> 0 -1 1552 2.1449999883770943e-02 2.6181999593973160e-02 3.0306598544120789e-01 <_> 0 -1 1553 -2.9214000329375267e-02 4.4940599799156189e-01 -2.2803099453449249e-01 <_> 0 -1 1554 4.8099999548867345e-04 -1.9879999756813049e-01 2.0744499564170837e-01 <_> 0 -1 1555 1.7109999898821115e-03 -5.4037201404571533e-01 6.7865997552871704e-02 <_> 0 -1 1556 8.6660003289580345e-03 -1.3128000311553478e-02 5.2297902107238770e-01 <_> 0 -1 1557 6.3657999038696289e-02 6.8299002945423126e-02 -4.9235099554061890e-01 <_> 0 -1 1558 -2.7968000620603561e-02 6.8183898925781250e-01 7.8781001269817352e-02 <_> 0 -1 1559 4.8953998833894730e-02 -2.0622399449348450e-01 5.0388097763061523e-01 <_> 169 -3.2396929264068604e+00 <_> 0 -1 1560 -2.9312999919056892e-02 7.1284699440002441e-01 -5.8230698108673096e-01 <_> 0 -1 1561 1.2415099889039993e-01 -3.6863499879837036e-01 6.0067200660705566e-01 <_> 0 -1 1562 7.9349996522068977e-03 -8.6008298397064209e-01 2.1724699437618256e-01 <_> 0 -1 1563 3.0365999788045883e-02 -2.7186998724937439e-01 6.1247897148132324e-01 <_> 0 -1 1564 2.5218000635504723e-02 -3.4748300909996033e-01 5.0427699089050293e-01 <_> 0 -1 1565 1.0014000348746777e-02 -3.1898999214172363e-01 4.1376799345016479e-01 <_> 0 -1 1566 -1.6775000840425491e-02 -6.9048100709915161e-01 9.4830997288227081e-02 <_> 0 -1 1567 -2.6950000319629908e-03 -2.0829799771308899e-01 2.3737199604511261e-01 <_> 0 -1 1568 4.2257998138666153e-02 -4.9366700649261475e-01 1.8170599639415741e-01 <_> 0 -1 1569 -4.8505000770092010e-02 1.3429640531539917e+00 3.9769001305103302e-02 <_> 0 -1 1570 2.8992999345064163e-02 4.6496000140905380e-02 -8.1643497943878174e-01 <_> 0 -1 1571 -4.0089000016450882e-02 -7.1197801828384399e-01 2.2553899884223938e-01 <_> 0 -1 1572 -4.1021998971700668e-02 1.0057929754257202e+00 -1.9690200686454773e-01 <_> 0 -1 1573 1.1838000267744064e-02 -1.2600000016391277e-02 8.0767101049423218e-01 <_> 0 -1 1574 -2.1328000351786613e-02 -8.2023900747299194e-01 2.0524999126791954e-02 <_> 0 -1 1575 -2.3904999718070030e-02 5.4210501909255981e-01 -7.4767000973224640e-02 <_> 0 -1 1576 1.8008999526500702e-02 -3.3827701210975647e-01 4.2358601093292236e-01 <_> 0 -1 1577 -4.3614000082015991e-02 -1.1983489990234375e+00 1.5566200017929077e-01 <_> 0 -1 1578 -9.2449998483061790e-03 -8.9029997587203979e-01 1.1003999970853329e-02 <_> 0 -1 1579 4.7485001385211945e-02 1.6664099693298340e-01 -9.0764498710632324e-01 <_> 0 -1 1580 -1.4233999885618687e-02 6.2695199251174927e-01 -2.5791200995445251e-01 <_> 0 -1 1581 3.8010000716894865e-03 -2.8229999542236328e-01 2.6624599099159241e-01 <_> 0 -1 1582 3.4330000635236502e-03 -6.3771998882293701e-01 9.8422996699810028e-02 <_> 0 -1 1583 -2.9221000149846077e-02 -7.6769900321960449e-01 2.2634500265121460e-01 <_> 0 -1 1584 -6.4949998632073402e-03 4.5600101351737976e-01 -2.6528900861740112e-01 <_> 0 -1 1585 -3.0034000054001808e-02 -7.6551097631454468e-01 1.4009299874305725e-01 <_> 0 -1 1586 7.8360000625252724e-03 4.6755999326705933e-02 -7.2356200218200684e-01 <_> 0 -1 1587 8.8550001382827759e-03 -4.9141999334096909e-02 5.1472699642181396e-01 <_> 0 -1 1588 9.5973998308181763e-02 -2.0068999379873276e-02 -1.0850950479507446e+00 <_> 0 -1 1589 -3.2876998186111450e-02 -9.5875298976898193e-01 1.4543600380420685e-01 <_> 0 -1 1590 -1.3384000398218632e-02 -7.0013600587844849e-01 2.9157999902963638e-02 <_> 0 -1 1591 1.5235999599099159e-02 -2.8235700726509094e-01 2.5367999076843262e-01 <_> 0 -1 1592 1.2054000049829483e-02 -2.5303399562835693e-01 4.6526700258255005e-01 <_> 0 -1 1593 -7.6295003294944763e-02 -6.9915801286697388e-01 1.3217200338840485e-01 <_> 0 -1 1594 -1.2040000408887863e-02 4.5894598960876465e-01 -2.3856499791145325e-01 <_> 0 -1 1595 2.1916000172495842e-02 1.8268600106239319e-01 -6.1629700660705566e-01 <_> 0 -1 1596 -2.7330000884830952e-03 -6.3257902860641479e-01 3.4219000488519669e-02 <_> 0 -1 1597 -4.8652000725269318e-02 -1.0297729969024658e+00 1.7386500537395477e-01 <_> 0 -1 1598 -1.0463999584317207e-02 3.4757301211357117e-01 -2.7464100718498230e-01 <_> 0 -1 1599 -6.6550001502037048e-03 -2.8980299830436707e-01 2.4037900567054749e-01 <_> 0 -1 1600 8.5469996556639671e-03 -4.4340500235557556e-01 1.4267399907112122e-01 <_> 0 -1 1601 1.9913999363780022e-02 1.7740400135517120e-01 -2.4096299707889557e-01 <_> 0 -1 1602 2.2012999281287193e-02 -1.0812000371515751e-02 -9.4690799713134766e-01 <_> 0 -1 1603 -5.2179001271724701e-02 1.6547499895095825e+00 9.6487000584602356e-02 <_> 0 -1 1604 1.9698999822139740e-02 -6.7560002207756042e-03 -8.6311501264572144e-01 <_> 0 -1 1605 2.3040000349283218e-02 -2.3519999813288450e-03 3.8531300425529480e-01 <_> 0 -1 1606 -1.5038000419735909e-02 -6.1905699968338013e-01 3.1077999621629715e-02 <_> 0 -1 1607 -4.9956001341342926e-02 7.0657497644424438e-01 4.7880999743938446e-02 <_> 0 -1 1608 -6.9269999861717224e-02 3.9212900400161743e-01 -2.3848000168800354e-01 <_> 0 -1 1609 4.7399997711181641e-03 -2.4309000000357628e-02 2.5386300683021545e-01 <_> 0 -1 1610 -3.3923998475074768e-02 4.6930399537086487e-01 -2.3321899771690369e-01 <_> 0 -1 1611 -1.6231000423431396e-02 3.2319200038909912e-01 -2.0545600354671478e-01 <_> 0 -1 1612 -5.0193000584840775e-02 -1.2277870178222656e+00 -4.0798000991344452e-02 <_> 0 -1 1613 5.6944001466035843e-02 4.5184001326560974e-02 6.0197502374649048e-01 <_> 0 -1 1614 4.0936999022960663e-02 -1.6772800683975220e-01 8.9819300174713135e-01 <_> 0 -1 1615 -3.0839999672025442e-03 3.3716198801994324e-01 -2.7240800857543945e-01 <_> 0 -1 1616 -3.2600000500679016e-02 -8.5446500778198242e-01 1.9664999097585678e-02 <_> 0 -1 1617 9.8480999469757080e-02 5.4742000997066498e-02 6.3827300071716309e-01 <_> 0 -1 1618 -3.8185000419616699e-02 5.2274698019027710e-01 -2.3384800553321838e-01 <_> 0 -1 1619 -4.5917000621557236e-02 6.2829202413558960e-01 3.2859001308679581e-02 <_> 0 -1 1620 -1.1955499649047852e-01 -6.1572700738906860e-01 3.4680001437664032e-02 <_> 0 -1 1621 -1.2044399976730347e-01 -8.4380000829696655e-01 1.6530700027942657e-01 <_> 0 -1 1622 7.0619001984596252e-02 -6.3261002302169800e-02 -1.9863929748535156e+00 <_> 0 -1 1623 8.4889996796846390e-03 -1.7663399875164032e-01 3.8011199235916138e-01 <_> 0 -1 1624 2.2710999473929405e-02 -2.7605999261140823e-02 -9.1921401023864746e-01 <_> 0 -1 1625 4.9700000090524554e-04 -2.4293200671672821e-01 2.2878900170326233e-01 <_> 0 -1 1626 3.4651998430490494e-02 -2.3705999553203583e-01 5.4010999202728271e-01 <_> 0 -1 1627 -4.4700000435113907e-03 3.9078998565673828e-01 -1.2693800032138824e-01 <_> 0 -1 1628 2.3643000051379204e-02 -2.6663699746131897e-01 3.2312598824501038e-01 <_> 0 -1 1629 1.2813000008463860e-02 1.7540800571441650e-01 -6.0787999629974365e-01 <_> 0 -1 1630 -1.1250999756157398e-02 -1.0852589607238770e+00 -2.8046000748872757e-02 <_> 0 -1 1631 -4.1535001248121262e-02 7.1887397766113281e-01 2.7982000261545181e-02 <_> 0 -1 1632 -9.3470998108386993e-02 -1.1906319856643677e+00 -4.4810999184846878e-02 <_> 0 -1 1633 -2.7249999344348907e-02 6.2942498922348022e-01 9.5039997249841690e-03 <_> 0 -1 1634 -2.1759999915957451e-02 1.3233649730682373e+00 -1.5027000010013580e-01 <_> 0 -1 1635 -9.6890004351735115e-03 -3.3947101235389709e-01 1.7085799574851990e-01 <_> 0 -1 1636 6.9395996630191803e-02 -2.5657799839973450e-01 4.7652098536491394e-01 <_> 0 -1 1637 3.1208999454975128e-02 1.4154000580310822e-01 -3.4942001104354858e-01 <_> 0 -1 1638 -4.9727000296115875e-02 -1.1675560474395752e+00 -4.0757998824119568e-02 <_> 0 -1 1639 -2.0301999524235725e-02 -3.9486399292945862e-01 1.5814900398254395e-01 <_> 0 -1 1640 -1.5367000363767147e-02 4.9300000071525574e-01 -2.0092099905014038e-01 <_> 0 -1 1641 -5.0735000520944595e-02 1.8736059665679932e+00 8.6730003356933594e-02 <_> 0 -1 1642 -2.0726000890135765e-02 -8.8938397169113159e-01 -7.3199998587369919e-03 <_> 0 -1 1643 -3.0993999913334846e-02 -1.1664899587631226e+00 1.4274600148200989e-01 <_> 0 -1 1644 -4.4269999489188194e-03 -6.6815102100372314e-01 4.4120000675320625e-03 <_> 0 -1 1645 -4.5743998140096664e-02 -4.7955200076103210e-01 1.5121999382972717e-01 <_> 0 -1 1646 1.6698999330401421e-02 1.2048599869012833e-01 -4.5235899090766907e-01 <_> 0 -1 1647 3.2210000790655613e-03 -7.7615000307559967e-02 2.7846598625183105e-01 <_> 0 -1 1648 2.4434000253677368e-02 -1.9987100362777710e-01 6.7253702878952026e-01 <_> 0 -1 1649 -7.9677999019622803e-02 9.2222398519515991e-01 9.2557996511459351e-02 <_> 0 -1 1650 4.4530000537633896e-02 -2.6690500974655151e-01 3.3320501446723938e-01 <_> 0 -1 1651 -1.2528300285339355e-01 -5.4253101348876953e-01 1.3976299762725830e-01 <_> 0 -1 1652 1.7971999943256378e-02 1.8219999969005585e-02 -6.8048501014709473e-01 <_> 0 -1 1653 1.9184000790119171e-02 -1.2583999894559383e-02 5.4126697778701782e-01 <_> 0 -1 1654 4.0024001151323318e-02 -1.7638799548149109e-01 7.8810399770736694e-01 <_> 0 -1 1655 1.3558999635279179e-02 2.0737600326538086e-01 -4.7744300961494446e-01 <_> 0 -1 1656 1.6220999881625175e-02 2.3076999932527542e-02 -6.1182099580764771e-01 <_> 0 -1 1657 1.1229000054299831e-02 -1.7728000879287720e-02 4.1764199733734131e-01 <_> 0 -1 1658 3.9193000644445419e-02 -1.8948499858379364e-01 7.4019300937652588e-01 <_> 0 -1 1659 -9.5539996400475502e-03 4.0947100520133972e-01 -1.3508899509906769e-01 <_> 0 -1 1660 2.7878999710083008e-02 -2.0350700616836548e-01 6.1625397205352783e-01 <_> 0 -1 1661 -2.3600999265909195e-02 -1.6967060565948486e+00 1.4633199572563171e-01 <_> 0 -1 1662 2.6930000633001328e-02 -3.0401999130845070e-02 -1.0909470319747925e+00 <_> 0 -1 1663 2.8999999631196260e-04 -2.0076000690460205e-01 2.2314099967479706e-01 <_> 0 -1 1664 -4.1124999523162842e-02 -4.5242199301719666e-01 5.7392001152038574e-02 <_> 0 -1 1665 6.6789998672902584e-03 2.3824900388717651e-01 -2.1262100338935852e-01 <_> 0 -1 1666 4.7864999622106552e-02 -1.8194800615310669e-01 6.1918401718139648e-01 <_> 0 -1 1667 -3.1679999083280563e-03 -2.7393200993537903e-01 2.5017300248146057e-01 <_> 0 -1 1668 -8.6230002343654633e-03 -4.6280300617218018e-01 4.2397998273372650e-02 <_> 0 -1 1669 -7.4350000359117985e-03 4.1796800494194031e-01 -1.7079999670386314e-03 <_> 0 -1 1670 -1.8769999733194709e-03 1.4602300524711609e-01 -3.3721101284027100e-01 <_> 0 -1 1671 -8.6226001381874084e-02 7.5143402814865112e-01 1.0711999610066414e-02 <_> 0 -1 1672 4.6833999454975128e-02 -1.9119599461555481e-01 4.8414900898933411e-01 <_> 0 -1 1673 -9.2000002041459084e-05 3.5220399498939514e-01 -1.7333300411701202e-01 <_> 0 -1 1674 -1.6343999654054642e-02 -6.4397698640823364e-01 9.0680001303553581e-03 <_> 0 -1 1675 4.5703999698162079e-02 1.8216000869870186e-02 3.1970798969268799e-01 <_> 0 -1 1676 -2.7382999658584595e-02 1.0564049482345581e+00 -1.7276400327682495e-01 <_> 0 -1 1677 -2.7602000162005424e-02 2.9715499281883240e-01 -9.4600003212690353e-03 <_> 0 -1 1678 7.6939999125897884e-03 -2.1660299599170685e-01 4.7385200858116150e-01 <_> 0 -1 1679 -7.0500001311302185e-04 2.4048799276351929e-01 -2.6776000857353210e-01 <_> 0 -1 1680 1.1054199934005737e-01 -3.3539000898599625e-02 -1.0233880281448364e+00 <_> 0 -1 1681 6.8765997886657715e-02 -4.3239998631179333e-03 5.7153397798538208e-01 <_> 0 -1 1682 1.7999999690800905e-03 7.7574998140335083e-02 -4.2092698812484741e-01 <_> 0 -1 1683 1.9232000410556793e-01 8.2021996378898621e-02 2.8810169696807861e+00 <_> 0 -1 1684 1.5742099285125732e-01 -1.3708199560642242e-01 2.0890059471130371e+00 <_> 0 -1 1685 -4.9387000501155853e-02 -1.8610910177230835e+00 1.4332099258899689e-01 <_> 0 -1 1686 5.1929000765085220e-02 -1.8737000226974487e-01 5.4231601953506470e-01 <_> 0 -1 1687 4.9965001642704010e-02 1.4175300300121307e-01 -1.5625779628753662e+00 <_> 0 -1 1688 -4.2633000761270523e-02 1.6059479713439941e+00 -1.4712899923324585e-01 <_> 0 -1 1689 -3.7553999572992325e-02 -8.0974900722503662e-01 1.3256999850273132e-01 <_> 0 -1 1690 -3.7174999713897705e-02 -1.3945020437240601e+00 -5.7055000215768814e-02 <_> 0 -1 1691 1.3945999555289745e-02 3.3427000045776367e-02 5.7474797964096069e-01 <_> 0 -1 1692 -4.4800000614486635e-04 -5.5327498912811279e-01 2.1952999755740166e-02 <_> 0 -1 1693 3.1993001699447632e-02 2.0340999588370323e-02 3.7459200620651245e-01 <_> 0 -1 1694 -4.2799999937415123e-03 4.4428700208663940e-01 -2.2999699413776398e-01 <_> 0 -1 1695 9.8550003021955490e-03 1.8315799534320831e-01 -4.0964999794960022e-01 <_> 0 -1 1696 9.3356996774673462e-02 -6.3661001622676849e-02 -1.6929290294647217e+00 <_> 0 -1 1697 1.7209999263286591e-02 2.0153899490833282e-01 -4.6061098575592041e-01 <_> 0 -1 1698 8.4319999441504478e-03 -3.2003998756408691e-01 1.5312199294567108e-01 <_> 0 -1 1699 -1.4054999686777592e-02 8.6882400512695312e-01 3.2575000077486038e-02 <_> 0 -1 1700 -7.7180000953376293e-03 6.3686698675155640e-01 -1.8425500392913818e-01 <_> 0 -1 1701 2.8005000203847885e-02 1.7357499897480011e-01 -4.7883599996566772e-01 <_> 0 -1 1702 -1.8884999677538872e-02 2.4101600050926208e-01 -2.6547598838806152e-01 <_> 0 -1 1703 -1.8585000187158585e-02 5.4232501983642578e-01 5.3633000701665878e-02 <_> 0 -1 1704 -3.6437001079320908e-02 2.3908898830413818e+00 -1.3634699583053589e-01 <_> 0 -1 1705 3.2455001026391983e-02 1.5910699963569641e-01 -6.7581498622894287e-01 <_> 0 -1 1706 5.9781998395919800e-02 -2.3479999508708715e-03 -7.3053699731826782e-01 <_> 0 -1 1707 9.8209995776414871e-03 -1.1444099992513657e-01 3.0570301413536072e-01 <_> 0 -1 1708 -3.5163998603820801e-02 -1.0511469841003418e+00 -3.3103000372648239e-02 <_> 0 -1 1709 2.7429999317973852e-03 -2.0135399699211121e-01 3.2754099369049072e-01 <_> 0 -1 1710 8.1059997901320457e-03 -2.1383500099182129e-01 4.3362098932266235e-01 <_> 0 -1 1711 8.8942997157573700e-02 1.0940899699926376e-01 -4.7609338760375977e+00 <_> 0 -1 1712 -3.0054999515414238e-02 -1.7169300317764282e+00 -6.0919001698493958e-02 <_> 0 -1 1713 -2.1734999492764473e-02 6.4778900146484375e-01 -3.2830998301506042e-02 <_> 0 -1 1714 3.7648998200893402e-02 -1.0060000233352184e-02 -7.6569098234176636e-01 <_> 0 -1 1715 2.7189999818801880e-03 1.9888900220394135e-01 -8.2479000091552734e-02 <_> 0 -1 1716 -1.0548000223934650e-02 -8.6613601446151733e-01 -2.5986000895500183e-02 <_> 0 -1 1717 1.2966300547122955e-01 1.3911999762058258e-01 -2.2271950244903564e+00 <_> 0 -1 1718 -1.7676999792456627e-02 3.3967700600624084e-01 -2.3989599943161011e-01 <_> 0 -1 1719 -7.7051997184753418e-02 -2.5017969608306885e+00 1.2841999530792236e-01 <_> 0 -1 1720 -1.9230000674724579e-02 5.0641202926635742e-01 -1.9751599431037903e-01 <_> 0 -1 1721 -5.1222998648881912e-02 -2.9333369731903076e+00 1.3858500123023987e-01 <_> 0 -1 1722 2.0830000285059214e-03 -6.0043597221374512e-01 2.9718000441789627e-02 <_> 0 -1 1723 2.5418000295758247e-02 3.3915799856185913e-01 -1.4392000436782837e-01 <_> 0 -1 1724 -2.3905999958515167e-02 -1.1082680225372314e+00 -4.7377001494169235e-02 <_> 0 -1 1725 -6.3740001060068607e-03 4.4533699750900269e-01 -6.7052997648715973e-02 <_> 0 -1 1726 -3.7698999047279358e-02 -1.0406579971313477e+00 -4.1790001094341278e-02 <_> 0 -1 1727 2.1655100584030151e-01 3.3863000571727753e-02 8.2017302513122559e-01 <_> 0 -1 1728 -1.3400999829173088e-02 5.2903497219085693e-01 -1.9133000075817108e-01 <_> 196 -3.2103500366210938e+00 <_> 0 -1 1729 7.1268998086452484e-02 -5.3631198406219482e-01 6.0715299844741821e-01 <_> 0 -1 1730 5.6111000478267670e-02 -5.0141602754592896e-01 4.3976101279258728e-01 <_> 0 -1 1731 4.0463998913764954e-02 -3.2922199368476868e-01 5.4834699630737305e-01 <_> 0 -1 1732 6.3155002892017365e-02 -3.1701698899269104e-01 4.6152999997138977e-01 <_> 0 -1 1733 1.0320999659597874e-02 1.0694999992847443e-01 -9.8243898153305054e-01 <_> 0 -1 1734 6.2606997787952423e-02 -1.4329700171947479e-01 7.1095001697540283e-01 <_> 0 -1 1735 -3.9416000247001648e-02 9.4380199909210205e-01 -2.1572099626064301e-01 <_> 0 -1 1736 -5.3960001096129417e-03 -5.4611998796463013e-01 2.5303798913955688e-01 <_> 0 -1 1737 1.0773199796676636e-01 1.2496000155806541e-02 -1.0809199810028076e+00 <_> 0 -1 1738 1.6982000321149826e-02 -3.1536400318145752e-01 5.1239997148513794e-01 <_> 0 -1 1739 3.1216999515891075e-02 -4.5199999585747719e-03 -1.2443480491638184e+00 <_> 0 -1 1740 -2.3106999695301056e-02 -7.6492899656295776e-01 2.0640599727630615e-01 <_> 0 -1 1741 -1.1203999631106853e-02 2.4092699587345123e-01 -3.5142099857330322e-01 <_> 0 -1 1742 -4.7479998320341110e-03 -9.7007997334003448e-02 2.0638099312782288e-01 <_> 0 -1 1743 -1.7358999699354172e-02 -7.9020297527313232e-01 2.1852999925613403e-02 <_> 0 -1 1744 1.8851999193429947e-02 -1.0394600033760071e-01 5.4844200611114502e-01 <_> 0 -1 1745 7.2249998338520527e-03 -4.0409401059150696e-01 2.6763799786567688e-01 <_> 0 -1 1746 1.8915999680757523e-02 2.0508000254631042e-01 -1.0206340551376343e+00 <_> 0 -1 1747 3.1156999990344048e-02 1.2400000123307109e-03 -8.7293499708175659e-01 <_> 0 -1 1748 2.0951999351382256e-02 -5.5559999309480190e-03 8.0356198549270630e-01 <_> 0 -1 1749 1.1291000060737133e-02 -3.6478400230407715e-01 2.2767899930477142e-01 <_> 0 -1 1750 -5.7011000812053680e-02 -1.4295619726181030e+00 1.4322000741958618e-01 <_> 0 -1 1751 7.2194002568721771e-02 -4.1850000619888306e-02 -1.9111829996109009e+00 <_> 0 -1 1752 -1.9874000921845436e-02 2.6425498723983765e-01 -3.2617700099945068e-01 <_> 0 -1 1753 -1.6692999750375748e-02 -8.3907800912857056e-01 4.0799999260343611e-04 <_> 0 -1 1754 -3.9834998548030853e-02 -4.8858499526977539e-01 1.6436100006103516e-01 <_> 0 -1 1755 2.7009999379515648e-02 -1.8862499296665192e-01 8.3419400453567505e-01 <_> 0 -1 1756 -3.9420002140104771e-03 2.3231500387191772e-01 -7.2360001504421234e-02 <_> 0 -1 1757 2.2833000868558884e-02 -3.5884000360965729e-02 -1.1549400091171265e+00 <_> 0 -1 1758 -6.8888001143932343e-02 -1.7837309837341309e+00 1.5159000456333160e-01 <_> 0 -1 1759 4.3097000569105148e-02 -2.1608099341392517e-01 5.0624102354049683e-01 <_> 0 -1 1760 8.6239995434880257e-03 -1.7795599997043610e-01 2.8957900404930115e-01 <_> 0 -1 1761 1.4561000280082226e-02 -1.1408000253140926e-02 -8.9402002096176147e-01 <_> 0 -1 1762 -1.1501000262796879e-02 3.0171999335289001e-01 -4.3659001588821411e-02 <_> 0 -1 1763 -1.0971499979496002e-01 -9.5147097110748291e-01 -1.9973000511527061e-02 <_> 0 -1 1764 4.5228000730276108e-02 3.3110998570919037e-02 9.6619802713394165e-01 <_> 0 -1 1765 -2.7047999203205109e-02 9.7963601350784302e-01 -1.7261900007724762e-01 <_> 0 -1 1766 1.8030999228358269e-02 -2.0801000297069550e-02 2.7385899424552917e-01 <_> 0 -1 1767 5.0524998456239700e-02 -5.6802999228239059e-02 -1.7775089740753174e+00 <_> 0 -1 1768 -2.9923999682068825e-02 6.5329200029373169e-01 -2.3537000641226768e-02 <_> 0 -1 1769 3.8058001548051834e-02 2.6317000389099121e-02 -7.0665699243545532e-01 <_> 0 -1 1770 1.8563899397850037e-01 -5.6039998307824135e-03 3.2873699069023132e-01 <_> 0 -1 1771 -4.0670000016689301e-03 3.4204798936843872e-01 -3.0171599984169006e-01 <_> 0 -1 1772 1.0108999907970428e-02 -7.3600001633167267e-03 5.7981598377227783e-01 <_> 0 -1 1773 -1.1567000299692154e-02 -5.2722197771072388e-01 4.6447999775409698e-02 <_> 0 -1 1774 -6.5649999305605888e-03 -5.8529102802276611e-01 1.9101899862289429e-01 <_> 0 -1 1775 1.0582000017166138e-02 2.1073000505566597e-02 -6.8892598152160645e-01 <_> 0 -1 1776 -2.0304000005125999e-02 -3.6400699615478516e-01 1.5338799357414246e-01 <_> 0 -1 1777 2.3529999889433384e-03 3.6164000630378723e-02 -5.9825098514556885e-01 <_> 0 -1 1778 -1.4690000098198652e-03 -1.4707699418067932e-01 3.7507998943328857e-01 <_> 0 -1 1779 8.6449999362230301e-03 -2.1708500385284424e-01 5.1936799287796021e-01 <_> 0 -1 1780 -2.4326000362634659e-02 -1.0846769809722900e+00 1.4084799587726593e-01 <_> 0 -1 1781 7.4418999254703522e-02 -1.5513800084590912e-01 1.1822769641876221e+00 <_> 0 -1 1782 1.7077999189496040e-02 4.4231001287698746e-02 9.1561102867126465e-01 <_> 0 -1 1783 -2.4577999487519264e-02 -1.5504100322723389e+00 -5.4745998233556747e-02 <_> 0 -1 1784 3.0205000191926956e-02 1.6662800312042236e-01 -1.0001239776611328e+00 <_> 0 -1 1785 1.2136000208556652e-02 -7.7079099416732788e-01 -4.8639997839927673e-03 <_> 0 -1 1786 8.6717002093791962e-02 1.1061699688434601e-01 -1.6857999563217163e+00 <_> 0 -1 1787 -4.2309001088142395e-02 1.1075930595397949e+00 -1.5438599884510040e-01 <_> 0 -1 1788 -2.6420000940561295e-03 2.7451899647712708e-01 -1.8456199765205383e-01 <_> 0 -1 1789 -5.6662000715732574e-02 -8.0625599622726440e-01 -1.6928000375628471e-02 <_> 0 -1 1790 2.3475000634789467e-02 1.4187699556350708e-01 -2.5500899553298950e-01 <_> 0 -1 1791 -2.0803000777959824e-02 1.9826300442218781e-01 -3.1171199679374695e-01 <_> 0 -1 1792 7.2599998675286770e-03 -5.0590999424457550e-02 4.1923800110816956e-01 <_> 0 -1 1793 3.4160000085830688e-01 -1.6674900054931641e-01 9.2748600244522095e-01 <_> 0 -1 1794 6.2029999680817127e-03 -1.2625899910926819e-01 4.0445300936698914e-01 <_> 0 -1 1795 3.2692000269889832e-02 -3.2634999603033066e-02 -9.8939800262451172e-01 <_> 0 -1 1796 2.1100000594742596e-04 -6.4534001052379608e-02 2.5473698973655701e-01 <_> 0 -1 1797 7.2100001852959394e-04 -3.6618599295616150e-01 1.1973100155591965e-01 <_> 0 -1 1798 5.4490998387336731e-02 1.2073499709367752e-01 -1.0291390419006348e+00 <_> 0 -1 1799 -1.0141000151634216e-02 -5.2177202701568604e-01 3.3734999597072601e-02 <_> 0 -1 1800 -1.8815999850630760e-02 6.5181797742843628e-01 1.3399999588727951e-03 <_> 0 -1 1801 -5.3480002097785473e-03 1.7370699346065521e-01 -3.4132000803947449e-01 <_> 0 -1 1802 -1.0847000405192375e-02 -1.9699899852275848e-01 1.5045499801635742e-01 <_> 0 -1 1803 -4.9926001578569412e-02 -5.0888502597808838e-01 3.0762000009417534e-02 <_> 0 -1 1804 1.2160000391304493e-02 -6.9251999258995056e-02 1.8745499849319458e-01 <_> 0 -1 1805 -2.2189998999238014e-03 -4.0849098563194275e-01 7.9954996705055237e-02 <_> 0 -1 1806 3.1580000650137663e-03 -2.1124599874019623e-01 2.2366400063037872e-01 <_> 0 -1 1807 4.1439998894929886e-03 -4.9900299310684204e-01 6.2917001545429230e-02 <_> 0 -1 1808 -7.3730000294744968e-03 -2.0553299784660339e-01 2.2096699476242065e-01 <_> 0 -1 1809 5.1812000572681427e-02 1.8096800148487091e-01 -4.3495801091194153e-01 <_> 0 -1 1810 1.8340000882744789e-02 1.5200000256299973e-02 3.7991699576377869e-01 <_> 0 -1 1811 1.7490799725055695e-01 -2.0920799672603607e-01 4.0013000369071960e-01 <_> 0 -1 1812 5.3993999958038330e-02 2.4751600623130798e-01 -2.6712900400161743e-01 <_> 0 -1 1813 -3.2033199071884155e-01 -1.9094380140304565e+00 -6.6960997879505157e-02 <_> 0 -1 1814 -2.7060000225901604e-02 -7.1371299028396606e-01 1.5904599428176880e-01 <_> 0 -1 1815 7.7463999390602112e-02 -1.6970199346542358e-01 7.7552998065948486e-01 <_> 0 -1 1816 2.3771999403834343e-02 1.9021899998188019e-01 -6.0162097215652466e-01 <_> 0 -1 1817 1.1501000262796879e-02 7.7039999887347221e-03 -6.1730301380157471e-01 <_> 0 -1 1818 3.2616000622510910e-02 1.7159199714660645e-01 -7.0978200435638428e-01 <_> 0 -1 1819 -4.4383000582456589e-02 -2.2606229782104492e+00 -7.3276996612548828e-02 <_> 0 -1 1820 -5.8476001024246216e-02 2.4087750911712646e+00 8.3091996610164642e-02 <_> 0 -1 1821 1.9303999841213226e-02 -2.7082300186157227e-01 2.7369999885559082e-01 <_> 0 -1 1822 -4.4705998152494431e-02 3.1355598568916321e-01 -6.2492001801729202e-02 <_> 0 -1 1823 -6.0334999114274979e-02 -1.4515119791030884e+00 -5.8761000633239746e-02 <_> 0 -1 1824 1.1667000129818916e-02 -1.8084999173879623e-02 5.0479698181152344e-01 <_> 0 -1 1825 2.8009999543428421e-02 -2.3302899301052094e-01 3.0708700418472290e-01 <_> 0 -1 1826 6.5397001802921295e-02 1.4135900139808655e-01 -5.0010901689529419e-01 <_> 0 -1 1827 9.6239997074007988e-03 -2.2054600715637207e-01 3.9191201329231262e-01 <_> 0 -1 1828 2.5510000996291637e-03 -1.1381500214338303e-01 2.0032300055027008e-01 <_> 0 -1 1829 3.1847000122070312e-02 2.5476999580860138e-02 -5.3326398134231567e-01 <_> 0 -1 1830 3.3055000007152557e-02 1.7807699739933014e-01 -6.2793898582458496e-01 <_> 0 -1 1831 4.7600999474525452e-02 -1.4747899770736694e-01 1.4204180240631104e+00 <_> 0 -1 1832 -1.9571999087929726e-02 -5.2693498134613037e-01 1.5838600695133209e-01 <_> 0 -1 1833 -5.4730001837015152e-02 8.8231599330902100e-01 -1.6627800464630127e-01 <_> 0 -1 1834 -2.2686000913381577e-02 -4.8386898636817932e-01 1.5000100433826447e-01 <_> 0 -1 1835 1.0713200271129608e-01 -2.1336199343204498e-01 4.2333900928497314e-01 <_> 0 -1 1836 -3.6380000412464142e-02 -7.4198000133037567e-02 1.4589400589466095e-01 <_> 0 -1 1837 1.3935999944806099e-02 -2.4911600351333618e-01 2.6771199703216553e-01 <_> 0 -1 1838 2.0991999655961990e-02 8.7959999218583107e-03 4.3064999580383301e-01 <_> 0 -1 1839 4.9118999391794205e-02 -1.7591999471187592e-01 6.9282901287078857e-01 <_> 0 -1 1840 3.6315999925136566e-02 1.3145299255847931e-01 -3.3597299456596375e-01 <_> 0 -1 1841 4.1228000074625015e-02 -4.5692000538110733e-02 -1.3515930175781250e+00 <_> 0 -1 1842 1.5672000125050545e-02 1.7544099688529968e-01 -6.0550000518560410e-02 <_> 0 -1 1843 -1.6286000609397888e-02 -1.1308189630508423e+00 -3.9533000439405441e-02 <_> 0 -1 1844 -3.0229999683797359e-03 -2.2454300522804260e-01 2.3628099262714386e-01 <_> 0 -1 1845 -1.3786299526691437e-01 4.5376899838447571e-01 -2.1098700165748596e-01 <_> 0 -1 1846 -9.6760001033544540e-03 -1.5105099976062775e-01 2.0781700313091278e-01 <_> 0 -1 1847 -2.4839999154210091e-02 -6.8350297212600708e-01 -8.0040004104375839e-03 <_> 0 -1 1848 -1.3964399695396423e-01 6.5011298656463623e-01 4.6544000506401062e-02 <_> 0 -1 1849 -8.2153998315334320e-02 4.4887199997901917e-01 -2.3591999709606171e-01 <_> 0 -1 1850 3.8449999410659075e-03 -8.8173002004623413e-02 2.7346798777580261e-01 <_> 0 -1 1851 -6.6579999402165413e-03 -4.6866598725318909e-01 7.7001996338367462e-02 <_> 0 -1 1852 -1.5898000448942184e-02 2.9268398880958557e-01 -2.1941000595688820e-02 <_> 0 -1 1853 -5.0946000963449478e-02 -1.2093789577484131e+00 -4.2109999805688858e-02 <_> 0 -1 1854 1.6837999224662781e-02 -4.5595999807119370e-02 5.0180697441101074e-01 <_> 0 -1 1855 1.5918999910354614e-02 -2.6904299855232239e-01 2.6516300439834595e-01 <_> 0 -1 1856 3.6309999413788319e-03 -1.3046100735664368e-01 3.1807100772857666e-01 <_> 0 -1 1857 -8.6144998669624329e-02 1.9443659782409668e+00 -1.3978299498558044e-01 <_> 0 -1 1858 3.3140998333692551e-02 1.5266799926757812e-01 -3.0866000801324844e-02 <_> 0 -1 1859 -3.9679999463260174e-03 -7.1202301979064941e-01 -1.3844000175595284e-02 <_> 0 -1 1860 -2.4008000269532204e-02 9.2007797956466675e-01 4.6723999083042145e-02 <_> 0 -1 1861 8.7320003658533096e-03 -2.2567300498485565e-01 3.1931799650192261e-01 <_> 0 -1 1862 -2.7786999940872192e-02 -7.2337102890014648e-01 1.7018599808216095e-01 <_> 0 -1 1863 -1.9455300271511078e-01 1.2461860179901123e+00 -1.4736199378967285e-01 <_> 0 -1 1864 -1.0869699716567993e-01 -1.4465179443359375e+00 1.2145300209522247e-01 <_> 0 -1 1865 -1.9494999200105667e-02 -7.8153097629547119e-01 -2.3732999339699745e-02 <_> 0 -1 1866 3.0650000553578138e-03 -8.5471397638320923e-01 1.6686999797821045e-01 <_> 0 -1 1867 5.9193998575210571e-02 -1.4853699505329132e-01 1.1273469924926758e+00 <_> 0 -1 1868 -5.4207999259233475e-02 5.4726999998092651e-01 3.5523999482393265e-02 <_> 0 -1 1869 -3.9324998855590820e-02 3.6642599105834961e-01 -2.0543999969959259e-01 <_> 0 -1 1870 8.2278996706008911e-02 -3.5007998347282410e-02 5.3994202613830566e-01 <_> 0 -1 1871 -7.4479999020695686e-03 -6.1537498235702515e-01 -3.5319998860359192e-03 <_> 0 -1 1872 7.3770000599324703e-03 -6.5591000020503998e-02 4.1961398720741272e-01 <_> 0 -1 1873 7.0779998786747456e-03 -3.4129500389099121e-01 1.2536799907684326e-01 <_> 0 -1 1874 -1.5581999905407429e-02 -3.0240398645401001e-01 2.1511000394821167e-01 <_> 0 -1 1875 -2.7399999089539051e-03 7.6553001999855042e-02 -4.1060501337051392e-01 <_> 0 -1 1876 -7.0600003004074097e-02 -9.7356200218200684e-01 1.1241800338029861e-01 <_> 0 -1 1877 -1.1706000193953514e-02 1.8560700118541718e-01 -2.9755198955535889e-01 <_> 0 -1 1878 7.1499997284263372e-04 -5.9650000184774399e-02 2.4824699759483337e-01 <_> 0 -1 1879 -3.6866001784801483e-02 3.2751700282096863e-01 -2.3059600591659546e-01 <_> 0 -1 1880 -3.2526999711990356e-02 -2.9320299625396729e-01 1.5427699685096741e-01 <_> 0 -1 1881 -7.4813999235630035e-02 -1.2143570184707642e+00 -5.2244000136852264e-02 <_> 0 -1 1882 4.1469998657703400e-02 1.3062499463558197e-01 -2.3274369239807129e+00 <_> 0 -1 1883 -2.8880000114440918e-02 -6.6074597835540771e-01 -9.0960003435611725e-03 <_> 0 -1 1884 4.6381998807191849e-02 1.6630199551582336e-01 -6.6949498653411865e-01 <_> 0 -1 1885 2.5424998998641968e-01 -5.4641999304294586e-02 -1.2676080465316772e+00 <_> 0 -1 1886 2.4000001139938831e-03 2.0276799798011780e-01 1.4667999930679798e-02 <_> 0 -1 1887 -8.2805998623371124e-02 -7.8713601827621460e-01 -2.4468999356031418e-02 <_> 0 -1 1888 -1.1438000015914440e-02 2.8623399138450623e-01 -3.0894000083208084e-02 <_> 0 -1 1889 -1.2913399934768677e-01 1.7292929887771606e+00 -1.4293900132179260e-01 <_> 0 -1 1890 3.8552999496459961e-02 1.9232999533414841e-02 3.7732601165771484e-01 <_> 0 -1 1891 1.0191400349140167e-01 -7.4533998966217041e-02 -3.3868899345397949e+00 <_> 0 -1 1892 -1.9068000838160515e-02 3.1814101338386536e-01 1.9261000677943230e-02 <_> 0 -1 1893 -6.0775000602006912e-02 7.6936298608779907e-01 -1.7644000053405762e-01 <_> 0 -1 1894 2.4679999798536301e-02 1.8396499752998352e-01 -3.0868801474571228e-01 <_> 0 -1 1895 2.6759000495076180e-02 -2.3454900085926056e-01 3.3056598901748657e-01 <_> 0 -1 1896 1.4969999901950359e-02 1.7213599383831024e-01 -1.8248899281024933e-01 <_> 0 -1 1897 2.6142999529838562e-02 -4.6463999897241592e-02 -1.1318379640579224e+00 <_> 0 -1 1898 -3.7512000650167465e-02 8.0404001474380493e-01 6.9660000503063202e-02 <_> 0 -1 1899 -5.3229997865855694e-03 -8.1884402036666870e-01 -1.8224999308586121e-02 <_> 0 -1 1900 1.7813000828027725e-02 1.4957800507545471e-01 -1.8667200207710266e-01 <_> 0 -1 1901 -3.4010000526905060e-02 -7.2852301597595215e-01 -1.6615999862551689e-02 <_> 0 -1 1902 -1.5953000634908676e-02 5.6944000720977783e-01 1.3832000084221363e-02 <_> 0 -1 1903 1.9743999466300011e-02 4.0525000542402267e-02 -4.1773399710655212e-01 <_> 0 -1 1904 -1.0374800115823746e-01 -1.9825149774551392e+00 1.1960200220346451e-01 <_> 0 -1 1905 -1.9285000860691071e-02 5.0230598449707031e-01 -1.9745899736881256e-01 <_> 0 -1 1906 -1.2780000455677509e-02 4.0195000171661377e-01 -2.6957999914884567e-02 <_> 0 -1 1907 -1.6352999955415726e-02 -7.6608800888061523e-01 -2.4209000170230865e-02 <_> 0 -1 1908 -1.2763699889183044e-01 8.6578500270843506e-01 6.4205996692180634e-02 <_> 0 -1 1909 1.9068999215960503e-02 -5.5929797887802124e-01 -1.6880000475794077e-03 <_> 0 -1 1910 3.2480999827384949e-02 4.0722001343965530e-02 4.8925098776817322e-01 <_> 0 -1 1911 9.4849998131394386e-03 -1.9231900572776794e-01 5.1139700412750244e-01 <_> 0 -1 1912 5.0470000132918358e-03 1.8706800043582916e-01 -1.6113600134849548e-01 <_> 0 -1 1913 4.1267998516559601e-02 -4.8817999660968781e-02 -1.1326299905776978e+00 <_> 0 -1 1914 -7.6358996331691742e-02 1.4169390201568604e+00 8.7319999933242798e-02 <_> 0 -1 1915 -7.2834998369216919e-02 1.3189860582351685e+00 -1.4819100499153137e-01 <_> 0 -1 1916 5.9576999396085739e-02 4.8376999795436859e-02 8.5611802339553833e-01 <_> 0 -1 1917 2.0263999700546265e-02 -2.1044099330902100e-01 3.3858999609947205e-01 <_> 0 -1 1918 -8.0301001667976379e-02 -1.2464400529861450e+00 1.1857099831104279e-01 <_> 0 -1 1919 -1.7835000529885292e-02 2.5782299041748047e-01 -2.4564799666404724e-01 <_> 0 -1 1920 1.1431000195443630e-02 2.2949799895286560e-01 -2.9497599601745605e-01 <_> 0 -1 1921 -2.5541000068187714e-02 -8.6252999305725098e-01 -7.0400000549852848e-04 <_> 0 -1 1922 -7.6899997657164931e-04 3.1511399149894714e-01 -1.4349000155925751e-01 <_> 0 -1 1923 -1.4453999698162079e-02 2.5148499011993408e-01 -2.8232899308204651e-01 <_> 0 -1 1924 8.6730001494288445e-03 2.6601400971412659e-01 -2.8190800547599792e-01 <_> 197 -3.2772979736328125e+00 <_> 0 -1 1925 5.4708998650312424e-02 -5.4144299030303955e-01 6.1043000221252441e-01 <_> 0 -1 1926 -1.0838799923658371e-01 7.1739900112152100e-01 -4.1196098923683167e-01 <_> 0 -1 1927 2.2996999323368073e-02 -5.8269798755645752e-01 2.9645600914955139e-01 <_> 0 -1 1928 2.7540000155568123e-03 -7.4243897199630737e-01 1.4183300733566284e-01 <_> 0 -1 1929 -2.1520000882446766e-03 1.7879900336265564e-01 -6.8548601865768433e-01 <_> 0 -1 1930 -2.2559000179171562e-02 -1.0775549411773682e+00 1.2388999760150909e-01 <_> 0 -1 1931 8.3025000989437103e-02 2.4500999599695206e-02 -1.0251879692077637e+00 <_> 0 -1 1932 -6.6740000620484352e-03 -4.5283100008964539e-01 2.1230199933052063e-01 <_> 0 -1 1933 7.6485000550746918e-02 -2.6972699165344238e-01 4.8580199480056763e-01 <_> 0 -1 1934 5.4910001344978809e-03 -4.8871201276779175e-01 3.1616398692131042e-01 <_> 0 -1 1935 -1.0414999909698963e-02 4.1512900590896606e-01 -3.0044800043106079e-01 <_> 0 -1 1936 2.7607999742031097e-02 1.6203799843788147e-01 -9.9868500232696533e-01 <_> 0 -1 1937 -2.3272000253200531e-02 -1.1024399995803833e+00 2.1124999970197678e-02 <_> 0 -1 1938 -5.5619999766349792e-02 6.5033102035522461e-01 -2.7938000857830048e-02 <_> 0 -1 1939 -4.0631998330354691e-02 4.2117300629615784e-01 -2.6763799786567688e-01 <_> 0 -1 1940 -7.3560001328587532e-03 3.5277798771858215e-01 -3.7854000926017761e-01 <_> 0 -1 1941 1.7007000744342804e-02 -2.9189500212669373e-01 4.1053798794746399e-01 <_> 0 -1 1942 -3.7034001201391220e-02 -1.3216309547424316e+00 1.2966500222682953e-01 <_> 0 -1 1943 -1.9633000716567039e-02 -8.7702298164367676e-01 1.0799999581649899e-03 <_> 0 -1 1944 -2.3546999320387840e-02 2.6106101274490356e-01 -2.1481400728225708e-01 <_> 0 -1 1945 -4.3352998793125153e-02 -9.9089699983596802e-01 -9.9560003727674484e-03 <_> 0 -1 1946 -2.2183999419212341e-02 6.3454401493072510e-01 -5.6547001004219055e-02 <_> 0 -1 1947 1.6530999913811684e-02 2.4664999917149544e-02 -7.3326802253723145e-01 <_> 0 -1 1948 -3.2744001597166061e-02 -5.6297200918197632e-01 1.6640299558639526e-01 <_> 0 -1 1949 7.1415998041629791e-02 -3.0000001424923539e-04 -9.3286401033401489e-01 <_> 0 -1 1950 8.0999999772757292e-04 -9.5380000770092010e-02 2.5184699892997742e-01 <_> 0 -1 1951 -8.4090000018477440e-03 -6.5496802330017090e-01 6.7300997674465179e-02 <_> 0 -1 1952 -1.7254000529646873e-02 -4.6492999792098999e-01 1.6070899367332458e-01 <_> 0 -1 1953 -1.8641000613570213e-02 -1.0594010353088379e+00 -1.9617000594735146e-02 <_> 0 -1 1954 -9.1979997232556343e-03 5.0716197490692139e-01 -1.5339200198650360e-01 <_> 0 -1 1955 1.8538000062108040e-02 -3.0498200654983521e-01 7.3506200313568115e-01 <_> 0 -1 1956 -5.0335001200437546e-02 -1.1140480041503906e+00 1.8000100553035736e-01 <_> 0 -1 1957 -2.3529000580310822e-02 -8.6907899379730225e-01 -1.2459999881684780e-02 <_> 0 -1 1958 -2.7100000530481339e-02 6.5942901372909546e-01 -3.5323999822139740e-02 <_> 0 -1 1959 6.5879998728632927e-03 -2.2953400015830994e-01 4.2425099015235901e-01 <_> 0 -1 1960 2.3360000923275948e-02 1.8356199562549591e-01 -9.8587298393249512e-01 <_> 0 -1 1961 1.2946999631822109e-02 -3.3147400617599487e-01 2.1323199570178986e-01 <_> 0 -1 1962 -6.6559999249875546e-03 -1.1951400339603424e-01 2.9752799868583679e-01 <_> 0 -1 1963 -2.2570999339222908e-02 3.8499400019645691e-01 -2.4434499442577362e-01 <_> 0 -1 1964 -6.3813999295234680e-02 -8.9383500814437866e-01 1.4217500388622284e-01 <_> 0 -1 1965 -4.9945000559091568e-02 5.3864401578903198e-01 -2.0485299825668335e-01 <_> 0 -1 1966 6.8319998681545258e-03 -5.6678999215364456e-02 3.9970999956130981e-01 <_> 0 -1 1967 -5.5835999548435211e-02 -1.5239470005035400e+00 -5.1183000206947327e-02 <_> 0 -1 1968 3.1957000494003296e-01 7.4574001133441925e-02 1.2447799444198608e+00 <_> 0 -1 1969 8.0955997109413147e-02 -1.9665500521659851e-01 5.9889698028564453e-01 <_> 0 -1 1970 -1.4911999925971031e-02 -6.4020597934722900e-01 1.5807600319385529e-01 <_> 0 -1 1971 4.6709001064300537e-02 8.5239000618457794e-02 -4.5487201213836670e-01 <_> 0 -1 1972 6.0539999976754189e-03 -4.3184000253677368e-01 2.2452600300312042e-01 <_> 0 -1 1973 -3.4375999122858047e-02 4.0202501416206360e-01 -2.3903599381446838e-01 <_> 0 -1 1974 -3.4924000501632690e-02 5.2870100736618042e-01 3.9709001779556274e-02 <_> 0 -1 1975 3.0030000489205122e-03 -3.8754299283027649e-01 1.4192600548267365e-01 <_> 0 -1 1976 -1.4132999815046787e-02 8.7528401613235474e-01 8.5507996380329132e-02 <_> 0 -1 1977 -6.7940000444650650e-03 -1.1649219989776611e+00 -3.3943001180887222e-02 <_> 0 -1 1978 -5.2886001765727997e-02 1.0930680036544800e+00 5.1187001168727875e-02 <_> 0 -1 1979 -2.1079999860376120e-03 1.3696199655532837e-01 -3.3849999308586121e-01 <_> 0 -1 1980 1.8353000283241272e-02 1.3661600649356842e-01 -4.0777799487113953e-01 <_> 0 -1 1981 1.2671999633312225e-02 -1.4936000108718872e-02 -8.1707501411437988e-01 <_> 0 -1 1982 1.2924999929964542e-02 1.7625099420547485e-01 -3.2491698861122131e-01 <_> 0 -1 1983 -1.7921000719070435e-02 -5.2745401859283447e-01 4.4443000108003616e-02 <_> 0 -1 1984 1.9160000374540687e-03 -1.0978599637746811e-01 2.2067500650882721e-01 <_> 0 -1 1985 -1.4697999693453312e-02 3.9067798852920532e-01 -2.2224999964237213e-01 <_> 0 -1 1986 -1.4972999691963196e-02 -2.5450900197029114e-01 1.7790000140666962e-01 <_> 0 -1 1987 1.4636999927461147e-02 -2.5125000625848770e-02 -8.7121301889419556e-01 <_> 0 -1 1988 -1.0974000208079815e-02 7.9082798957824707e-01 2.0121000707149506e-02 <_> 0 -1 1989 -9.1599998995661736e-03 -4.7906899452209473e-01 5.2232000976800919e-02 <_> 0 -1 1990 4.6179997734725475e-03 -1.7244599759578705e-01 3.4527799487113953e-01 <_> 0 -1 1991 2.3476999253034592e-02 3.7760001141577959e-03 -6.5333700180053711e-01 <_> 0 -1 1992 3.1766999512910843e-02 1.6364000737667084e-02 5.8723700046539307e-01 <_> 0 -1 1993 -1.8419999629259109e-02 1.9993899762630463e-01 -3.2056498527526855e-01 <_> 0 -1 1994 1.9543999806046486e-02 1.8450200557708740e-01 -2.3793600499629974e-01 <_> 0 -1 1995 4.1159498691558838e-01 -6.0382001101970673e-02 -1.6072119474411011e+00 <_> 0 -1 1996 -4.1595999151468277e-02 -3.2756200432777405e-01 1.5058000385761261e-01 <_> 0 -1 1997 -1.0335999540984631e-02 -6.2394398450851440e-01 1.3112000189721584e-02 <_> 0 -1 1998 1.2392999604344368e-02 -3.3114999532699585e-02 5.5579900741577148e-01 <_> 0 -1 1999 -8.7270000949501991e-03 1.9883200526237488e-01 -3.7635600566864014e-01 <_> 0 -1 2000 1.6295000910758972e-02 2.0373000204563141e-01 -4.2800799012184143e-01 <_> 0 -1 2001 -1.0483999736607075e-02 -5.6847000122070312e-01 4.4199001044034958e-02 <_> 0 -1 2002 -1.2431999668478966e-02 7.4641901254653931e-01 4.3678998947143555e-02 <_> 0 -1 2003 -5.0374999642372131e-02 8.5090100765228271e-01 -1.7773799598217010e-01 <_> 0 -1 2004 4.9548000097274780e-02 1.6784900426864624e-01 -2.9877498745918274e-01 <_> 0 -1 2005 -4.1085001081228256e-02 -1.3302919864654541e+00 -4.9182001501321793e-02 <_> 0 -1 2006 1.0069999843835831e-03 -6.0538999736309052e-02 1.8483200669288635e-01 <_> 0 -1 2007 -5.0142999738454819e-02 7.6447701454162598e-01 -1.8356999754905701e-01 <_> 0 -1 2008 -8.7879998609423637e-03 2.2655999660491943e-01 -6.3156999647617340e-02 <_> 0 -1 2009 -5.0170999020338058e-02 -1.5899070501327515e+00 -6.1255000531673431e-02 <_> 0 -1 2010 1.0216099768877029e-01 1.2071800231933594e-01 -1.4120110273361206e+00 <_> 0 -1 2011 -1.4372999779880047e-02 -1.3116970062255859e+00 -5.1936000585556030e-02 <_> 0 -1 2012 1.0281999595463276e-02 -2.1639999467879534e-03 4.4247201085090637e-01 <_> 0 -1 2013 -1.1814000084996223e-02 6.5378099679946899e-01 -1.8723699450492859e-01 <_> 0 -1 2014 7.2114996612071991e-02 7.1846999228000641e-02 8.1496298313140869e-01 <_> 0 -1 2015 -1.9001999869942665e-02 -6.7427200078964233e-01 -4.3200000072829425e-04 <_> 0 -1 2016 -4.6990001574158669e-03 3.3311501145362854e-01 5.5794000625610352e-02 <_> 0 -1 2017 -5.8157000690698624e-02 4.5572298765182495e-01 -2.0305100083351135e-01 <_> 0 -1 2018 1.1360000353306532e-03 -4.4686999171972275e-02 2.2681899368762970e-01 <_> 0 -1 2019 -4.9414999783039093e-02 2.6694598793983459e-01 -2.6116999983787537e-01 <_> 0 -1 2020 -1.1913800239562988e-01 -8.3017998933792114e-01 1.3248500227928162e-01 <_> 0 -1 2021 -1.8303999677300453e-02 -6.7499202489852905e-01 1.7092000693082809e-02 <_> 0 -1 2022 -7.9199997708201408e-03 -7.2287000715732574e-02 1.4425800740718842e-01 <_> 0 -1 2023 5.1925998181104660e-02 3.0921999365091324e-02 -5.5860602855682373e-01 <_> 0 -1 2024 6.6724002361297607e-02 1.3666400313377380e-01 -2.9411000013351440e-01 <_> 0 -1 2025 -1.3778000138700008e-02 -5.9443902969360352e-01 1.5300000086426735e-02 <_> 0 -1 2026 -1.7760999500751495e-02 4.0496501326560974e-01 -3.3559999428689480e-03 <_> 0 -1 2027 -4.2234998196363449e-02 -1.0897940397262573e+00 -4.0224999189376831e-02 <_> 0 -1 2028 -1.3524999842047691e-02 2.8921899199485779e-01 -2.5194799900054932e-01 <_> 0 -1 2029 -1.1106000281870365e-02 6.5312802791595459e-01 -1.8053700029850006e-01 <_> 0 -1 2030 -1.2284599989652634e-01 -1.9570649862289429e+00 1.4815400540828705e-01 <_> 0 -1 2031 4.7715999186038971e-02 -2.2875599563121796e-01 3.4233701229095459e-01 <_> 0 -1 2032 3.1817000359296799e-02 1.5976299345493317e-01 -1.0091969966888428e+00 <_> 0 -1 2033 4.2570000514388084e-03 -3.8881298899650574e-01 8.4210000932216644e-02 <_> 0 -1 2034 -6.1372999101877213e-02 1.7152810096740723e+00 5.9324998408555984e-02 <_> 0 -1 2035 -2.7030000928789377e-03 -3.8161700963973999e-01 8.5127003490924835e-02 <_> 0 -1 2036 -6.8544000387191772e-02 -3.0925889015197754e+00 1.1788000166416168e-01 <_> 0 -1 2037 1.0372500121593475e-01 -1.3769300282001495e-01 1.9009410142898560e+00 <_> 0 -1 2038 1.5799000859260559e-02 -6.2660001218318939e-02 2.5917699933052063e-01 <_> 0 -1 2039 -9.8040001466870308e-03 -5.6291598081588745e-01 4.3923001736402512e-02 <_> 0 -1 2040 -9.0229995548725128e-03 2.5287100672721863e-01 -4.1225999593734741e-02 <_> 0 -1 2041 -6.3754998147487640e-02 -2.6178569793701172e+00 -7.4005998671054840e-02 <_> 0 -1 2042 3.8954999297857285e-02 5.9032998979091644e-02 8.5945600271224976e-01 <_> 0 -1 2043 -3.9802998304367065e-02 9.3600499629974365e-01 -1.5639400482177734e-01 <_> 0 -1 2044 5.0301998853683472e-02 1.3725900650024414e-01 -2.5549728870391846e+00 <_> 0 -1 2045 4.6250000596046448e-02 -1.3964000158011913e-02 -7.1026200056076050e-01 <_> 0 -1 2046 6.2196001410484314e-02 5.9526000171899796e-02 1.6509100198745728e+00 <_> 0 -1 2047 -6.4776003360748291e-02 7.1368998289108276e-01 -1.7270000278949738e-01 <_> 0 -1 2048 2.7522999793291092e-02 1.4631600677967072e-01 -8.1428997218608856e-02 <_> 0 -1 2049 3.9900001138448715e-04 -3.7144500017166138e-01 1.0152699798345566e-01 <_> 0 -1 2050 -4.3299999088048935e-03 -2.3756299912929535e-01 2.6798400282859802e-01 <_> 0 -1 2051 4.7297000885009766e-02 -2.7682000771164894e-02 -8.4910297393798828e-01 <_> 0 -1 2052 1.2508999556303024e-02 1.8730199337005615e-01 -5.6001102924346924e-01 <_> 0 -1 2053 4.5899000018835068e-02 -1.5601199865341187e-01 9.7073000669479370e-01 <_> 0 -1 2054 1.9853399693965912e-01 1.4895500242710114e-01 -1.1015529632568359e+00 <_> 0 -1 2055 1.6674999147653580e-02 -1.6615299880504608e-01 8.2210999727249146e-01 <_> 0 -1 2056 1.9829999655485153e-03 -7.1249999105930328e-02 2.8810900449752808e-01 <_> 0 -1 2057 2.2447999566793442e-02 -2.0981000736355782e-02 -7.8416502475738525e-01 <_> 0 -1 2058 -1.3913000002503395e-02 -1.8165799975395203e-01 2.0491799712181091e-01 <_> 0 -1 2059 -7.7659999951720238e-03 -4.5595899224281311e-01 6.3576996326446533e-02 <_> 0 -1 2060 -1.3209000229835510e-02 2.6632300019264221e-01 -1.7795999348163605e-01 <_> 0 -1 2061 4.9052998423576355e-02 -1.5476800501346588e-01 1.1069979667663574e+00 <_> 0 -1 2062 2.0263999700546265e-02 6.8915002048015594e-02 6.9867497682571411e-01 <_> 0 -1 2063 -1.6828000545501709e-02 2.7607199549674988e-01 -2.5139200687408447e-01 <_> 0 -1 2064 -1.6939499974250793e-01 -3.0767529010772705e+00 1.1617500334978104e-01 <_> 0 -1 2065 -1.1336100101470947e-01 -1.4639229774475098e+00 -5.1447000354528427e-02 <_> 0 -1 2066 -7.7685996890068054e-02 8.8430202007293701e-01 4.3306998908519745e-02 <_> 0 -1 2067 -1.5568000264465809e-02 1.3672499358654022e-01 -3.4505501389503479e-01 <_> 0 -1 2068 -6.6018998622894287e-02 -1.0300110578536987e+00 1.1601399630308151e-01 <_> 0 -1 2069 8.3699999377131462e-03 7.6429001986980438e-02 -4.4002500176429749e-01 <_> 0 -1 2070 3.5402998328208923e-02 1.1979500204324722e-01 -7.2668302059173584e-01 <_> 0 -1 2071 -3.9051000028848648e-02 6.7375302314758301e-01 -1.8196000158786774e-01 <_> 0 -1 2072 -9.7899995744228363e-03 2.1264599263668060e-01 3.6756001412868500e-02 <_> 0 -1 2073 -2.3047000169754028e-02 4.4742199778556824e-01 -2.0986700057983398e-01 <_> 0 -1 2074 3.1169999856501818e-03 3.7544000893831253e-02 2.7808201313018799e-01 <_> 0 -1 2075 1.3136000372469425e-02 -1.9842399656772614e-01 5.4335701465606689e-01 <_> 0 -1 2076 1.4782000333070755e-02 1.3530600070953369e-01 -1.1153600364923477e-01 <_> 0 -1 2077 -6.0139000415802002e-02 8.4039300680160522e-01 -1.6711600124835968e-01 <_> 0 -1 2078 5.1998998969793320e-02 1.7372000217437744e-01 -7.8547602891921997e-01 <_> 0 -1 2079 2.4792000651359558e-02 -1.7739200592041016e-01 6.6752600669860840e-01 <_> 0 -1 2080 -1.2014999985694885e-02 -1.4263699948787689e-01 1.6070500016212463e-01 <_> 0 -1 2081 -9.8655998706817627e-02 1.0429769754409790e+00 -1.5770199894905090e-01 <_> 0 -1 2082 1.1758299916982651e-01 1.0955700278282166e-01 -4.4920377731323242e+00 <_> 0 -1 2083 -1.8922999501228333e-02 -7.8543400764465332e-01 1.2984000146389008e-02 <_> 0 -1 2084 -2.8390999883413315e-02 -6.0569900274276733e-01 1.2903499603271484e-01 <_> 0 -1 2085 1.3182999566197395e-02 -1.4415999874472618e-02 -7.3210501670837402e-01 <_> 0 -1 2086 -1.1653000116348267e-01 -2.0442469120025635e+00 1.4053100347518921e-01 <_> 0 -1 2087 -3.8880000356584787e-03 -4.1861599683761597e-01 7.8704997897148132e-02 <_> 0 -1 2088 3.1229000538587570e-02 2.4632999673485756e-02 4.1870400309562683e-01 <_> 0 -1 2089 2.5198999792337418e-02 -1.7557799816131592e-01 6.4710599184036255e-01 <_> 0 -1 2090 -2.8124000877141953e-02 -2.2005599737167358e-01 1.4121000468730927e-01 <_> 0 -1 2091 3.6499001085758209e-02 -6.8426996469497681e-02 -2.3410849571228027e+00 <_> 0 -1 2092 -7.2292998433113098e-02 1.2898750305175781e+00 8.4875002503395081e-02 <_> 0 -1 2093 -4.1671000421047211e-02 -1.1630970239639282e+00 -5.3752999752759933e-02 <_> 0 -1 2094 4.7703001648187637e-02 7.0101000368595123e-02 7.3676502704620361e-01 <_> 0 -1 2095 6.5793000161647797e-02 -1.7755299806594849e-01 6.9780498743057251e-01 <_> 0 -1 2096 1.3904999941587448e-02 2.1936799585819244e-01 -2.0390799641609192e-01 <_> 0 -1 2097 -2.7730999514460564e-02 6.1867898702621460e-01 -1.7804099619388580e-01 <_> 0 -1 2098 -1.5879999846220016e-02 -4.6484100818634033e-01 1.8828600645065308e-01 <_> 0 -1 2099 7.4128001928329468e-02 -1.2858100235462189e-01 3.2792479991912842e+00 <_> 0 -1 2100 -8.9000002481043339e-04 -3.0117601156234741e-01 2.3818799853324890e-01 <_> 0 -1 2101 1.7965000122785568e-02 -2.2284999489784241e-01 2.9954001307487488e-01 <_> 0 -1 2102 -2.5380000006407499e-03 2.5064399838447571e-01 -1.3665600121021271e-01 <_> 0 -1 2103 -9.0680001303553581e-03 2.9017499089241028e-01 -2.8929701447486877e-01 <_> 0 -1 2104 4.9169998615980148e-02 1.9156399369239807e-01 -6.8328702449798584e-01 <_> 0 -1 2105 -3.0680999159812927e-02 -7.5677001476287842e-01 -1.3279999606311321e-02 <_> 0 -1 2106 1.0017400234937668e-01 8.4453999996185303e-02 1.0888710021972656e+00 <_> 0 -1 2107 3.1950001139193773e-03 -2.6919400691986084e-01 1.9537900388240814e-01 <_> 0 -1 2108 3.5503000020980835e-02 1.3632300496101379e-01 -5.6917202472686768e-01 <_> 0 -1 2109 4.5900000259280205e-04 -4.0443998575210571e-01 1.4074799418449402e-01 <_> 0 -1 2110 2.5258999317884445e-02 1.6243200004100800e-01 -5.5741798877716064e-01 <_> 0 -1 2111 -5.1549999043345451e-03 3.1132599711418152e-01 -2.2756099700927734e-01 <_> 0 -1 2112 1.5869999770075083e-03 -2.6867699623107910e-01 1.9565400481224060e-01 <_> 0 -1 2113 -1.6204999759793282e-02 1.5486499667167664e-01 -3.4057798981666565e-01 <_> 0 -1 2114 -2.9624000191688538e-02 1.1466799974441528e+00 9.0557999908924103e-02 <_> 0 -1 2115 -1.5930000226944685e-03 -7.1257501840591431e-01 -7.0400000549852848e-04 <_> 0 -1 2116 -5.4019000381231308e-02 4.1537499427795410e-01 2.7246000245213509e-02 <_> 0 -1 2117 -6.6211000084877014e-02 -1.3340090513229370e+00 -4.7352999448776245e-02 <_> 0 -1 2118 2.7940999716520309e-02 1.4446300268173218e-01 -5.1518398523330688e-01 <_> 0 -1 2119 2.8957000002264977e-02 -4.9966000020503998e-02 -1.1929039955139160e+00 <_> 0 -1 2120 -2.0424999296665192e-02 6.3881301879882812e-01 3.8141001015901566e-02 <_> 0 -1 2121 1.2416999787092209e-02 -2.1547000110149384e-01 4.9477699398994446e-01 <_> 181 -3.3196411132812500e+00 <_> 0 -1 2122 4.3274000287055969e-02 -8.0494397878646851e-01 3.9897298812866211e-01 <_> 0 -1 2123 1.8615500628948212e-01 -3.1655299663543701e-01 6.8877297639846802e-01 <_> 0 -1 2124 3.1860999763011932e-02 -6.4266198873519897e-01 2.5550898909568787e-01 <_> 0 -1 2125 1.4022000133991241e-02 -4.5926600694656372e-01 3.1171199679374695e-01 <_> 0 -1 2126 -6.3029997982084751e-03 4.6026900410652161e-01 -2.7438500523567200e-01 <_> 0 -1 2127 -5.4310001432895660e-03 3.6608600616455078e-01 -2.7205801010131836e-01 <_> 0 -1 2128 1.6822999343276024e-02 2.3476999253034592e-02 -8.8443797826766968e-01 <_> 0 -1 2129 2.6039000600576401e-02 1.7488799989223480e-01 -5.4564702510833740e-01 <_> 0 -1 2130 -2.6720000430941582e-02 -9.6396499872207642e-01 2.3524999618530273e-02 <_> 0 -1 2131 -1.7041999846696854e-02 -7.0848798751831055e-01 2.1468099951744080e-01 <_> 0 -1 2132 5.9569999575614929e-03 7.3601000010967255e-02 -6.8225598335266113e-01 <_> 0 -1 2133 -2.8679999522864819e-03 -7.4935001134872437e-01 2.3803399503231049e-01 <_> 0 -1 2134 -4.3774999678134918e-02 6.8323302268981934e-01 -2.1380299329757690e-01 <_> 0 -1 2135 5.1633000373840332e-02 -1.2566499412059784e-01 6.7523801326751709e-01 <_> 0 -1 2136 8.1780003383755684e-03 7.0689998567104340e-02 -8.0665898323059082e-01 <_> 0 -1 2137 -5.2841998636722565e-02 9.5433902740478516e-01 1.6548000276088715e-02 <_> 0 -1 2138 5.2583999931812286e-02 -2.8414401412010193e-01 4.7129800915718079e-01 <_> 0 -1 2139 -1.2659000232815742e-02 3.8445401191711426e-01 -6.2288001179695129e-02 <_> 0 -1 2140 1.1694000102579594e-02 5.6000000768108293e-05 -1.0173139572143555e+00 <_> 0 -1 2141 -2.3918999359011650e-02 8.4921300411224365e-01 5.7399999350309372e-03 <_> 0 -1 2142 -6.1673998832702637e-02 -9.2571401596069336e-01 -1.7679999582469463e-03 <_> 0 -1 2143 -1.8279999494552612e-03 -5.4372298717498779e-01 2.4932399392127991e-01 <_> 0 -1 2144 3.5257998853921890e-02 -7.3719997890293598e-03 -9.3963998556137085e-01 <_> 0 -1 2145 -1.8438000231981277e-02 7.2136700153350830e-01 1.0491999797523022e-02 <_> 0 -1 2146 -3.8389001041650772e-02 1.9272600114345551e-01 -3.5832101106643677e-01 <_> 0 -1 2147 9.9720999598503113e-02 1.1354199796915054e-01 -1.6304190158843994e+00 <_> 0 -1 2148 8.4462001919746399e-02 -5.3420998156070709e-02 -1.6981120109558105e+00 <_> 0 -1 2149 4.0270000696182251e-02 -1.0783199965953827e-01 5.1926600933074951e-01 <_> 0 -1 2150 5.8935999870300293e-02 -1.8053700029850006e-01 9.5119798183441162e-01 <_> 0 -1 2151 1.4957000315189362e-01 1.6785299777984619e-01 -1.1591869592666626e+00 <_> 0 -1 2152 6.9399998756125569e-04 2.0491400361061096e-01 -3.3118200302124023e-01 <_> 0 -1 2153 -3.3369001001119614e-02 9.3468099832534790e-01 -2.9639999847859144e-03 <_> 0 -1 2154 9.3759996816515923e-03 3.7000000011175871e-03 -7.7549797296524048e-01 <_> 0 -1 2155 4.3193999677896500e-02 -2.2040000185370445e-03 7.4589699506759644e-01 <_> 0 -1 2156 -6.7555002868175507e-02 7.2292101383209229e-01 -1.8404200673103333e-01 <_> 0 -1 2157 -3.1168600916862488e-01 1.0014270544052124e+00 3.4003000706434250e-02 <_> 0 -1 2158 2.9743999242782593e-02 -4.6356000006198883e-02 -1.2781809568405151e+00 <_> 0 -1 2159 1.0737000033259392e-02 1.4812000095844269e-02 6.6649997234344482e-01 <_> 0 -1 2160 -2.8841000050306320e-02 -9.4222599267959595e-01 -2.0796999335289001e-02 <_> 0 -1 2161 -5.7649998925626278e-03 -4.3541899323463440e-01 2.3386000096797943e-01 <_> 0 -1 2162 2.8410999104380608e-02 -1.7615799605846405e-01 8.5765302181243896e-01 <_> 0 -1 2163 -2.9007999226450920e-02 5.7978099584579468e-01 2.8565999120473862e-02 <_> 0 -1 2164 2.4965999647974968e-02 -2.2729000076651573e-02 -9.6773099899291992e-01 <_> 0 -1 2165 1.2036000378429890e-02 -1.4214700460433960e-01 5.1687997579574585e-01 <_> 0 -1 2166 -4.2514000087976456e-02 9.7273802757263184e-01 -1.8119800090789795e-01 <_> 0 -1 2167 1.0276000015437603e-02 -8.3099998533725739e-02 3.1762799620628357e-01 <_> 0 -1 2168 -6.9191999733448029e-02 -2.0668580532073975e+00 -6.0173999518156052e-02 <_> 0 -1 2169 -4.6769999898970127e-03 4.4131800532341003e-01 2.3209000006318092e-02 <_> 0 -1 2170 -1.3923999853432178e-02 2.8606700897216797e-01 -2.9152700304985046e-01 <_> 0 -1 2171 -1.5333999879658222e-02 -5.7414501905441284e-01 2.3063300549983978e-01 <_> 0 -1 2172 -1.0239000432193279e-02 3.4479200839996338e-01 -2.6080399751663208e-01 <_> 0 -1 2173 -5.0988998264074326e-02 5.6154102087020874e-01 6.1218999326229095e-02 <_> 0 -1 2174 3.0689999461174011e-02 -1.4772799611091614e-01 1.6378489732742310e+00 <_> 0 -1 2175 -1.1223999783396721e-02 2.4006199836730957e-01 -4.4864898920059204e-01 <_> 0 -1 2176 -6.2899999320507050e-03 4.3119499087333679e-01 -2.3808999359607697e-01 <_> 0 -1 2177 7.8590996563434601e-02 1.9865000620484352e-02 8.0853801965713501e-01 <_> 0 -1 2178 -1.0178999975323677e-02 1.8193200230598450e-01 -3.2877799868583679e-01 <_> 0 -1 2179 3.1227000057697296e-02 1.4973899722099304e-01 -1.4180339574813843e+00 <_> 0 -1 2180 4.0196999907493591e-02 -1.9760499894618988e-01 5.8508199453353882e-01 <_> 0 -1 2181 1.6138000413775444e-02 5.0000002374872565e-04 3.9050000905990601e-01 <_> 0 -1 2182 -4.5519001781940460e-02 1.2646820545196533e+00 -1.5632599592208862e-01 <_> 0 -1 2183 -1.8130000680685043e-02 6.5148502588272095e-01 1.0235999710857868e-02 <_> 0 -1 2184 -1.4001999981701374e-02 -1.0344820022583008e+00 -3.2182998955249786e-02 <_> 0 -1 2185 -3.8816001266241074e-02 -4.7874298691749573e-01 1.6290700435638428e-01 <_> 0 -1 2186 3.1656000763177872e-02 -2.0983399450778961e-01 5.4575902223587036e-01 <_> 0 -1 2187 -1.0839999653398991e-02 5.1898801326751709e-01 -1.5080000273883343e-02 <_> 0 -1 2188 1.2032999657094479e-02 -2.1107600629329681e-01 7.5937002897262573e-01 <_> 0 -1 2189 7.0772998034954071e-02 1.8048800528049469e-01 -7.4048501253128052e-01 <_> 0 -1 2190 5.3139799833297729e-01 -1.4491699635982513e-01 1.5360039472579956e+00 <_> 0 -1 2191 -1.4774000272154808e-02 -2.8153699636459351e-01 2.0407299697399139e-01 <_> 0 -1 2192 -2.2410000674426556e-03 -4.4876301288604736e-01 5.3989000618457794e-02 <_> 0 -1 2193 4.9968000501394272e-02 4.1514001786708832e-02 2.9417100548744202e-01 <_> 0 -1 2194 -4.7701999545097351e-02 3.9674299955368042e-01 -2.8301799297332764e-01 <_> 0 -1 2195 -9.1311000287532806e-02 2.1994259357452393e+00 8.7964996695518494e-02 <_> 0 -1 2196 3.8070000708103180e-02 -2.8025600314140320e-01 2.5156199932098389e-01 <_> 0 -1 2197 -1.5538999810814857e-02 3.4157499670982361e-01 1.7924999818205833e-02 <_> 0 -1 2198 -1.5445999801158905e-02 2.8680199384689331e-01 -2.5135898590087891e-01 <_> 0 -1 2199 -5.7388000190258026e-02 6.3830000162124634e-01 8.8597998023033142e-02 <_> 0 -1 2200 -5.9440000914037228e-03 7.9016998410224915e-02 -4.0774899721145630e-01 <_> 0 -1 2201 -6.9968998432159424e-02 -4.4644200801849365e-01 1.7219600081443787e-01 <_> 0 -1 2202 -2.5064999237656593e-02 -9.8270201683044434e-01 -3.5388000309467316e-02 <_> 0 -1 2203 1.7216000705957413e-02 2.2705900669097900e-01 -8.0550098419189453e-01 <_> 0 -1 2204 -4.4279001653194427e-02 8.3951997756958008e-01 -1.7429600656032562e-01 <_> 0 -1 2205 4.3988998979330063e-02 1.1557199805974960e-01 -1.9666889905929565e+00 <_> 0 -1 2206 1.5907000750303268e-02 -3.7576001137495041e-02 -1.0311100482940674e+00 <_> 0 -1 2207 -9.2754997313022614e-02 -1.3530019521713257e+00 1.2141299992799759e-01 <_> 0 -1 2208 7.1037001907825470e-02 -1.7684300243854523e-01 7.4485200643539429e-01 <_> 0 -1 2209 5.7762000709772110e-02 1.2835599482059479e-01 -4.4444200396537781e-01 <_> 0 -1 2210 -1.6432000324130058e-02 8.0152702331542969e-01 -1.7491699755191803e-01 <_> 0 -1 2211 2.3939000442624092e-02 1.6144999861717224e-01 -1.2364500015974045e-01 <_> 0 -1 2212 1.2636000290513039e-02 1.5411999821662903e-01 -3.3293798565864563e-01 <_> 0 -1 2213 -5.4347999393939972e-02 -1.8400700092315674e+00 1.4835999906063080e-01 <_> 0 -1 2214 -1.3261999934911728e-02 -8.0838799476623535e-01 -2.7726000174880028e-02 <_> 0 -1 2215 6.1340001411736012e-03 -1.3785000145435333e-01 3.2858499884605408e-01 <_> 0 -1 2216 2.8991000726819038e-02 -2.5516999885439873e-02 -8.3387202024459839e-01 <_> 0 -1 2217 -2.1986000239849091e-02 -7.3739999532699585e-01 1.7887100577354431e-01 <_> 0 -1 2218 5.3269998170435429e-03 -4.5449298620223999e-01 6.8791002035140991e-02 <_> 0 -1 2219 8.6047999560832977e-02 2.1008500456809998e-01 -3.7808901071548462e-01 <_> 0 -1 2220 -8.5549997165799141e-03 4.0134999155998230e-01 -2.1074099838733673e-01 <_> 0 -1 2221 6.7790001630783081e-03 -2.1648999303579330e-02 4.5421499013900757e-01 <_> 0 -1 2222 -6.3959998078644276e-03 -4.9818599224090576e-01 7.5907997786998749e-02 <_> 0 -1 2223 8.9469999074935913e-03 1.7857700586318970e-01 -2.8454899787902832e-01 <_> 0 -1 2224 3.2589999027550220e-03 4.6624999493360519e-02 -5.5206298828125000e-01 <_> 0 -1 2225 4.1476998478174210e-02 1.7550499737262726e-01 -2.0703999698162079e-01 <_> 0 -1 2226 -6.7449999041855335e-03 -4.6392598748207092e-01 6.9303996860980988e-02 <_> 0 -1 2227 3.0564999207854271e-02 5.1734998822212219e-02 7.5550502538681030e-01 <_> 0 -1 2228 -7.4780001305043697e-03 1.4893899857997894e-01 -3.1906801462173462e-01 <_> 0 -1 2229 8.9088998734951019e-02 1.3738800585269928e-01 -1.1379710435867310e+00 <_> 0 -1 2230 7.3230001144111156e-03 -2.8829199075698853e-01 1.9088600575923920e-01 <_> 0 -1 2231 -1.8205000087618828e-02 -3.0178600549697876e-01 1.6795800626277924e-01 <_> 0 -1 2232 -2.5828000158071518e-02 -9.8137998580932617e-01 -1.9860999658703804e-02 <_> 0 -1 2233 1.0936199873685837e-01 4.8790000379085541e-02 5.3118300437927246e-01 <_> 0 -1 2234 -1.1424999684095383e-02 2.3705999553203583e-01 -2.7925300598144531e-01 <_> 0 -1 2235 -5.7565998286008835e-02 4.7255399823188782e-01 6.5171003341674805e-02 <_> 0 -1 2236 1.0278300195932388e-01 -2.0765100419521332e-01 5.0947701930999756e-01 <_> 0 -1 2237 2.7041999623179436e-02 1.6421200335025787e-01 -1.4508620500564575e+00 <_> 0 -1 2238 -1.3635000213980675e-02 -5.6543898582458496e-01 2.3788999766111374e-02 <_> 0 -1 2239 -3.2158198952674866e-01 -3.5602829456329346e+00 1.1801300197839737e-01 <_> 0 -1 2240 2.0458100736141205e-01 -3.7016000598669052e-02 -1.0225499868392944e+00 <_> 0 -1 2241 -7.0347003638744354e-02 -5.6491899490356445e-01 1.8525199592113495e-01 <_> 0 -1 2242 3.7831000983715057e-02 -2.9901999980211258e-02 -8.2921499013900757e-01 <_> 0 -1 2243 -7.0298001170158386e-02 -5.3172302246093750e-01 1.4430199563503265e-01 <_> 0 -1 2244 6.3221000134944916e-02 -2.2041200101375580e-01 4.7952198982238770e-01 <_> 0 -1 2245 3.6393001675605774e-02 1.4222699403762817e-01 -6.1193901300430298e-01 <_> 0 -1 2246 4.0099998004734516e-03 -3.4560799598693848e-01 1.1738699674606323e-01 <_> 0 -1 2247 -4.9106001853942871e-02 9.5984101295471191e-01 6.4934998750686646e-02 <_> 0 -1 2248 -7.1583002805709839e-02 1.7385669946670532e+00 -1.4252899587154388e-01 <_> 0 -1 2249 -3.8008999079465866e-02 1.3872820138931274e+00 6.6188000142574310e-02 <_> 0 -1 2250 -3.1570000573992729e-03 5.3677000105381012e-02 -5.4048001766204834e-01 <_> 0 -1 2251 1.9458999857306480e-02 -9.3620002269744873e-02 3.9131000638008118e-01 <_> 0 -1 2252 1.1293999850749969e-02 3.7223998457193375e-02 -5.4251801967620850e-01 <_> 0 -1 2253 -3.3495001494884491e-02 9.5307898521423340e-01 3.7696998566389084e-02 <_> 0 -1 2254 9.2035003006458282e-02 -1.3488399982452393e-01 2.2897069454193115e+00 <_> 0 -1 2255 3.7529999390244484e-03 2.2824199497699738e-01 -5.9983700513839722e-01 <_> 0 -1 2256 1.2848000042140484e-02 -2.2005200386047363e-01 3.7221899628639221e-01 <_> 0 -1 2257 -1.4316199719905853e-01 1.2855789661407471e+00 4.7237001359462738e-02 <_> 0 -1 2258 -9.6879996359348297e-02 -3.9550929069519043e+00 -7.2903998196125031e-02 <_> 0 -1 2259 -8.8459998369216919e-03 3.7674999237060547e-01 -4.6484000980854034e-02 <_> 0 -1 2260 1.5900000929832458e-02 -2.4457000195980072e-02 -8.0034798383712769e-01 <_> 0 -1 2261 7.0372000336647034e-02 1.7019000649452209e-01 -6.3068997859954834e-01 <_> 0 -1 2262 -3.7953998893499374e-02 -9.3667197227478027e-01 -4.1214000433683395e-02 <_> 0 -1 2263 5.1597899198532104e-01 1.3080599904060364e-01 -1.5802290439605713e+00 <_> 0 -1 2264 -3.2843001186847687e-02 -1.1441620588302612e+00 -4.9173999577760696e-02 <_> 0 -1 2265 -3.6357000470161438e-02 4.9606400728225708e-01 -3.4458998590707779e-02 <_> 0 -1 2266 6.8080001510679722e-03 -3.0997800827026367e-01 1.7054800689220428e-01 <_> 0 -1 2267 -1.6114000231027603e-02 -3.7904599308967590e-01 1.6078999638557434e-01 <_> 0 -1 2268 8.4530003368854523e-03 -1.8655499815940857e-01 5.6367701292037964e-01 <_> 0 -1 2269 -1.3752399384975433e-01 -5.8989900350570679e-01 1.1749500036239624e-01 <_> 0 -1 2270 1.7688000202178955e-01 -1.5424899756908417e-01 9.2911100387573242e-01 <_> 0 -1 2271 7.9309996217489243e-03 3.2190701365470886e-01 -1.6392600536346436e-01 <_> 0 -1 2272 1.0971800237894058e-01 -1.5876500308513641e-01 1.0186259746551514e+00 <_> 0 -1 2273 -3.0293000862002373e-02 7.5587302446365356e-01 3.1794998794794083e-02 <_> 0 -1 2274 -2.3118000477552414e-02 -8.8451498746871948e-01 -9.5039997249841690e-03 <_> 0 -1 2275 -3.0900000128895044e-03 2.3838299512863159e-01 -1.1606200039386749e-01 <_> 0 -1 2276 -3.3392000943422318e-02 -1.8738139867782593e+00 -6.8502999842166901e-02 <_> 0 -1 2277 1.3190000317990780e-02 1.2919899821281433e-01 -6.7512202262878418e-01 <_> 0 -1 2278 1.4661000110208988e-02 -2.4829000234603882e-02 -7.4396800994873047e-01 <_> 0 -1 2279 -1.3248000293970108e-02 4.6820199489593506e-01 -2.4165000766515732e-02 <_> 0 -1 2280 -1.6218999400734901e-02 4.0083798766136169e-01 -2.1255700290203094e-01 <_> 0 -1 2281 -2.9052000492811203e-02 -1.5650019645690918e+00 1.4375899732112885e-01 <_> 0 -1 2282 -1.0153199732303619e-01 -1.9220689535140991e+00 -6.9559998810291290e-02 <_> 0 -1 2283 3.7753999233245850e-02 1.3396799564361572e-01 -2.2639141082763672e+00 <_> 0 -1 2284 -2.8555598855018616e-01 1.0215270519256592e+00 -1.5232199430465698e-01 <_> 0 -1 2285 1.5360699594020844e-01 -9.7409002482891083e-02 4.1662400960922241e-01 <_> 0 -1 2286 -2.1199999901000410e-04 1.1271899938583374e-01 -4.1653999686241150e-01 <_> 0 -1 2287 -2.0597999915480614e-02 6.0540497303009033e-01 6.2467999756336212e-02 <_> 0 -1 2288 3.7353999912738800e-02 -1.8919000029563904e-01 4.6464699506759644e-01 <_> 0 -1 2289 5.7275000959634781e-02 1.1565300077199936e-01 -1.3213009834289551e+00 <_> 0 -1 2290 5.1029999740421772e-03 -2.8061500191688538e-01 1.9313399493694305e-01 <_> 0 -1 2291 -5.4644998162984848e-02 7.2428500652313232e-01 7.5447998940944672e-02 <_> 0 -1 2292 2.5349000468850136e-02 -1.9481800496578217e-01 4.6032801270484924e-01 <_> 0 -1 2293 2.4311000481247902e-02 1.5564100444316864e-01 -4.9913901090621948e-01 <_> 0 -1 2294 3.5962000489234924e-02 -5.8573000133037567e-02 -1.5418399572372437e+00 <_> 0 -1 2295 -1.0000699758529663e-01 -1.6100039482116699e+00 1.1450500041246414e-01 <_> 0 -1 2296 8.4435999393463135e-02 -6.1406999826431274e-02 -1.4673349857330322e+00 <_> 0 -1 2297 1.5947999432682991e-02 1.6287900507450104e-01 -1.1026400327682495e-01 <_> 0 -1 2298 3.3824000507593155e-02 -1.7932699620723724e-01 5.7218402624130249e-01 <_> 0 -1 2299 -6.1996001750230789e-02 4.6511812210083008e+00 9.4534002244472504e-02 <_> 0 -1 2300 6.9876998662948608e-02 -1.6985900700092316e-01 8.7028998136520386e-01 <_> 0 -1 2301 -2.7916999533772469e-02 9.1042500734329224e-01 5.6827001273632050e-02 <_> 0 -1 2302 -1.2764000333845615e-02 2.2066700458526611e-01 -2.7769100666046143e-01 <_> 199 -3.2573320865631104e+00 <_> 0 -1 2303 2.1662000566720963e-02 -8.9868897199630737e-01 2.9436299204826355e-01 <_> 0 -1 2304 1.0044500231742859e-01 -3.7659201025962830e-01 6.0891002416610718e-01 <_> 0 -1 2305 2.6003999635577202e-02 -3.8128501176834106e-01 3.9217400550842285e-01 <_> 0 -1 2306 2.8441000729799271e-02 -1.8182300031185150e-01 5.8927202224731445e-01 <_> 0 -1 2307 3.8612000644207001e-02 -2.2399599850177765e-01 6.3779997825622559e-01 <_> 0 -1 2308 -4.6594999730587006e-02 7.0812201499938965e-01 -1.4666199684143066e-01 <_> 0 -1 2309 -4.2791999876499176e-02 4.7680398821830750e-01 -2.9233199357986450e-01 <_> 0 -1 2310 3.7960000336170197e-03 -1.8510299921035767e-01 5.2626699209213257e-01 <_> 0 -1 2311 4.2348999530076981e-02 3.9244998246431351e-02 -8.9197701215744019e-01 <_> 0 -1 2312 1.9598999992012978e-02 -2.3358400166034698e-01 4.4146499037742615e-01 <_> 0 -1 2313 8.7400001939386129e-04 -4.6063598990440369e-01 1.7689600586891174e-01 <_> 0 -1 2314 -4.3629999272525311e-03 3.3493199944496155e-01 -2.9893401265144348e-01 <_> 0 -1 2315 1.6973000019788742e-02 -1.6408699750900269e-01 1.5993679761886597e+00 <_> 0 -1 2316 3.6063998937606812e-02 2.2601699829101562e-01 -5.3186100721359253e-01 <_> 0 -1 2317 -7.0864997804164886e-02 1.5220500528812408e-01 -4.1914600133895874e-01 <_> 0 -1 2318 -6.3075996935367584e-02 -1.4874019622802734e+00 1.2953700125217438e-01 <_> 0 -1 2319 2.9670000076293945e-02 -1.9145900011062622e-01 9.8184901475906372e-01 <_> 0 -1 2320 3.7873998284339905e-02 1.3459500670433044e-01 -5.6316298246383667e-01 <_> 0 -1 2321 -3.3289000391960144e-02 -1.0828030109405518e+00 -1.1504000052809715e-02 <_> 0 -1 2322 -3.1608998775482178e-02 -5.9224498271942139e-01 1.3394799828529358e-01 <_> 0 -1 2323 1.0740000288933516e-03 -4.9185800552368164e-01 9.4446003437042236e-02 <_> 0 -1 2324 -7.1556001901626587e-02 5.9710198640823364e-01 -3.9553001523017883e-02 <_> 0 -1 2325 -8.1170000135898590e-02 -1.1817820072174072e+00 -2.8254000470042229e-02 <_> 0 -1 2326 4.4860001653432846e-03 -6.1028099060058594e-01 2.2619099915027618e-01 <_> 0 -1 2327 -4.2176000773906708e-02 -1.1435619592666626e+00 -2.9001999646425247e-02 <_> 0 -1 2328 -6.5640002489089966e-02 -1.6470279693603516e+00 1.2810300290584564e-01 <_> 0 -1 2329 1.8188999965786934e-02 -3.1149399280548096e-01 2.5739601254463196e-01 <_> 0 -1 2330 -5.1520001143217087e-02 -6.9206899404525757e-01 1.5270799398422241e-01 <_> 0 -1 2331 -4.7150999307632446e-02 -7.1868300437927246e-01 2.6879999786615372e-03 <_> 0 -1 2332 1.7488999292254448e-02 2.2371199727058411e-01 -5.5381798744201660e-01 <_> 0 -1 2333 -2.5264000520110130e-02 1.0319819450378418e+00 -1.7496499419212341e-01 <_> 0 -1 2334 -4.0745001286268234e-02 4.4961598515510559e-01 3.9349000900983810e-02 <_> 0 -1 2335 -3.7666998803615570e-02 -8.5475701093673706e-01 -1.2463999912142754e-02 <_> 0 -1 2336 -1.3411000370979309e-02 5.7845598459243774e-01 -1.7467999830842018e-02 <_> 0 -1 2337 -7.8999997640494257e-05 -3.7749201059341431e-01 1.3961799442768097e-01 <_> 0 -1 2338 -1.1415000073611736e-02 -2.6186600327491760e-01 2.3712499439716339e-01 <_> 0 -1 2339 3.7200000137090683e-02 -2.8626000508666039e-02 -1.2945239543914795e+00 <_> 0 -1 2340 3.4050000831484795e-03 2.0531399548053741e-01 -1.8747499585151672e-01 <_> 0 -1 2341 -2.2483000531792641e-02 6.7027199268341064e-01 -1.9594000279903412e-01 <_> 0 -1 2342 2.3274999111890793e-02 1.7405399680137634e-01 -3.2746300101280212e-01 <_> 0 -1 2343 -1.3917000032961369e-02 -8.3954298496246338e-01 -6.3760001212358475e-03 <_> 0 -1 2344 7.5429999269545078e-03 -3.4194998443126678e-02 5.8998197317123413e-01 <_> 0 -1 2345 -1.1539000086486340e-02 4.2142799496650696e-01 -2.3510499298572540e-01 <_> 0 -1 2346 5.2501998841762543e-02 6.9303996860980988e-02 7.3226499557495117e-01 <_> 0 -1 2347 5.2715998142957687e-02 -1.5688100457191467e-01 1.0907289981842041e+00 <_> 0 -1 2348 -1.1726000346243382e-02 -7.0934301614761353e-01 1.6828800737857819e-01 <_> 0 -1 2349 9.5945999026298523e-02 -1.6192899644374847e-01 1.0072519779205322e+00 <_> 0 -1 2350 -1.5871999785304070e-02 3.9008399844169617e-01 -5.3777001798152924e-02 <_> 0 -1 2351 3.4818001091480255e-02 1.7179999500513077e-02 -9.3941801786422729e-01 <_> 0 -1 2352 3.4791998565196991e-02 5.0462998449802399e-02 5.4465699195861816e-01 <_> 0 -1 2353 1.6284000128507614e-02 -2.6981300115585327e-01 4.0365299582481384e-01 <_> 0 -1 2354 -4.4319000095129013e-02 8.4399998188018799e-01 3.2882999628782272e-02 <_> 0 -1 2355 -5.5689997971057892e-03 1.5309399366378784e-01 -3.4959799051284790e-01 <_> 0 -1 2356 -6.5842002630233765e-02 -9.2711198329925537e-01 1.6800999641418457e-01 <_> 0 -1 2357 -7.3337003588676453e-02 5.1614499092102051e-01 -2.0236000418663025e-01 <_> 0 -1 2358 1.6450000926852226e-02 1.3950599730014801e-01 -4.9301299452781677e-01 <_> 0 -1 2359 -9.2630004510283470e-03 -9.0101999044418335e-01 -1.6116000711917877e-02 <_> 0 -1 2360 5.9139998629689217e-03 1.9858199357986450e-01 -1.6731299459934235e-01 <_> 0 -1 2361 -8.4699998842552304e-04 9.4005003571510315e-02 -4.1570898890495300e-01 <_> 0 -1 2362 2.0532900094985962e-01 -6.0022000223398209e-02 7.0993602275848389e-01 <_> 0 -1 2363 -1.6883000731468201e-02 2.4392199516296387e-01 -3.0551800131797791e-01 <_> 0 -1 2364 -1.9111000001430511e-02 6.1229902505874634e-01 2.4252999573945999e-02 <_> 0 -1 2365 -2.5962999090552330e-02 9.0764999389648438e-01 -1.6722099483013153e-01 <_> 0 -1 2366 -2.1762000396847725e-02 -3.1384700536727905e-01 2.0134599506855011e-01 <_> 0 -1 2367 -2.4119999259710312e-02 -6.6588401794433594e-01 7.4559999629855156e-03 <_> 0 -1 2368 4.7129999846220016e-02 5.9533998370170593e-02 8.7804502248764038e-01 <_> 0 -1 2369 -4.5984998345375061e-02 8.0067998170852661e-01 -1.7252300679683685e-01 <_> 0 -1 2370 2.6507999747991562e-02 1.8774099647998810e-01 -6.0850602388381958e-01 <_> 0 -1 2371 -4.8615001142024994e-02 5.8644098043441772e-01 -1.9427700340747833e-01 <_> 0 -1 2372 -1.8562000244855881e-02 -2.5587901473045349e-01 1.6326199471950531e-01 <_> 0 -1 2373 1.2678000144660473e-02 -1.4228000305593014e-02 -7.6738101243972778e-01 <_> 0 -1 2374 -1.1919999960809946e-03 2.0495000481605530e-01 -1.1404299736022949e-01 <_> 0 -1 2375 -4.9088999629020691e-02 -1.0740849971771240e+00 -3.8940999656915665e-02 <_> 0 -1 2376 -1.7436999827623367e-02 -5.7973802089691162e-01 1.8584500253200531e-01 <_> 0 -1 2377 -1.4770000241696835e-02 -6.6150301694869995e-01 5.3119999356567860e-03 <_> 0 -1 2378 -2.2905200719833374e-01 -4.8305100202560425e-01 1.2326399981975555e-01 <_> 0 -1 2379 -1.2707099318504333e-01 5.7452601194381714e-01 -1.9420400261878967e-01 <_> 0 -1 2380 1.0339000262320042e-02 -5.4641999304294586e-02 2.4501800537109375e-01 <_> 0 -1 2381 6.9010001607239246e-03 1.2180600315332413e-01 -3.8797399401664734e-01 <_> 0 -1 2382 2.9025399684906006e-01 1.0966199636459351e-01 -30. <_> 0 -1 2383 -2.3804999887943268e-01 -1.7352679967880249e+00 -6.3809998333454132e-02 <_> 0 -1 2384 6.2481001019477844e-02 1.3523000478744507e-01 -7.0301097631454468e-01 <_> 0 -1 2385 4.7109997831285000e-03 -4.6984100341796875e-01 6.0341998934745789e-02 <_> 0 -1 2386 -2.7815999463200569e-02 6.9807600975036621e-01 1.3719999697059393e-03 <_> 0 -1 2387 -1.7020000144839287e-02 1.6870440244674683e+00 -1.4314800500869751e-01 <_> 0 -1 2388 -4.9754999577999115e-02 7.9497700929641724e-01 7.7199999941512942e-04 <_> 0 -1 2389 -7.4732996523380280e-02 -1.0132360458374023e+00 -1.9388999789953232e-02 <_> 0 -1 2390 3.2009001821279526e-02 1.4412100613117218e-01 -4.2139101028442383e-01 <_> 0 -1 2391 -9.4463996589183807e-02 5.0682598352432251e-01 -2.0478899776935577e-01 <_> 0 -1 2392 -1.5426999889314175e-02 -1.5811300277709961e-01 1.7806899547576904e-01 <_> 0 -1 2393 -4.0540001355111599e-03 -5.4366701841354370e-01 3.1235000118613243e-02 <_> 0 -1 2394 3.0080000869929790e-03 -1.7376799881458282e-01 3.0441701412200928e-01 <_> 0 -1 2395 -1.0091999545693398e-02 2.5103801488876343e-01 -2.6224100589752197e-01 <_> 0 -1 2396 -3.8818001747131348e-02 9.3226701021194458e-01 7.2659999132156372e-02 <_> 0 -1 2397 3.4651998430490494e-02 -3.3934999257326126e-02 -8.5707902908325195e-01 <_> 0 -1 2398 -4.6729999594390392e-03 3.4969300031661987e-01 -4.8517998307943344e-02 <_> 0 -1 2399 6.8499997723847628e-04 6.6573001444339752e-02 -4.4973799586296082e-01 <_> 0 -1 2400 3.5317000001668930e-02 1.4275799691677094e-01 -4.6726399660110474e-01 <_> 0 -1 2401 -2.3569999262690544e-02 -1.0286079645156860e+00 -4.5288000255823135e-02 <_> 0 -1 2402 -1.9109999993816018e-03 -1.9652199745178223e-01 2.8661000728607178e-01 <_> 0 -1 2403 -1.6659000888466835e-02 -7.7532202005386353e-01 -8.3280000835657120e-03 <_> 0 -1 2404 6.6062200069427490e-01 1.3232499361038208e-01 -3.5266680717468262e+00 <_> 0 -1 2405 1.0970599949359894e-01 -1.5547199547290802e-01 1.4674140214920044e+00 <_> 0 -1 2406 1.3500999659299850e-02 1.5233400464057922e-01 -1.3020930290222168e+00 <_> 0 -1 2407 -2.2871999070048332e-02 -7.1325999498367310e-01 -8.7040001526474953e-03 <_> 0 -1 2408 -8.1821002066135406e-02 1.1127580404281616e+00 8.3219997584819794e-02 <_> 0 -1 2409 -5.2728001028299332e-02 9.3165099620819092e-01 -1.7103999853134155e-01 <_> 0 -1 2410 -2.5242000818252563e-02 -1.9733799993991852e-01 2.5359401106834412e-01 <_> 0 -1 2411 -4.3818999081850052e-02 4.1815200448036194e-01 -2.4585500359535217e-01 <_> 0 -1 2412 -1.8188999965786934e-02 -5.1743197441101074e-01 2.0174199342727661e-01 <_> 0 -1 2413 2.3466000333428383e-02 -4.3071001768112183e-02 -1.0636579990386963e+00 <_> 0 -1 2414 3.4216001629829407e-02 5.3780999034643173e-02 4.9707201123237610e-01 <_> 0 -1 2415 2.5692999362945557e-02 -2.3800100386142731e-01 4.1651499271392822e-01 <_> 0 -1 2416 -2.6565000414848328e-02 -8.8574802875518799e-01 1.3365900516510010e-01 <_> 0 -1 2417 6.0942001640796661e-02 -2.0669700205326080e-01 5.8309000730514526e-01 <_> 0 -1 2418 1.4474500715732574e-01 1.3282300531864166e-01 -3.1449348926544189e+00 <_> 0 -1 2419 5.3410999476909637e-02 -1.7325200140476227e-01 6.9190698862075806e-01 <_> 0 -1 2420 1.1408000253140926e-02 5.4822001606225967e-02 3.0240398645401001e-01 <_> 0 -1 2421 -2.3179999552667141e-03 1.5820899605751038e-01 -3.1973201036453247e-01 <_> 0 -1 2422 -2.9695000499486923e-02 7.1274799108505249e-01 5.8136001229286194e-02 <_> 0 -1 2423 2.7249999344348907e-02 -1.5754100680351257e-01 9.2143797874450684e-01 <_> 0 -1 2424 -3.6200000904500484e-03 -3.4548398852348328e-01 2.0220999419689178e-01 <_> 0 -1 2425 -1.2578999623656273e-02 -5.5650299787521362e-01 2.0388999953866005e-02 <_> 0 -1 2426 -8.8849000632762909e-02 -3.6100010871887207e+00 1.3164199888706207e-01 <_> 0 -1 2427 -1.9256999716162682e-02 5.1908999681472778e-01 -1.9284300506114960e-01 <_> 0 -1 2428 -1.6666999086737633e-02 -8.7499998509883881e-02 1.5812499821186066e-01 <_> 0 -1 2429 1.2931999750435352e-02 2.7405999600887299e-02 -5.5123901367187500e-01 <_> 0 -1 2430 -1.3431999832391739e-02 2.3457799851894379e-01 -4.3235000222921371e-02 <_> 0 -1 2431 1.8810000270605087e-02 -3.9680998772382736e-02 -9.4373297691345215e-01 <_> 0 -1 2432 -6.4349998719990253e-03 4.5703700184822083e-01 -4.0520001202821732e-03 <_> 0 -1 2433 -2.4249000474810600e-02 -7.6248002052307129e-01 -1.9857000559568405e-02 <_> 0 -1 2434 -2.9667999595403671e-02 -3.7412509918212891e+00 1.1250600218772888e-01 <_> 0 -1 2435 5.1150000654160976e-03 -6.3781797885894775e-01 1.1223999783396721e-02 <_> 0 -1 2436 -5.7819997891783714e-03 1.9374400377273560e-01 -8.2042001187801361e-02 <_> 0 -1 2437 1.6606999561190605e-02 -1.6192099452018738e-01 1.1334990262985229e+00 <_> 0 -1 2438 3.8228001445531845e-02 2.1105000749230385e-02 7.6264202594757080e-01 <_> 0 -1 2439 -5.7094000279903412e-02 -1.6974929571151733e+00 -5.9762001037597656e-02 <_> 0 -1 2440 -5.3883001208305359e-02 1.1850190162658691e+00 9.0966999530792236e-02 <_> 0 -1 2441 -2.6110000908374786e-03 -4.0941199660301208e-01 8.3820998668670654e-02 <_> 0 -1 2442 2.9714399576187134e-01 1.5529899299144745e-01 -1.0995409488677979e+00 <_> 0 -1 2443 -8.9063003659248352e-02 4.8947200179100037e-01 -2.0041200518608093e-01 <_> 0 -1 2444 -5.6193001568317413e-02 -2.4581399559974670e-01 1.4365500211715698e-01 <_> 0 -1 2445 3.7004999816417694e-02 -4.8168998211622238e-02 -1.2310709953308105e+00 <_> 0 -1 2446 -8.4840003401041031e-03 4.3372601270675659e-01 1.3779999688267708e-02 <_> 0 -1 2447 -2.4379999376833439e-03 1.8949699401855469e-01 -3.2294198870658875e-01 <_> 0 -1 2448 -7.1639999747276306e-02 -4.3979001045227051e-01 2.2730199992656708e-01 <_> 0 -1 2449 5.2260002121329308e-03 -2.0548400282859802e-01 5.0933301448822021e-01 <_> 0 -1 2450 -6.1360001564025879e-03 3.1157198548316956e-01 7.0680998265743256e-02 <_> 0 -1 2451 1.5595000237226486e-02 -3.0934798717498779e-01 1.5627700090408325e-01 <_> 0 -1 2452 2.5995999574661255e-02 1.3821600377559662e-01 -1.7616599798202515e-01 <_> 0 -1 2453 -1.2085000053048134e-02 -5.1070201396942139e-01 5.8440998196601868e-02 <_> 0 -1 2454 -6.7836001515388489e-02 4.7757101058959961e-01 -7.1446001529693604e-02 <_> 0 -1 2455 -1.4715000055730343e-02 4.5238900184631348e-01 -1.9861400127410889e-01 <_> 0 -1 2456 2.5118999183177948e-02 1.2954899668693542e-01 -8.6266398429870605e-01 <_> 0 -1 2457 1.8826000392436981e-02 -4.1570000350475311e-02 -1.1354700326919556e+00 <_> 0 -1 2458 -2.1263999864459038e-02 -3.4738001227378845e-01 1.5779499709606171e-01 <_> 0 -1 2459 9.4609996303915977e-03 4.8639997839927673e-03 -6.1654800176620483e-01 <_> 0 -1 2460 2.2957700490951538e-01 8.1372998654842377e-02 6.9841402769088745e-01 <_> 0 -1 2461 -3.8061998784542084e-02 1.1616369485855103e+00 -1.4976699650287628e-01 <_> 0 -1 2462 -1.3484999537467957e-02 -3.2036399841308594e-01 1.7365099489688873e-01 <_> 0 -1 2463 3.6238998174667358e-02 -1.8158499896526337e-01 6.1956697702407837e-01 <_> 0 -1 2464 6.7210001870989799e-03 7.9600000753998756e-04 4.2441400885581970e-01 <_> 0 -1 2465 9.6525996923446655e-02 -1.4696800708770752e-01 1.2525680065155029e+00 <_> 0 -1 2466 -3.5656999796628952e-02 -3.9781698584556580e-01 1.4191399514675140e-01 <_> 0 -1 2467 1.0772000066936016e-02 -1.8194000422954559e-01 5.9762197732925415e-01 <_> 0 -1 2468 7.9279996454715729e-02 1.4642499387264252e-01 -7.8836899995803833e-01 <_> 0 -1 2469 3.2841000705957413e-02 -6.2408000230789185e-02 -1.4227490425109863e+00 <_> 0 -1 2470 -2.7781000360846519e-02 3.4033098816871643e-01 3.0670000240206718e-02 <_> 0 -1 2471 -4.0339999832212925e-03 3.1084701418876648e-01 -2.2595700621604919e-01 <_> 0 -1 2472 7.4260002002120018e-03 -3.8936998695135117e-02 3.1702101230621338e-01 <_> 0 -1 2473 1.1213999986648560e-01 -1.7578299343585968e-01 6.5056598186492920e-01 <_> 0 -1 2474 -1.1878100037574768e-01 -1.0092990398406982e+00 1.1069700121879578e-01 <_> 0 -1 2475 -4.1584998369216919e-02 -5.3806400299072266e-01 1.9905000925064087e-02 <_> 0 -1 2476 -2.7966000139713287e-02 4.8143199086189270e-01 3.3590998500585556e-02 <_> 0 -1 2477 -1.2506400048732758e-01 2.6352199912071228e-01 -2.5737899541854858e-01 <_> 0 -1 2478 2.3666900396347046e-01 3.6508001387119293e-02 9.0655601024627686e-01 <_> 0 -1 2479 -2.9475999996066093e-02 -6.0048800706863403e-01 9.5880003646016121e-03 <_> 0 -1 2480 3.7792999297380447e-02 1.5506200492382050e-01 -9.5733499526977539e-01 <_> 0 -1 2481 7.2044000029563904e-02 -1.4525899291038513e-01 1.3676730394363403e+00 <_> 0 -1 2482 9.7759999334812164e-03 1.2915999628603458e-02 2.1640899777412415e-01 <_> 0 -1 2483 5.2154000848531723e-02 -1.6359999775886536e-02 -8.8356298208236694e-01 <_> 0 -1 2484 -4.3790999799966812e-02 3.5829600691795349e-01 6.5131001174449921e-02 <_> 0 -1 2485 -3.8378998637199402e-02 1.1961040496826172e+00 -1.4971500635147095e-01 <_> 0 -1 2486 -9.8838999867439270e-02 -6.1834001541137695e-01 1.2786200642585754e-01 <_> 0 -1 2487 -1.2190700322389603e-01 -1.8276120424270630e+00 -6.4862996339797974e-02 <_> 0 -1 2488 -1.1981700360774994e-01 -30. 1.1323300004005432e-01 <_> 0 -1 2489 3.0910000205039978e-02 -2.3934000730514526e-01 3.6332899332046509e-01 <_> 0 -1 2490 1.0800999589264393e-02 -3.5140000283718109e-02 2.7707898616790771e-01 <_> 0 -1 2491 5.6844998151063919e-02 -1.5524299442768097e-01 1.0802700519561768e+00 <_> 0 -1 2492 1.0280000278726220e-03 -6.1202999204397202e-02 2.0508000254631042e-01 <_> 0 -1 2493 -2.8273999691009521e-02 -6.4778000116348267e-01 2.3917000740766525e-02 <_> 0 -1 2494 -1.6013599932193756e-01 1.0892050266265869e+00 5.8389000594615936e-02 <_> 0 -1 2495 4.9629998393356800e-03 -2.5806298851966858e-01 2.0834599435329437e-01 <_> 0 -1 2496 4.6937000006437302e-02 1.3886299729347229e-01 -1.5662620067596436e+00 <_> 0 -1 2497 2.4286000058054924e-02 -2.0728300511837006e-01 5.2430999279022217e-01 <_> 0 -1 2498 7.0202000439167023e-02 1.4796899259090424e-01 -1.3095090389251709e+00 <_> 0 -1 2499 9.8120002076029778e-03 2.7906000614166260e-02 -5.0864601135253906e-01 <_> 0 -1 2500 -5.6200999766588211e-02 1.2618130445480347e+00 6.3801996409893036e-02 <_> 0 -1 2501 1.0982800275087357e-01 -1.2850099802017212e-01 3.0776169300079346e+00 <_> 211 -3.3703000545501709e+00 <_> 0 -1 2502 2.0910000428557396e-02 -6.8559402227401733e-01 3.8984298706054688e-01 <_> 0 -1 2503 3.5032000392675400e-02 -4.7724398970603943e-01 4.5027199387550354e-01 <_> 0 -1 2504 3.9799001067876816e-02 -4.7011101245880127e-01 4.2702499032020569e-01 <_> 0 -1 2505 -4.8409998416900635e-03 2.5614300370216370e-01 -6.6556298732757568e-01 <_> 0 -1 2506 2.3439999204128981e-03 -4.8083499073982239e-01 2.8013798594474792e-01 <_> 0 -1 2507 2.5312999263405800e-02 -2.3948200047016144e-01 4.4191798567771912e-01 <_> 0 -1 2508 -3.2193001359701157e-02 7.6086699962615967e-01 -2.5059100985527039e-01 <_> 0 -1 2509 7.5409002602100372e-02 -3.4974598884582520e-01 3.4380298852920532e-01 <_> 0 -1 2510 -1.8469000235199928e-02 -7.9085600376129150e-01 3.4788001328706741e-02 <_> 0 -1 2511 -1.2802000157535076e-02 4.7107800841331482e-01 -6.0006000101566315e-02 <_> 0 -1 2512 -2.6598000898957253e-02 6.7116099596023560e-01 -2.4257500469684601e-01 <_> 0 -1 2513 2.1988999098539352e-02 2.4717499315738678e-01 -4.8301699757575989e-01 <_> 0 -1 2514 1.4654099941253662e-01 -2.1504099667072296e-01 7.2055900096893311e-01 <_> 0 -1 2515 3.5310001112520695e-03 2.7930998802185059e-01 -3.4339898824691772e-01 <_> 0 -1 2516 9.4010001048445702e-03 5.5861998349428177e-02 -8.2143598794937134e-01 <_> 0 -1 2517 -8.6390003561973572e-03 -9.9620598554611206e-01 1.8874999880790710e-01 <_> 0 -1 2518 -3.9193000644445419e-02 -1.1945559978485107e+00 -2.9198000207543373e-02 <_> 0 -1 2519 2.4855000898241997e-02 1.4987599849700928e-01 -5.4137802124023438e-01 <_> 0 -1 2520 -3.4995000809431076e-02 -1.4210180044174194e+00 -4.2314000427722931e-02 <_> 0 -1 2521 -1.8378999084234238e-02 -2.8242599964141846e-01 1.5581800043582916e-01 <_> 0 -1 2522 -1.3592000119388103e-02 4.7317099571228027e-01 -2.1937200427055359e-01 <_> 0 -1 2523 6.2629999592900276e-03 -5.9714000672101974e-02 6.0625898838043213e-01 <_> 0 -1 2524 -1.8478000536561012e-02 -8.5647201538085938e-01 -1.3783999718725681e-02 <_> 0 -1 2525 1.4236000366508961e-02 1.6654799878597260e-01 -2.7713999152183533e-01 <_> 0 -1 2526 -3.2547000795602798e-02 -1.1728240251541138e+00 -4.0185000747442245e-02 <_> 0 -1 2527 -2.6410000864416361e-03 2.6514300704002380e-01 -5.6343000382184982e-02 <_> 0 -1 2528 -8.7799999164417386e-04 3.6556001752614975e-02 -5.5075198411941528e-01 <_> 0 -1 2529 4.7371998429298401e-02 -4.2614001780748367e-02 4.8194900155067444e-01 <_> 0 -1 2530 -7.0790001191198826e-03 2.8698998689651489e-01 -3.2923001050949097e-01 <_> 0 -1 2531 -4.3145999312400818e-02 -1.4065419435501099e+00 1.2836399674415588e-01 <_> 0 -1 2532 2.0592000335454941e-02 -2.1435299515724182e-01 5.3981798887252808e-01 <_> 0 -1 2533 -2.2367000579833984e-02 3.3718299865722656e-01 4.5212000608444214e-02 <_> 0 -1 2534 5.0039999186992645e-02 -2.5121700763702393e-01 4.1750499606132507e-01 <_> 0 -1 2535 6.1794999986886978e-02 4.0084999054670334e-02 6.8779802322387695e-01 <_> 0 -1 2536 -4.1861999779939651e-02 5.3027397394180298e-01 -2.2901999950408936e-01 <_> 0 -1 2537 -3.1959998887032270e-03 2.5161498785018921e-01 -2.1514600515365601e-01 <_> 0 -1 2538 2.4255000054836273e-02 7.2320001199841499e-03 -7.2519099712371826e-01 <_> 0 -1 2539 -1.7303999513387680e-02 -4.9958199262619019e-01 1.8394500017166138e-01 <_> 0 -1 2540 -4.1470001451671124e-03 8.5211999714374542e-02 -4.6364700794219971e-01 <_> 0 -1 2541 -1.4369999989867210e-02 -5.2258902788162231e-01 2.3892599344253540e-01 <_> 0 -1 2542 -9.0399999171495438e-03 -6.3250398635864258e-01 3.2551001757383347e-02 <_> 0 -1 2543 -1.2373100221157074e-01 1.2856210470199585e+00 7.6545000076293945e-02 <_> 0 -1 2544 -8.2221999764442444e-02 8.3208197355270386e-01 -1.8590599298477173e-01 <_> 0 -1 2545 6.5659001469612122e-02 1.1298800259828568e-01 -30. <_> 0 -1 2546 -3.1582999974489212e-02 -1.3485900163650513e+00 -4.7097001224756241e-02 <_> 0 -1 2547 -7.9636000096797943e-02 -1.3533639907836914e+00 1.5668800473213196e-01 <_> 0 -1 2548 -1.8880000337958336e-02 4.0300300717353821e-01 -2.5148901343345642e-01 <_> 0 -1 2549 -5.0149997696280479e-03 -2.6287099719047546e-01 1.8582500517368317e-01 <_> 0 -1 2550 -1.2218000367283821e-02 5.8692401647567749e-01 -1.9427700340747833e-01 <_> 0 -1 2551 1.2710000155493617e-03 -1.6688999533653259e-01 2.3006899654865265e-01 <_> 0 -1 2552 2.9743999242782593e-02 1.2520000338554382e-02 -6.6723597049713135e-01 <_> 0 -1 2553 2.8175000101327896e-02 -1.7060000449419022e-02 6.4579397439956665e-01 <_> 0 -1 2554 3.0345000326633453e-02 -2.4178700149059296e-01 3.4878900647163391e-01 <_> 0 -1 2555 -1.7325999215245247e-02 -5.3599399328231812e-01 2.0995999872684479e-01 <_> 0 -1 2556 -8.4178000688552856e-02 7.5093299150466919e-01 -1.7593200504779816e-01 <_> 0 -1 2557 7.4950000271201134e-03 -1.6188099980354309e-01 3.0657500028610229e-01 <_> 0 -1 2558 5.6494999676942825e-02 -1.7318800091743469e-01 1.0016150474548340e+00 <_> 0 -1 2559 -5.2939997985959053e-03 2.3417599499225616e-01 -6.5347000956535339e-02 <_> 0 -1 2560 -1.4945000410079956e-02 2.5018900632858276e-01 -3.0591198801994324e-01 <_> 0 -1 2561 5.4919000715017319e-02 1.3121999800205231e-01 -9.3765097856521606e-01 <_> 0 -1 2562 -1.9721999764442444e-02 -8.3978497982025146e-01 -2.3473000153899193e-02 <_> 0 -1 2563 -6.7158997058868408e-02 2.3586840629577637e+00 8.2970999181270599e-02 <_> 0 -1 2564 -1.4325999654829502e-02 1.8814499676227570e-01 -3.1221601366996765e-01 <_> 0 -1 2565 2.9841000214219093e-02 1.4825099706649780e-01 -8.4681701660156250e-01 <_> 0 -1 2566 5.1883000880479813e-02 -4.3731000274419785e-02 -1.3366169929504395e+00 <_> 0 -1 2567 4.1127000004053116e-02 1.7660099267959595e-01 -6.0904097557067871e-01 <_> 0 -1 2568 -1.2865099310874939e-01 -9.8701000213623047e-01 -3.7785001099109650e-02 <_> 0 -1 2569 2.4170000106096268e-03 -1.6119599342346191e-01 3.2675701379776001e-01 <_> 0 -1 2570 7.7030002139508724e-03 -2.3841500282287598e-01 2.9319399595260620e-01 <_> 0 -1 2571 4.5520000159740448e-02 1.4424599707126617e-01 -1.5010160207748413e+00 <_> 0 -1 2572 -7.8700996935367584e-02 -1.0394560098648071e+00 -4.5375999063253403e-02 <_> 0 -1 2573 7.8619997948408127e-03 1.9633600115776062e-01 -1.4472399652004242e-01 <_> 0 -1 2574 -1.3458999805152416e-02 -9.0634697675704956e-01 -3.8049001246690750e-02 <_> 0 -1 2575 2.8827000409364700e-02 -2.9473999515175819e-02 6.0058397054672241e-01 <_> 0 -1 2576 -2.7365999296307564e-02 -9.9804002046585083e-01 -3.8653001189231873e-02 <_> 0 -1 2577 -7.2917997837066650e-02 7.3361498117446899e-01 5.7440001517534256e-02 <_> 0 -1 2578 -1.3988999649882317e-02 2.7892601490020752e-01 -2.6516300439834595e-01 <_> 0 -1 2579 4.3242998421192169e-02 4.7760000452399254e-03 3.5925900936126709e-01 <_> 0 -1 2580 2.9533000662922859e-02 -2.0083999633789062e-01 5.1202899217605591e-01 <_> 0 -1 2581 -3.1897000968456268e-02 6.4721697568893433e-01 -1.3760000001639128e-03 <_> 0 -1 2582 3.7868998944759369e-02 -1.8363800644874573e-01 6.1343097686767578e-01 <_> 0 -1 2583 -2.2417999804019928e-02 -2.9187899827957153e-01 1.8194800615310669e-01 <_> 0 -1 2584 5.8958999812602997e-02 -6.6451996564865112e-02 -1.9290030002593994e+00 <_> 0 -1 2585 3.1222999095916748e-02 -1.2732000090181828e-02 6.1560797691345215e-01 <_> 0 -1 2586 3.7484999746084213e-02 -2.0856900513172150e-01 4.4363999366760254e-01 <_> 0 -1 2587 -2.0966000854969025e-02 -3.5712799429893494e-01 2.4252200126647949e-01 <_> 0 -1 2588 -2.5477999821305275e-02 1.0846560001373291e+00 -1.5054400265216827e-01 <_> 0 -1 2589 -7.2570000775158405e-03 2.1302600204944611e-01 -1.8308199942111969e-01 <_> 0 -1 2590 -5.0983000546693802e-02 5.1736801862716675e-01 -1.8833099305629730e-01 <_> 0 -1 2591 -2.0640000700950623e-02 -4.4030201435089111e-01 2.2745999693870544e-01 <_> 0 -1 2592 1.0672999545931816e-02 3.5059999674558640e-02 -5.1665002107620239e-01 <_> 0 -1 2593 3.1895998865365982e-02 1.3228000141680241e-02 3.4915199875831604e-01 <_> 0 -1 2594 -2.3824999108910561e-02 3.4118801355361938e-01 -2.1510200202465057e-01 <_> 0 -1 2595 -6.0680001042783260e-03 3.2937398552894592e-01 -2.8523799777030945e-01 <_> 0 -1 2596 2.3881999775767326e-02 -2.5333800911903381e-01 2.6296100020408630e-01 <_> 0 -1 2597 2.7966000139713287e-02 1.4049099385738373e-01 -4.9887099862098694e-01 <_> 0 -1 2598 1.4603000134229660e-02 -1.5395999886095524e-02 -7.6958000659942627e-01 <_> 0 -1 2599 1.0872399806976318e-01 1.9069600105285645e-01 -3.2393100857734680e-01 <_> 0 -1 2600 -1.4038000255823135e-02 3.4924700856208801e-01 -2.2358700633049011e-01 <_> 0 -1 2601 4.0440000593662262e-03 -3.8329001516103745e-02 5.1177299022674561e-01 <_> 0 -1 2602 -4.9769999459385872e-03 -4.2888298630714417e-01 4.9173999577760696e-02 <_> 0 -1 2603 -8.5183002054691315e-02 6.6624599695205688e-01 7.8079998493194580e-03 <_> 0 -1 2604 2.1559998858720064e-03 -4.9135199189186096e-01 6.9555997848510742e-02 <_> 0 -1 2605 3.6384499073028564e-01 1.2997099757194519e-01 -1.8949509859085083e+00 <_> 0 -1 2606 2.2082500159740448e-01 -5.7211998850107193e-02 -1.4281120300292969e+00 <_> 0 -1 2607 -1.6140000894665718e-02 -5.7589399814605713e-01 1.8062500655651093e-01 <_> 0 -1 2608 -4.8330001533031464e-02 9.7308498620986938e-01 -1.6513000428676605e-01 <_> 0 -1 2609 1.7529999837279320e-02 1.7932699620723724e-01 -2.7948901057243347e-01 <_> 0 -1 2610 -3.4309998154640198e-02 -8.1072497367858887e-01 -1.6596000641584396e-02 <_> 0 -1 2611 -4.5830002054572105e-03 2.7908998727798462e-01 -7.4519999325275421e-03 <_> 0 -1 2612 1.2896400690078735e-01 -1.3508500158786774e-01 2.5411539077758789e+00 <_> 0 -1 2613 3.0361000448465347e-02 -6.8419001996517181e-02 2.8734099864959717e-01 <_> 0 -1 2614 4.4086001813411713e-02 -1.8135899305343628e-01 6.5413200855255127e-01 <_> 0 -1 2615 3.0159999150782824e-03 -1.5690499544143677e-01 2.6963800191879272e-01 <_> 0 -1 2616 -2.6336999610066414e-02 2.9175600409507751e-01 -2.5274100899696350e-01 <_> 0 -1 2617 -2.7866000309586525e-02 4.4387501478195190e-01 5.5038001388311386e-02 <_> 0 -1 2618 1.1725000105798244e-02 -1.9346499443054199e-01 4.6656700968742371e-01 <_> 0 -1 2619 1.5689999563619494e-03 -8.2360003143548965e-03 2.5700899958610535e-01 <_> 0 -1 2620 -3.5550000611692667e-03 -4.2430898547172546e-01 7.1174003183841705e-02 <_> 0 -1 2621 -3.1695000827312469e-02 -8.5393500328063965e-01 1.6916200518608093e-01 <_> 0 -1 2622 -3.2097000628709793e-02 8.3784902095794678e-01 -1.7597299814224243e-01 <_> 0 -1 2623 1.5544199943542480e-01 9.9550001323223114e-02 2.3873300552368164e+00 <_> 0 -1 2624 8.8045999407768250e-02 -1.8725299835205078e-01 6.2384301424026489e-01 <_> 0 -1 2625 -1.6720000421628356e-03 2.5008699297904968e-01 -6.5118998289108276e-02 <_> 0 -1 2626 9.3409996479749680e-03 -3.5378900170326233e-01 1.0715000331401825e-01 <_> 0 -1 2627 3.7138000130653381e-02 1.6387000679969788e-01 -9.1718399524688721e-01 <_> 0 -1 2628 8.0183997750282288e-02 -1.4812999963760376e-01 1.4895190000534058e+00 <_> 0 -1 2629 -7.9100002767518163e-04 -2.1326899528503418e-01 1.9676400721073151e-01 <_> 0 -1 2630 -5.0400001928210258e-03 -7.1318697929382324e-01 1.8240000354126096e-03 <_> 0 -1 2631 1.1962399631738663e-01 3.3098999410867691e-02 1.0441709756851196e+00 <_> 0 -1 2632 -4.5280000194907188e-03 -2.7308499813079834e-01 2.7229800820350647e-01 <_> 0 -1 2633 -2.9639000073075294e-02 3.6225798726081848e-01 5.6795001029968262e-02 <_> 0 -1 2634 2.6650000363588333e-02 -4.8041000962257385e-02 -9.6723502874374390e-01 <_> 0 -1 2635 4.4422000646591187e-02 1.3052900135517120e-01 -3.5077300667762756e-01 <_> 0 -1 2636 -2.4359999224543571e-02 -1.0766899585723877e+00 -5.1222998648881912e-02 <_> 0 -1 2637 1.9734999164938927e-02 2.6238000020384789e-02 2.8070500493049622e-01 <_> 0 -1 2638 5.4930001497268677e-03 -2.6111298799514771e-01 2.1011400222778320e-01 <_> 0 -1 2639 -2.3200300335884094e-01 -1.7748440504074097e+00 1.1482600122690201e-01 <_> 0 -1 2640 -2.5614000856876373e-02 2.9900801181793213e-01 -2.2502499818801880e-01 <_> 0 -1 2641 -6.4949998632073402e-03 1.9563800096511841e-01 -9.9762998521327972e-02 <_> 0 -1 2642 3.9840000681579113e-03 -4.3021500110626221e-01 8.1261001527309418e-02 <_> 0 -1 2643 -3.5813000053167343e-02 -5.0987398624420166e-01 1.6345900297164917e-01 <_> 0 -1 2644 -1.4169000089168549e-02 7.7978098392486572e-01 -1.7476299405097961e-01 <_> 0 -1 2645 -1.2642100453376770e-01 -6.3047897815704346e-01 1.2728300690650940e-01 <_> 0 -1 2646 6.8677999079227448e-02 -4.6447999775409698e-02 -1.1128979921340942e+00 <_> 0 -1 2647 8.5864998400211334e-02 1.1835400015115738e-01 -4.8235158920288086e+00 <_> 0 -1 2648 1.5511999838054180e-02 -1.7467999830842018e-02 -6.3693398237228394e-01 <_> 0 -1 2649 8.1091001629829407e-02 8.6133003234863281e-02 2.4559431076049805e+00 <_> 0 -1 2650 1.8495000898838043e-02 4.0229000151157379e-02 -5.0858199596405029e-01 <_> 0 -1 2651 -8.6320996284484863e-02 -1.9006760120391846e+00 1.1019100248813629e-01 <_> 0 -1 2652 7.2355002164840698e-02 -6.2111999839544296e-02 -1.4165179729461670e+00 <_> 0 -1 2653 -7.8179001808166504e-02 8.8849300146102905e-01 4.2369998991489410e-02 <_> 0 -1 2654 9.6681997179985046e-02 -2.2094200551509857e-01 3.3575099706649780e-01 <_> 0 -1 2655 -3.9875999093055725e-02 5.7804799079895020e-01 4.5347999781370163e-02 <_> 0 -1 2656 -9.5349997282028198e-03 -5.4175698757171631e-01 3.2399999909102917e-03 <_> 0 -1 2657 4.0600000647827983e-04 -8.1549003720283508e-02 3.5837900638580322e-01 <_> 0 -1 2658 1.2107999995350838e-02 -2.0280399918556213e-01 4.3768000602722168e-01 <_> 0 -1 2659 -2.0873999223113060e-02 4.1469898819923401e-01 -4.5568000525236130e-02 <_> 0 -1 2660 5.7888001203536987e-02 -2.9009999707341194e-02 -9.1822302341461182e-01 <_> 0 -1 2661 1.3200000103097409e-04 -1.1772400140762329e-01 2.0000000298023224e-01 <_> 0 -1 2662 -1.7137000337243080e-02 3.3004799485206604e-01 -2.3055200278759003e-01 <_> 0 -1 2663 3.0655000358819962e-02 -2.1545000374317169e-02 2.6878198981285095e-01 <_> 0 -1 2664 -7.8699999721720815e-04 -4.4100698828697205e-01 4.9157999455928802e-02 <_> 0 -1 2665 8.8036999106407166e-02 1.1782000213861465e-01 -2.8293309211730957e+00 <_> 0 -1 2666 -3.9028998464345932e-02 9.1777199506759644e-01 -1.5827399492263794e-01 <_> 0 -1 2667 8.0105997622013092e-02 1.1289200186729431e-01 -1.9937280416488647e+00 <_> 0 -1 2668 3.9538998156785965e-02 -1.4357399940490723e-01 1.3085240125656128e+00 <_> 0 -1 2669 2.0684000104665756e-02 2.0048099756240845e-01 -4.4186998158693314e-02 <_> 0 -1 2670 -6.7037999629974365e-02 3.2618600130081177e-01 -2.0550400018692017e-01 <_> 0 -1 2671 4.6815000474452972e-02 1.5825299918651581e-01 -9.5535099506378174e-01 <_> 0 -1 2672 7.8443996608257294e-02 -7.4651002883911133e-02 -2.1161499023437500e+00 <_> 0 -1 2673 6.6380001604557037e-02 1.1641900241374969e-01 -1.6113519668579102e+00 <_> 0 -1 2674 3.0053999274969101e-02 -1.6562600433826447e-01 7.0025402307510376e-01 <_> 0 -1 2675 1.7119999974966049e-02 2.2627699375152588e-01 -4.0114998817443848e-01 <_> 0 -1 2676 2.0073000341653824e-02 -1.9389699399471283e-01 4.4420298933982849e-01 <_> 0 -1 2677 3.3101998269557953e-02 1.1637499928474426e-01 -1.5771679878234863e+00 <_> 0 -1 2678 -1.4882000163197517e-02 -8.9680302143096924e-01 -4.2010001838207245e-02 <_> 0 -1 2679 -1.0281000286340714e-02 3.5602998733520508e-01 -1.3124000281095505e-02 <_> 0 -1 2680 -2.8695000335574150e-02 -4.6039599180221558e-01 2.6801999658346176e-02 <_> 0 -1 2681 -4.7189998440444469e-03 2.3788799345493317e-01 -6.5518997609615326e-02 <_> 0 -1 2682 3.2201600074768066e-01 -2.8489999473094940e-02 -8.4234601259231567e-01 <_> 0 -1 2683 -1.7045000568032265e-02 -5.0938802957534790e-01 1.6057600080966949e-01 <_> 0 -1 2684 -7.3469998314976692e-03 -5.4154998064041138e-01 4.7320001758635044e-03 <_> 0 -1 2685 -3.0001999810338020e-02 -8.8785797357559204e-01 1.3621799647808075e-01 <_> 0 -1 2686 -1.1292999610304832e-02 8.0615198612213135e-01 -1.6159500181674957e-01 <_> 0 -1 2687 4.7749998047947884e-03 1.2968000024557114e-02 5.5079901218414307e-01 <_> 0 -1 2688 5.0710001960396767e-03 -4.5728001743555069e-02 -1.0766259431838989e+00 <_> 0 -1 2689 1.9344100356101990e-01 7.1262001991271973e-02 1.1694519519805908e+00 <_> 0 -1 2690 5.3750001825392246e-03 -1.9736200571060181e-01 3.8206899166107178e-01 <_> 0 -1 2691 -6.8276003003120422e-02 -5.4372339248657227e+00 1.1151900142431259e-01 <_> 0 -1 2692 -3.4933000802993774e-02 4.4793400168418884e-01 -1.8657900393009186e-01 <_> 0 -1 2693 5.1219998858869076e-03 -1.4871999621391296e-02 1.8413899838924408e-01 <_> 0 -1 2694 9.5311999320983887e-02 -1.5117099881172180e-01 9.4991499185562134e-01 <_> 0 -1 2695 -6.2849000096321106e-02 4.6473601460456848e-01 3.8405001163482666e-02 <_> 0 -1 2696 -1.7040699720382690e-01 -1.6499999761581421e+00 -6.3236996531486511e-02 <_> 0 -1 2697 1.0583999566733837e-02 -3.8348998874425888e-02 4.1913801431655884e-01 <_> 0 -1 2698 -4.1579000651836395e-02 3.4461900591850281e-01 -2.1187700331211090e-01 <_> 0 -1 2699 1.2718600034713745e-01 1.2398199737071991e-01 -2.1254889965057373e+00 <_> 0 -1 2700 8.2557000219821930e-02 -6.2024001032114029e-02 -1.4875819683074951e+00 <_> 0 -1 2701 8.5293002426624298e-02 1.7087999731302261e-02 3.2076600193977356e-01 <_> 0 -1 2702 5.5544000118970871e-02 -2.7414000034332275e-01 1.8976399302482605e-01 <_> 0 -1 2703 4.5650000683963299e-03 -1.7920200526714325e-01 2.7967301011085510e-01 <_> 0 -1 2704 1.2997999787330627e-02 -3.2297500967979431e-01 2.6941800117492676e-01 <_> 0 -1 2705 5.7891998440027237e-02 1.2644399702548981e-01 -6.0713499784469604e-01 <_> 0 -1 2706 -2.2824000567197800e-02 -4.9682098627090454e-01 2.2376999258995056e-02 <_> 0 -1 2707 4.8312000930309296e-02 4.3607000261545181e-02 4.8537799715995789e-01 <_> 0 -1 2708 2.5714000687003136e-02 -4.2950998991727829e-02 -9.3023502826690674e-01 <_> 0 -1 2709 6.9269998930394650e-03 -2.9680000152438879e-03 3.4296301007270813e-01 <_> 0 -1 2710 -3.4446999430656433e-02 -1.5299769639968872e+00 -6.1014998704195023e-02 <_> 0 -1 2711 2.9387999325990677e-02 3.7595998495817184e-02 6.4172399044036865e-01 <_> 0 -1 2712 -2.4319998919963837e-03 9.9088996648788452e-02 -3.9688101410865784e-01 <_> 200 -2.9928278923034668e+00 <_> 0 -1 2713 -9.5944002270698547e-02 6.2419098615646362e-01 -4.5875200629234314e-01 <_> 0 -1 2714 1.6834000125527382e-02 -9.3072801828384399e-01 2.1563600003719330e-01 <_> 0 -1 2715 2.6049999520182610e-02 -4.0532299876213074e-01 4.2256599664688110e-01 <_> 0 -1 2716 3.6500001442618668e-04 9.5288001000881195e-02 -6.3298100233078003e-01 <_> 0 -1 2717 -6.6940002143383026e-03 3.7243801355361938e-01 -3.0332401394844055e-01 <_> 0 -1 2718 1.8874000757932663e-02 -2.3357200622558594e-01 4.0330699086189270e-01 <_> 0 -1 2719 -1.6300000424962491e-04 4.2886998504400253e-02 -7.7796798944473267e-01 <_> 0 -1 2720 -7.6259002089500427e-02 -4.9628499150276184e-01 1.6335399448871613e-01 <_> 0 -1 2721 5.0149001181125641e-02 3.2747000455856323e-02 -8.0047899484634399e-01 <_> 0 -1 2722 -2.9239999130368233e-03 -5.0002801418304443e-01 2.5480601191520691e-01 <_> 0 -1 2723 1.6243999823927879e-02 3.8913000375032425e-02 -7.0724898576736450e-01 <_> 0 -1 2724 3.7811998277902603e-02 -6.6267997026443481e-02 7.3868799209594727e-01 <_> 0 -1 2725 -1.2319999746978283e-02 4.8696398735046387e-01 -2.4485599994659424e-01 <_> 0 -1 2726 5.8003999292850494e-02 1.3459099829196930e-01 -1.3232100009918213e-01 <_> 0 -1 2727 4.8630000092089176e-03 -4.4172900915145874e-01 1.4005599915981293e-01 <_> 0 -1 2728 4.5690998435020447e-02 3.1217999756336212e-02 8.9818298816680908e-01 <_> 0 -1 2729 2.1321000531315804e-02 1.2008000165224075e-02 -8.6066198348999023e-01 <_> 0 -1 2730 1.5679100155830383e-01 1.4055999927222729e-02 8.5332900285720825e-01 <_> 0 -1 2731 -1.0328999720513821e-02 2.9022800922393799e-01 -2.9478800296783447e-01 <_> 0 -1 2732 2.4290001019835472e-03 -4.0439900755882263e-01 1.9400200247764587e-01 <_> 0 -1 2733 -2.3338999599218369e-02 3.2945200800895691e-01 -2.5712698698043823e-01 <_> 0 -1 2734 -6.8970001302659512e-03 -5.3352999687194824e-01 2.1635200083255768e-01 <_> 0 -1 2735 -3.4403000026941299e-02 -1.4425489902496338e+00 -4.4682998210191727e-02 <_> 0 -1 2736 -2.1235000342130661e-02 -7.9017502069473267e-01 1.9084100425243378e-01 <_> 0 -1 2737 2.0620001014322042e-03 -2.6931199431419373e-01 3.1488001346588135e-01 <_> 0 -1 2738 -4.2190002277493477e-03 -5.4464399814605713e-01 1.6574600338935852e-01 <_> 0 -1 2739 -1.4334999956190586e-02 2.2105000913143158e-02 -6.2342500686645508e-01 <_> 0 -1 2740 -8.2120001316070557e-03 -4.9884998798370361e-01 1.9237099587917328e-01 <_> 0 -1 2741 -9.3350000679492950e-03 -7.9131197929382324e-01 -1.4143999665975571e-02 <_> 0 -1 2742 -3.7937998771667480e-02 7.9841297864913940e-01 -3.3799000084400177e-02 <_> 0 -1 2743 4.7059999778866768e-03 -3.3163401484489441e-01 2.0726299285888672e-01 <_> 0 -1 2744 -4.4499998912215233e-03 -2.7256301045417786e-01 1.8402199447154999e-01 <_> 0 -1 2745 5.2189999260008335e-03 -5.3096002340316772e-01 5.2607998251914978e-02 <_> 0 -1 2746 -9.5399999991059303e-03 -5.6485402584075928e-01 1.9269399344921112e-01 <_> 0 -1 2747 4.4969998300075531e-02 -1.7411500215530396e-01 9.5382601022720337e-01 <_> 0 -1 2748 1.4209000393748283e-02 -9.1949000954627991e-02 2.4836100637912750e-01 <_> 0 -1 2749 1.6380199790000916e-01 -5.8497000485658646e-02 -1.6404409408569336e+00 <_> 0 -1 2750 2.5579999200999737e-03 2.3447999358177185e-01 -9.2734001576900482e-02 <_> 0 -1 2751 -3.8499999791383743e-03 1.7880700528621674e-01 -3.5844099521636963e-01 <_> 0 -1 2752 -2.5221999734640121e-02 -4.2903000116348267e-01 2.0244500041007996e-01 <_> 0 -1 2753 -1.9415000453591347e-02 5.8016300201416016e-01 -1.8806399405002594e-01 <_> 0 -1 2754 1.4419999904930592e-02 3.2846998423337936e-02 8.1980502605438232e-01 <_> 0 -1 2755 5.1582999527454376e-02 6.9176003336906433e-02 -4.5866298675537109e-01 <_> 0 -1 2756 -3.7960000336170197e-02 -1.2553000450134277e+00 1.4332899451255798e-01 <_> 0 -1 2757 -2.9560999944806099e-02 5.3151798248291016e-01 -2.0596499741077423e-01 <_> 0 -1 2758 -3.9110999554395676e-02 1.1658719778060913e+00 5.3897000849246979e-02 <_> 0 -1 2759 -2.9159000143408775e-02 3.9307600259780884e-01 -2.2184500098228455e-01 <_> 0 -1 2760 -8.3617001771926880e-02 -7.3744499683380127e-01 1.4268200099468231e-01 <_> 0 -1 2761 4.2004001140594482e-01 -1.4277400076389313e-01 1.7894840240478516e+00 <_> 0 -1 2762 6.0005001723766327e-02 1.1976700276136398e-01 -1.8886189460754395e+00 <_> 0 -1 2763 -1.8981000408530235e-02 -1.4148449897766113e+00 -5.6522998958826065e-02 <_> 0 -1 2764 -6.0049998573958874e-03 4.4170799851417542e-01 -1.0200800001621246e-01 <_> 0 -1 2765 -5.8214001357555389e-02 -1.3918470144271851e+00 -4.8268999904394150e-02 <_> 0 -1 2766 -1.2271000072360039e-02 5.1317697763442993e-01 -9.3696996569633484e-02 <_> 0 -1 2767 4.6585999429225922e-02 -5.7484000921249390e-02 -1.4283169507980347e+00 <_> 0 -1 2768 1.2110000243410468e-03 -8.0891996622085571e-02 3.2333201169967651e-01 <_> 0 -1 2769 -8.8642001152038574e-02 -8.6449098587036133e-01 -3.3146999776363373e-02 <_> 0 -1 2770 -2.3184999823570251e-02 5.2162200212478638e-01 -1.6168000176548958e-02 <_> 0 -1 2771 4.3090000748634338e-02 -1.6153800487518311e-01 1.0915000438690186e+00 <_> 0 -1 2772 2.0599999697878957e-04 -1.7091499269008636e-01 3.1236699223518372e-01 <_> 0 -1 2773 8.9159999042749405e-03 -6.7039998248219490e-03 -6.8810397386550903e-01 <_> 0 -1 2774 -1.7752999439835548e-02 6.3292801380157471e-01 -4.2360001243650913e-03 <_> 0 -1 2775 6.2299999408423901e-03 -3.3637198805809021e-01 1.2790599465370178e-01 <_> 0 -1 2776 2.2770000621676445e-02 -3.4703999757766724e-02 3.9141800999641418e-01 <_> 0 -1 2777 -2.1534999832510948e-02 6.4765101671218872e-01 -2.0097799599170685e-01 <_> 0 -1 2778 6.1758998781442642e-02 5.4297000169754028e-02 9.0700101852416992e-01 <_> 0 -1 2779 -7.8069999814033508e-02 6.5523397922515869e-01 -1.9754399359226227e-01 <_> 0 -1 2780 1.1315000243484974e-02 1.9385300576686859e-01 -5.1707297563552856e-01 <_> 0 -1 2781 -2.5590000674128532e-02 -9.3096500635147095e-01 -3.1546998769044876e-02 <_> 0 -1 2782 -3.8058999925851822e-02 -6.8326902389526367e-01 1.2709100544452667e-01 <_> 0 -1 2783 9.7970003262162209e-03 1.5523999929428101e-02 -6.3347899913787842e-01 <_> 0 -1 2784 -1.3841999694705009e-02 1.0060529708862305e+00 6.2812998890876770e-02 <_> 0 -1 2785 8.3459997549653053e-03 -2.3383200168609619e-01 3.0982699990272522e-01 <_> 0 -1 2786 -7.1439996361732483e-02 -7.2505402565002441e-01 1.7148299515247345e-01 <_> 0 -1 2787 1.0006000287830830e-02 -2.2071999311447144e-01 3.5266199707984924e-01 <_> 0 -1 2788 1.1005300283432007e-01 1.6662000119686127e-01 -7.4318999052047729e-01 <_> 0 -1 2789 3.5310998558998108e-02 -2.3982700705528259e-01 4.1435998678207397e-01 <_> 0 -1 2790 -1.1174699664115906e-01 5.1045399904251099e-01 2.2319999989122152e-03 <_> 0 -1 2791 -1.1367800086736679e-01 9.0475201606750488e-01 -1.6615299880504608e-01 <_> 0 -1 2792 1.6667999327182770e-02 1.4024500548839569e-01 -5.2178502082824707e-01 <_> 0 -1 2793 -8.0340001732110977e-03 -6.6178399324417114e-01 3.7640000227838755e-03 <_> 0 -1 2794 -3.3096998929977417e-02 8.0185902118682861e-01 5.9385001659393311e-02 <_> 0 -1 2795 1.2547999620437622e-02 -3.3545500040054321e-01 1.4578600227832794e-01 <_> 0 -1 2796 -4.2073998600244522e-02 -5.5509102344512939e-01 1.3266600668430328e-01 <_> 0 -1 2797 2.5221999734640121e-02 -6.1631999909877777e-02 -1.3678770065307617e+00 <_> 0 -1 2798 -2.4268999695777893e-02 3.4185099601745605e-01 -7.4160001240670681e-03 <_> 0 -1 2799 -1.2280000373721123e-02 2.7745801210403442e-01 -3.1033900380134583e-01 <_> 0 -1 2800 -1.1377099901437759e-01 1.1719540357589722e+00 8.3681002259254456e-02 <_> 0 -1 2801 -8.4771998226642609e-02 8.1694799661636353e-01 -1.7837500572204590e-01 <_> 0 -1 2802 -2.4552000686526299e-02 -1.8627299368381500e-01 1.4340099692344666e-01 <_> 0 -1 2803 -9.0269995853304863e-03 3.2659199833869934e-01 -2.3541299998760223e-01 <_> 0 -1 2804 1.1177999898791313e-02 1.9761200249195099e-01 -2.1701000630855560e-02 <_> 0 -1 2805 -2.9366999864578247e-02 -9.3414801359176636e-01 -2.1704999729990959e-02 <_> 0 -1 2806 6.3640000298619270e-03 2.5573000311851501e-02 4.6412798762321472e-01 <_> 0 -1 2807 1.4026000164449215e-02 -2.1228599548339844e-01 4.0078800916671753e-01 <_> 0 -1 2808 -1.3341999612748623e-02 7.4202698469161987e-01 2.9001999646425247e-02 <_> 0 -1 2809 2.8422799706459045e-01 -1.9243599474430084e-01 4.3631199002265930e-01 <_> 0 -1 2810 -2.3724000155925751e-01 6.9736397266387939e-01 6.9307997822761536e-02 <_> 0 -1 2811 -1.1169700324535370e-01 3.9147201180458069e-01 -2.0922000706195831e-01 <_> 0 -1 2812 1.2787500023841858e-01 -7.2555996477603912e-02 3.6088201403617859e-01 <_> 0 -1 2813 -6.2900997698307037e-02 9.5424997806549072e-01 -1.5402799844741821e-01 <_> 0 -1 2814 1.7439000308513641e-02 -5.1134999841451645e-02 2.7750301361083984e-01 <_> 0 -1 2815 1.2319999514147639e-03 7.5627997517585754e-02 -3.6456099152565002e-01 <_> 0 -1 2816 2.7495000511407852e-02 5.1844000816345215e-02 4.1562598943710327e-01 <_> 0 -1 2817 -4.3543998152017593e-02 7.1969997882843018e-01 -1.7132200300693512e-01 <_> 0 -1 2818 1.1025999672710896e-02 1.4354600012302399e-01 -6.5403002500534058e-01 <_> 0 -1 2819 2.0865999162197113e-02 4.0089000016450882e-02 -4.5743298530578613e-01 <_> 0 -1 2820 -2.2304000332951546e-02 5.3855001926422119e-01 7.1662999689579010e-02 <_> 0 -1 2821 3.2492000609636307e-02 -4.5991998165845871e-02 -1.0047069787979126e+00 <_> 0 -1 2822 1.2269999831914902e-02 3.4334998577833176e-02 4.2431798577308655e-01 <_> 0 -1 2823 8.3820000290870667e-03 -2.5850600004196167e-01 2.6263499259948730e-01 <_> 0 -1 2824 3.7353999912738800e-02 1.5692499279975891e-01 -1.0429090261459351e+00 <_> 0 -1 2825 -1.4111000113189220e-02 -7.3177701234817505e-01 -2.0276999101042747e-02 <_> 0 -1 2826 5.7066999375820160e-02 8.3360001444816589e-02 1.5661499500274658e+00 <_> 0 -1 2827 4.9680001102387905e-03 -3.5318198800086975e-01 1.4698399603366852e-01 <_> 0 -1 2828 -2.4492999538779259e-02 2.8325900435447693e-01 -3.4640000667423010e-03 <_> 0 -1 2829 -1.1254999786615372e-02 -8.4017497301101685e-01 -3.6251999437808990e-02 <_> 0 -1 2830 3.4533001482486725e-02 1.4998500049114227e-01 -8.7367099523544312e-01 <_> 0 -1 2831 2.4303000420331955e-02 -1.8787500262260437e-01 5.9483999013900757e-01 <_> 0 -1 2832 -7.8790001571178436e-03 4.4315698742866516e-01 -5.6570999324321747e-02 <_> 0 -1 2833 3.5142000764608383e-02 -5.6494999676942825e-02 -1.3617190122604370e+00 <_> 0 -1 2834 4.6259998343884945e-03 -3.1161698698997498e-01 2.5447699427604675e-01 <_> 0 -1 2835 -8.3131000399589539e-02 1.6424349546432495e+00 -1.4429399371147156e-01 <_> 0 -1 2836 -1.4015999622642994e-02 -7.7819502353668213e-01 1.7173300683498383e-01 <_> 0 -1 2837 1.2450000504031777e-03 -2.3191399872303009e-01 2.8527900576591492e-01 <_> 0 -1 2838 -1.6803000122308731e-02 -3.5965099930763245e-01 2.0412999391555786e-01 <_> 0 -1 2839 -7.6747998595237732e-02 7.8050500154495239e-01 -1.5612800419330597e-01 <_> 0 -1 2840 -2.3671999573707581e-01 1.1813700199127197e+00 7.8111998736858368e-02 <_> 0 -1 2841 -1.0057400166988373e-01 -4.7104099392890930e-01 7.9172998666763306e-02 <_> 0 -1 2842 1.3239999534562230e-03 2.2262699902057648e-01 -3.7099799513816833e-01 <_> 0 -1 2843 2.2152999415993690e-02 -3.8649000227451324e-02 -9.2274999618530273e-01 <_> 0 -1 2844 -1.1246199905872345e-01 4.1899600625038147e-01 8.0411002039909363e-02 <_> 0 -1 2845 1.6481000930070877e-02 -1.6756699979305267e-01 7.1842402219772339e-01 <_> 0 -1 2846 6.8113997578620911e-02 1.5719899535179138e-01 -8.7681102752685547e-01 <_> 0 -1 2847 1.6011999920010567e-02 -4.1600000113248825e-03 -5.9327799081802368e-01 <_> 0 -1 2848 4.6640001237392426e-03 -3.0153999105095863e-02 4.8345300555229187e-01 <_> 0 -1 2849 6.7579997703433037e-03 -2.2667400538921356e-01 3.3662301301956177e-01 <_> 0 -1 2850 4.7289999201893806e-03 -6.0373999178409576e-02 3.1458100676536560e-01 <_> 0 -1 2851 2.5869999080896378e-03 -2.9872599244117737e-01 1.7787499725818634e-01 <_> 0 -1 2852 2.8989999555051327e-03 2.1890200674533844e-01 -2.9567098617553711e-01 <_> 0 -1 2853 -3.0053999274969101e-02 1.2150429487228394e+00 -1.4354999363422394e-01 <_> 0 -1 2854 1.4181000180542469e-02 1.2451999820768833e-02 5.5490100383758545e-01 <_> 0 -1 2855 -6.0527000576257706e-02 -1.4933999776840210e+00 -6.5227001905441284e-02 <_> 0 -1 2856 -1.9882999360561371e-02 -3.8526400923728943e-01 1.9761200249195099e-01 <_> 0 -1 2857 3.1218999996781349e-02 -2.1281200647354126e-01 2.9446500539779663e-01 <_> 0 -1 2858 1.8271999433636665e-02 9.7200000891461968e-04 6.6814202070236206e-01 <_> 0 -1 2859 1.1089999461546540e-03 -6.2467902898788452e-01 -1.6599999507889152e-03 <_> 0 -1 2860 -3.6713998764753342e-02 -4.2333900928497314e-01 1.2084700167179108e-01 <_> 0 -1 2861 1.2044000439345837e-02 2.5882000103592873e-02 -5.0732398033142090e-01 <_> 0 -1 2862 7.4749000370502472e-02 1.3184699416160583e-01 -2.1739600598812103e-01 <_> 0 -1 2863 -2.3473200201988220e-01 1.1775610446929932e+00 -1.5114699304103851e-01 <_> 0 -1 2864 1.4096499979496002e-01 3.3991001546382904e-02 3.9923098683357239e-01 <_> 0 -1 2865 6.1789997853338718e-03 -3.1806701421737671e-01 1.1681699752807617e-01 <_> 0 -1 2866 -5.7216998189687729e-02 8.4399098157882690e-01 8.3889000117778778e-02 <_> 0 -1 2867 -5.5227000266313553e-02 3.6888301372528076e-01 -1.8913400173187256e-01 <_> 0 -1 2868 -2.1583000198006630e-02 -5.2161800861358643e-01 1.5772600471973419e-01 <_> 0 -1 2869 2.5747999548912048e-02 -5.9921998530626297e-02 -1.0674990415573120e+00 <_> 0 -1 2870 -1.3098999857902527e-02 7.8958398103713989e-01 5.2099999040365219e-02 <_> 0 -1 2871 2.2799998987466097e-03 -1.1704430580139160e+00 -5.9356998652219772e-02 <_> 0 -1 2872 8.8060004636645317e-03 4.1717998683452606e-02 6.6352599859237671e-01 <_> 0 -1 2873 -8.9699998497962952e-03 -3.5862699151039124e-01 6.0458000749349594e-02 <_> 0 -1 2874 4.0230001322925091e-03 2.0979399979114532e-01 -2.4806000292301178e-01 <_> 0 -1 2875 2.5017000734806061e-02 -1.8795900046825409e-01 3.9547100663185120e-01 <_> 0 -1 2876 -5.9009999968111515e-03 2.5663900375366211e-01 -9.4919003546237946e-02 <_> 0 -1 2877 4.3850000947713852e-03 3.3139001578092575e-02 -4.6075400710105896e-01 <_> 0 -1 2878 -3.3771999180316925e-02 -9.8881602287292480e-01 1.4636899530887604e-01 <_> 0 -1 2879 4.4523000717163086e-02 -1.3286699354648590e-01 1.5796790122985840e+00 <_> 0 -1 2880 -4.0929000824689865e-02 3.3877098560333252e-01 7.4970997869968414e-02 <_> 0 -1 2881 3.9351999759674072e-02 -1.8327899277210236e-01 4.6980699896812439e-01 <_> 0 -1 2882 -7.0322997868061066e-02 -9.8322701454162598e-01 1.1808100342750549e-01 <_> 0 -1 2883 3.5743001848459244e-02 -3.3050999045372009e-02 -8.3610898256301880e-01 <_> 0 -1 2884 -4.2961999773979187e-02 1.1670809984207153e+00 8.0692000687122345e-02 <_> 0 -1 2885 -2.1007999777793884e-02 6.3869798183441162e-01 -1.7626300454139709e-01 <_> 0 -1 2886 -1.5742200613021851e-01 -2.3302499949932098e-01 1.2517499923706055e-01 <_> 0 -1 2887 7.8659998252987862e-03 -2.2037999331951141e-01 2.7196800708770752e-01 <_> 0 -1 2888 2.3622000589966774e-02 1.6127300262451172e-01 -4.3329000473022461e-01 <_> 0 -1 2889 7.4692003428936005e-02 -1.6991999745368958e-01 5.8884900808334351e-01 <_> 0 -1 2890 -6.4799998654052615e-04 2.5842899084091187e-01 -3.5911999642848969e-02 <_> 0 -1 2891 -1.6290999948978424e-02 -7.6764398813247681e-01 -2.0472999662160873e-02 <_> 0 -1 2892 -3.3133998513221741e-02 -2.7180099487304688e-01 1.4325700700283051e-01 <_> 0 -1 2893 4.8797998577356339e-02 7.6408997178077698e-02 -4.1445198655128479e-01 <_> 0 -1 2894 2.2869999520480633e-03 -3.8628999143838882e-02 2.0753799378871918e-01 <_> 0 -1 2895 4.5304000377655029e-02 -1.7777900397777557e-01 6.3461399078369141e-01 <_> 0 -1 2896 1.0705800354480743e-01 1.8972299993038177e-01 -5.1236200332641602e-01 <_> 0 -1 2897 -4.0525000542402267e-02 7.0614999532699585e-01 -1.7803299427032471e-01 <_> 0 -1 2898 3.1968999654054642e-02 6.8149998784065247e-02 6.8733102083206177e-01 <_> 0 -1 2899 -5.7617001235485077e-02 7.5170499086380005e-01 -1.5764999389648438e-01 <_> 0 -1 2900 1.3593999668955803e-02 1.9411900639533997e-01 -2.4561899900436401e-01 <_> 0 -1 2901 7.1396000683307648e-02 -4.6881001442670822e-02 -8.8198298215866089e-01 <_> 0 -1 2902 -1.4895999804139137e-02 -4.4532400369644165e-01 1.7679899930953979e-01 <_> 0 -1 2903 -1.0026000440120697e-02 6.5122699737548828e-01 -1.6709999740123749e-01 <_> 0 -1 2904 3.7589999847114086e-03 -5.8301001787185669e-02 3.4483298659324646e-01 <_> 0 -1 2905 1.6263000667095184e-02 -1.5581500530242920e-01 8.6432701349258423e-01 <_> 0 -1 2906 -4.0176000446081161e-02 -6.1028599739074707e-01 1.1796399950981140e-01 <_> 0 -1 2907 2.7080999687314034e-02 -4.9601998180150986e-02 -8.9990001916885376e-01 <_> 0 -1 2908 5.2420001477003098e-02 1.1297199875116348e-01 -1.0833640098571777e+00 <_> 0 -1 2909 -1.9160000607371330e-02 -7.9880100488662720e-01 -3.4079000353813171e-02 <_> 0 -1 2910 -3.7730000913143158e-03 -1.9124099612236023e-01 2.1535199880599976e-01 <_> 0 -1 2911 7.5762003660202026e-02 -1.3421699404716492e-01 1.6807060241699219e+00 <_> 0 -1 2912 -2.2173000499606133e-02 4.8600998520851135e-01 3.6160000599920750e-03 <_> <_> 6 4 12 9 -1. <_> 6 7 12 3 3. <_> <_> 6 4 12 7 -1. <_> 10 4 4 7 3. <_> <_> 3 9 18 9 -1. <_> 3 12 18 3 3. <_> <_> 8 18 9 6 -1. <_> 8 20 9 2 3. <_> <_> 3 5 4 19 -1. <_> 5 5 2 19 2. <_> <_> 6 5 12 16 -1. <_> 6 13 12 8 2. <_> <_> 5 8 12 6 -1. <_> 5 11 12 3 2. <_> <_> 11 14 4 10 -1. <_> 11 19 4 5 2. <_> <_> 4 0 7 6 -1. <_> 4 3 7 3 2. <_> <_> 6 6 12 6 -1. <_> 6 8 12 2 3. <_> <_> 6 4 12 7 -1. <_> 10 4 4 7 3. <_> <_> 1 8 19 12 -1. <_> 1 12 19 4 3. <_> <_> 0 2 24 3 -1. <_> 8 2 8 3 3. <_> <_> 9 9 6 15 -1. <_> 9 14 6 5 3. <_> <_> 5 6 14 10 -1. <_> 5 11 14 5 2. <_> <_> 5 0 14 9 -1. <_> 5 3 14 3 3. <_> <_> 13 11 9 6 -1. <_> 16 11 3 6 3. <_> <_> 7 5 6 10 -1. <_> 9 5 2 10 3. <_> <_> 10 8 6 10 -1. <_> 12 8 2 10 3. <_> <_> 2 5 4 9 -1. <_> 4 5 2 9 2. <_> <_> 18 0 6 11 -1. <_> 20 0 2 11 3. <_> <_> 0 6 24 13 -1. <_> 8 6 8 13 3. <_> <_> 9 6 6 9 -1. <_> 11 6 2 9 3. <_> <_> 7 18 10 6 -1. <_> 7 20 10 2 3. <_> <_> 5 7 14 12 -1. <_> 5 13 14 6 2. <_> <_> 0 3 24 3 -1. <_> 8 3 8 3 3. <_> <_> 5 8 15 6 -1. <_> 5 11 15 3 2. <_> <_> 9 6 5 14 -1. <_> 9 13 5 7 2. <_> <_> 9 5 6 10 -1. <_> 11 5 2 10 3. <_> <_> 6 6 3 12 -1. <_> 6 12 3 6 2. <_> <_> 3 21 18 3 -1. <_> 9 21 6 3 3. <_> <_> 5 6 13 6 -1. <_> 5 8 13 2 3. <_> <_> 18 1 6 15 -1. <_> 18 1 3 15 2. <_> <_> 1 1 6 15 -1. <_> 4 1 3 15 2. <_> <_> 0 8 24 15 -1. <_> 8 8 8 15 3. <_> <_> 5 6 14 12 -1. <_> 5 6 7 6 2. <_> 12 12 7 6 2. <_> <_> 2 12 21 12 -1. <_> 2 16 21 4 3. <_> <_> 8 1 4 10 -1. <_> 10 1 2 10 2. <_> <_> 2 13 20 10 -1. <_> 2 13 10 10 2. <_> <_> 0 1 6 13 -1. <_> 2 1 2 13 3. <_> <_> 20 2 4 13 -1. <_> 20 2 2 13 2. <_> <_> 0 5 22 19 -1. <_> 11 5 11 19 2. <_> <_> 18 4 6 9 -1. <_> 20 4 2 9 3. <_> <_> 0 3 6 11 -1. <_> 2 3 2 11 3. <_> <_> 12 1 4 9 -1. <_> 12 1 2 9 2. <_> <_> 0 6 19 3 -1. <_> 0 7 19 1 3. <_> <_> 12 1 4 9 -1. <_> 12 1 2 9 2. <_> <_> 8 1 4 9 -1. <_> 10 1 2 9 2. <_> <_> 5 5 14 14 -1. <_> 12 5 7 7 2. <_> 5 12 7 7 2. <_> <_> 1 10 18 2 -1. <_> 1 11 18 1 2. <_> <_> 17 13 4 11 -1. <_> 17 13 2 11 2. <_> <_> 0 4 6 9 -1. <_> 0 7 6 3 3. <_> <_> 6 4 12 9 -1. <_> 6 7 12 3 3. <_> <_> 6 5 12 6 -1. <_> 10 5 4 6 3. <_> <_> 0 1 24 5 -1. <_> 8 1 8 5 3. <_> <_> 4 10 18 6 -1. <_> 4 12 18 2 3. <_> <_> 2 17 12 6 -1. <_> 2 17 6 3 2. <_> 8 20 6 3 2. <_> <_> 19 3 4 13 -1. <_> 19 3 2 13 2. <_> <_> 1 3 4 13 -1. <_> 3 3 2 13 2. <_> <_> 0 1 24 23 -1. <_> 8 1 8 23 3. <_> <_> 1 7 8 12 -1. <_> 1 11 8 4 3. <_> <_> 14 7 3 14 -1. <_> 14 14 3 7 2. <_> <_> 3 12 16 6 -1. <_> 3 12 8 3 2. <_> 11 15 8 3 2. <_> <_> 6 6 12 6 -1. <_> 6 8 12 2 3. <_> <_> 8 7 6 12 -1. <_> 8 13 6 6 2. <_> <_> 15 15 9 6 -1. <_> 15 17 9 2 3. <_> <_> 1 17 18 3 -1. <_> 1 18 18 1 3. <_> <_> 4 4 16 12 -1. <_> 4 10 16 6 2. <_> <_> 0 1 4 20 -1. <_> 2 1 2 20 2. <_> <_> 3 0 18 2 -1. <_> 3 1 18 1 2. <_> <_> 1 5 20 14 -1. <_> 1 5 10 7 2. <_> 11 12 10 7 2. <_> <_> 5 8 14 12 -1. <_> 5 12 14 4 3. <_> <_> 3 14 7 9 -1. <_> 3 17 7 3 3. <_> <_> 14 15 9 6 -1. <_> 14 17 9 2 3. <_> <_> 1 15 9 6 -1. <_> 1 17 9 2 3. <_> <_> 11 6 8 10 -1. <_> 15 6 4 5 2. <_> 11 11 4 5 2. <_> <_> 5 5 14 14 -1. <_> 5 5 7 7 2. <_> 12 12 7 7 2. <_> <_> 6 0 12 5 -1. <_> 10 0 4 5 3. <_> <_> 9 0 6 9 -1. <_> 9 3 6 3 3. <_> <_> 9 6 6 9 -1. <_> 11 6 2 9 3. <_> <_> 7 0 6 9 -1. <_> 9 0 2 9 3. <_> <_> 10 6 6 9 -1. <_> 12 6 2 9 3. <_> <_> 8 6 6 9 -1. <_> 10 6 2 9 3. <_> <_> 3 8 18 4 -1. <_> 9 8 6 4 3. <_> <_> 6 0 12 9 -1. <_> 6 3 12 3 3. <_> <_> 0 0 24 6 -1. <_> 8 0 8 6 3. <_> <_> 4 7 16 12 -1. <_> 4 11 16 4 3. <_> <_> 11 6 6 6 -1. <_> 11 6 3 6 2. <_> <_> 0 20 24 3 -1. <_> 8 20 8 3 3. <_> <_> 11 6 4 9 -1. <_> 11 6 2 9 2. <_> <_> 4 13 15 4 -1. <_> 9 13 5 4 3. <_> <_> 11 6 4 9 -1. <_> 11 6 2 9 2. <_> <_> 9 6 4 9 -1. <_> 11 6 2 9 2. <_> <_> 9 12 6 12 -1. <_> 9 18 6 6 2. <_> <_> 1 22 18 2 -1. <_> 1 23 18 1 2. <_> <_> 10 7 4 10 -1. <_> 10 12 4 5 2. <_> <_> 6 7 8 10 -1. <_> 6 12 8 5 2. <_> <_> 7 6 10 6 -1. <_> 7 8 10 2 3. <_> <_> 0 14 10 4 -1. <_> 0 16 10 2 2. <_> <_> 6 18 18 2 -1. <_> 6 19 18 1 2. <_> <_> 1 1 22 3 -1. <_> 1 2 22 1 3. <_> <_> 6 16 18 3 -1. <_> 6 17 18 1 3. <_> <_> 2 4 6 15 -1. <_> 5 4 3 15 2. <_> <_> 20 4 4 10 -1. <_> 20 4 2 10 2. <_> <_> 0 4 4 10 -1. <_> 2 4 2 10 2. <_> <_> 2 16 20 6 -1. <_> 12 16 10 3 2. <_> 2 19 10 3 2. <_> <_> 0 12 8 9 -1. <_> 4 12 4 9 2. <_> <_> 12 0 6 9 -1. <_> 14 0 2 9 3. <_> <_> 5 10 6 6 -1. <_> 8 10 3 6 2. <_> <_> 11 8 12 6 -1. <_> 17 8 6 3 2. <_> 11 11 6 3 2. <_> <_> 0 8 12 6 -1. <_> 0 8 6 3 2. <_> 6 11 6 3 2. <_> <_> 12 0 6 9 -1. <_> 14 0 2 9 3. <_> <_> 6 0 6 9 -1. <_> 8 0 2 9 3. <_> <_> 8 14 9 6 -1. <_> 8 16 9 2 3. <_> <_> 0 16 9 6 -1. <_> 0 18 9 2 3. <_> <_> 10 8 6 10 -1. <_> 12 8 2 10 3. <_> <_> 3 19 12 3 -1. <_> 9 19 6 3 2. <_> <_> 2 10 20 2 -1. <_> 2 11 20 1 2. <_> <_> 2 9 18 12 -1. <_> 2 9 9 6 2. <_> 11 15 9 6 2. <_> <_> 3 0 18 24 -1. <_> 3 0 9 24 2. <_> <_> 5 6 14 10 -1. <_> 5 6 7 5 2. <_> 12 11 7 5 2. <_> <_> 9 5 10 12 -1. <_> 14 5 5 6 2. <_> 9 11 5 6 2. <_> <_> 4 5 12 12 -1. <_> 4 5 6 6 2. <_> 10 11 6 6 2. <_> <_> 4 14 18 3 -1. <_> 4 15 18 1 3. <_> <_> 6 13 8 8 -1. <_> 6 17 8 4 2. <_> <_> 3 16 18 6 -1. <_> 3 19 18 3 2. <_> <_> 0 0 6 6 -1. <_> 3 0 3 6 2. <_> <_> 6 6 12 18 -1. <_> 10 6 4 18 3. <_> <_> 6 1 4 14 -1. <_> 8 1 2 14 2. <_> <_> 3 2 19 2 -1. <_> 3 3 19 1 2. <_> <_> 1 8 22 13 -1. <_> 12 8 11 13 2. <_> <_> 8 9 11 4 -1. <_> 8 11 11 2 2. <_> <_> 0 12 15 10 -1. <_> 5 12 5 10 3. <_> <_> 12 16 12 6 -1. <_> 16 16 4 6 3. <_> <_> 0 16 12 6 -1. <_> 4 16 4 6 3. <_> <_> 19 1 5 12 -1. <_> 19 5 5 4 3. <_> <_> 0 2 24 4 -1. <_> 8 2 8 4 3. <_> <_> 6 8 12 4 -1. <_> 6 10 12 2 2. <_> <_> 7 5 9 6 -1. <_> 10 5 3 6 3. <_> <_> 9 17 6 6 -1. <_> 9 20 6 3 2. <_> <_> 0 7 22 15 -1. <_> 0 12 22 5 3. <_> <_> 4 1 17 9 -1. <_> 4 4 17 3 3. <_> <_> 7 5 6 10 -1. <_> 9 5 2 10 3. <_> <_> 18 1 6 8 -1. <_> 18 1 3 8 2. <_> <_> 0 1 6 7 -1. <_> 3 1 3 7 2. <_> <_> 18 0 6 22 -1. <_> 18 0 3 22 2. <_> <_> 0 0 6 22 -1. <_> 3 0 3 22 2. <_> <_> 16 7 8 16 -1. <_> 16 7 4 16 2. <_> <_> 2 10 19 6 -1. <_> 2 12 19 2 3. <_> <_> 9 9 6 12 -1. <_> 9 13 6 4 3. <_> <_> 2 15 17 6 -1. <_> 2 17 17 2 3. <_> <_> 14 7 3 14 -1. <_> 14 14 3 7 2. <_> <_> 5 6 8 10 -1. <_> 5 6 4 5 2. <_> 9 11 4 5 2. <_> <_> 15 8 9 11 -1. <_> 18 8 3 11 3. <_> <_> 0 8 9 11 -1. <_> 3 8 3 11 3. <_> <_> 8 6 10 18 -1. <_> 8 15 10 9 2. <_> <_> 7 7 3 14 -1. <_> 7 14 3 7 2. <_> <_> 0 14 24 8 -1. <_> 8 14 8 8 3. <_> <_> 1 10 18 14 -1. <_> 10 10 9 14 2. <_> <_> 14 12 6 6 -1. <_> 14 15 6 3 2. <_> <_> 7 0 10 16 -1. <_> 7 0 5 8 2. <_> 12 8 5 8 2. <_> <_> 10 0 9 6 -1. <_> 13 0 3 6 3. <_> <_> 4 3 16 4 -1. <_> 12 3 8 4 2. <_> <_> 10 0 9 6 -1. <_> 13 0 3 6 3. <_> <_> 1 1 20 4 -1. <_> 1 1 10 2 2. <_> 11 3 10 2 2. <_> <_> 10 0 9 6 -1. <_> 13 0 3 6 3. <_> <_> 5 0 9 6 -1. <_> 8 0 3 6 3. <_> <_> 8 18 10 6 -1. <_> 8 20 10 2 3. <_> <_> 6 3 6 9 -1. <_> 8 3 2 9 3. <_> <_> 7 3 12 6 -1. <_> 7 5 12 2 3. <_> <_> 0 10 18 3 -1. <_> 0 11 18 1 3. <_> <_> 1 10 22 3 -1. <_> 1 11 22 1 3. <_> <_> 5 11 8 8 -1. <_> 9 11 4 8 2. <_> <_> 12 11 6 6 -1. <_> 12 11 3 6 2. <_> <_> 6 11 6 6 -1. <_> 9 11 3 6 2. <_> <_> 7 10 11 6 -1. <_> 7 12 11 2 3. <_> <_> 0 13 24 4 -1. <_> 0 13 12 2 2. <_> 12 15 12 2 2. <_> <_> 2 4 22 12 -1. <_> 13 4 11 6 2. <_> 2 10 11 6 2. <_> <_> 2 0 20 17 -1. <_> 12 0 10 17 2. <_> <_> 14 0 2 24 -1. <_> 14 0 1 24 2. <_> <_> 8 0 2 24 -1. <_> 9 0 1 24 2. <_> <_> 14 1 2 22 -1. <_> 14 1 1 22 2. <_> <_> 8 1 2 22 -1. <_> 9 1 1 22 2. <_> <_> 17 6 3 18 -1. <_> 18 6 1 18 3. <_> <_> 6 14 9 6 -1. <_> 6 16 9 2 3. <_> <_> 13 14 9 4 -1. <_> 13 16 9 2 2. <_> <_> 3 18 18 3 -1. <_> 3 19 18 1 3. <_> <_> 9 4 8 18 -1. <_> 13 4 4 9 2. <_> 9 13 4 9 2. <_> <_> 0 17 18 3 -1. <_> 0 18 18 1 3. <_> <_> 0 2 12 4 -1. <_> 6 2 6 4 2. <_> <_> 6 8 14 6 -1. <_> 6 11 14 3 2. <_> <_> 7 5 6 6 -1. <_> 10 5 3 6 2. <_> <_> 10 5 6 16 -1. <_> 10 13 6 8 2. <_> <_> 1 4 9 16 -1. <_> 4 4 3 16 3. <_> <_> 5 0 18 9 -1. <_> 5 3 18 3 3. <_> <_> 9 15 5 8 -1. <_> 9 19 5 4 2. <_> <_> 20 0 4 9 -1. <_> 20 0 2 9 2. <_> <_> 2 0 18 3 -1. <_> 2 1 18 1 3. <_> <_> 5 22 19 2 -1. <_> 5 23 19 1 2. <_> <_> 0 0 4 9 -1. <_> 2 0 2 9 2. <_> <_> 5 6 19 18 -1. <_> 5 12 19 6 3. <_> <_> 0 1 6 9 -1. <_> 2 1 2 9 3. <_> <_> 6 5 14 12 -1. <_> 13 5 7 6 2. <_> 6 11 7 6 2. <_> <_> 0 1 20 2 -1. <_> 0 2 20 1 2. <_> <_> 1 2 22 3 -1. <_> 1 3 22 1 3. <_> <_> 2 8 7 9 -1. <_> 2 11 7 3 3. <_> <_> 2 12 22 4 -1. <_> 13 12 11 2 2. <_> 2 14 11 2 2. <_> <_> 0 12 22 4 -1. <_> 0 12 11 2 2. <_> 11 14 11 2 2. <_> <_> 9 7 6 11 -1. <_> 11 7 2 11 3. <_> <_> 7 1 9 6 -1. <_> 10 1 3 6 3. <_> <_> 11 2 4 10 -1. <_> 11 7 4 5 2. <_> <_> 6 4 12 12 -1. <_> 6 10 12 6 2. <_> <_> 18 1 6 15 -1. <_> 18 6 6 5 3. <_> <_> 3 15 18 3 -1. <_> 3 16 18 1 3. <_> <_> 18 5 6 9 -1. <_> 18 8 6 3 3. <_> <_> 1 5 16 6 -1. <_> 1 5 8 3 2. <_> 9 8 8 3 2. <_> <_> 11 0 6 9 -1. <_> 13 0 2 9 3. <_> <_> 0 4 24 14 -1. <_> 0 4 12 7 2. <_> 12 11 12 7 2. <_> <_> 13 0 4 13 -1. <_> 13 0 2 13 2. <_> <_> 7 0 4 13 -1. <_> 9 0 2 13 2. <_> <_> 11 6 6 9 -1. <_> 13 6 2 9 3. <_> <_> 8 7 6 9 -1. <_> 10 7 2 9 3. <_> <_> 13 17 9 6 -1. <_> 13 19 9 2 3. <_> <_> 2 18 14 6 -1. <_> 2 18 7 3 2. <_> 9 21 7 3 2. <_> <_> 3 18 18 4 -1. <_> 12 18 9 2 2. <_> 3 20 9 2 2. <_> <_> 0 20 15 4 -1. <_> 5 20 5 4 3. <_> <_> 9 15 15 9 -1. <_> 14 15 5 9 3. <_> <_> 4 4 16 4 -1. <_> 4 6 16 2 2. <_> <_> 7 6 10 6 -1. <_> 7 8 10 2 3. <_> <_> 0 14 15 10 -1. <_> 5 14 5 10 3. <_> <_> 7 9 10 14 -1. <_> 12 9 5 7 2. <_> 7 16 5 7 2. <_> <_> 7 6 6 9 -1. <_> 9 6 2 9 3. <_> <_> 3 6 18 3 -1. <_> 3 7 18 1 3. <_> <_> 0 10 18 3 -1. <_> 0 11 18 1 3. <_> <_> 3 16 18 4 -1. <_> 12 16 9 2 2. <_> 3 18 9 2 2. <_> <_> 4 6 14 6 -1. <_> 4 6 7 3 2. <_> 11 9 7 3 2. <_> <_> 13 0 2 18 -1. <_> 13 0 1 18 2. <_> <_> 9 0 2 18 -1. <_> 10 0 1 18 2. <_> <_> 5 7 15 10 -1. <_> 10 7 5 10 3. <_> <_> 1 20 21 4 -1. <_> 8 20 7 4 3. <_> <_> 10 5 5 18 -1. <_> 10 14 5 9 2. <_> <_> 0 2 24 6 -1. <_> 0 2 12 3 2. <_> 12 5 12 3 2. <_> <_> 1 1 22 8 -1. <_> 12 1 11 4 2. <_> 1 5 11 4 2. <_> <_> 4 0 15 9 -1. <_> 4 3 15 3 3. <_> <_> 0 0 24 19 -1. <_> 8 0 8 19 3. <_> <_> 2 21 18 3 -1. <_> 11 21 9 3 2. <_> <_> 9 7 10 4 -1. <_> 9 7 5 4 2. <_> <_> 5 7 10 4 -1. <_> 10 7 5 4 2. <_> <_> 17 8 6 16 -1. <_> 20 8 3 8 2. <_> 17 16 3 8 2. <_> <_> 1 15 20 4 -1. <_> 1 15 10 2 2. <_> 11 17 10 2 2. <_> <_> 14 15 10 6 -1. <_> 14 17 10 2 3. <_> <_> 3 0 16 9 -1. <_> 3 3 16 3 3. <_> <_> 15 6 7 15 -1. <_> 15 11 7 5 3. <_> <_> 9 1 6 13 -1. <_> 11 1 2 13 3. <_> <_> 17 2 6 14 -1. <_> 17 2 3 14 2. <_> <_> 3 14 12 10 -1. <_> 3 14 6 5 2. <_> 9 19 6 5 2. <_> <_> 7 6 10 6 -1. <_> 7 8 10 2 3. <_> <_> 1 2 6 14 -1. <_> 4 2 3 14 2. <_> <_> 10 4 5 12 -1. <_> 10 8 5 4 3. <_> <_> 0 17 24 5 -1. <_> 8 17 8 5 3. <_> <_> 15 7 5 12 -1. <_> 15 11 5 4 3. <_> <_> 3 1 6 12 -1. <_> 3 1 3 6 2. <_> 6 7 3 6 2. <_> <_> 12 13 6 6 -1. <_> 12 16 6 3 2. <_> <_> 6 13 6 6 -1. <_> 6 16 6 3 2. <_> <_> 14 6 3 16 -1. <_> 14 14 3 8 2. <_> <_> 1 12 13 6 -1. <_> 1 14 13 2 3. <_> <_> 13 1 4 9 -1. <_> 13 1 2 9 2. <_> <_> 7 0 9 6 -1. <_> 10 0 3 6 3. <_> <_> 12 2 6 9 -1. <_> 12 2 3 9 2. <_> <_> 6 2 6 9 -1. <_> 9 2 3 9 2. <_> <_> 6 18 12 6 -1. <_> 6 20 12 2 3. <_> <_> 7 6 6 9 -1. <_> 9 6 2 9 3. <_> <_> 7 7 12 3 -1. <_> 7 7 6 3 2. <_> <_> 8 3 8 21 -1. <_> 8 10 8 7 3. <_> <_> 7 4 10 12 -1. <_> 7 8 10 4 3. <_> <_> 0 1 6 9 -1. <_> 0 4 6 3 3. <_> <_> 15 2 2 20 -1. <_> 15 2 1 20 2. <_> <_> 0 3 6 9 -1. <_> 0 6 6 3 3. <_> <_> 15 3 2 21 -1. <_> 15 3 1 21 2. <_> <_> 7 0 2 23 -1. <_> 8 0 1 23 2. <_> <_> 15 8 9 4 -1. <_> 15 10 9 2 2. <_> <_> 0 8 9 4 -1. <_> 0 10 9 2 2. <_> <_> 8 14 9 6 -1. <_> 8 16 9 2 3. <_> <_> 0 14 9 6 -1. <_> 0 16 9 2 3. <_> <_> 3 10 18 4 -1. <_> 9 10 6 4 3. <_> <_> 0 0 24 19 -1. <_> 8 0 8 19 3. <_> <_> 9 1 8 12 -1. <_> 9 7 8 6 2. <_> <_> 10 6 4 10 -1. <_> 12 6 2 10 2. <_> <_> 7 9 10 12 -1. <_> 12 9 5 6 2. <_> 7 15 5 6 2. <_> <_> 5 0 3 19 -1. <_> 6 0 1 19 3. <_> <_> 14 0 6 10 -1. <_> 16 0 2 10 3. <_> <_> 2 0 6 12 -1. <_> 2 0 3 6 2. <_> 5 6 3 6 2. <_> <_> 0 11 24 2 -1. <_> 0 12 24 1 2. <_> <_> 4 9 13 4 -1. <_> 4 11 13 2 2. <_> <_> 9 8 6 9 -1. <_> 9 11 6 3 3. <_> <_> 0 12 16 4 -1. <_> 0 14 16 2 2. <_> <_> 18 12 6 9 -1. <_> 18 15 6 3 3. <_> <_> 0 12 6 9 -1. <_> 0 15 6 3 3. <_> <_> 8 7 10 4 -1. <_> 8 7 5 4 2. <_> <_> 8 7 6 9 -1. <_> 10 7 2 9 3. <_> <_> 11 0 6 9 -1. <_> 13 0 2 9 3. <_> <_> 7 0 6 9 -1. <_> 9 0 2 9 3. <_> <_> 12 3 6 15 -1. <_> 14 3 2 15 3. <_> <_> 6 3 6 15 -1. <_> 8 3 2 15 3. <_> <_> 15 2 9 4 -1. <_> 15 4 9 2 2. <_> <_> 5 10 6 7 -1. <_> 8 10 3 7 2. <_> <_> 9 14 6 10 -1. <_> 9 19 6 5 2. <_> <_> 7 13 5 8 -1. <_> 7 17 5 4 2. <_> <_> 14 5 3 16 -1. <_> 14 13 3 8 2. <_> <_> 2 17 18 3 -1. <_> 2 18 18 1 3. <_> <_> 5 18 19 3 -1. <_> 5 19 19 1 3. <_> <_> 9 0 6 9 -1. <_> 11 0 2 9 3. <_> <_> 12 4 3 18 -1. <_> 13 4 1 18 3. <_> <_> 9 4 3 18 -1. <_> 10 4 1 18 3. <_> <_> 3 3 18 9 -1. <_> 9 3 6 9 3. <_> <_> 6 1 6 14 -1. <_> 8 1 2 14 3. <_> <_> 12 16 9 6 -1. <_> 12 19 9 3 2. <_> <_> 1 3 20 16 -1. <_> 1 3 10 8 2. <_> 11 11 10 8 2. <_> <_> 12 5 6 12 -1. <_> 15 5 3 6 2. <_> 12 11 3 6 2. <_> <_> 1 2 22 16 -1. <_> 1 2 11 8 2. <_> 12 10 11 8 2. <_> <_> 10 14 5 10 -1. <_> 10 19 5 5 2. <_> <_> 3 21 18 3 -1. <_> 3 22 18 1 3. <_> <_> 10 14 6 10 -1. <_> 12 14 2 10 3. <_> <_> 0 2 24 4 -1. <_> 8 2 8 4 3. <_> <_> 6 4 12 9 -1. <_> 6 7 12 3 3. <_> <_> 6 6 12 5 -1. <_> 10 6 4 5 3. <_> <_> 5 8 14 12 -1. <_> 5 12 14 4 3. <_> <_> 4 14 8 10 -1. <_> 4 14 4 5 2. <_> 8 19 4 5 2. <_> <_> 11 6 5 14 -1. <_> 11 13 5 7 2. <_> <_> 7 6 3 16 -1. <_> 7 14 3 8 2. <_> <_> 3 7 18 8 -1. <_> 9 7 6 8 3. <_> <_> 2 3 20 2 -1. <_> 2 4 20 1 2. <_> <_> 3 12 19 6 -1. <_> 3 14 19 2 3. <_> <_> 8 6 6 9 -1. <_> 10 6 2 9 3. <_> <_> 16 6 6 14 -1. <_> 16 6 3 14 2. <_> <_> 7 9 6 12 -1. <_> 9 9 2 12 3. <_> <_> 18 6 6 18 -1. <_> 21 6 3 9 2. <_> 18 15 3 9 2. <_> <_> 0 6 6 18 -1. <_> 0 6 3 9 2. <_> 3 15 3 9 2. <_> <_> 18 2 6 9 -1. <_> 18 5 6 3 3. <_> <_> 3 18 15 6 -1. <_> 3 20 15 2 3. <_> <_> 18 2 6 9 -1. <_> 18 5 6 3 3. <_> <_> 0 2 6 9 -1. <_> 0 5 6 3 3. <_> <_> 5 10 18 2 -1. <_> 5 11 18 1 2. <_> <_> 6 0 12 6 -1. <_> 6 2 12 2 3. <_> <_> 10 0 6 9 -1. <_> 12 0 2 9 3. <_> <_> 8 0 6 9 -1. <_> 10 0 2 9 3. <_> <_> 15 12 9 6 -1. <_> 15 14 9 2 3. <_> <_> 3 6 13 6 -1. <_> 3 8 13 2 3. <_> <_> 15 12 9 6 -1. <_> 15 14 9 2 3. <_> <_> 2 5 6 15 -1. <_> 5 5 3 15 2. <_> <_> 8 8 9 6 -1. <_> 11 8 3 6 3. <_> <_> 8 6 3 14 -1. <_> 8 13 3 7 2. <_> <_> 15 12 9 6 -1. <_> 15 14 9 2 3. <_> <_> 4 12 10 4 -1. <_> 9 12 5 4 2. <_> <_> 13 1 4 19 -1. <_> 13 1 2 19 2. <_> <_> 7 1 4 19 -1. <_> 9 1 2 19 2. <_> <_> 18 9 6 9 -1. <_> 18 12 6 3 3. <_> <_> 1 21 18 3 -1. <_> 1 22 18 1 3. <_> <_> 14 13 10 9 -1. <_> 14 16 10 3 3. <_> <_> 1 13 22 4 -1. <_> 1 13 11 2 2. <_> 12 15 11 2 2. <_> <_> 4 6 16 6 -1. <_> 12 6 8 3 2. <_> 4 9 8 3 2. <_> <_> 1 0 18 22 -1. <_> 1 0 9 11 2. <_> 10 11 9 11 2. <_> <_> 10 7 8 14 -1. <_> 14 7 4 7 2. <_> 10 14 4 7 2. <_> <_> 0 4 6 20 -1. <_> 0 4 3 10 2. <_> 3 14 3 10 2. <_> <_> 15 0 6 9 -1. <_> 17 0 2 9 3. <_> <_> 3 0 6 9 -1. <_> 5 0 2 9 3. <_> <_> 15 12 6 12 -1. <_> 18 12 3 6 2. <_> 15 18 3 6 2. <_> <_> 3 12 6 12 -1. <_> 3 12 3 6 2. <_> 6 18 3 6 2. <_> <_> 15 12 9 6 -1. <_> 15 14 9 2 3. <_> <_> 0 12 9 6 -1. <_> 0 14 9 2 3. <_> <_> 4 14 19 3 -1. <_> 4 15 19 1 3. <_> <_> 2 13 19 3 -1. <_> 2 14 19 1 3. <_> <_> 14 15 10 6 -1. <_> 14 17 10 2 3. <_> <_> 6 0 10 12 -1. <_> 6 0 5 6 2. <_> 11 6 5 6 2. <_> <_> 17 1 6 12 -1. <_> 20 1 3 6 2. <_> 17 7 3 6 2. <_> <_> 1 1 6 12 -1. <_> 1 1 3 6 2. <_> 4 7 3 6 2. <_> <_> 16 14 6 9 -1. <_> 16 17 6 3 3. <_> <_> 7 3 9 12 -1. <_> 7 9 9 6 2. <_> <_> 12 1 4 12 -1. <_> 12 7 4 6 2. <_> <_> 4 0 14 8 -1. <_> 4 4 14 4 2. <_> <_> 10 6 6 9 -1. <_> 12 6 2 9 3. <_> <_> 2 10 18 3 -1. <_> 8 10 6 3 3. <_> <_> 15 15 9 6 -1. <_> 15 17 9 2 3. <_> <_> 0 1 21 23 -1. <_> 7 1 7 23 3. <_> <_> 6 9 17 4 -1. <_> 6 11 17 2 2. <_> <_> 1 0 11 18 -1. <_> 1 6 11 6 3. <_> <_> 6 15 13 6 -1. <_> 6 17 13 2 3. <_> <_> 0 15 9 6 -1. <_> 0 17 9 2 3. <_> <_> 8 7 15 4 -1. <_> 13 7 5 4 3. <_> <_> 9 12 6 9 -1. <_> 9 15 6 3 3. <_> <_> 6 8 18 3 -1. <_> 12 8 6 3 3. <_> <_> 0 14 24 4 -1. <_> 8 14 8 4 3. <_> <_> 16 10 3 12 -1. <_> 16 16 3 6 2. <_> <_> 0 3 24 3 -1. <_> 0 4 24 1 3. <_> <_> 14 17 10 6 -1. <_> 14 19 10 2 3. <_> <_> 1 13 18 3 -1. <_> 7 13 6 3 3. <_> <_> 5 0 18 9 -1. <_> 5 3 18 3 3. <_> <_> 4 3 16 9 -1. <_> 4 6 16 3 3. <_> <_> 16 5 3 12 -1. <_> 16 11 3 6 2. <_> <_> 0 7 18 4 -1. <_> 6 7 6 4 3. <_> <_> 10 6 6 9 -1. <_> 12 6 2 9 3. <_> <_> 9 8 6 10 -1. <_> 11 8 2 10 3. <_> <_> 9 15 6 9 -1. <_> 11 15 2 9 3. <_> <_> 3 1 18 21 -1. <_> 12 1 9 21 2. <_> <_> 6 8 12 7 -1. <_> 6 8 6 7 2. <_> <_> 8 5 6 9 -1. <_> 10 5 2 9 3. <_> <_> 0 2 24 4 -1. <_> 8 2 8 4 3. <_> <_> 14 7 5 12 -1. <_> 14 11 5 4 3. <_> <_> 5 7 5 12 -1. <_> 5 11 5 4 3. <_> <_> 9 6 6 9 -1. <_> 11 6 2 9 3. <_> <_> 0 1 6 17 -1. <_> 3 1 3 17 2. <_> <_> 3 1 19 9 -1. <_> 3 4 19 3 3. <_> <_> 3 18 12 6 -1. <_> 3 18 6 3 2. <_> 9 21 6 3 2. <_> <_> 20 4 4 19 -1. <_> 20 4 2 19 2. <_> <_> 0 16 10 7 -1. <_> 5 16 5 7 2. <_> <_> 8 7 10 12 -1. <_> 13 7 5 6 2. <_> 8 13 5 6 2. <_> <_> 6 7 10 12 -1. <_> 6 7 5 6 2. <_> 11 13 5 6 2. <_> <_> 9 2 9 6 -1. <_> 12 2 3 6 3. <_> <_> 1 20 21 4 -1. <_> 8 20 7 4 3. <_> <_> 9 12 9 6 -1. <_> 9 14 9 2 3. <_> <_> 7 2 9 6 -1. <_> 10 2 3 6 3. <_> <_> 13 0 4 14 -1. <_> 13 0 2 14 2. <_> <_> 7 0 4 14 -1. <_> 9 0 2 14 2. <_> <_> 14 15 9 6 -1. <_> 14 17 9 2 3. <_> <_> 2 8 18 5 -1. <_> 8 8 6 5 3. <_> <_> 18 3 6 11 -1. <_> 20 3 2 11 3. <_> <_> 6 5 11 14 -1. <_> 6 12 11 7 2. <_> <_> 18 4 6 9 -1. <_> 18 7 6 3 3. <_> <_> 7 6 9 6 -1. <_> 7 8 9 2 3. <_> <_> 18 4 6 9 -1. <_> 18 7 6 3 3. <_> <_> 0 4 6 9 -1. <_> 0 7 6 3 3. <_> <_> 9 4 9 4 -1. <_> 9 6 9 2 2. <_> <_> 0 22 19 2 -1. <_> 0 23 19 1 2. <_> <_> 17 14 6 9 -1. <_> 17 17 6 3 3. <_> <_> 1 14 6 9 -1. <_> 1 17 6 3 3. <_> <_> 14 11 4 9 -1. <_> 14 11 2 9 2. <_> <_> 6 11 4 9 -1. <_> 8 11 2 9 2. <_> <_> 3 9 18 7 -1. <_> 9 9 6 7 3. <_> <_> 9 12 6 10 -1. <_> 9 17 6 5 2. <_> <_> 12 0 6 9 -1. <_> 14 0 2 9 3. <_> <_> 6 0 6 9 -1. <_> 8 0 2 9 3. <_> <_> 6 17 18 3 -1. <_> 6 18 18 1 3. <_> <_> 1 17 18 3 -1. <_> 1 18 18 1 3. <_> <_> 10 6 11 12 -1. <_> 10 12 11 6 2. <_> <_> 5 6 14 6 -1. <_> 5 6 7 3 2. <_> 12 9 7 3 2. <_> <_> 5 4 15 4 -1. <_> 5 6 15 2 2. <_> <_> 0 0 22 2 -1. <_> 0 1 22 1 2. <_> <_> 0 0 24 24 -1. <_> 8 0 8 24 3. <_> <_> 1 15 18 4 -1. <_> 10 15 9 4 2. <_> <_> 6 8 12 9 -1. <_> 6 11 12 3 3. <_> <_> 4 12 7 12 -1. <_> 4 16 7 4 3. <_> <_> 1 2 22 6 -1. <_> 12 2 11 3 2. <_> 1 5 11 3 2. <_> <_> 5 20 14 3 -1. <_> 12 20 7 3 2. <_> <_> 0 0 24 16 -1. <_> 12 0 12 8 2. <_> 0 8 12 8 2. <_> <_> 3 13 18 4 -1. <_> 3 13 9 2 2. <_> 12 15 9 2 2. <_> <_> 2 10 22 2 -1. <_> 2 11 22 1 2. <_> <_> 6 3 11 8 -1. <_> 6 7 11 4 2. <_> <_> 14 5 6 6 -1. <_> 14 8 6 3 2. <_> <_> 0 7 24 6 -1. <_> 0 9 24 2 3. <_> <_> 14 0 10 10 -1. <_> 19 0 5 5 2. <_> 14 5 5 5 2. <_> <_> 0 0 10 10 -1. <_> 0 0 5 5 2. <_> 5 5 5 5 2. <_> <_> 0 1 24 4 -1. <_> 12 1 12 2 2. <_> 0 3 12 2 2. <_> <_> 0 17 18 3 -1. <_> 0 18 18 1 3. <_> <_> 5 15 16 6 -1. <_> 13 15 8 3 2. <_> 5 18 8 3 2. <_> <_> 3 15 16 6 -1. <_> 3 15 8 3 2. <_> 11 18 8 3 2. <_> <_> 6 16 18 3 -1. <_> 6 17 18 1 3. <_> <_> 0 13 21 10 -1. <_> 0 18 21 5 2. <_> <_> 13 0 6 24 -1. <_> 15 0 2 24 3. <_> <_> 7 4 6 11 -1. <_> 9 4 2 11 3. <_> <_> 9 5 9 6 -1. <_> 12 5 3 6 3. <_> <_> 1 4 2 20 -1. <_> 1 14 2 10 2. <_> <_> 13 0 6 24 -1. <_> 15 0 2 24 3. <_> <_> 5 0 6 24 -1. <_> 7 0 2 24 3. <_> <_> 16 7 6 14 -1. <_> 19 7 3 7 2. <_> 16 14 3 7 2. <_> <_> 4 7 4 12 -1. <_> 6 7 2 12 2. <_> <_> 0 5 24 14 -1. <_> 8 5 8 14 3. <_> <_> 5 13 10 6 -1. <_> 5 15 10 2 3. <_> <_> 12 0 6 9 -1. <_> 14 0 2 9 3. <_> <_> 2 7 6 14 -1. <_> 2 7 3 7 2. <_> 5 14 3 7 2. <_> <_> 15 2 9 15 -1. <_> 18 2 3 15 3. <_> <_> 0 2 6 9 -1. <_> 2 2 2 9 3. <_> <_> 12 2 10 14 -1. <_> 17 2 5 7 2. <_> 12 9 5 7 2. <_> <_> 11 6 2 18 -1. <_> 12 6 1 18 2. <_> <_> 9 5 15 6 -1. <_> 14 5 5 6 3. <_> <_> 8 6 6 10 -1. <_> 10 6 2 10 3. <_> <_> 12 0 6 9 -1. <_> 14 0 2 9 3. <_> <_> 3 3 9 7 -1. <_> 6 3 3 7 3. <_> <_> 6 7 14 3 -1. <_> 6 7 7 3 2. <_> <_> 7 7 8 6 -1. <_> 11 7 4 6 2. <_> <_> 12 7 7 12 -1. <_> 12 13 7 6 2. <_> <_> 10 6 4 18 -1. <_> 10 6 2 9 2. <_> 12 15 2 9 2. <_> <_> 16 14 6 9 -1. <_> 16 17 6 3 3. <_> <_> 4 0 6 13 -1. <_> 6 0 2 13 3. <_> <_> 2 2 21 3 -1. <_> 9 2 7 3 3. <_> <_> 5 4 5 12 -1. <_> 5 8 5 4 3. <_> <_> 10 3 4 10 -1. <_> 10 8 4 5 2. <_> <_> 8 4 5 8 -1. <_> 8 8 5 4 2. <_> <_> 6 0 11 9 -1. <_> 6 3 11 3 3. <_> <_> 6 6 12 5 -1. <_> 10 6 4 5 3. <_> <_> 0 0 24 5 -1. <_> 8 0 8 5 3. <_> <_> 1 10 23 6 -1. <_> 1 12 23 2 3. <_> <_> 3 21 18 3 -1. <_> 9 21 6 3 3. <_> <_> 3 6 21 6 -1. <_> 3 8 21 2 3. <_> <_> 0 5 6 12 -1. <_> 2 5 2 12 3. <_> <_> 10 2 4 15 -1. <_> 10 7 4 5 3. <_> <_> 8 7 8 10 -1. <_> 8 12 8 5 2. <_> <_> 5 7 15 12 -1. <_> 10 7 5 12 3. <_> <_> 0 17 10 6 -1. <_> 0 19 10 2 3. <_> <_> 14 18 9 6 -1. <_> 14 20 9 2 3. <_> <_> 9 6 6 16 -1. <_> 9 14 6 8 2. <_> <_> 14 18 9 6 -1. <_> 14 20 9 2 3. <_> <_> 1 18 9 6 -1. <_> 1 20 9 2 3. <_> <_> 15 9 9 6 -1. <_> 15 11 9 2 3. <_> <_> 0 9 9 6 -1. <_> 0 11 9 2 3. <_> <_> 17 3 6 9 -1. <_> 19 3 2 9 3. <_> <_> 2 17 18 3 -1. <_> 2 18 18 1 3. <_> <_> 3 15 21 6 -1. <_> 3 17 21 2 3. <_> <_> 9 17 6 6 -1. <_> 9 20 6 3 2. <_> <_> 18 3 6 9 -1. <_> 18 6 6 3 3. <_> <_> 0 3 6 9 -1. <_> 0 6 6 3 3. <_> <_> 4 0 16 10 -1. <_> 12 0 8 5 2. <_> 4 5 8 5 2. <_> <_> 2 0 10 16 -1. <_> 2 0 5 8 2. <_> 7 8 5 8 2. <_> <_> 14 0 10 5 -1. <_> 14 0 5 5 2. <_> <_> 0 0 10 5 -1. <_> 5 0 5 5 2. <_> <_> 18 3 6 10 -1. <_> 18 3 3 10 2. <_> <_> 5 11 12 6 -1. <_> 5 11 6 3 2. <_> 11 14 6 3 2. <_> <_> 21 0 3 18 -1. <_> 22 0 1 18 3. <_> <_> 6 0 6 9 -1. <_> 8 0 2 9 3. <_> <_> 8 8 9 7 -1. <_> 11 8 3 7 3. <_> <_> 7 12 8 10 -1. <_> 7 12 4 5 2. <_> 11 17 4 5 2. <_> <_> 21 0 3 18 -1. <_> 22 0 1 18 3. <_> <_> 10 6 4 9 -1. <_> 12 6 2 9 2. <_> <_> 15 0 9 6 -1. <_> 15 2 9 2 3. <_> <_> 0 2 24 3 -1. <_> 0 3 24 1 3. <_> <_> 11 7 6 9 -1. <_> 13 7 2 9 3. <_> <_> 7 6 6 10 -1. <_> 9 6 2 10 3. <_> <_> 12 1 6 12 -1. <_> 14 1 2 12 3. <_> <_> 6 4 12 12 -1. <_> 6 10 12 6 2. <_> <_> 14 3 2 21 -1. <_> 14 3 1 21 2. <_> <_> 6 1 12 8 -1. <_> 6 5 12 4 2. <_> <_> 3 0 18 8 -1. <_> 3 4 18 4 2. <_> <_> 3 0 18 3 -1. <_> 3 1 18 1 3. <_> <_> 0 13 24 4 -1. <_> 12 13 12 2 2. <_> 0 15 12 2 2. <_> <_> 10 5 4 9 -1. <_> 12 5 2 9 2. <_> <_> 11 1 6 9 -1. <_> 13 1 2 9 3. <_> <_> 6 2 6 22 -1. <_> 8 2 2 22 3. <_> <_> 16 10 8 14 -1. <_> 20 10 4 7 2. <_> 16 17 4 7 2. <_> <_> 3 4 16 15 -1. <_> 3 9 16 5 3. <_> <_> 16 10 8 14 -1. <_> 20 10 4 7 2. <_> 16 17 4 7 2. <_> <_> 0 10 8 14 -1. <_> 0 10 4 7 2. <_> 4 17 4 7 2. <_> <_> 10 14 11 6 -1. <_> 10 17 11 3 2. <_> <_> 0 7 24 9 -1. <_> 8 7 8 9 3. <_> <_> 13 1 4 16 -1. <_> 13 1 2 16 2. <_> <_> 7 1 4 16 -1. <_> 9 1 2 16 2. <_> <_> 5 5 16 8 -1. <_> 13 5 8 4 2. <_> 5 9 8 4 2. <_> <_> 0 9 6 9 -1. <_> 0 12 6 3 3. <_> <_> 6 16 18 3 -1. <_> 6 17 18 1 3. <_> <_> 3 12 6 9 -1. <_> 3 15 6 3 3. <_> <_> 8 14 9 6 -1. <_> 8 16 9 2 3. <_> <_> 2 13 8 10 -1. <_> 2 13 4 5 2. <_> 6 18 4 5 2. <_> <_> 15 5 3 18 -1. <_> 15 11 3 6 3. <_> <_> 3 5 18 3 -1. <_> 3 6 18 1 3. <_> <_> 17 5 6 11 -1. <_> 19 5 2 11 3. <_> <_> 1 5 6 11 -1. <_> 3 5 2 11 3. <_> <_> 19 1 4 9 -1. <_> 19 1 2 9 2. <_> <_> 1 1 4 9 -1. <_> 3 1 2 9 2. <_> <_> 4 15 18 9 -1. <_> 4 15 9 9 2. <_> <_> 6 9 12 4 -1. <_> 6 11 12 2 2. <_> <_> 15 2 9 6 -1. <_> 15 4 9 2 3. <_> <_> 0 2 9 6 -1. <_> 0 4 9 2 3. <_> <_> 15 0 6 17 -1. <_> 17 0 2 17 3. <_> <_> 3 0 6 17 -1. <_> 5 0 2 17 3. <_> <_> 8 17 9 4 -1. <_> 8 19 9 2 2. <_> <_> 6 5 3 18 -1. <_> 6 11 3 6 3. <_> <_> 5 2 14 12 -1. <_> 5 8 14 6 2. <_> <_> 10 2 3 12 -1. <_> 10 8 3 6 2. <_> <_> 10 7 14 15 -1. <_> 10 12 14 5 3. <_> <_> 0 7 14 15 -1. <_> 0 12 14 5 3. <_> <_> 15 0 9 6 -1. <_> 15 2 9 2 3. <_> <_> 0 0 9 6 -1. <_> 0 2 9 2 3. <_> <_> 12 6 6 14 -1. <_> 14 6 2 14 3. <_> <_> 9 7 6 9 -1. <_> 11 7 2 9 3. <_> <_> 12 6 6 15 -1. <_> 14 6 2 15 3. <_> <_> 6 6 6 15 -1. <_> 8 6 2 15 3. <_> <_> 15 3 8 9 -1. <_> 15 3 4 9 2. <_> <_> 0 0 9 21 -1. <_> 3 0 3 21 3. <_> <_> 11 9 8 12 -1. <_> 11 13 8 4 3. <_> <_> 6 7 10 12 -1. <_> 6 7 5 6 2. <_> 11 13 5 6 2. <_> <_> 10 6 4 18 -1. <_> 12 6 2 9 2. <_> 10 15 2 9 2. <_> <_> 0 0 6 9 -1. <_> 0 3 6 3 3. <_> <_> 3 14 18 3 -1. <_> 3 15 18 1 3. <_> <_> 3 14 8 10 -1. <_> 3 14 4 5 2. <_> 7 19 4 5 2. <_> <_> 0 12 24 4 -1. <_> 12 12 12 2 2. <_> 0 14 12 2 2. <_> <_> 0 2 3 20 -1. <_> 1 2 1 20 3. <_> <_> 12 16 10 8 -1. <_> 17 16 5 4 2. <_> 12 20 5 4 2. <_> <_> 2 16 10 8 -1. <_> 2 16 5 4 2. <_> 7 20 5 4 2. <_> <_> 7 0 10 9 -1. <_> 7 3 10 3 3. <_> <_> 0 0 24 3 -1. <_> 8 0 8 3 3. <_> <_> 3 8 15 4 -1. <_> 3 10 15 2 2. <_> <_> 6 5 12 6 -1. <_> 10 5 4 6 3. <_> <_> 5 13 14 6 -1. <_> 5 16 14 3 2. <_> <_> 11 14 4 10 -1. <_> 11 19 4 5 2. <_> <_> 0 6 6 7 -1. <_> 3 6 3 7 2. <_> <_> 18 0 6 6 -1. <_> 18 0 3 6 2. <_> <_> 3 1 18 3 -1. <_> 3 2 18 1 3. <_> <_> 9 6 14 18 -1. <_> 9 12 14 6 3. <_> <_> 0 0 6 6 -1. <_> 3 0 3 6 2. <_> <_> 13 11 6 6 -1. <_> 13 11 3 6 2. <_> <_> 0 20 24 3 -1. <_> 8 20 8 3 3. <_> <_> 13 11 6 7 -1. <_> 13 11 3 7 2. <_> <_> 4 12 10 6 -1. <_> 4 14 10 2 3. <_> <_> 13 11 6 6 -1. <_> 13 11 3 6 2. <_> <_> 5 11 6 7 -1. <_> 8 11 3 7 2. <_> <_> 7 4 11 12 -1. <_> 7 8 11 4 3. <_> <_> 6 15 10 4 -1. <_> 6 17 10 2 2. <_> <_> 14 0 6 9 -1. <_> 16 0 2 9 3. <_> <_> 4 0 6 9 -1. <_> 6 0 2 9 3. <_> <_> 11 2 4 15 -1. <_> 11 7 4 5 3. <_> <_> 0 0 20 3 -1. <_> 0 1 20 1 3. <_> <_> 13 18 10 6 -1. <_> 13 20 10 2 3. <_> <_> 2 7 6 11 -1. <_> 5 7 3 11 2. <_> <_> 10 14 10 9 -1. <_> 10 17 10 3 3. <_> <_> 8 2 4 9 -1. <_> 10 2 2 9 2. <_> <_> 14 3 10 4 -1. <_> 14 3 5 4 2. <_> <_> 6 6 12 6 -1. <_> 6 6 6 3 2. <_> 12 9 6 3 2. <_> <_> 8 8 8 10 -1. <_> 12 8 4 5 2. <_> 8 13 4 5 2. <_> <_> 7 4 4 16 -1. <_> 7 12 4 8 2. <_> <_> 8 8 9 4 -1. <_> 8 10 9 2 2. <_> <_> 5 2 14 9 -1. <_> 5 5 14 3 3. <_> <_> 3 16 19 8 -1. <_> 3 20 19 4 2. <_> <_> 0 0 10 8 -1. <_> 5 0 5 8 2. <_> <_> 5 2 16 18 -1. <_> 5 2 8 18 2. <_> <_> 0 11 24 11 -1. <_> 8 11 8 11 3. <_> <_> 3 3 18 5 -1. <_> 3 3 9 5 2. <_> <_> 1 16 18 3 -1. <_> 1 17 18 1 3. <_> <_> 5 17 18 3 -1. <_> 5 18 18 1 3. <_> <_> 1 13 9 6 -1. <_> 1 15 9 2 3. <_> <_> 1 9 23 10 -1. <_> 1 14 23 5 2. <_> <_> 3 7 18 3 -1. <_> 3 8 18 1 3. <_> <_> 6 8 12 3 -1. <_> 6 8 6 3 2. <_> <_> 6 2 3 22 -1. <_> 7 2 1 22 3. <_> <_> 14 17 10 6 -1. <_> 14 19 10 2 3. <_> <_> 1 18 10 6 -1. <_> 1 20 10 2 3. <_> <_> 11 3 6 12 -1. <_> 13 3 2 12 3. <_> <_> 10 6 4 9 -1. <_> 12 6 2 9 2. <_> <_> 11 0 6 9 -1. <_> 13 0 2 9 3. <_> <_> 7 0 6 9 -1. <_> 9 0 2 9 3. <_> <_> 12 10 9 6 -1. <_> 15 10 3 6 3. <_> <_> 2 11 6 9 -1. <_> 5 11 3 9 2. <_> <_> 14 5 3 19 -1. <_> 15 5 1 19 3. <_> <_> 6 6 9 6 -1. <_> 6 8 9 2 3. <_> <_> 14 5 3 19 -1. <_> 15 5 1 19 3. <_> <_> 0 3 6 9 -1. <_> 0 6 6 3 3. <_> <_> 5 21 18 3 -1. <_> 5 22 18 1 3. <_> <_> 1 10 18 4 -1. <_> 7 10 6 4 3. <_> <_> 13 4 8 10 -1. <_> 17 4 4 5 2. <_> 13 9 4 5 2. <_> <_> 7 8 9 6 -1. <_> 10 8 3 6 3. <_> <_> 12 9 9 8 -1. <_> 15 9 3 8 3. <_> <_> 0 6 5 12 -1. <_> 0 10 5 4 3. <_> <_> 7 6 14 6 -1. <_> 14 6 7 3 2. <_> 7 9 7 3 2. <_> <_> 7 5 3 19 -1. <_> 8 5 1 19 3. <_> <_> 8 4 15 20 -1. <_> 13 4 5 20 3. <_> <_> 1 4 15 20 -1. <_> 6 4 5 20 3. <_> <_> 13 10 6 6 -1. <_> 13 10 3 6 2. <_> <_> 5 10 6 6 -1. <_> 8 10 3 6 2. <_> <_> 14 2 6 14 -1. <_> 17 2 3 7 2. <_> 14 9 3 7 2. <_> <_> 4 2 6 14 -1. <_> 4 2 3 7 2. <_> 7 9 3 7 2. <_> <_> 12 4 6 7 -1. <_> 12 4 3 7 2. <_> <_> 9 4 6 9 -1. <_> 11 4 2 9 3. <_> <_> 11 4 8 10 -1. <_> 11 4 4 10 2. <_> <_> 5 4 8 10 -1. <_> 9 4 4 10 2. <_> <_> 8 18 10 6 -1. <_> 8 20 10 2 3. <_> <_> 1 18 21 6 -1. <_> 1 20 21 2 3. <_> <_> 9 2 12 6 -1. <_> 9 2 6 6 2. <_> <_> 3 2 12 6 -1. <_> 9 2 6 6 2. <_> <_> 12 5 12 6 -1. <_> 18 5 6 3 2. <_> 12 8 6 3 2. <_> <_> 8 8 6 9 -1. <_> 8 11 6 3 3. <_> <_> 2 7 20 6 -1. <_> 2 9 20 2 3. <_> <_> 0 5 12 6 -1. <_> 0 5 6 3 2. <_> 6 8 6 3 2. <_> <_> 14 14 8 10 -1. <_> 18 14 4 5 2. <_> 14 19 4 5 2. <_> <_> 2 14 8 10 -1. <_> 2 14 4 5 2. <_> 6 19 4 5 2. <_> <_> 2 11 20 13 -1. <_> 2 11 10 13 2. <_> <_> 6 9 12 5 -1. <_> 12 9 6 5 2. <_> <_> 5 6 16 6 -1. <_> 13 6 8 3 2. <_> 5 9 8 3 2. <_> <_> 1 19 9 4 -1. <_> 1 21 9 2 2. <_> <_> 7 5 12 5 -1. <_> 11 5 4 5 3. <_> <_> 3 5 14 12 -1. <_> 3 5 7 6 2. <_> 10 11 7 6 2. <_> <_> 9 4 9 6 -1. <_> 12 4 3 6 3. <_> <_> 2 6 19 3 -1. <_> 2 7 19 1 3. <_> <_> 18 10 6 9 -1. <_> 18 13 6 3 3. <_> <_> 3 7 18 2 -1. <_> 3 8 18 1 2. <_> <_> 20 2 4 18 -1. <_> 22 2 2 9 2. <_> 20 11 2 9 2. <_> <_> 2 18 20 3 -1. <_> 2 19 20 1 3. <_> <_> 1 9 22 3 -1. <_> 1 10 22 1 3. <_> <_> 0 2 4 18 -1. <_> 0 2 2 9 2. <_> 2 11 2 9 2. <_> <_> 19 0 4 23 -1. <_> 19 0 2 23 2. <_> <_> 0 3 6 19 -1. <_> 3 3 3 19 2. <_> <_> 18 2 6 9 -1. <_> 20 2 2 9 3. <_> <_> 0 5 10 6 -1. <_> 0 7 10 2 3. <_> <_> 7 0 12 12 -1. <_> 13 0 6 6 2. <_> 7 6 6 6 2. <_> <_> 0 3 24 6 -1. <_> 0 3 12 3 2. <_> 12 6 12 3 2. <_> <_> 10 14 4 10 -1. <_> 10 19 4 5 2. <_> <_> 8 9 4 15 -1. <_> 8 14 4 5 3. <_> <_> 4 11 17 6 -1. <_> 4 14 17 3 2. <_> <_> 2 5 18 8 -1. <_> 2 5 9 4 2. <_> 11 9 9 4 2. <_> <_> 7 6 14 6 -1. <_> 14 6 7 3 2. <_> 7 9 7 3 2. <_> <_> 3 6 14 6 -1. <_> 3 6 7 3 2. <_> 10 9 7 3 2. <_> <_> 16 5 3 18 -1. <_> 17 5 1 18 3. <_> <_> 5 5 3 18 -1. <_> 6 5 1 18 3. <_> <_> 10 10 14 4 -1. <_> 10 12 14 2 2. <_> <_> 4 10 9 4 -1. <_> 4 12 9 2 2. <_> <_> 2 0 18 9 -1. <_> 2 3 18 3 3. <_> <_> 6 3 12 8 -1. <_> 10 3 4 8 3. <_> <_> 1 1 8 5 -1. <_> 5 1 4 5 2. <_> <_> 12 7 7 8 -1. <_> 12 11 7 4 2. <_> <_> 0 12 22 4 -1. <_> 0 14 22 2 2. <_> <_> 15 6 4 15 -1. <_> 15 11 4 5 3. <_> <_> 5 7 7 8 -1. <_> 5 11 7 4 2. <_> <_> 8 18 9 4 -1. <_> 8 20 9 2 2. <_> <_> 1 2 22 4 -1. <_> 1 4 22 2 2. <_> <_> 17 3 6 17 -1. <_> 19 3 2 17 3. <_> <_> 8 2 8 18 -1. <_> 8 11 8 9 2. <_> <_> 17 0 6 12 -1. <_> 20 0 3 6 2. <_> 17 6 3 6 2. <_> <_> 7 0 6 9 -1. <_> 9 0 2 9 3. <_> <_> 15 5 9 12 -1. <_> 15 11 9 6 2. <_> <_> 2 22 18 2 -1. <_> 2 23 18 1 2. <_> <_> 10 10 12 6 -1. <_> 16 10 6 3 2. <_> 10 13 6 3 2. <_> <_> 0 1 4 11 -1. <_> 2 1 2 11 2. <_> <_> 20 0 4 10 -1. <_> 20 0 2 10 2. <_> <_> 1 3 6 17 -1. <_> 3 3 2 17 3. <_> <_> 15 15 9 6 -1. <_> 15 17 9 2 3. <_> <_> 0 13 8 9 -1. <_> 0 16 8 3 3. <_> <_> 16 8 6 12 -1. <_> 16 12 6 4 3. <_> <_> 2 8 6 12 -1. <_> 2 12 6 4 3. <_> <_> 10 2 4 15 -1. <_> 10 7 4 5 3. <_> <_> 1 5 19 3 -1. <_> 1 6 19 1 3. <_> <_> 11 8 9 7 -1. <_> 14 8 3 7 3. <_> <_> 3 8 12 9 -1. <_> 3 11 12 3 3. <_> <_> 3 6 18 3 -1. <_> 3 7 18 1 3. <_> <_> 10 0 4 12 -1. <_> 10 6 4 6 2. <_> <_> 3 9 18 14 -1. <_> 3 9 9 14 2. <_> <_> 0 0 4 9 -1. <_> 2 0 2 9 2. <_> <_> 12 5 4 18 -1. <_> 12 5 2 18 2. <_> <_> 8 5 4 18 -1. <_> 10 5 2 18 2. <_> <_> 10 5 6 10 -1. <_> 12 5 2 10 3. <_> <_> 9 4 4 11 -1. <_> 11 4 2 11 2. <_> <_> 4 16 18 3 -1. <_> 4 17 18 1 3. <_> <_> 0 16 20 3 -1. <_> 0 17 20 1 3. <_> <_> 9 9 6 12 -1. <_> 9 13 6 4 3. <_> <_> 8 13 8 8 -1. <_> 8 17 8 4 2. <_> <_> 13 10 3 12 -1. <_> 13 16 3 6 2. <_> <_> 5 9 14 14 -1. <_> 5 9 7 7 2. <_> 12 16 7 7 2. <_> <_> 0 0 24 10 -1. <_> 12 0 12 5 2. <_> 0 5 12 5 2. <_> <_> 1 11 18 2 -1. <_> 1 12 18 1 2. <_> <_> 19 5 5 12 -1. <_> 19 9 5 4 3. <_> <_> 0 5 5 12 -1. <_> 0 9 5 4 3. <_> <_> 16 6 8 18 -1. <_> 20 6 4 9 2. <_> 16 15 4 9 2. <_> <_> 0 6 8 18 -1. <_> 0 6 4 9 2. <_> 4 15 4 9 2. <_> <_> 12 5 12 12 -1. <_> 18 5 6 6 2. <_> 12 11 6 6 2. <_> <_> 7 6 6 9 -1. <_> 9 6 2 9 3. <_> <_> 9 13 6 11 -1. <_> 11 13 2 11 3. <_> <_> 0 5 12 12 -1. <_> 0 5 6 6 2. <_> 6 11 6 6 2. <_> <_> 1 2 23 3 -1. <_> 1 3 23 1 3. <_> <_> 1 15 19 3 -1. <_> 1 16 19 1 3. <_> <_> 13 17 11 4 -1. <_> 13 19 11 2 2. <_> <_> 0 13 8 5 -1. <_> 4 13 4 5 2. <_> <_> 12 10 10 4 -1. <_> 12 10 5 4 2. <_> <_> 4 6 9 9 -1. <_> 4 9 9 3 3. <_> <_> 15 14 9 6 -1. <_> 15 16 9 2 3. <_> <_> 1 12 9 6 -1. <_> 1 14 9 2 3. <_> <_> 3 10 20 8 -1. <_> 13 10 10 4 2. <_> 3 14 10 4 2. <_> <_> 2 0 9 18 -1. <_> 5 0 3 18 3. <_> <_> 13 11 9 10 -1. <_> 16 11 3 10 3. <_> <_> 1 2 8 5 -1. <_> 5 2 4 5 2. <_> <_> 3 4 21 6 -1. <_> 10 4 7 6 3. <_> <_> 7 0 10 14 -1. <_> 7 0 5 7 2. <_> 12 7 5 7 2. <_> <_> 12 17 12 4 -1. <_> 12 19 12 2 2. <_> <_> 0 6 23 4 -1. <_> 0 8 23 2 2. <_> <_> 13 10 8 10 -1. <_> 17 10 4 5 2. <_> 13 15 4 5 2. <_> <_> 0 16 18 3 -1. <_> 0 17 18 1 3. <_> <_> 15 16 9 4 -1. <_> 15 18 9 2 2. <_> <_> 0 16 9 4 -1. <_> 0 18 9 2 2. <_> <_> 13 11 6 6 -1. <_> 13 11 3 6 2. <_> <_> 5 11 6 6 -1. <_> 8 11 3 6 2. <_> <_> 0 3 24 6 -1. <_> 12 3 12 3 2. <_> 0 6 12 3 2. <_> <_> 2 4 18 3 -1. <_> 2 5 18 1 3. <_> <_> 0 0 24 4 -1. <_> 12 0 12 2 2. <_> 0 2 12 2 2. <_> <_> 1 16 18 3 -1. <_> 1 17 18 1 3. <_> <_> 15 15 9 6 -1. <_> 15 17 9 2 3. <_> <_> 0 15 9 6 -1. <_> 0 17 9 2 3. <_> <_> 6 17 18 3 -1. <_> 6 18 18 1 3. <_> <_> 8 8 6 10 -1. <_> 10 8 2 10 3. <_> <_> 10 6 6 9 -1. <_> 12 6 2 9 3. <_> <_> 8 8 5 8 -1. <_> 8 12 5 4 2. <_> <_> 12 8 6 8 -1. <_> 12 12 6 4 2. <_> <_> 6 5 6 11 -1. <_> 8 5 2 11 3. <_> <_> 13 6 8 9 -1. <_> 13 9 8 3 3. <_> <_> 1 7 21 6 -1. <_> 1 9 21 2 3. <_> <_> 15 5 3 12 -1. <_> 15 11 3 6 2. <_> <_> 6 9 11 12 -1. <_> 6 13 11 4 3. <_> <_> 13 8 10 8 -1. <_> 18 8 5 4 2. <_> 13 12 5 4 2. <_> <_> 5 8 12 3 -1. <_> 11 8 6 3 2. <_> <_> 6 11 18 4 -1. <_> 12 11 6 4 3. <_> <_> 0 0 22 22 -1. <_> 0 11 22 11 2. <_> <_> 11 2 6 8 -1. <_> 11 6 6 4 2. <_> <_> 9 0 6 9 -1. <_> 11 0 2 9 3. <_> <_> 10 0 6 9 -1. <_> 12 0 2 9 3. <_> <_> 8 3 6 14 -1. <_> 8 3 3 7 2. <_> 11 10 3 7 2. <_> <_> 3 10 18 8 -1. <_> 9 10 6 8 3. <_> <_> 10 0 3 14 -1. <_> 10 7 3 7 2. <_> <_> 4 3 16 20 -1. <_> 4 13 16 10 2. <_> <_> 9 4 6 10 -1. <_> 11 4 2 10 3. <_> <_> 5 0 16 4 -1. <_> 5 2 16 2 2. <_> <_> 2 5 18 4 -1. <_> 8 5 6 4 3. <_> <_> 13 0 6 9 -1. <_> 15 0 2 9 3. <_> <_> 8 4 8 5 -1. <_> 12 4 4 5 2. <_> <_> 12 10 10 4 -1. <_> 12 10 5 4 2. <_> <_> 2 10 10 4 -1. <_> 7 10 5 4 2. <_> <_> 7 11 12 5 -1. <_> 11 11 4 5 3. <_> <_> 3 10 8 10 -1. <_> 3 10 4 5 2. <_> 7 15 4 5 2. <_> <_> 11 12 9 8 -1. <_> 14 12 3 8 3. <_> <_> 0 21 24 3 -1. <_> 8 21 8 3 3. <_> <_> 3 20 18 4 -1. <_> 9 20 6 4 3. <_> <_> 1 15 9 6 -1. <_> 1 17 9 2 3. <_> <_> 11 17 10 4 -1. <_> 11 19 10 2 2. <_> <_> 9 12 4 12 -1. <_> 9 18 4 6 2. <_> <_> 9 6 9 6 -1. <_> 12 6 3 6 3. <_> <_> 1 13 6 9 -1. <_> 1 16 6 3 3. <_> <_> 6 16 12 4 -1. <_> 6 18 12 2 2. <_> <_> 1 5 20 3 -1. <_> 1 6 20 1 3. <_> <_> 8 1 9 9 -1. <_> 8 4 9 3 3. <_> <_> 2 19 9 4 -1. <_> 2 21 9 2 2. <_> <_> 11 1 4 18 -1. <_> 11 7 4 6 3. <_> <_> 7 2 8 12 -1. <_> 7 2 4 6 2. <_> 11 8 4 6 2. <_> <_> 11 10 9 8 -1. <_> 14 10 3 8 3. <_> <_> 5 11 12 5 -1. <_> 9 11 4 5 3. <_> <_> 11 9 9 6 -1. <_> 14 9 3 6 3. <_> <_> 5 10 6 9 -1. <_> 7 10 2 9 3. <_> <_> 4 7 5 12 -1. <_> 4 11 5 4 3. <_> <_> 2 0 21 6 -1. <_> 9 0 7 6 3. <_> <_> 7 6 10 6 -1. <_> 7 8 10 2 3. <_> <_> 9 0 6 15 -1. <_> 11 0 2 15 3. <_> <_> 2 2 18 2 -1. <_> 2 3 18 1 2. <_> <_> 8 17 8 6 -1. <_> 8 20 8 3 2. <_> <_> 3 0 18 2 -1. <_> 3 1 18 1 2. <_> <_> 8 0 9 6 -1. <_> 11 0 3 6 3. <_> <_> 0 17 18 3 -1. <_> 0 18 18 1 3. <_> <_> 6 7 12 5 -1. <_> 10 7 4 5 3. <_> <_> 0 3 6 9 -1. <_> 2 3 2 9 3. <_> <_> 20 2 4 9 -1. <_> 20 2 2 9 2. <_> <_> 0 2 4 9 -1. <_> 2 2 2 9 2. <_> <_> 0 1 24 4 -1. <_> 12 1 12 2 2. <_> 0 3 12 2 2. <_> <_> 0 16 9 6 -1. <_> 0 18 9 2 3. <_> <_> 14 13 9 6 -1. <_> 14 15 9 2 3. <_> <_> 0 15 19 3 -1. <_> 0 16 19 1 3. <_> <_> 1 5 22 12 -1. <_> 12 5 11 6 2. <_> 1 11 11 6 2. <_> <_> 5 13 6 6 -1. <_> 8 13 3 6 2. <_> <_> 4 2 20 3 -1. <_> 4 3 20 1 3. <_> <_> 8 14 6 10 -1. <_> 10 14 2 10 3. <_> <_> 6 12 16 6 -1. <_> 14 12 8 3 2. <_> 6 15 8 3 2. <_> <_> 2 13 8 9 -1. <_> 2 16 8 3 3. <_> <_> 11 8 6 14 -1. <_> 14 8 3 7 2. <_> 11 15 3 7 2. <_> <_> 2 12 16 6 -1. <_> 2 12 8 3 2. <_> 10 15 8 3 2. <_> <_> 5 16 16 8 -1. <_> 5 20 16 4 2. <_> <_> 9 1 4 12 -1. <_> 9 7 4 6 2. <_> <_> 8 2 8 10 -1. <_> 12 2 4 5 2. <_> 8 7 4 5 2. <_> <_> 6 6 12 6 -1. <_> 6 6 6 3 2. <_> 12 9 6 3 2. <_> <_> 10 7 6 9 -1. <_> 12 7 2 9 3. <_> <_> 0 0 8 12 -1. <_> 0 0 4 6 2. <_> 4 6 4 6 2. <_> <_> 18 8 6 9 -1. <_> 18 11 6 3 3. <_> <_> 2 12 6 6 -1. <_> 5 12 3 6 2. <_> <_> 3 21 21 3 -1. <_> 10 21 7 3 3. <_> <_> 2 0 16 6 -1. <_> 2 3 16 3 2. <_> <_> 13 6 7 6 -1. <_> 13 9 7 3 2. <_> <_> 6 4 4 14 -1. <_> 6 11 4 7 2. <_> <_> 9 7 6 9 -1. <_> 11 7 2 9 3. <_> <_> 7 8 6 14 -1. <_> 7 8 3 7 2. <_> 10 15 3 7 2. <_> <_> 18 8 4 16 -1. <_> 18 16 4 8 2. <_> <_> 9 14 6 10 -1. <_> 11 14 2 10 3. <_> <_> 6 11 12 5 -1. <_> 10 11 4 5 3. <_> <_> 0 12 23 3 -1. <_> 0 13 23 1 3. <_> <_> 13 0 6 12 -1. <_> 15 0 2 12 3. <_> <_> 0 10 12 5 -1. <_> 4 10 4 5 3. <_> <_> 13 2 10 4 -1. <_> 13 4 10 2 2. <_> <_> 5 0 6 12 -1. <_> 7 0 2 12 3. <_> <_> 11 6 9 6 -1. <_> 14 6 3 6 3. <_> <_> 4 6 9 6 -1. <_> 7 6 3 6 3. <_> <_> 6 11 18 13 -1. <_> 12 11 6 13 3. <_> <_> 0 11 18 13 -1. <_> 6 11 6 13 3. <_> <_> 12 16 12 6 -1. <_> 16 16 4 6 3. <_> <_> 0 6 21 3 -1. <_> 0 7 21 1 3. <_> <_> 12 16 12 6 -1. <_> 16 16 4 6 3. <_> <_> 5 7 6 14 -1. <_> 5 14 6 7 2. <_> <_> 5 10 19 2 -1. <_> 5 11 19 1 2. <_> <_> 5 4 14 4 -1. <_> 5 6 14 2 2. <_> <_> 3 18 18 4 -1. <_> 9 18 6 4 3. <_> <_> 7 0 4 9 -1. <_> 9 0 2 9 2. <_> <_> 13 3 11 4 -1. <_> 13 5 11 2 2. <_> <_> 2 0 9 6 -1. <_> 5 0 3 6 3. <_> <_> 19 1 4 23 -1. <_> 19 1 2 23 2. <_> <_> 1 1 4 23 -1. <_> 3 1 2 23 2. <_> <_> 5 16 18 3 -1. <_> 5 17 18 1 3. <_> <_> 0 3 11 4 -1. <_> 0 5 11 2 2. <_> <_> 2 16 20 3 -1. <_> 2 17 20 1 3. <_> <_> 5 3 13 4 -1. <_> 5 5 13 2 2. <_> <_> 1 9 22 15 -1. <_> 1 9 11 15 2. <_> <_> 3 4 14 3 -1. <_> 10 4 7 3 2. <_> <_> 8 7 10 4 -1. <_> 8 7 5 4 2. <_> <_> 6 7 10 4 -1. <_> 11 7 5 4 2. <_> <_> 10 4 6 9 -1. <_> 12 4 2 9 3. <_> <_> 1 12 9 6 -1. <_> 4 12 3 6 3. <_> <_> 8 3 8 10 -1. <_> 12 3 4 5 2. <_> 8 8 4 5 2. <_> <_> 3 6 16 6 -1. <_> 3 6 8 3 2. <_> 11 9 8 3 2. <_> <_> 5 6 14 6 -1. <_> 5 9 14 3 2. <_> <_> 4 3 9 6 -1. <_> 4 5 9 2 3. <_> <_> 6 3 18 2 -1. <_> 6 4 18 1 2. <_> <_> 7 6 9 6 -1. <_> 10 6 3 6 3. <_> <_> 0 1 24 3 -1. <_> 0 2 24 1 3. <_> <_> 0 17 10 6 -1. <_> 0 19 10 2 3. <_> <_> 3 18 18 3 -1. <_> 3 19 18 1 3. <_> <_> 2 5 6 16 -1. <_> 2 5 3 8 2. <_> 5 13 3 8 2. <_> <_> 7 6 11 6 -1. <_> 7 8 11 2 3. <_> <_> 5 2 12 22 -1. <_> 5 13 12 11 2. <_> <_> 10 7 4 10 -1. <_> 10 12 4 5 2. <_> <_> 9 0 4 18 -1. <_> 9 6 4 6 3. <_> <_> 18 8 6 9 -1. <_> 18 11 6 3 3. <_> <_> 4 7 15 10 -1. <_> 9 7 5 10 3. <_> <_> 10 5 6 9 -1. <_> 12 5 2 9 3. <_> <_> 9 9 6 10 -1. <_> 11 9 2 10 3. <_> <_> 11 14 6 10 -1. <_> 13 14 2 10 3. <_> <_> 7 14 6 10 -1. <_> 9 14 2 10 3. <_> <_> 4 8 16 9 -1. <_> 4 11 16 3 3. <_> <_> 2 11 20 3 -1. <_> 2 12 20 1 3. <_> <_> 13 0 4 13 -1. <_> 13 0 2 13 2. <_> <_> 7 0 4 13 -1. <_> 9 0 2 13 2. <_> <_> 3 1 18 7 -1. <_> 9 1 6 7 3. <_> <_> 1 11 6 9 -1. <_> 1 14 6 3 3. <_> <_> 8 18 9 6 -1. <_> 8 20 9 2 3. <_> <_> 3 9 15 6 -1. <_> 3 11 15 2 3. <_> <_> 5 10 19 2 -1. <_> 5 11 19 1 2. <_> <_> 8 6 7 16 -1. <_> 8 14 7 8 2. <_> <_> 9 14 9 6 -1. <_> 9 16 9 2 3. <_> <_> 0 7 8 12 -1. <_> 0 11 8 4 3. <_> <_> 6 4 18 3 -1. <_> 6 5 18 1 3. <_> <_> 0 16 12 6 -1. <_> 4 16 4 6 3. <_> <_> 13 13 9 4 -1. <_> 13 15 9 2 2. <_> <_> 5 8 14 14 -1. <_> 5 8 7 7 2. <_> 12 15 7 7 2. <_> <_> 1 16 22 6 -1. <_> 12 16 11 3 2. <_> 1 19 11 3 2. <_> <_> 9 0 6 9 -1. <_> 11 0 2 9 3. <_> <_> 9 5 10 10 -1. <_> 14 5 5 5 2. <_> 9 10 5 5 2. <_> <_> 5 5 10 10 -1. <_> 5 5 5 5 2. <_> 10 10 5 5 2. <_> <_> 4 6 16 6 -1. <_> 12 6 8 3 2. <_> 4 9 8 3 2. <_> <_> 0 7 6 9 -1. <_> 0 10 6 3 3. <_> <_> 16 10 8 14 -1. <_> 20 10 4 7 2. <_> 16 17 4 7 2. <_> <_> 9 12 6 12 -1. <_> 9 18 6 6 2. <_> <_> 8 10 8 12 -1. <_> 12 10 4 6 2. <_> 8 16 4 6 2. <_> <_> 8 0 4 9 -1. <_> 10 0 2 9 2. <_> <_> 10 4 8 16 -1. <_> 14 4 4 8 2. <_> 10 12 4 8 2. <_> <_> 7 10 10 6 -1. <_> 7 12 10 2 3. <_> <_> 5 6 14 14 -1. <_> 12 6 7 7 2. <_> 5 13 7 7 2. <_> <_> 2 11 20 2 -1. <_> 2 12 20 1 2. <_> <_> 18 8 4 16 -1. <_> 18 16 4 8 2. <_> <_> 1 11 12 10 -1. <_> 1 11 6 5 2. <_> 7 16 6 5 2. <_> <_> 6 9 12 4 -1. <_> 6 11 12 2 2. <_> <_> 9 12 6 7 -1. <_> 12 12 3 7 2. <_> <_> 10 4 8 16 -1. <_> 14 4 4 8 2. <_> 10 12 4 8 2. <_> <_> 6 4 8 16 -1. <_> 6 4 4 8 2. <_> 10 12 4 8 2. <_> <_> 8 9 9 6 -1. <_> 11 9 3 6 3. <_> <_> 1 5 16 12 -1. <_> 1 5 8 6 2. <_> 9 11 8 6 2. <_> <_> 9 9 6 8 -1. <_> 9 9 3 8 2. <_> <_> 6 0 3 18 -1. <_> 7 0 1 18 3. <_> <_> 17 9 5 14 -1. <_> 17 16 5 7 2. <_> <_> 2 9 5 14 -1. <_> 2 16 5 7 2. <_> <_> 7 4 10 6 -1. <_> 7 7 10 3 2. <_> <_> 1 3 23 18 -1. <_> 1 9 23 6 3. <_> <_> 1 1 21 3 -1. <_> 8 1 7 3 3. <_> <_> 9 6 6 9 -1. <_> 11 6 2 9 3. <_> <_> 3 18 12 6 -1. <_> 3 18 6 3 2. <_> 9 21 6 3 2. <_> <_> 16 8 8 16 -1. <_> 20 8 4 8 2. <_> 16 16 4 8 2. <_> <_> 0 19 24 4 -1. <_> 8 19 8 4 3. <_> <_> 16 8 8 16 -1. <_> 20 8 4 8 2. <_> 16 16 4 8 2. <_> <_> 0 8 8 16 -1. <_> 0 8 4 8 2. <_> 4 16 4 8 2. <_> <_> 8 12 8 10 -1. <_> 8 17 8 5 2. <_> <_> 5 7 5 8 -1. <_> 5 11 5 4 2. <_> <_> 4 1 19 2 -1. <_> 4 2 19 1 2. <_> <_> 0 12 24 9 -1. <_> 8 12 8 9 3. <_> <_> 6 0 13 8 -1. <_> 6 4 13 4 2. <_> <_> 0 0 24 3 -1. <_> 0 1 24 1 3. <_> <_> 20 3 4 11 -1. <_> 20 3 2 11 2. <_> <_> 8 6 6 9 -1. <_> 10 6 2 9 3. <_> <_> 6 11 12 8 -1. <_> 12 11 6 4 2. <_> 6 15 6 4 2. <_> <_> 0 8 12 6 -1. <_> 0 8 6 3 2. <_> 6 11 6 3 2. <_> <_> 6 17 18 3 -1. <_> 6 18 18 1 3. <_> <_> 0 14 9 6 -1. <_> 0 16 9 2 3. <_> <_> 20 3 4 9 -1. <_> 20 3 2 9 2. <_> <_> 0 3 4 9 -1. <_> 2 3 2 9 2. <_> <_> 15 0 9 19 -1. <_> 18 0 3 19 3. <_> <_> 0 0 9 19 -1. <_> 3 0 3 19 3. <_> <_> 13 11 6 8 -1. <_> 13 11 3 8 2. <_> <_> 5 11 6 8 -1. <_> 8 11 3 8 2. <_> <_> 5 11 19 3 -1. <_> 5 12 19 1 3. <_> <_> 3 20 18 4 -1. <_> 9 20 6 4 3. <_> <_> 6 6 16 6 -1. <_> 6 8 16 2 3. <_> <_> 6 0 9 6 -1. <_> 9 0 3 6 3. <_> <_> 10 3 4 14 -1. <_> 10 10 4 7 2. <_> <_> 1 5 15 12 -1. <_> 1 11 15 6 2. <_> <_> 11 12 8 5 -1. <_> 11 12 4 5 2. <_> <_> 5 0 6 9 -1. <_> 7 0 2 9 3. <_> <_> 12 0 6 9 -1. <_> 14 0 2 9 3. <_> <_> 5 5 12 8 -1. <_> 5 5 6 4 2. <_> 11 9 6 4 2. <_> <_> 13 12 11 6 -1. <_> 13 14 11 2 3. <_> <_> 0 13 21 3 -1. <_> 0 14 21 1 3. <_> <_> 8 1 8 12 -1. <_> 12 1 4 6 2. <_> 8 7 4 6 2. <_> <_> 1 0 6 12 -1. <_> 1 0 3 6 2. <_> 4 6 3 6 2. <_> <_> 2 2 21 2 -1. <_> 2 3 21 1 2. <_> <_> 2 2 19 3 -1. <_> 2 3 19 1 3. <_> <_> 17 10 6 14 -1. <_> 20 10 3 7 2. <_> 17 17 3 7 2. <_> <_> 1 10 6 14 -1. <_> 1 10 3 7 2. <_> 4 17 3 7 2. <_> <_> 7 6 14 14 -1. <_> 14 6 7 7 2. <_> 7 13 7 7 2. <_> <_> 0 12 9 6 -1. <_> 0 14 9 2 3. <_> <_> 15 14 8 9 -1. <_> 15 17 8 3 3. <_> <_> 1 1 22 4 -1. <_> 1 1 11 2 2. <_> 12 3 11 2 2. <_> <_> 9 11 9 6 -1. <_> 9 13 9 2 3. <_> <_> 0 15 18 3 -1. <_> 0 16 18 1 3. <_> <_> 16 14 7 9 -1. <_> 16 17 7 3 3. <_> <_> 4 3 16 4 -1. <_> 12 3 8 4 2. <_> <_> 7 6 12 5 -1. <_> 7 6 6 5 2. <_> <_> 9 6 4 9 -1. <_> 11 6 2 9 2. <_> <_> 12 1 4 10 -1. <_> 12 1 2 10 2. <_> <_> 8 1 4 10 -1. <_> 10 1 2 10 2. <_> <_> 15 15 6 9 -1. <_> 15 18 6 3 3. <_> <_> 3 15 6 9 -1. <_> 3 18 6 3 3. <_> <_> 15 1 3 19 -1. <_> 16 1 1 19 3. <_> <_> 1 3 6 9 -1. <_> 3 3 2 9 3. <_> <_> 15 0 3 19 -1. <_> 16 0 1 19 3. <_> <_> 6 3 12 4 -1. <_> 12 3 6 4 2. <_> <_> 10 5 4 9 -1. <_> 10 5 2 9 2. <_> <_> 6 0 3 19 -1. <_> 7 0 1 19 3. <_> <_> 11 1 3 12 -1. <_> 11 7 3 6 2. <_> <_> 6 7 10 5 -1. <_> 11 7 5 5 2. <_> <_> 11 3 3 18 -1. <_> 12 3 1 18 3. <_> <_> 9 3 6 12 -1. <_> 11 3 2 12 3. <_> <_> 3 7 19 3 -1. <_> 3 8 19 1 3. <_> <_> 2 7 18 3 -1. <_> 2 8 18 1 3. <_> <_> 3 13 18 4 -1. <_> 12 13 9 2 2. <_> 3 15 9 2 2. <_> <_> 3 5 6 9 -1. <_> 5 5 2 9 3. <_> <_> 4 1 20 4 -1. <_> 14 1 10 2 2. <_> 4 3 10 2 2. <_> <_> 0 1 20 4 -1. <_> 0 1 10 2 2. <_> 10 3 10 2 2. <_> <_> 10 15 6 6 -1. <_> 10 15 3 6 2. <_> <_> 0 2 24 8 -1. <_> 8 2 8 8 3. <_> <_> 5 5 18 3 -1. <_> 5 6 18 1 3. <_> <_> 8 15 6 6 -1. <_> 11 15 3 6 2. <_> <_> 11 12 8 5 -1. <_> 11 12 4 5 2. <_> <_> 5 12 8 5 -1. <_> 9 12 4 5 2. <_> <_> 5 0 14 6 -1. <_> 5 2 14 2 3. <_> <_> 10 2 4 15 -1. <_> 10 7 4 5 3. <_> <_> 10 7 5 12 -1. <_> 10 11 5 4 3. <_> <_> 7 9 8 14 -1. <_> 7 9 4 7 2. <_> 11 16 4 7 2. <_> <_> 1 5 22 6 -1. <_> 12 5 11 3 2. <_> 1 8 11 3 2. <_> <_> 0 5 6 6 -1. <_> 0 8 6 3 2. <_> <_> 12 17 9 4 -1. <_> 12 19 9 2 2. <_> <_> 2 18 19 3 -1. <_> 2 19 19 1 3. <_> <_> 12 17 9 4 -1. <_> 12 19 9 2 2. <_> <_> 1 17 18 3 -1. <_> 1 18 18 1 3. <_> <_> 12 17 9 4 -1. <_> 12 19 9 2 2. <_> <_> 0 0 24 3 -1. <_> 0 1 24 1 3. <_> <_> 5 0 14 4 -1. <_> 5 2 14 2 2. <_> <_> 6 14 9 6 -1. <_> 6 16 9 2 3. <_> <_> 14 13 6 9 -1. <_> 14 16 6 3 3. <_> <_> 5 20 13 4 -1. <_> 5 22 13 2 2. <_> <_> 9 9 6 12 -1. <_> 9 13 6 4 3. <_> <_> 1 10 21 3 -1. <_> 8 10 7 3 3. <_> <_> 8 8 9 6 -1. <_> 11 8 3 6 3. <_> <_> 3 10 9 7 -1. <_> 6 10 3 7 3. <_> <_> 12 10 10 8 -1. <_> 17 10 5 4 2. <_> 12 14 5 4 2. <_> <_> 0 15 24 3 -1. <_> 8 15 8 3 3. <_> <_> 8 5 9 6 -1. <_> 8 7 9 2 3. <_> <_> 4 13 6 9 -1. <_> 4 16 6 3 3. <_> <_> 12 17 9 4 -1. <_> 12 19 9 2 2. <_> <_> 9 12 6 6 -1. <_> 9 15 6 3 2. <_> <_> 9 9 14 10 -1. <_> 16 9 7 5 2. <_> 9 14 7 5 2. <_> <_> 1 9 14 10 -1. <_> 1 9 7 5 2. <_> 8 14 7 5 2. <_> <_> 8 7 9 17 -1. <_> 11 7 3 17 3. <_> <_> 3 4 6 20 -1. <_> 3 4 3 10 2. <_> 6 14 3 10 2. <_> <_> 7 8 10 4 -1. <_> 7 8 5 4 2. <_> <_> 10 7 4 9 -1. <_> 12 7 2 9 2. <_> <_> 10 15 6 9 -1. <_> 12 15 2 9 3. <_> <_> 3 8 6 16 -1. <_> 3 8 3 8 2. <_> 6 16 3 8 2. <_> <_> 12 17 9 4 -1. <_> 12 19 9 2 2. <_> <_> 3 17 9 4 -1. <_> 3 19 9 2 2. <_> <_> 10 1 9 6 -1. <_> 13 1 3 6 3. <_> <_> 5 7 4 10 -1. <_> 5 12 4 5 2. <_> <_> 7 5 12 6 -1. <_> 11 5 4 6 3. <_> <_> 6 4 9 8 -1. <_> 9 4 3 8 3. <_> <_> 12 16 10 8 -1. <_> 17 16 5 4 2. <_> 12 20 5 4 2. <_> <_> 2 16 10 8 -1. <_> 2 16 5 4 2. <_> 7 20 5 4 2. <_> <_> 0 0 24 4 -1. <_> 12 0 12 2 2. <_> 0 2 12 2 2. <_> <_> 0 6 9 6 -1. <_> 0 8 9 2 3. <_> <_> 0 4 24 6 -1. <_> 12 4 12 3 2. <_> 0 7 12 3 2. <_> <_> 5 0 11 4 -1. <_> 5 2 11 2 2. <_> <_> 1 1 22 4 -1. <_> 12 1 11 2 2. <_> 1 3 11 2 2. <_> <_> 9 6 6 18 -1. <_> 9 15 6 9 2. <_> <_> 2 9 20 4 -1. <_> 2 11 20 2 2. <_> <_> 5 2 14 14 -1. <_> 5 9 14 7 2. <_> <_> 4 2 16 6 -1. <_> 4 5 16 3 2. <_> <_> 2 3 19 3 -1. <_> 2 4 19 1 3. <_> <_> 7 1 10 4 -1. <_> 7 3 10 2 2. <_> <_> 0 9 4 15 -1. <_> 0 14 4 5 3. <_> <_> 2 10 21 3 -1. <_> 2 11 21 1 3. <_> <_> 3 0 6 6 -1. <_> 6 0 3 6 2. <_> <_> 6 4 14 9 -1. <_> 6 7 14 3 3. <_> <_> 9 1 6 9 -1. <_> 11 1 2 9 3. <_> <_> 15 8 9 9 -1. <_> 15 11 9 3 3. <_> <_> 8 0 4 21 -1. <_> 8 7 4 7 3. <_> <_> 3 22 19 2 -1. <_> 3 23 19 1 2. <_> <_> 2 15 20 3 -1. <_> 2 16 20 1 3. <_> <_> 19 0 4 13 -1. <_> 19 0 2 13 2. <_> <_> 1 7 8 8 -1. <_> 1 11 8 4 2. <_> <_> 14 14 6 9 -1. <_> 14 17 6 3 3. <_> <_> 4 14 6 9 -1. <_> 4 17 6 3 3. <_> <_> 14 5 4 10 -1. <_> 14 5 2 10 2. <_> <_> 6 5 4 10 -1. <_> 8 5 2 10 2. <_> <_> 14 5 6 6 -1. <_> 14 8 6 3 2. <_> <_> 4 5 6 6 -1. <_> 4 8 6 3 2. <_> <_> 0 2 24 21 -1. <_> 8 2 8 21 3. <_> <_> 1 2 6 13 -1. <_> 3 2 2 13 3. <_> <_> 20 0 4 21 -1. <_> 20 0 2 21 2. <_> <_> 0 4 4 20 -1. <_> 2 4 2 20 2. <_> <_> 8 16 9 6 -1. <_> 8 18 9 2 3. <_> <_> 7 0 6 9 -1. <_> 9 0 2 9 3. <_> <_> 16 12 7 9 -1. <_> 16 15 7 3 3. <_> <_> 5 21 14 3 -1. <_> 12 21 7 3 2. <_> <_> 11 5 6 9 -1. <_> 11 5 3 9 2. <_> <_> 10 5 4 10 -1. <_> 12 5 2 10 2. <_> <_> 10 6 6 9 -1. <_> 12 6 2 9 3. <_> <_> 7 5 6 9 -1. <_> 10 5 3 9 2. <_> <_> 14 14 10 4 -1. <_> 14 16 10 2 2. <_> <_> 5 5 14 14 -1. <_> 5 5 7 7 2. <_> 12 12 7 7 2. <_> <_> 12 8 12 6 -1. <_> 18 8 6 3 2. <_> 12 11 6 3 2. <_> <_> 6 6 12 12 -1. <_> 6 6 6 6 2. <_> 12 12 6 6 2. <_> <_> 11 13 6 10 -1. <_> 13 13 2 10 3. <_> <_> 1 10 20 8 -1. <_> 1 10 10 4 2. <_> 11 14 10 4 2. <_> <_> 15 13 9 6 -1. <_> 15 15 9 2 3. <_> <_> 9 0 6 9 -1. <_> 9 3 6 3 3. <_> <_> 10 1 5 14 -1. <_> 10 8 5 7 2. <_> <_> 3 4 16 6 -1. <_> 3 6 16 2 3. <_> <_> 16 3 8 9 -1. <_> 16 6 8 3 3. <_> <_> 7 13 6 10 -1. <_> 9 13 2 10 3. <_> <_> 15 13 9 6 -1. <_> 15 15 9 2 3. <_> <_> 0 13 9 6 -1. <_> 0 15 9 2 3. <_> <_> 13 16 9 6 -1. <_> 13 18 9 2 3. <_> <_> 2 16 9 6 -1. <_> 2 18 9 2 3. <_> <_> 5 16 18 3 -1. <_> 5 17 18 1 3. <_> <_> 1 16 18 3 -1. <_> 1 17 18 1 3. <_> <_> 5 0 18 3 -1. <_> 5 1 18 1 3. <_> <_> 1 1 19 2 -1. <_> 1 2 19 1 2. <_> <_> 14 2 6 11 -1. <_> 16 2 2 11 3. <_> <_> 4 15 15 6 -1. <_> 9 15 5 6 3. <_> <_> 14 2 6 11 -1. <_> 16 2 2 11 3. <_> <_> 4 2 6 11 -1. <_> 6 2 2 11 3. <_> <_> 18 2 6 9 -1. <_> 18 5 6 3 3. <_> <_> 1 2 22 4 -1. <_> 1 2 11 2 2. <_> 12 4 11 2 2. <_> <_> 2 0 21 12 -1. <_> 9 0 7 12 3. <_> <_> 0 12 18 3 -1. <_> 0 13 18 1 3. <_> <_> 12 2 6 9 -1. <_> 14 2 2 9 3. <_> <_> 3 10 18 3 -1. <_> 3 11 18 1 3. <_> <_> 16 3 8 9 -1. <_> 16 6 8 3 3. <_> <_> 3 7 18 3 -1. <_> 3 8 18 1 3. <_> <_> 9 11 6 9 -1. <_> 11 11 2 9 3. <_> <_> 9 8 6 9 -1. <_> 11 8 2 9 3. <_> <_> 15 0 2 18 -1. <_> 15 0 1 18 2. <_> <_> 7 0 2 18 -1. <_> 8 0 1 18 2. <_> <_> 17 3 7 9 -1. <_> 17 6 7 3 3. <_> <_> 3 18 9 6 -1. <_> 3 20 9 2 3. <_> <_> 3 18 21 3 -1. <_> 3 19 21 1 3. <_> <_> 0 3 7 9 -1. <_> 0 6 7 3 3. <_> <_> 2 7 22 3 -1. <_> 2 8 22 1 3. <_> <_> 0 3 24 16 -1. <_> 0 3 12 8 2. <_> 12 11 12 8 2. <_> <_> 13 17 9 4 -1. <_> 13 19 9 2 2. <_> <_> 5 5 12 8 -1. <_> 5 5 6 4 2. <_> 11 9 6 4 2. <_> <_> 5 6 14 6 -1. <_> 12 6 7 3 2. <_> 5 9 7 3 2. <_> <_> 5 16 14 6 -1. <_> 5 16 7 3 2. <_> 12 19 7 3 2. <_> <_> 18 2 6 9 -1. <_> 18 5 6 3 3. <_> <_> 0 2 6 9 -1. <_> 0 5 6 3 3. <_> <_> 3 4 20 10 -1. <_> 13 4 10 5 2. <_> 3 9 10 5 2. <_> <_> 2 13 9 8 -1. <_> 5 13 3 8 3. <_> <_> 2 1 21 15 -1. <_> 9 1 7 15 3. <_> <_> 5 12 14 8 -1. <_> 12 12 7 8 2. <_> <_> 6 7 12 4 -1. <_> 6 7 6 4 2. <_> <_> 6 5 9 6 -1. <_> 9 5 3 6 3. <_> <_> 13 11 6 6 -1. <_> 13 11 3 6 2. <_> <_> 5 11 6 6 -1. <_> 8 11 3 6 2. <_> <_> 6 4 18 2 -1. <_> 6 5 18 1 2. <_> <_> 0 2 6 11 -1. <_> 2 2 2 11 3. <_> <_> 18 0 6 15 -1. <_> 20 0 2 15 3. <_> <_> 0 0 6 13 -1. <_> 2 0 2 13 3. <_> <_> 12 0 6 9 -1. <_> 14 0 2 9 3. <_> <_> 6 0 6 9 -1. <_> 8 0 2 9 3. <_> <_> 0 2 24 4 -1. <_> 8 2 8 4 3. <_> <_> 3 13 18 4 -1. <_> 12 13 9 4 2. <_> <_> 9 7 10 4 -1. <_> 9 7 5 4 2. <_> <_> 5 8 12 3 -1. <_> 11 8 6 3 2. <_> <_> 4 14 19 3 -1. <_> 4 15 19 1 3. <_> <_> 10 0 4 20 -1. <_> 10 10 4 10 2. <_> <_> 8 15 9 6 -1. <_> 8 17 9 2 3. <_> <_> 2 9 15 4 -1. <_> 7 9 5 4 3. <_> <_> 8 4 12 7 -1. <_> 12 4 4 7 3. <_> <_> 0 10 6 9 -1. <_> 0 13 6 3 3. <_> <_> 18 5 6 9 -1. <_> 18 8 6 3 3. <_> <_> 0 18 16 6 -1. <_> 0 18 8 3 2. <_> 8 21 8 3 2. <_> <_> 9 18 14 6 -1. <_> 16 18 7 3 2. <_> 9 21 7 3 2. <_> <_> 1 20 20 4 -1. <_> 1 20 10 2 2. <_> 11 22 10 2 2. <_> <_> 2 8 20 6 -1. <_> 12 8 10 3 2. <_> 2 11 10 3 2. <_> <_> 7 8 6 9 -1. <_> 9 8 2 9 3. <_> <_> 8 5 12 8 -1. <_> 12 5 4 8 3. <_> <_> 4 5 12 8 -1. <_> 8 5 4 8 3. <_> <_> 10 6 6 9 -1. <_> 12 6 2 9 3. <_> <_> 2 0 6 16 -1. <_> 4 0 2 16 3. <_> <_> 15 4 6 12 -1. <_> 15 8 6 4 3. <_> <_> 3 4 6 12 -1. <_> 3 8 6 4 3. <_> <_> 15 12 9 6 -1. <_> 15 14 9 2 3. <_> <_> 4 0 15 22 -1. <_> 4 11 15 11 2. <_> <_> 15 12 9 6 -1. <_> 15 14 9 2 3. <_> <_> 0 12 9 6 -1. <_> 0 14 9 2 3. <_> <_> 15 15 9 6 -1. <_> 15 17 9 2 3. <_> <_> 0 15 9 6 -1. <_> 0 17 9 2 3. <_> <_> 10 0 8 10 -1. <_> 14 0 4 5 2. <_> 10 5 4 5 2. <_> <_> 1 0 4 16 -1. <_> 3 0 2 16 2. <_> <_> 7 6 10 6 -1. <_> 7 8 10 2 3. <_> <_> 10 12 4 10 -1. <_> 10 17 4 5 2. <_> <_> 8 4 10 6 -1. <_> 8 6 10 2 3. <_> <_> 3 22 18 2 -1. <_> 12 22 9 2 2. <_> <_> 7 7 11 6 -1. <_> 7 9 11 2 3. <_> <_> 0 0 12 10 -1. <_> 0 0 6 5 2. <_> 6 5 6 5 2. <_> <_> 10 1 12 6 -1. <_> 16 1 6 3 2. <_> 10 4 6 3 2. <_> <_> 7 16 9 4 -1. <_> 7 18 9 2 2. <_> <_> 5 7 15 16 -1. <_> 10 7 5 16 3. <_> <_> 5 10 12 13 -1. <_> 11 10 6 13 2. <_> <_> 6 2 12 6 -1. <_> 12 2 6 3 2. <_> 6 5 6 3 2. <_> <_> 3 9 12 9 -1. <_> 3 12 12 3 3. <_> <_> 16 2 8 6 -1. <_> 16 5 8 3 2. <_> <_> 0 2 8 6 -1. <_> 0 5 8 3 2. <_> <_> 0 3 24 11 -1. <_> 0 3 12 11 2. <_> <_> 0 13 8 10 -1. <_> 0 13 4 5 2. <_> 4 18 4 5 2. <_> <_> 10 14 4 10 -1. <_> 10 19 4 5 2. <_> <_> 10 2 4 21 -1. <_> 10 9 4 7 3. <_> <_> 4 4 15 9 -1. <_> 4 7 15 3 3. <_> <_> 0 1 24 6 -1. <_> 8 1 8 6 3. <_> <_> 9 6 5 16 -1. <_> 9 14 5 8 2. <_> <_> 3 21 18 3 -1. <_> 9 21 6 3 3. <_> <_> 6 5 3 12 -1. <_> 6 11 3 6 2. <_> <_> 11 6 4 9 -1. <_> 11 6 2 9 2. <_> <_> 5 6 9 8 -1. <_> 8 6 3 8 3. <_> <_> 4 3 20 2 -1. <_> 4 4 20 1 2. <_> <_> 2 10 18 3 -1. <_> 8 10 6 3 3. <_> <_> 7 15 10 6 -1. <_> 7 17 10 2 3. <_> <_> 1 4 4 18 -1. <_> 1 4 2 9 2. <_> 3 13 2 9 2. <_> <_> 13 0 6 9 -1. <_> 15 0 2 9 3. <_> <_> 5 0 6 9 -1. <_> 7 0 2 9 3. <_> <_> 11 0 6 9 -1. <_> 13 0 2 9 3. <_> <_> 6 7 9 6 -1. <_> 9 7 3 6 3. <_> <_> 3 0 18 2 -1. <_> 3 1 18 1 2. <_> <_> 0 10 20 4 -1. <_> 0 10 10 2 2. <_> 10 12 10 2 2. <_> <_> 10 2 4 12 -1. <_> 10 8 4 6 2. <_> <_> 6 5 6 12 -1. <_> 6 5 3 6 2. <_> 9 11 3 6 2. <_> <_> 6 0 18 22 -1. <_> 15 0 9 11 2. <_> 6 11 9 11 2. <_> <_> 0 0 18 22 -1. <_> 0 0 9 11 2. <_> 9 11 9 11 2. <_> <_> 18 2 6 11 -1. <_> 20 2 2 11 3. <_> <_> 0 2 6 11 -1. <_> 2 2 2 11 3. <_> <_> 11 0 6 9 -1. <_> 13 0 2 9 3. <_> <_> 0 0 20 3 -1. <_> 0 1 20 1 3. <_> <_> 2 2 20 2 -1. <_> 2 3 20 1 2. <_> <_> 1 10 18 2 -1. <_> 1 11 18 1 2. <_> <_> 18 7 6 9 -1. <_> 18 10 6 3 3. <_> <_> 0 0 22 9 -1. <_> 0 3 22 3 3. <_> <_> 17 3 6 9 -1. <_> 17 6 6 3 3. <_> <_> 0 7 6 9 -1. <_> 0 10 6 3 3. <_> <_> 0 6 24 6 -1. <_> 0 8 24 2 3. <_> <_> 0 2 6 10 -1. <_> 2 2 2 10 3. <_> <_> 10 6 6 9 -1. <_> 12 6 2 9 3. <_> <_> 7 0 6 9 -1. <_> 9 0 2 9 3. <_> <_> 15 0 6 9 -1. <_> 17 0 2 9 3. <_> <_> 3 0 6 9 -1. <_> 5 0 2 9 3. <_> <_> 15 17 9 6 -1. <_> 15 19 9 2 3. <_> <_> 0 17 18 3 -1. <_> 0 18 18 1 3. <_> <_> 15 14 9 6 -1. <_> 15 16 9 2 3. <_> <_> 0 15 23 6 -1. <_> 0 17 23 2 3. <_> <_> 5 15 18 3 -1. <_> 5 16 18 1 3. <_> <_> 0 14 9 6 -1. <_> 0 16 9 2 3. <_> <_> 9 8 8 10 -1. <_> 13 8 4 5 2. <_> 9 13 4 5 2. <_> <_> 3 7 15 6 -1. <_> 8 7 5 6 3. <_> <_> 9 8 8 10 -1. <_> 13 8 4 5 2. <_> 9 13 4 5 2. <_> <_> 5 0 6 12 -1. <_> 8 0 3 12 2. <_> <_> 9 8 8 10 -1. <_> 13 8 4 5 2. <_> 9 13 4 5 2. <_> <_> 8 5 6 9 -1. <_> 10 5 2 9 3. <_> <_> 10 6 4 18 -1. <_> 12 6 2 9 2. <_> 10 15 2 9 2. <_> <_> 5 7 12 4 -1. <_> 11 7 6 4 2. <_> <_> 9 8 8 10 -1. <_> 13 8 4 5 2. <_> 9 13 4 5 2. <_> <_> 7 8 8 10 -1. <_> 7 8 4 5 2. <_> 11 13 4 5 2. <_> <_> 11 10 6 14 -1. <_> 14 10 3 7 2. <_> 11 17 3 7 2. <_> <_> 9 5 6 19 -1. <_> 12 5 3 19 2. <_> <_> 6 12 12 6 -1. <_> 12 12 6 3 2. <_> 6 15 6 3 2. <_> <_> 1 9 18 6 -1. <_> 1 9 9 3 2. <_> 10 12 9 3 2. <_> <_> 16 14 8 10 -1. <_> 20 14 4 5 2. <_> 16 19 4 5 2. <_> <_> 0 9 22 8 -1. <_> 0 9 11 4 2. <_> 11 13 11 4 2. <_> <_> 8 18 12 6 -1. <_> 14 18 6 3 2. <_> 8 21 6 3 2. <_> <_> 0 6 20 18 -1. <_> 0 6 10 9 2. <_> 10 15 10 9 2. <_> <_> 3 6 20 12 -1. <_> 13 6 10 6 2. <_> 3 12 10 6 2. <_> <_> 0 16 10 8 -1. <_> 0 16 5 4 2. <_> 5 20 5 4 2. <_> <_> 6 16 18 3 -1. <_> 6 17 18 1 3. <_> <_> 0 11 19 3 -1. <_> 0 12 19 1 3. <_> <_> 14 6 6 9 -1. <_> 14 9 6 3 3. <_> <_> 1 7 22 4 -1. <_> 1 7 11 2 2. <_> 12 9 11 2 2. <_> <_> 13 6 7 12 -1. <_> 13 10 7 4 3. <_> <_> 4 7 11 9 -1. <_> 4 10 11 3 3. <_> <_> 12 10 10 8 -1. <_> 17 10 5 4 2. <_> 12 14 5 4 2. <_> <_> 2 12 9 7 -1. <_> 5 12 3 7 3. <_> <_> 16 14 6 9 -1. <_> 16 17 6 3 3. <_> <_> 3 12 6 12 -1. <_> 3 16 6 4 3. <_> <_> 14 13 6 6 -1. <_> 14 16 6 3 2. <_> <_> 8 0 6 9 -1. <_> 10 0 2 9 3. <_> <_> 9 1 6 23 -1. <_> 11 1 2 23 3. <_> <_> 0 16 9 6 -1. <_> 0 18 9 2 3. <_> <_> 4 17 18 3 -1. <_> 4 18 18 1 3. <_> <_> 5 2 13 14 -1. <_> 5 9 13 7 2. <_> <_> 15 0 8 12 -1. <_> 19 0 4 6 2. <_> 15 6 4 6 2. <_> <_> 0 0 8 12 -1. <_> 0 0 4 6 2. <_> 4 6 4 6 2. <_> <_> 8 2 8 7 -1. <_> 8 2 4 7 2. <_> <_> 1 1 6 9 -1. <_> 3 1 2 9 3. <_> <_> 14 8 6 12 -1. <_> 17 8 3 6 2. <_> 14 14 3 6 2. <_> <_> 4 8 6 12 -1. <_> 4 8 3 6 2. <_> 7 14 3 6 2. <_> <_> 16 5 5 15 -1. <_> 16 10 5 5 3. <_> <_> 3 5 5 15 -1. <_> 3 10 5 5 3. <_> <_> 18 4 6 9 -1. <_> 18 7 6 3 3. <_> <_> 1 7 6 15 -1. <_> 1 12 6 5 3. <_> <_> 11 15 12 8 -1. <_> 17 15 6 4 2. <_> 11 19 6 4 2. <_> <_> 0 2 24 4 -1. <_> 0 2 12 2 2. <_> 12 4 12 2 2. <_> <_> 15 1 2 19 -1. <_> 15 1 1 19 2. <_> <_> 7 1 2 19 -1. <_> 8 1 1 19 2. <_> <_> 22 1 2 20 -1. <_> 22 1 1 20 2. <_> <_> 0 1 2 20 -1. <_> 1 1 1 20 2. <_> <_> 18 11 6 12 -1. <_> 20 11 2 12 3. <_> <_> 0 11 6 12 -1. <_> 2 11 2 12 3. <_> <_> 3 6 18 14 -1. <_> 3 13 18 7 2. <_> <_> 6 10 7 8 -1. <_> 6 14 7 4 2. <_> <_> 7 9 12 12 -1. <_> 7 13 12 4 3. <_> <_> 2 18 18 5 -1. <_> 11 18 9 5 2. <_> <_> 4 21 20 3 -1. <_> 4 22 20 1 3. <_> <_> 9 12 6 12 -1. <_> 9 12 3 6 2. <_> 12 18 3 6 2. <_> <_> 4 6 18 3 -1. <_> 4 7 18 1 3. <_> <_> 3 6 18 3 -1. <_> 3 7 18 1 3. <_> <_> 18 4 6 9 -1. <_> 18 7 6 3 3. <_> <_> 2 12 9 6 -1. <_> 2 14 9 2 3. <_> <_> 4 14 18 4 -1. <_> 13 14 9 2 2. <_> 4 16 9 2 2. <_> <_> 7 7 6 14 -1. <_> 7 7 3 7 2. <_> 10 14 3 7 2. <_> <_> 7 13 12 6 -1. <_> 13 13 6 3 2. <_> 7 16 6 3 2. <_> <_> 6 7 12 9 -1. <_> 10 7 4 9 3. <_> <_> 12 12 6 6 -1. <_> 12 12 3 6 2. <_> <_> 0 2 4 10 -1. <_> 0 7 4 5 2. <_> <_> 8 0 9 6 -1. <_> 11 0 3 6 3. <_> <_> 2 9 12 6 -1. <_> 2 12 12 3 2. <_> <_> 13 10 6 9 -1. <_> 13 13 6 3 3. <_> <_> 5 10 6 9 -1. <_> 5 13 6 3 3. <_> <_> 9 15 9 6 -1. <_> 9 17 9 2 3. <_> <_> 5 16 12 6 -1. <_> 5 19 12 3 2. <_> <_> 3 2 20 3 -1. <_> 3 3 20 1 3. <_> <_> 2 5 12 6 -1. <_> 6 5 4 6 3. <_> <_> 11 0 3 24 -1. <_> 12 0 1 24 3. <_> <_> 3 16 15 4 -1. <_> 8 16 5 4 3. <_> <_> 9 12 6 12 -1. <_> 9 18 6 6 2. <_> <_> 1 15 12 8 -1. <_> 1 15 6 4 2. <_> 7 19 6 4 2. <_> <_> 15 10 8 14 -1. <_> 19 10 4 7 2. <_> 15 17 4 7 2. <_> <_> 1 9 8 14 -1. <_> 1 9 4 7 2. <_> 5 16 4 7 2. <_> <_> 9 11 9 10 -1. <_> 9 16 9 5 2. <_> <_> 6 7 12 6 -1. <_> 6 9 12 2 3. <_> <_> 10 15 6 9 -1. <_> 12 15 2 9 3. <_> <_> 7 8 9 7 -1. <_> 10 8 3 7 3. <_> <_> 10 4 8 10 -1. <_> 14 4 4 5 2. <_> 10 9 4 5 2. <_> <_> 4 6 6 9 -1. <_> 4 9 6 3 3. <_> <_> 0 6 24 12 -1. <_> 8 6 8 12 3. <_> <_> 3 7 6 14 -1. <_> 6 7 3 14 2. <_> <_> 19 8 5 8 -1. <_> 19 12 5 4 2. <_> <_> 0 8 5 8 -1. <_> 0 12 5 4 2. <_> <_> 17 3 6 6 -1. <_> 17 6 6 3 2. <_> <_> 1 3 6 6 -1. <_> 1 6 6 3 2. <_> <_> 18 2 6 9 -1. <_> 18 5 6 3 3. <_> <_> 0 2 6 9 -1. <_> 0 5 6 3 3. <_> <_> 3 3 18 6 -1. <_> 3 5 18 2 3. <_> <_> 2 3 9 6 -1. <_> 2 5 9 2 3. <_> <_> 9 3 10 8 -1. <_> 14 3 5 4 2. <_> 9 7 5 4 2. <_> <_> 5 3 10 8 -1. <_> 5 3 5 4 2. <_> 10 7 5 4 2. <_> <_> 10 11 6 12 -1. <_> 10 11 3 12 2. <_> <_> 8 11 6 11 -1. <_> 11 11 3 11 2. <_> <_> 7 8 10 4 -1. <_> 7 8 5 4 2. <_> <_> 9 6 6 7 -1. <_> 12 6 3 7 2. <_> <_> 5 18 18 3 -1. <_> 5 19 18 1 3. <_> <_> 8 4 6 9 -1. <_> 10 4 2 9 3. <_> <_> 8 1 9 7 -1. <_> 11 1 3 7 3. <_> <_> 6 11 6 6 -1. <_> 9 11 3 6 2. <_> <_> 14 12 4 11 -1. <_> 14 12 2 11 2. <_> <_> 6 12 4 11 -1. <_> 8 12 2 11 2. <_> <_> 8 0 12 18 -1. <_> 12 0 4 18 3. <_> <_> 2 12 10 5 -1. <_> 7 12 5 5 2. <_> <_> 2 20 22 3 -1. <_> 2 21 22 1 3. <_> <_> 0 4 2 20 -1. <_> 1 4 1 20 2. <_> <_> 0 2 24 4 -1. <_> 8 2 8 4 3. <_> <_> 7 8 10 4 -1. <_> 7 10 10 2 2. <_> <_> 6 7 8 10 -1. <_> 6 7 4 5 2. <_> 10 12 4 5 2. <_> <_> 14 0 6 14 -1. <_> 17 0 3 7 2. <_> 14 7 3 7 2. <_> <_> 4 11 5 8 -1. <_> 4 15 5 4 2. <_> <_> 2 0 20 9 -1. <_> 2 3 20 3 3. <_> <_> 6 7 12 8 -1. <_> 6 7 6 4 2. <_> 12 11 6 4 2. <_> <_> 9 17 6 6 -1. <_> 9 20 6 3 2. <_> <_> 7 10 10 4 -1. <_> 7 12 10 2 2. <_> <_> 6 5 12 9 -1. <_> 10 5 4 9 3. <_> <_> 5 11 6 8 -1. <_> 8 11 3 8 2. <_> <_> 18 4 4 17 -1. <_> 18 4 2 17 2. <_> <_> 0 0 6 6 -1. <_> 3 0 3 6 2. <_> <_> 18 4 4 17 -1. <_> 18 4 2 17 2. <_> <_> 2 4 4 17 -1. <_> 4 4 2 17 2. <_> <_> 5 18 19 3 -1. <_> 5 19 19 1 3. <_> <_> 11 0 2 18 -1. <_> 11 9 2 9 2. <_> <_> 15 4 2 18 -1. <_> 15 13 2 9 2. <_> <_> 7 4 2 18 -1. <_> 7 13 2 9 2. <_> <_> 7 11 10 8 -1. <_> 12 11 5 4 2. <_> 7 15 5 4 2. <_> <_> 10 6 4 9 -1. <_> 12 6 2 9 2. <_> <_> 10 0 6 9 -1. <_> 12 0 2 9 3. <_> <_> 2 9 16 8 -1. <_> 2 9 8 4 2. <_> 10 13 8 4 2. <_> <_> 14 15 6 9 -1. <_> 14 18 6 3 3. <_> <_> 8 7 6 9 -1. <_> 10 7 2 9 3. <_> <_> 14 15 6 9 -1. <_> 14 18 6 3 3. <_> <_> 3 12 12 6 -1. <_> 3 14 12 2 3. <_> <_> 14 12 9 6 -1. <_> 14 14 9 2 3. <_> <_> 1 12 9 6 -1. <_> 1 14 9 2 3. <_> <_> 3 7 18 3 -1. <_> 3 8 18 1 3. <_> <_> 1 7 22 6 -1. <_> 1 9 22 2 3. <_> <_> 18 4 6 6 -1. <_> 18 7 6 3 2. <_> <_> 0 4 6 6 -1. <_> 0 7 6 3 2. <_> <_> 5 11 16 6 -1. <_> 5 14 16 3 2. <_> <_> 6 16 9 4 -1. <_> 6 18 9 2 2. <_> <_> 14 15 6 9 -1. <_> 14 18 6 3 3. <_> <_> 4 15 6 9 -1. <_> 4 18 6 3 3. <_> <_> 15 1 6 23 -1. <_> 17 1 2 23 3. <_> <_> 0 21 24 3 -1. <_> 8 21 8 3 3. <_> <_> 0 20 24 4 -1. <_> 8 20 8 4 3. <_> <_> 3 1 6 23 -1. <_> 5 1 2 23 3. <_> <_> 3 17 18 3 -1. <_> 3 18 18 1 3. <_> <_> 0 16 18 3 -1. <_> 0 17 18 1 3. <_> <_> 1 16 22 4 -1. <_> 12 16 11 2 2. <_> 1 18 11 2 2. <_> <_> 0 16 9 6 -1. <_> 0 18 9 2 3. <_> <_> 2 10 21 3 -1. <_> 9 10 7 3 3. <_> <_> 2 18 12 6 -1. <_> 2 18 6 3 2. <_> 8 21 6 3 2. <_> <_> 0 5 24 4 -1. <_> 0 7 24 2 2. <_> <_> 10 2 4 15 -1. <_> 10 7 4 5 3. <_> <_> 10 7 6 12 -1. <_> 10 13 6 6 2. <_> <_> 6 6 6 9 -1. <_> 8 6 2 9 3. <_> <_> 11 0 6 9 -1. <_> 13 0 2 9 3. <_> <_> 9 7 6 9 -1. <_> 11 7 2 9 3. <_> <_> 2 1 20 3 -1. <_> 2 2 20 1 3. <_> <_> 1 18 12 6 -1. <_> 1 18 6 3 2. <_> 7 21 6 3 2. <_> <_> 13 2 4 13 -1. <_> 13 2 2 13 2. <_> <_> 6 7 12 4 -1. <_> 12 7 6 4 2. <_> <_> 10 1 4 13 -1. <_> 10 1 2 13 2. <_> <_> 6 0 3 18 -1. <_> 7 0 1 18 3. <_> <_> 14 3 10 5 -1. <_> 14 3 5 5 2. <_> <_> 6 15 12 8 -1. <_> 10 15 4 8 3. <_> <_> 9 10 6 9 -1. <_> 11 10 2 9 3. <_> <_> 8 3 4 9 -1. <_> 10 3 2 9 2. <_> <_> 17 0 6 14 -1. <_> 20 0 3 7 2. <_> 17 7 3 7 2. <_> <_> 1 0 6 14 -1. <_> 1 0 3 7 2. <_> 4 7 3 7 2. <_> <_> 14 0 6 16 -1. <_> 17 0 3 8 2. <_> 14 8 3 8 2. <_> <_> 7 4 4 10 -1. <_> 9 4 2 10 2. <_> <_> 3 17 18 6 -1. <_> 12 17 9 3 2. <_> 3 20 9 3 2. <_> <_> 1 20 22 4 -1. <_> 12 20 11 4 2. <_> <_> 14 3 10 5 -1. <_> 14 3 5 5 2. <_> <_> 0 3 10 5 -1. <_> 5 3 5 5 2. <_> <_> 12 6 12 16 -1. <_> 16 6 4 16 3. <_> <_> 0 6 12 16 -1. <_> 4 6 4 16 3. <_> <_> 10 9 5 15 -1. <_> 10 14 5 5 3. <_> <_> 1 18 21 2 -1. <_> 1 19 21 1 2. <_> <_> 15 0 9 6 -1. <_> 15 2 9 2 3. <_> <_> 6 1 12 4 -1. <_> 12 1 6 4 2. <_> <_> 6 0 12 12 -1. <_> 12 0 6 6 2. <_> 6 6 6 6 2. <_> <_> 8 10 8 12 -1. <_> 8 10 4 6 2. <_> 12 16 4 6 2. <_> <_> 14 16 10 8 -1. <_> 19 16 5 4 2. <_> 14 20 5 4 2. <_> <_> 0 16 10 8 -1. <_> 0 16 5 4 2. <_> 5 20 5 4 2. <_> <_> 10 12 12 5 -1. <_> 14 12 4 5 3. <_> <_> 6 16 10 8 -1. <_> 6 16 5 4 2. <_> 11 20 5 4 2. <_> <_> 7 6 12 6 -1. <_> 13 6 6 3 2. <_> 7 9 6 3 2. <_> <_> 9 6 4 18 -1. <_> 9 6 2 9 2. <_> 11 15 2 9 2. <_> <_> 10 9 6 14 -1. <_> 13 9 3 7 2. <_> 10 16 3 7 2. <_> <_> 8 9 6 14 -1. <_> 8 9 3 7 2. <_> 11 16 3 7 2. <_> <_> 7 4 11 12 -1. <_> 7 10 11 6 2. <_> <_> 4 8 6 16 -1. <_> 4 8 3 8 2. <_> 7 16 3 8 2. <_> <_> 17 3 4 21 -1. <_> 17 10 4 7 3. <_> <_> 3 3 4 21 -1. <_> 3 10 4 7 3. <_> <_> 10 1 8 18 -1. <_> 14 1 4 9 2. <_> 10 10 4 9 2. <_> <_> 2 5 16 8 -1. <_> 2 5 8 4 2. <_> 10 9 8 4 2. <_> <_> 3 6 18 12 -1. <_> 3 10 18 4 3. <_> <_> 4 10 16 12 -1. <_> 4 14 16 4 3. <_> <_> 15 4 8 20 -1. <_> 19 4 4 10 2. <_> 15 14 4 10 2. <_> <_> 7 2 9 6 -1. <_> 10 2 3 6 3. <_> <_> 15 4 8 20 -1. <_> 19 4 4 10 2. <_> 15 14 4 10 2. <_> <_> 1 4 8 20 -1. <_> 1 4 4 10 2. <_> 5 14 4 10 2. <_> <_> 11 8 8 14 -1. <_> 15 8 4 7 2. <_> 11 15 4 7 2. <_> <_> 5 8 8 14 -1. <_> 5 8 4 7 2. <_> 9 15 4 7 2. <_> <_> 10 13 5 8 -1. <_> 10 17 5 4 2. <_> <_> 4 13 7 9 -1. <_> 4 16 7 3 3. <_> <_> 0 13 24 10 -1. <_> 0 18 24 5 2. <_> <_> 4 2 8 11 -1. <_> 8 2 4 11 2. <_> <_> 10 2 8 16 -1. <_> 14 2 4 8 2. <_> 10 10 4 8 2. <_> <_> 0 2 24 6 -1. <_> 0 2 12 3 2. <_> 12 5 12 3 2. <_> <_> 6 0 12 9 -1. <_> 6 3 12 3 3. <_> <_> 1 2 12 12 -1. <_> 1 2 6 6 2. <_> 7 8 6 6 2. <_> <_> 18 5 6 9 -1. <_> 18 8 6 3 3. <_> <_> 4 3 8 10 -1. <_> 4 3 4 5 2. <_> 8 8 4 5 2. <_> <_> 6 21 18 3 -1. <_> 6 22 18 1 3. <_> <_> 1 10 18 2 -1. <_> 1 11 18 1 2. <_> <_> 1 10 22 3 -1. <_> 1 11 22 1 3. <_> <_> 2 8 12 9 -1. <_> 2 11 12 3 3. <_> <_> 12 8 12 6 -1. <_> 18 8 6 3 2. <_> 12 11 6 3 2. <_> <_> 0 8 12 6 -1. <_> 0 8 6 3 2. <_> 6 11 6 3 2. <_> <_> 10 15 6 9 -1. <_> 12 15 2 9 3. <_> <_> 7 13 9 6 -1. <_> 7 15 9 2 3. <_> <_> 9 8 7 12 -1. <_> 9 14 7 6 2. <_> <_> 4 13 9 6 -1. <_> 7 13 3 6 3. <_> <_> 6 15 18 4 -1. <_> 12 15 6 4 3. <_> <_> 5 4 4 16 -1. <_> 7 4 2 16 2. <_> <_> 10 15 6 9 -1. <_> 12 15 2 9 3. <_> <_> 8 15 6 9 -1. <_> 10 15 2 9 3. <_> <_> 9 11 12 10 -1. <_> 15 11 6 5 2. <_> 9 16 6 5 2. <_> <_> 3 6 14 6 -1. <_> 3 8 14 2 3. <_> <_> 4 2 17 8 -1. <_> 4 6 17 4 2. <_> <_> 6 2 12 21 -1. <_> 6 9 12 7 3. <_> <_> 8 1 9 9 -1. <_> 8 4 9 3 3. <_> <_> 0 7 24 3 -1. <_> 12 7 12 3 2. <_> <_> 11 6 9 10 -1. <_> 11 11 9 5 2. <_> <_> 2 11 18 3 -1. <_> 2 12 18 1 3. <_> <_> 8 16 9 4 -1. <_> 8 18 9 2 2. <_> <_> 0 0 9 6 -1. <_> 0 2 9 2 3. <_> <_> 0 11 24 6 -1. <_> 0 13 24 2 3. <_> <_> 2 9 20 6 -1. <_> 2 12 20 3 2. <_> <_> 4 5 16 12 -1. <_> 12 5 8 6 2. <_> 4 11 8 6 2. <_> <_> 10 2 4 15 -1. <_> 10 7 4 5 3. <_> <_> 7 3 10 4 -1. <_> 7 5 10 2 2. <_> <_> 9 15 6 8 -1. <_> 9 19 6 4 2. <_> <_> 17 0 7 10 -1. <_> 17 5 7 5 2. <_> <_> 0 0 7 10 -1. <_> 0 5 7 5 2. <_> <_> 16 1 6 12 -1. <_> 19 1 3 6 2. <_> 16 7 3 6 2. <_> <_> 1 0 19 8 -1. <_> 1 4 19 4 2. <_> <_> 12 2 9 4 -1. <_> 12 4 9 2 2. <_> <_> 3 2 9 4 -1. <_> 3 4 9 2 2. <_> <_> 12 2 10 6 -1. <_> 12 4 10 2 3. <_> <_> 3 4 18 2 -1. <_> 12 4 9 2 2. <_> <_> 12 1 4 9 -1. <_> 12 1 2 9 2. <_> <_> 8 1 4 9 -1. <_> 10 1 2 9 2. <_> <_> 10 5 8 10 -1. <_> 14 5 4 5 2. <_> 10 10 4 5 2. <_> <_> 6 4 12 13 -1. <_> 10 4 4 13 3. <_> <_> 13 5 6 6 -1. <_> 13 5 3 6 2. <_> <_> 1 5 12 3 -1. <_> 7 5 6 3 2. <_> <_> 7 5 10 6 -1. <_> 7 7 10 2 3. <_> <_> 2 0 21 5 -1. <_> 9 0 7 5 3. <_> <_> 0 8 9 9 -1. <_> 0 11 9 3 3. <_> <_> 9 6 6 9 -1. <_> 11 6 2 9 3. <_> <_> 0 3 6 7 -1. <_> 3 3 3 7 2. <_> <_> 9 18 12 6 -1. <_> 15 18 6 3 2. <_> 9 21 6 3 2. <_> <_> 2 8 20 6 -1. <_> 2 8 10 3 2. <_> 12 11 10 3 2. <_> <_> 13 2 10 4 -1. <_> 13 4 10 2 2. <_> <_> 4 5 5 18 -1. <_> 4 11 5 6 3. <_> <_> 20 4 4 9 -1. <_> 20 4 2 9 2. <_> <_> 8 6 8 14 -1. <_> 8 13 8 7 2. <_> <_> 0 1 24 6 -1. <_> 12 1 12 3 2. <_> 0 4 12 3 2. <_> <_> 0 4 4 9 -1. <_> 2 4 2 9 2. <_> <_> 3 6 18 3 -1. <_> 3 7 18 1 3. <_> <_> 3 17 16 6 -1. <_> 3 19 16 2 3. <_> <_> 13 6 6 9 -1. <_> 13 9 6 3 3. <_> <_> 5 6 14 6 -1. <_> 5 6 7 3 2. <_> 12 9 7 3 2. <_> <_> 13 5 8 10 -1. <_> 17 5 4 5 2. <_> 13 10 4 5 2. <_> <_> 2 2 20 3 -1. <_> 2 3 20 1 3. <_> <_> 9 2 9 6 -1. <_> 12 2 3 6 3. <_> <_> 8 6 6 9 -1. <_> 10 6 2 9 3. <_> <_> 12 3 4 11 -1. <_> 12 3 2 11 2. <_> <_> 8 3 4 11 -1. <_> 10 3 2 11 2. <_> <_> 8 3 8 10 -1. <_> 12 3 4 5 2. <_> 8 8 4 5 2. <_> <_> 11 1 2 18 -1. <_> 12 1 1 18 2. <_> <_> 9 2 9 6 -1. <_> 12 2 3 6 3. <_> <_> 0 2 19 3 -1. <_> 0 3 19 1 3. <_> <_> 9 14 9 6 -1. <_> 9 16 9 2 3. <_> <_> 1 8 18 5 -1. <_> 7 8 6 5 3. <_> <_> 12 0 6 9 -1. <_> 14 0 2 9 3. <_> <_> 6 0 6 9 -1. <_> 8 0 2 9 3. <_> <_> 13 6 4 15 -1. <_> 13 11 4 5 3. <_> <_> 1 5 18 3 -1. <_> 1 6 18 1 3. <_> <_> 9 7 14 6 -1. <_> 9 9 14 2 3. <_> <_> 2 16 18 3 -1. <_> 2 17 18 1 3. <_> <_> 15 17 9 6 -1. <_> 15 19 9 2 3. <_> <_> 0 8 12 6 -1. <_> 0 8 6 3 2. <_> 6 11 6 3 2. <_> <_> 9 13 7 8 -1. <_> 9 17 7 4 2. <_> <_> 2 17 20 3 -1. <_> 2 18 20 1 3. <_> <_> 15 17 9 6 -1. <_> 15 19 9 2 3. <_> <_> 4 0 15 4 -1. <_> 4 2 15 2 2. <_> <_> 17 2 6 6 -1. <_> 17 5 6 3 2. <_> <_> 0 3 6 9 -1. <_> 0 6 6 3 3. <_> <_> 15 17 9 6 -1. <_> 15 19 9 2 3. <_> <_> 0 17 9 6 -1. <_> 0 19 9 2 3. <_> <_> 9 18 12 6 -1. <_> 15 18 6 3 2. <_> 9 21 6 3 2. <_> <_> 3 15 6 9 -1. <_> 3 18 6 3 3. <_> <_> 16 13 8 10 -1. <_> 20 13 4 5 2. <_> 16 18 4 5 2. <_> <_> 0 14 24 4 -1. <_> 8 14 8 4 3. <_> <_> 13 18 6 6 -1. <_> 13 18 3 6 2. <_> <_> 0 13 8 10 -1. <_> 0 13 4 5 2. <_> 4 18 4 5 2. <_> <_> 0 14 24 6 -1. <_> 0 17 24 3 2. <_> <_> 5 2 12 8 -1. <_> 5 2 6 4 2. <_> 11 6 6 4 2. <_> <_> 8 9 9 6 -1. <_> 11 9 3 6 3. <_> <_> 4 3 16 4 -1. <_> 4 5 16 2 2. <_> <_> 10 2 4 10 -1. <_> 10 7 4 5 2. <_> <_> 8 4 5 8 -1. <_> 8 8 5 4 2. <_> <_> 11 5 9 12 -1. <_> 11 9 9 4 3. <_> <_> 4 5 9 12 -1. <_> 4 9 9 4 3. <_> <_> 14 6 6 9 -1. <_> 14 9 6 3 3. <_> <_> 2 4 20 12 -1. <_> 2 8 20 4 3. <_> <_> 4 4 17 16 -1. <_> 4 12 17 8 2. <_> <_> 8 7 7 6 -1. <_> 8 10 7 3 2. <_> <_> 1 9 23 2 -1. <_> 1 10 23 1 2. <_> <_> 7 0 6 9 -1. <_> 9 0 2 9 3. <_> <_> 13 3 4 9 -1. <_> 13 3 2 9 2. <_> <_> 8 1 6 13 -1. <_> 10 1 2 13 3. <_> <_> 4 22 18 2 -1. <_> 4 23 18 1 2. <_> <_> 3 10 9 6 -1. <_> 6 10 3 6 3. <_> <_> 14 0 2 24 -1. <_> 14 0 1 24 2. <_> <_> 8 0 2 24 -1. <_> 9 0 1 24 2. <_> <_> 3 2 18 10 -1. <_> 9 2 6 10 3. <_> <_> 4 13 15 6 -1. <_> 9 13 5 6 3. <_> <_> 3 21 18 3 -1. <_> 9 21 6 3 3. <_> <_> 9 1 4 11 -1. <_> 11 1 2 11 2. <_> <_> 9 7 10 4 -1. <_> 9 7 5 4 2. <_> <_> 7 0 10 18 -1. <_> 12 0 5 18 2. <_> <_> 12 1 6 16 -1. <_> 14 1 2 16 3. <_> <_> 6 1 6 16 -1. <_> 8 1 2 16 3. <_> <_> 18 2 6 6 -1. <_> 18 5 6 3 2. <_> <_> 3 5 18 2 -1. <_> 3 6 18 1 2. <_> <_> 18 2 6 6 -1. <_> 18 5 6 3 2. <_> <_> 0 2 6 6 -1. <_> 0 5 6 3 2. <_> <_> 13 11 11 6 -1. <_> 13 13 11 2 3. <_> <_> 5 7 10 4 -1. <_> 10 7 5 4 2. <_> <_> 11 9 10 7 -1. <_> 11 9 5 7 2. <_> <_> 3 9 10 7 -1. <_> 8 9 5 7 2. <_> <_> 16 4 6 6 -1. <_> 16 4 3 6 2. <_> <_> 5 6 10 8 -1. <_> 5 6 5 4 2. <_> 10 10 5 4 2. <_> <_> 7 21 16 3 -1. <_> 7 21 8 3 2. <_> <_> 1 21 16 3 -1. <_> 9 21 8 3 2. <_> <_> 2 5 22 14 -1. <_> 13 5 11 7 2. <_> 2 12 11 7 2. <_> <_> 3 10 8 10 -1. <_> 3 10 4 5 2. <_> 7 15 4 5 2. <_> <_> 17 0 6 12 -1. <_> 20 0 3 6 2. <_> 17 6 3 6 2. <_> <_> 5 2 6 18 -1. <_> 7 2 2 18 3. <_> <_> 13 0 6 9 -1. <_> 15 0 2 9 3. <_> <_> 0 12 7 9 -1. <_> 0 15 7 3 3. <_> <_> 15 13 8 10 -1. <_> 19 13 4 5 2. <_> 15 18 4 5 2. <_> <_> 1 0 6 12 -1. <_> 1 0 3 6 2. <_> 4 6 3 6 2. <_> <_> 12 1 3 12 -1. <_> 12 7 3 6 2. <_> <_> 1 13 8 10 -1. <_> 1 13 4 5 2. <_> 5 18 4 5 2. <_> <_> 3 21 19 2 -1. <_> 3 22 19 1 2. <_> <_> 6 3 4 13 -1. <_> 8 3 2 13 2. <_> <_> 5 10 18 3 -1. <_> 5 11 18 1 3. <_> <_> 9 3 5 12 -1. <_> 9 7 5 4 3. <_> <_> 11 2 4 15 -1. <_> 11 7 4 5 3. <_> <_> 4 1 16 4 -1. <_> 4 3 16 2 2. <_> <_> 6 0 18 3 -1. <_> 6 1 18 1 3. <_> <_> 5 1 10 8 -1. <_> 5 1 5 4 2. <_> 10 5 5 4 2. <_> <_> 11 18 12 6 -1. <_> 17 18 6 3 2. <_> 11 21 6 3 2. <_> <_> 5 15 12 3 -1. <_> 11 15 6 3 2. <_> <_> 1 10 22 4 -1. <_> 1 10 11 4 2. <_> <_> 7 9 9 6 -1. <_> 10 9 3 6 3. <_> <_> 6 11 12 5 -1. <_> 10 11 4 5 3. <_> <_> 6 7 10 7 -1. <_> 11 7 5 7 2. <_> <_> 11 2 8 10 -1. <_> 11 2 4 10 2. <_> <_> 5 2 8 10 -1. <_> 9 2 4 10 2. <_> <_> 6 4 18 6 -1. <_> 15 4 9 3 2. <_> 6 7 9 3 2. <_> <_> 0 5 10 9 -1. <_> 0 8 10 3 3. <_> <_> 2 7 21 6 -1. <_> 2 9 21 2 3. <_> <_> 0 4 22 16 -1. <_> 0 4 11 8 2. <_> 11 12 11 8 2. <_> <_> 9 0 6 22 -1. <_> 9 11 6 11 2. <_> <_> 9 1 3 12 -1. <_> 9 7 3 6 2. <_> <_> 12 0 12 18 -1. <_> 18 0 6 9 2. <_> 12 9 6 9 2. <_> <_> 0 0 12 18 -1. <_> 0 0 6 9 2. <_> 6 9 6 9 2. <_> <_> 1 1 22 4 -1. <_> 12 1 11 2 2. <_> 1 3 11 2 2. <_> <_> 3 0 18 4 -1. <_> 3 2 18 2 2. <_> <_> 2 5 22 6 -1. <_> 2 7 22 2 3. <_> <_> 5 0 6 9 -1. <_> 5 3 6 3 3. <_> <_> 10 14 6 9 -1. <_> 12 14 2 9 3. <_> <_> 8 14 6 9 -1. <_> 10 14 2 9 3. <_> <_> 5 18 18 3 -1. <_> 5 19 18 1 3. <_> <_> 6 0 6 13 -1. <_> 9 0 3 13 2. <_> <_> 7 4 12 4 -1. <_> 7 4 6 4 2. <_> <_> 5 2 12 6 -1. <_> 9 2 4 6 3. <_> <_> 4 1 18 3 -1. <_> 4 2 18 1 3. <_> <_> 0 8 6 12 -1. <_> 0 12 6 4 3. <_> <_> 9 15 6 9 -1. <_> 11 15 2 9 3. <_> <_> 9 10 6 13 -1. <_> 11 10 2 13 3. <_> <_> 6 17 18 2 -1. <_> 6 18 18 1 2. <_> <_> 9 4 6 9 -1. <_> 11 4 2 9 3. <_> <_> 10 0 6 9 -1. <_> 12 0 2 9 3. <_> <_> 5 6 10 8 -1. <_> 5 6 5 4 2. <_> 10 10 5 4 2. <_> <_> 14 9 5 8 -1. <_> 14 13 5 4 2. <_> <_> 5 9 5 8 -1. <_> 5 13 5 4 2. <_> <_> 14 11 9 6 -1. <_> 14 13 9 2 3. <_> <_> 0 2 23 15 -1. <_> 0 7 23 5 3. <_> <_> 16 0 8 12 -1. <_> 16 6 8 6 2. <_> <_> 4 15 6 9 -1. <_> 4 18 6 3 3. <_> <_> 8 18 9 4 -1. <_> 8 20 9 2 2. <_> <_> 0 17 18 3 -1. <_> 0 18 18 1 3. <_> <_> 13 11 11 6 -1. <_> 13 13 11 2 3. <_> <_> 0 11 11 6 -1. <_> 0 13 11 2 3. <_> <_> 0 9 24 6 -1. <_> 12 9 12 3 2. <_> 0 12 12 3 2. <_> <_> 6 16 8 8 -1. <_> 6 20 8 4 2. <_> <_> 10 16 14 6 -1. <_> 10 18 14 2 3. <_> <_> 1 1 21 3 -1. <_> 1 2 21 1 3. <_> <_> 0 2 24 3 -1. <_> 0 2 12 3 2. <_> <_> 2 15 8 5 -1. <_> 6 15 4 5 2. <_> <_> 2 11 21 3 -1. <_> 9 11 7 3 3. <_> <_> 1 18 12 6 -1. <_> 1 18 6 3 2. <_> 7 21 6 3 2. <_> <_> 10 14 4 10 -1. <_> 10 19 4 5 2. <_> <_> 7 7 4 10 -1. <_> 7 12 4 5 2. <_> <_> 9 8 6 12 -1. <_> 9 12 6 4 3. <_> <_> 7 1 9 6 -1. <_> 10 1 3 6 3. <_> <_> 3 14 19 2 -1. <_> 3 15 19 1 2. <_> <_> 7 7 10 10 -1. <_> 7 7 5 5 2. <_> 12 12 5 5 2. <_> <_> 3 12 18 12 -1. <_> 3 12 9 12 2. <_> <_> 8 0 6 12 -1. <_> 10 0 2 12 3. <_> <_> 3 0 17 9 -1. <_> 3 3 17 3 3. <_> <_> 6 0 12 11 -1. <_> 10 0 4 11 3. <_> <_> 1 0 6 13 -1. <_> 4 0 3 13 2. <_> <_> 5 8 16 6 -1. <_> 5 11 16 3 2. <_> <_> 8 8 5 12 -1. <_> 8 14 5 6 2. <_> <_> 3 21 18 3 -1. <_> 9 21 6 3 3. <_> <_> 0 0 6 6 -1. <_> 3 0 3 6 2. <_> <_> 2 0 20 3 -1. <_> 2 1 20 1 3. <_> <_> 4 6 15 10 -1. <_> 9 6 5 10 3. <_> <_> 9 6 6 9 -1. <_> 11 6 2 9 3. <_> <_> 9 0 6 9 -1. <_> 11 0 2 9 3. <_> <_> 14 0 6 9 -1. <_> 16 0 2 9 3. <_> <_> 7 16 9 6 -1. <_> 7 18 9 2 3. <_> <_> 14 0 6 9 -1. <_> 16 0 2 9 3. <_> <_> 4 0 6 9 -1. <_> 6 0 2 9 3. <_> <_> 17 1 6 16 -1. <_> 19 1 2 16 3. <_> <_> 1 1 6 16 -1. <_> 3 1 2 16 3. <_> <_> 14 13 6 9 -1. <_> 14 16 6 3 3. <_> <_> 0 0 6 9 -1. <_> 0 3 6 3 3. <_> <_> 9 5 6 6 -1. <_> 9 5 3 6 2. <_> <_> 3 10 9 6 -1. <_> 6 10 3 6 3. <_> <_> 14 7 3 16 -1. <_> 14 15 3 8 2. <_> <_> 4 10 14 12 -1. <_> 4 10 7 6 2. <_> 11 16 7 6 2. <_> <_> 7 6 12 6 -1. <_> 7 8 12 2 3. <_> <_> 7 2 4 20 -1. <_> 9 2 2 20 2. <_> <_> 14 13 6 9 -1. <_> 14 16 6 3 3. <_> <_> 10 6 4 9 -1. <_> 12 6 2 9 2. <_> <_> 14 13 6 9 -1. <_> 14 16 6 3 3. <_> <_> 5 20 14 4 -1. <_> 5 22 14 2 2. <_> <_> 4 4 16 12 -1. <_> 4 10 16 6 2. <_> <_> 9 6 6 9 -1. <_> 11 6 2 9 3. <_> <_> 3 0 21 4 -1. <_> 3 2 21 2 2. <_> <_> 4 13 6 9 -1. <_> 4 16 6 3 3. <_> <_> 16 16 5 8 -1. <_> 16 20 5 4 2. <_> <_> 4 0 16 16 -1. <_> 4 0 8 8 2. <_> 12 8 8 8 2. <_> <_> 6 6 14 6 -1. <_> 13 6 7 3 2. <_> 6 9 7 3 2. <_> <_> 10 5 4 15 -1. <_> 10 10 4 5 3. <_> <_> 9 15 12 8 -1. <_> 15 15 6 4 2. <_> 9 19 6 4 2. <_> <_> 6 7 12 4 -1. <_> 12 7 6 4 2. <_> <_> 5 6 14 6 -1. <_> 12 6 7 3 2. <_> 5 9 7 3 2. <_> <_> 3 6 18 10 -1. <_> 3 6 9 5 2. <_> 12 11 9 5 2. <_> <_> 6 0 18 21 -1. <_> 12 0 6 21 3. <_> <_> 0 0 24 21 -1. <_> 8 0 8 21 3. <_> <_> 6 18 18 3 -1. <_> 6 19 18 1 3. <_> <_> 0 15 9 6 -1. <_> 0 17 9 2 3. <_> <_> 4 3 19 2 -1. <_> 4 4 19 1 2. <_> <_> 0 3 24 2 -1. <_> 0 4 24 1 2. <_> <_> 15 14 9 4 -1. <_> 15 16 9 2 2. <_> <_> 0 14 9 4 -1. <_> 0 16 9 2 2. <_> <_> 6 15 18 2 -1. <_> 6 16 18 1 2. <_> <_> 3 17 18 3 -1. <_> 3 18 18 1 3. <_> <_> 12 0 3 23 -1. <_> 13 0 1 23 3. <_> <_> 6 0 8 6 -1. <_> 6 3 8 3 2. <_> <_> 6 16 18 3 -1. <_> 6 17 18 1 3. <_> <_> 9 0 3 23 -1. <_> 10 0 1 23 3. <_> <_> 10 7 4 10 -1. <_> 10 12 4 5 2. <_> <_> 7 8 10 12 -1. <_> 7 12 10 4 3. <_> <_> 14 9 6 14 -1. <_> 17 9 3 7 2. <_> 14 16 3 7 2. <_> <_> 2 0 10 9 -1. <_> 2 3 10 3 3. <_> <_> 11 1 5 12 -1. <_> 11 7 5 6 2. <_> <_> 1 4 12 10 -1. <_> 1 4 6 5 2. <_> 7 9 6 5 2. <_> <_> 15 1 9 4 -1. <_> 15 3 9 2 2. <_> <_> 1 2 8 10 -1. <_> 1 2 4 5 2. <_> 5 7 4 5 2. <_> <_> 10 1 5 12 -1. <_> 10 5 5 4 3. <_> <_> 4 0 14 24 -1. <_> 11 0 7 24 2. <_> <_> 7 17 10 4 -1. <_> 7 19 10 2 2. <_> <_> 10 14 4 10 -1. <_> 10 19 4 5 2. <_> <_> 13 15 6 9 -1. <_> 15 15 2 9 3. <_> <_> 3 21 18 3 -1. <_> 3 22 18 1 3. <_> <_> 13 15 6 9 -1. <_> 15 15 2 9 3. <_> <_> 5 15 6 9 -1. <_> 7 15 2 9 3. <_> <_> 10 6 4 18 -1. <_> 12 6 2 9 2. <_> 10 15 2 9 2. <_> <_> 7 3 6 11 -1. <_> 9 3 2 11 3. <_> <_> 15 1 9 4 -1. <_> 15 3 9 2 2. <_> <_> 5 4 14 8 -1. <_> 5 8 14 4 2. <_> <_> 8 1 15 9 -1. <_> 8 4 15 3 3. <_> <_> 7 2 8 10 -1. <_> 7 2 4 5 2. <_> 11 7 4 5 2. <_> <_> 12 2 6 12 -1. <_> 12 2 3 12 2. <_> <_> 6 2 6 12 -1. <_> 9 2 3 12 2. <_> <_> 7 7 12 4 -1. <_> 7 7 6 4 2. <_> <_> 6 3 12 10 -1. <_> 10 3 4 10 3. <_> <_> 5 6 16 6 -1. <_> 13 6 8 3 2. <_> 5 9 8 3 2. <_> <_> 3 1 18 9 -1. <_> 9 1 6 9 3. <_> <_> 3 8 18 5 -1. <_> 9 8 6 5 3. <_> <_> 0 0 24 22 -1. <_> 0 0 12 11 2. <_> 12 11 12 11 2. <_> <_> 14 16 9 6 -1. <_> 14 18 9 2 3. <_> <_> 0 16 24 8 -1. <_> 0 20 24 4 2. <_> <_> 1 19 22 4 -1. <_> 12 19 11 2 2. <_> 1 21 11 2 2. <_> <_> 1 16 9 6 -1. <_> 1 18 9 2 3. <_> <_> 7 8 10 4 -1. <_> 7 8 5 4 2. <_> <_> 9 15 6 9 -1. <_> 11 15 2 9 3. <_> <_> 10 18 12 6 -1. <_> 16 18 6 3 2. <_> 10 21 6 3 2. <_> <_> 2 18 12 6 -1. <_> 2 18 6 3 2. <_> 8 21 6 3 2. <_> <_> 8 3 16 9 -1. <_> 8 6 16 3 3. <_> <_> 0 5 10 6 -1. <_> 0 7 10 2 3. <_> <_> 5 5 18 3 -1. <_> 5 6 18 1 3. <_> <_> 2 6 9 6 -1. <_> 2 9 9 3 2. <_> <_> 14 2 10 9 -1. <_> 14 5 10 3 3. <_> <_> 3 6 18 3 -1. <_> 3 7 18 1 3. <_> <_> 9 2 15 6 -1. <_> 9 4 15 2 3. <_> <_> 4 8 15 6 -1. <_> 4 10 15 2 3. <_> <_> 0 5 24 4 -1. <_> 12 5 12 2 2. <_> 0 7 12 2 2. <_> <_> 7 8 6 12 -1. <_> 9 8 2 12 3. <_> <_> 11 0 6 9 -1. <_> 13 0 2 9 3. <_> <_> 0 12 6 12 -1. <_> 0 12 3 6 2. <_> 3 18 3 6 2. <_> <_> 14 12 10 6 -1. <_> 14 14 10 2 3. <_> <_> 2 7 18 9 -1. <_> 2 10 18 3 3. <_> <_> 11 14 10 9 -1. <_> 11 17 10 3 3. <_> <_> 7 6 10 8 -1. <_> 7 6 5 4 2. <_> 12 10 5 4 2. <_> <_> 6 6 14 6 -1. <_> 13 6 7 3 2. <_> 6 9 7 3 2. <_> <_> 4 13 9 7 -1. <_> 7 13 3 7 3. <_> <_> 14 10 6 12 -1. <_> 17 10 3 6 2. <_> 14 16 3 6 2. <_> <_> 4 10 6 12 -1. <_> 4 10 3 6 2. <_> 7 16 3 6 2. <_> <_> 13 9 8 6 -1. <_> 13 9 4 6 2. <_> <_> 8 3 4 14 -1. <_> 10 3 2 14 2. <_> <_> 17 0 3 18 -1. <_> 18 0 1 18 3. <_> <_> 4 12 16 12 -1. <_> 12 12 8 12 2. <_> <_> 15 0 6 14 -1. <_> 17 0 2 14 3. <_> <_> 3 0 6 14 -1. <_> 5 0 2 14 3. <_> <_> 12 2 12 20 -1. <_> 16 2 4 20 3. <_> <_> 0 2 12 20 -1. <_> 4 2 4 20 3. <_> <_> 16 0 6 17 -1. <_> 18 0 2 17 3. <_> <_> 2 0 6 17 -1. <_> 4 0 2 17 3. <_> <_> 15 6 9 6 -1. <_> 15 8 9 2 3. <_> <_> 0 6 9 6 -1. <_> 0 8 9 2 3. <_> <_> 18 1 6 13 -1. <_> 20 1 2 13 3. <_> <_> 0 1 6 13 -1. <_> 2 1 2 13 3. <_> <_> 16 0 4 9 -1. <_> 16 0 2 9 2. <_> <_> 5 10 12 7 -1. <_> 9 10 4 7 3. <_> <_> 12 9 12 6 -1. <_> 12 11 12 2 3. <_> <_> 0 9 12 6 -1. <_> 0 11 12 2 3. <_> <_> 5 7 14 9 -1. <_> 5 10 14 3 3. <_> <_> 0 15 20 3 -1. <_> 0 16 20 1 3. <_> <_> 8 10 8 10 -1. <_> 12 10 4 5 2. <_> 8 15 4 5 2. <_> <_> 5 4 13 9 -1. <_> 5 7 13 3 3. <_> <_> 10 2 6 18 -1. <_> 10 8 6 6 3. <_> <_> 6 0 6 9 -1. <_> 8 0 2 9 3. <_> <_> 6 9 12 4 -1. <_> 6 11 12 2 2. <_> <_> 3 2 15 12 -1. <_> 3 6 15 4 3. <_> <_> 12 0 12 5 -1. <_> 16 0 4 5 3. <_> <_> 0 15 18 3 -1. <_> 6 15 6 3 3. <_> <_> 0 14 24 5 -1. <_> 8 14 8 5 3. <_> <_> 5 1 3 18 -1. <_> 6 1 1 18 3. <_> <_> 10 0 4 14 -1. <_> 10 0 2 14 2. <_> <_> 9 3 4 9 -1. <_> 11 3 2 9 2. <_> <_> 8 2 12 6 -1. <_> 14 2 6 3 2. <_> 8 5 6 3 2. <_> <_> 0 4 17 4 -1. <_> 0 6 17 2 2. <_> <_> 16 16 5 8 -1. <_> 16 20 5 4 2. <_> <_> 3 16 5 8 -1. <_> 3 20 5 4 2. <_> <_> 6 18 18 2 -1. <_> 6 19 18 1 2. <_> <_> 0 0 12 5 -1. <_> 4 0 4 5 3. <_> <_> 14 3 6 12 -1. <_> 17 3 3 6 2. <_> 14 9 3 6 2. <_> <_> 0 12 6 12 -1. <_> 2 12 2 12 3. <_> <_> 2 3 21 3 -1. <_> 2 4 21 1 3. <_> <_> 4 3 6 12 -1. <_> 4 3 3 6 2. <_> 7 9 3 6 2. <_> <_> 12 8 12 6 -1. <_> 18 8 6 3 2. <_> 12 11 6 3 2. <_> <_> 0 15 16 9 -1. <_> 8 15 8 9 2. <_> <_> 6 13 18 5 -1. <_> 6 13 9 5 2. <_> <_> 1 6 15 6 -1. <_> 6 6 5 6 3. <_> <_> 11 9 9 6 -1. <_> 14 9 3 6 3. <_> <_> 3 0 15 11 -1. <_> 8 0 5 11 3. <_> <_> 15 3 3 18 -1. <_> 15 9 3 6 3. <_> <_> 6 3 3 18 -1. <_> 6 9 3 6 3. <_> <_> 9 5 10 8 -1. <_> 14 5 5 4 2. <_> 9 9 5 4 2. <_> <_> 4 4 16 8 -1. <_> 4 4 8 4 2. <_> 12 8 8 4 2. <_> <_> 7 7 12 3 -1. <_> 7 7 6 3 2. <_> <_> 5 0 9 13 -1. <_> 8 0 3 13 3. <_> <_> 11 0 6 9 -1. <_> 13 0 2 9 3. <_> <_> 7 0 6 9 -1. <_> 9 0 2 9 3. <_> <_> 8 1 10 9 -1. <_> 8 4 10 3 3. <_> <_> 0 2 18 2 -1. <_> 0 3 18 1 2. <_> <_> 10 13 14 6 -1. <_> 17 13 7 3 2. <_> 10 16 7 3 2. <_> <_> 0 13 14 6 -1. <_> 0 13 7 3 2. <_> 7 16 7 3 2. <_> <_> 20 2 3 21 -1. <_> 21 2 1 21 3. <_> <_> 0 9 5 12 -1. <_> 0 13 5 4 3. <_> <_> 12 6 12 6 -1. <_> 12 8 12 2 3. <_> <_> 1 8 20 3 -1. <_> 1 9 20 1 3. <_> <_> 5 7 19 3 -1. <_> 5 8 19 1 3. <_> <_> 1 12 9 6 -1. <_> 1 14 9 2 3. <_> <_> 6 10 14 12 -1. <_> 6 14 14 4 3. <_> <_> 5 6 14 18 -1. <_> 5 12 14 6 3. <_> <_> 11 12 9 7 -1. <_> 14 12 3 7 3. <_> <_> 1 15 18 4 -1. <_> 1 17 18 2 2. <_> <_> 11 14 6 9 -1. <_> 11 17 6 3 3. <_> <_> 0 8 18 4 -1. <_> 0 8 9 2 2. <_> 9 10 9 2 2. <_> <_> 3 10 20 6 -1. <_> 13 10 10 3 2. <_> 3 13 10 3 2. <_> <_> 1 10 20 6 -1. <_> 1 10 10 3 2. <_> 11 13 10 3 2. <_> <_> 0 9 24 2 -1. <_> 0 9 12 2 2. <_> <_> 1 12 20 8 -1. <_> 1 12 10 4 2. <_> 11 16 10 4 2. <_> <_> 11 12 9 7 -1. <_> 14 12 3 7 3. <_> <_> 4 12 9 7 -1. <_> 7 12 3 7 3. <_> <_> 12 12 8 5 -1. <_> 12 12 4 5 2. <_> <_> 4 12 8 5 -1. <_> 8 12 4 5 2. <_> <_> 13 10 4 10 -1. <_> 13 10 2 10 2. <_> <_> 1 15 20 2 -1. <_> 11 15 10 2 2. <_> <_> 9 10 6 6 -1. <_> 9 10 3 6 2. <_> <_> 0 1 21 3 -1. <_> 7 1 7 3 3. <_> <_> 6 4 13 9 -1. <_> 6 7 13 3 3. <_> <_> 6 5 12 5 -1. <_> 10 5 4 5 3. <_> <_> 10 10 10 6 -1. <_> 10 12 10 2 3. <_> <_> 6 12 5 8 -1. <_> 6 16 5 4 2. <_> <_> 13 0 6 9 -1. <_> 15 0 2 9 3. <_> <_> 2 10 18 6 -1. <_> 8 10 6 6 3. <_> <_> 11 2 9 4 -1. <_> 11 4 9 2 2. <_> <_> 1 20 21 3 -1. <_> 8 20 7 3 3. <_> <_> 1 10 22 2 -1. <_> 1 11 22 1 2. <_> <_> 0 17 18 3 -1. <_> 0 18 18 1 3. <_> <_> 13 0 6 9 -1. <_> 15 0 2 9 3. <_> <_> 5 0 6 9 -1. <_> 7 0 2 9 3. <_> <_> 18 2 6 20 -1. <_> 20 2 2 20 3. <_> <_> 0 2 6 20 -1. <_> 2 2 2 20 3. <_> <_> 11 7 6 14 -1. <_> 14 7 3 7 2. <_> 11 14 3 7 2. <_> <_> 0 1 4 9 -1. <_> 2 1 2 9 2. <_> <_> 12 14 9 4 -1. <_> 12 16 9 2 2. <_> <_> 1 13 9 4 -1. <_> 1 15 9 2 2. <_> <_> 7 6 15 6 -1. <_> 7 8 15 2 3. <_> <_> 8 2 3 18 -1. <_> 8 8 3 6 3. <_> <_> 6 6 12 6 -1. <_> 12 6 6 3 2. <_> 6 9 6 3 2. <_> <_> 2 19 20 4 -1. <_> 2 19 10 2 2. <_> 12 21 10 2 2. <_> <_> 14 15 6 9 -1. <_> 14 18 6 3 3. <_> <_> 3 5 18 14 -1. <_> 3 5 9 7 2. <_> 12 12 9 7 2. <_> <_> 15 6 4 18 -1. <_> 17 6 2 9 2. <_> 15 15 2 9 2. <_> <_> 5 6 4 18 -1. <_> 5 6 2 9 2. <_> 7 15 2 9 2. <_> <_> 11 0 6 9 -1. <_> 13 0 2 9 3. <_> <_> 7 0 6 9 -1. <_> 9 0 2 9 3. <_> <_> 11 5 6 9 -1. <_> 13 5 2 9 3. <_> <_> 9 5 6 6 -1. <_> 12 5 3 6 2. <_> <_> 4 1 16 6 -1. <_> 12 1 8 3 2. <_> 4 4 8 3 2. <_> <_> 9 13 6 11 -1. <_> 11 13 2 11 3. <_> <_> 17 1 6 12 -1. <_> 20 1 3 6 2. <_> 17 7 3 6 2. <_> <_> 1 17 18 3 -1. <_> 1 18 18 1 3. <_> <_> 7 13 10 8 -1. <_> 7 17 10 4 2. <_> <_> 6 18 10 6 -1. <_> 6 20 10 2 3. <_> <_> 9 14 9 4 -1. <_> 9 16 9 2 2. <_> <_> 1 1 6 12 -1. <_> 1 1 3 6 2. <_> 4 7 3 6 2. <_> <_> 19 4 5 12 -1. <_> 19 8 5 4 3. <_> <_> 0 0 8 8 -1. <_> 4 0 4 8 2. <_> <_> 3 5 19 3 -1. <_> 3 6 19 1 3. <_> <_> 1 5 12 6 -1. <_> 1 5 6 3 2. <_> 7 8 6 3 2. <_> <_> 2 1 21 8 -1. <_> 9 1 7 8 3. <_> <_> 4 1 16 8 -1. <_> 4 5 16 4 2. <_> <_> 6 0 18 3 -1. <_> 6 1 18 1 3. <_> <_> 4 4 10 14 -1. <_> 4 11 10 7 2. <_> <_> 15 6 4 10 -1. <_> 15 11 4 5 2. <_> <_> 3 18 18 3 -1. <_> 9 18 6 3 3. <_> <_> 8 18 12 6 -1. <_> 12 18 4 6 3. <_> <_> 3 15 6 9 -1. <_> 6 15 3 9 2. <_> <_> 15 7 6 8 -1. <_> 15 11 6 4 2. <_> <_> 3 7 6 8 -1. <_> 3 11 6 4 2. <_> <_> 5 9 18 6 -1. <_> 14 9 9 3 2. <_> 5 12 9 3 2. <_> <_> 1 13 12 6 -1. <_> 1 15 12 2 3. <_> <_> 14 15 10 6 -1. <_> 14 17 10 2 3. <_> <_> 0 15 10 6 -1. <_> 0 17 10 2 3. <_> <_> 15 13 6 9 -1. <_> 15 16 6 3 3. <_> <_> 3 13 6 9 -1. <_> 3 16 6 3 3. <_> <_> 9 5 8 8 -1. <_> 9 5 4 8 2. <_> <_> 1 18 12 6 -1. <_> 1 18 6 3 2. <_> 7 21 6 3 2. <_> <_> 13 19 10 4 -1. <_> 13 21 10 2 2. <_> <_> 1 19 10 4 -1. <_> 1 21 10 2 2. <_> <_> 6 19 18 3 -1. <_> 6 20 18 1 3. <_> <_> 8 14 4 10 -1. <_> 8 19 4 5 2. <_> <_> 0 0 24 6 -1. <_> 0 2 24 2 3. <_> <_> 0 1 6 9 -1. <_> 0 4 6 3 3. <_> <_> 4 9 20 6 -1. <_> 14 9 10 3 2. <_> 4 12 10 3 2. <_> <_> 1 15 19 8 -1. <_> 1 19 19 4 2. <_> <_> 14 0 10 6 -1. <_> 14 2 10 2 3. <_> <_> 1 10 21 14 -1. <_> 8 10 7 14 3. <_> <_> 10 10 8 8 -1. <_> 10 10 4 8 2. <_> <_> 6 8 10 4 -1. <_> 11 8 5 4 2. <_> <_> 10 5 4 9 -1. <_> 10 5 2 9 2. <_> <_> 7 5 6 10 -1. <_> 9 5 2 10 3. <_> <_> 14 4 4 13 -1. <_> 14 4 2 13 2. <_> <_> 6 4 4 13 -1. <_> 8 4 2 13 2. <_> <_> 8 7 9 6 -1. <_> 11 7 3 6 3. <_> <_> 3 6 16 6 -1. <_> 3 6 8 3 2. <_> 11 9 8 3 2. <_> <_> 5 4 16 14 -1. <_> 13 4 8 7 2. <_> 5 11 8 7 2. <_> <_> 0 0 24 4 -1. <_> 0 0 12 2 2. <_> 12 2 12 2 2. <_> <_> 9 1 9 6 -1. <_> 12 1 3 6 3. <_> <_> 4 1 14 4 -1. <_> 11 1 7 4 2. <_> <_> 10 14 7 9 -1. <_> 10 17 7 3 3. <_> <_> 8 3 8 10 -1. <_> 8 3 4 5 2. <_> 12 8 4 5 2. <_> <_> 7 3 12 5 -1. <_> 11 3 4 5 3. <_> <_> 8 2 4 13 -1. <_> 10 2 2 13 2. <_> <_> 11 2 3 19 -1. <_> 12 2 1 19 3. <_> <_> 7 7 9 6 -1. <_> 10 7 3 6 3. <_> <_> 4 22 20 2 -1. <_> 4 22 10 2 2. <_> <_> 0 16 24 4 -1. <_> 0 16 12 2 2. <_> 12 18 12 2 2. <_> <_> 7 3 12 5 -1. <_> 11 3 4 5 3. <_> <_> 1 10 8 14 -1. <_> 1 10 4 7 2. <_> 5 17 4 7 2. <_> <_> 11 16 6 6 -1. <_> 11 19 6 3 2. <_> <_> 6 0 10 24 -1. <_> 6 0 5 12 2. <_> 11 12 5 12 2. <_> <_> 7 5 14 14 -1. <_> 14 5 7 7 2. <_> 7 12 7 7 2. <_> <_> 7 8 10 8 -1. <_> 7 8 5 4 2. <_> 12 12 5 4 2. <_> <_> 9 1 9 6 -1. <_> 12 1 3 6 3. <_> <_> 0 6 24 3 -1. <_> 12 6 12 3 2. <_> <_> 7 3 12 5 -1. <_> 11 3 4 5 3. <_> <_> 1 13 22 4 -1. <_> 1 13 11 2 2. <_> 12 15 11 2 2. <_> <_> 9 12 12 6 -1. <_> 9 14 12 2 3. <_> <_> 0 5 9 6 -1. <_> 0 7 9 2 3. <_> <_> 1 5 23 6 -1. <_> 1 7 23 2 3. <_> <_> 1 6 19 12 -1. <_> 1 10 19 4 3. <_> <_> 9 1 6 21 -1. <_> 9 8 6 7 3. <_> <_> 3 19 18 3 -1. <_> 9 19 6 3 3. <_> <_> 9 14 6 9 -1. <_> 11 14 2 9 3. <_> <_> 9 6 4 12 -1. <_> 11 6 2 12 2. <_> <_> 16 0 6 9 -1. <_> 18 0 2 9 3. <_> <_> 2 0 6 9 -1. <_> 4 0 2 9 3. <_> <_> 13 1 4 22 -1. <_> 15 1 2 11 2. <_> 13 12 2 11 2. <_> <_> 1 8 8 12 -1. <_> 1 14 8 6 2. <_> <_> 14 7 7 9 -1. <_> 14 10 7 3 3. <_> <_> 3 12 18 4 -1. <_> 3 12 9 2 2. <_> 12 14 9 2 2. <_> <_> 13 1 4 22 -1. <_> 15 1 2 11 2. <_> 13 12 2 11 2. <_> <_> 7 1 4 22 -1. <_> 7 1 2 11 2. <_> 9 12 2 11 2. <_> <_> 4 7 20 4 -1. <_> 14 7 10 2 2. <_> 4 9 10 2 2. <_> <_> 9 10 6 7 -1. <_> 12 10 3 7 2. <_> <_> 7 7 10 4 -1. <_> 7 7 5 4 2. <_> <_> 0 3 4 15 -1. <_> 0 8 4 5 3. <_> <_> 15 0 8 12 -1. <_> 19 0 4 6 2. <_> 15 6 4 6 2. <_> <_> 1 0 8 12 -1. <_> 1 0 4 6 2. <_> 5 6 4 6 2. <_> <_> 14 5 6 16 -1. <_> 16 5 2 16 3. <_> <_> 4 5 6 16 -1. <_> 6 5 2 16 3. <_> <_> 15 0 6 16 -1. <_> 17 0 2 16 3. <_> <_> 3 0 6 16 -1. <_> 5 0 2 16 3. <_> <_> 0 2 24 3 -1. <_> 0 3 24 1 3. <_> <_> 7 1 10 4 -1. <_> 7 3 10 2 2. <_> <_> 1 0 23 8 -1. <_> 1 4 23 4 2. <_> <_> 1 17 19 3 -1. <_> 1 18 19 1 3. <_> <_> 6 18 18 2 -1. <_> 6 19 18 1 2. <_> <_> 1 17 9 6 -1. <_> 1 19 9 2 3. <_> <_> 15 15 6 9 -1. <_> 15 18 6 3 3. <_> <_> 3 15 6 9 -1. <_> 3 18 6 3 3. <_> <_> 4 14 20 6 -1. <_> 4 17 20 3 2. <_> <_> 0 10 6 14 -1. <_> 0 10 3 7 2. <_> 3 17 3 7 2. <_> <_> 6 18 18 3 -1. <_> 6 19 18 1 3. <_> <_> 4 12 9 7 -1. <_> 7 12 3 7 3. <_> <_> 6 10 18 5 -1. <_> 12 10 6 5 3. <_> <_> 0 10 18 5 -1. <_> 6 10 6 5 3. <_> <_> 3 2 18 9 -1. <_> 9 2 6 9 3. <_> <_> 4 6 10 10 -1. <_> 4 6 5 5 2. <_> 9 11 5 5 2. <_> <_> 20 14 4 9 -1. <_> 20 14 2 9 2. <_> <_> 0 14 4 9 -1. <_> 2 14 2 9 2. <_> <_> 11 1 4 20 -1. <_> 13 1 2 10 2. <_> 11 11 2 10 2. <_> <_> 6 21 12 3 -1. <_> 12 21 6 3 2. <_> <_> 11 1 4 20 -1. <_> 13 1 2 10 2. <_> 11 11 2 10 2. <_> <_> 1 16 10 8 -1. <_> 1 16 5 4 2. <_> 6 20 5 4 2. <_> <_> 11 1 4 20 -1. <_> 13 1 2 10 2. <_> 11 11 2 10 2. <_> <_> 1 0 3 19 -1. <_> 2 0 1 19 3. <_> <_> 11 1 4 20 -1. <_> 13 1 2 10 2. <_> 11 11 2 10 2. <_> <_> 0 1 6 9 -1. <_> 2 1 2 9 3. <_> <_> 3 7 19 4 -1. <_> 3 9 19 2 2. <_> <_> 7 14 9 6 -1. <_> 7 16 9 2 3. <_> <_> 17 1 7 6 -1. <_> 17 4 7 3 2. <_> <_> 5 0 14 8 -1. <_> 5 4 14 4 2. <_> <_> 16 1 8 6 -1. <_> 16 4 8 3 2. <_> <_> 0 1 8 6 -1. <_> 0 4 8 3 2. <_> <_> 6 0 18 4 -1. <_> 15 0 9 2 2. <_> 6 2 9 2 2. <_> <_> 0 14 9 6 -1. <_> 0 16 9 2 3. <_> <_> 3 7 18 8 -1. <_> 9 7 6 8 3. <_> <_> 2 11 6 9 -1. <_> 4 11 2 9 3. <_> <_> 10 5 6 9 -1. <_> 12 5 2 9 3. <_> <_> 10 6 4 18 -1. <_> 10 6 2 9 2. <_> 12 15 2 9 2. <_> <_> 11 1 4 20 -1. <_> 13 1 2 10 2. <_> 11 11 2 10 2. <_> <_> 9 1 4 20 -1. <_> 9 1 2 10 2. <_> 11 11 2 10 2. <_> <_> 5 9 18 6 -1. <_> 14 9 9 3 2. <_> 5 12 9 3 2. <_> <_> 6 4 6 9 -1. <_> 8 4 2 9 3. <_> <_> 10 16 8 6 -1. <_> 10 16 4 6 2. <_> <_> 0 0 18 8 -1. <_> 0 0 9 4 2. <_> 9 4 9 4 2. <_> <_> 6 5 14 12 -1. <_> 13 5 7 6 2. <_> 6 11 7 6 2. <_> <_> 4 3 15 7 -1. <_> 9 3 5 7 3. <_> <_> 14 12 10 6 -1. <_> 14 14 10 2 3. <_> <_> 0 11 4 10 -1. <_> 0 16 4 5 2. <_> <_> 1 10 22 3 -1. <_> 1 11 22 1 3. <_> <_> 8 9 6 10 -1. <_> 10 9 2 10 3. <_> <_> 13 2 6 12 -1. <_> 16 2 3 6 2. <_> 13 8 3 6 2. <_> <_> 10 6 4 18 -1. <_> 10 6 2 9 2. <_> 12 15 2 9 2. <_> <_> 7 8 10 16 -1. <_> 12 8 5 8 2. <_> 7 16 5 8 2. <_> <_> 8 1 8 12 -1. <_> 8 1 4 6 2. <_> 12 7 4 6 2. <_> <_> 7 1 12 14 -1. <_> 13 1 6 7 2. <_> 7 8 6 7 2. <_> <_> 2 14 12 6 -1. <_> 2 16 12 2 3. <_> <_> 11 16 6 6 -1. <_> 11 19 6 3 2. <_> <_> 7 16 6 6 -1. <_> 7 19 6 3 2. <_> <_> 13 4 4 10 -1. <_> 13 4 2 10 2. <_> <_> 0 19 19 3 -1. <_> 0 20 19 1 3. <_> <_> 12 8 6 8 -1. <_> 12 12 6 4 2. <_> <_> 8 1 8 22 -1. <_> 8 12 8 11 2. <_> <_> 12 8 6 8 -1. <_> 12 12 6 4 2. <_> <_> 6 8 6 8 -1. <_> 6 12 6 4 2. <_> <_> 14 5 6 9 -1. <_> 14 8 6 3 3. <_> <_> 0 6 24 4 -1. <_> 0 8 24 2 2. <_> <_> 14 12 10 6 -1. <_> 14 14 10 2 3. <_> <_> 0 12 10 6 -1. <_> 0 14 10 2 3. <_> <_> 4 6 19 3 -1. <_> 4 7 19 1 3. <_> <_> 1 6 19 3 -1. <_> 1 7 19 1 3. <_> <_> 4 0 16 9 -1. <_> 4 3 16 3 3. <_> <_> 0 1 24 5 -1. <_> 8 1 8 5 3. <_> <_> 3 6 6 15 -1. <_> 3 11 6 5 3. <_> <_> 9 6 6 9 -1. <_> 11 6 2 9 3. <_> <_> 0 17 18 3 -1. <_> 0 18 18 1 3. <_> <_> 6 22 18 2 -1. <_> 6 23 18 1 2. <_> <_> 2 12 6 9 -1. <_> 2 15 6 3 3. <_> <_> 18 12 6 9 -1. <_> 18 15 6 3 3. <_> <_> 0 12 6 9 -1. <_> 0 15 6 3 3. <_> <_> 11 14 4 10 -1. <_> 11 19 4 5 2. <_> <_> 9 6 6 16 -1. <_> 9 14 6 8 2. <_> <_> 7 7 10 10 -1. <_> 7 12 10 5 2. <_> <_> 1 3 6 13 -1. <_> 3 3 2 13 3. <_> <_> 18 1 6 13 -1. <_> 18 1 3 13 2. <_> <_> 5 1 6 9 -1. <_> 7 1 2 9 3. <_> <_> 18 2 6 11 -1. <_> 18 2 3 11 2. <_> <_> 0 2 6 11 -1. <_> 3 2 3 11 2. <_> <_> 9 12 15 6 -1. <_> 9 14 15 2 3. <_> <_> 2 2 20 3 -1. <_> 2 3 20 1 3. <_> <_> 10 6 4 9 -1. <_> 10 6 2 9 2. <_> <_> 5 6 12 14 -1. <_> 5 6 6 7 2. <_> 11 13 6 7 2. <_> <_> 9 0 6 9 -1. <_> 11 0 2 9 3. <_> <_> 7 0 9 6 -1. <_> 10 0 3 6 3. <_> <_> 10 6 6 9 -1. <_> 12 6 2 9 3. <_> <_> 4 1 12 20 -1. <_> 4 1 6 10 2. <_> 10 11 6 10 2. <_> <_> 6 7 18 3 -1. <_> 6 7 9 3 2. <_> <_> 0 7 18 3 -1. <_> 9 7 9 3 2. <_> <_> 3 20 18 3 -1. <_> 9 20 6 3 3. <_> <_> 9 6 6 9 -1. <_> 11 6 2 9 3. <_> <_> 6 2 12 15 -1. <_> 10 2 4 15 3. <_> <_> 2 3 18 3 -1. <_> 2 4 18 1 3. <_> <_> 19 4 4 18 -1. <_> 21 4 2 9 2. <_> 19 13 2 9 2. <_> <_> 0 1 19 3 -1. <_> 0 2 19 1 3. <_> <_> 5 0 15 4 -1. <_> 5 2 15 2 2. <_> <_> 5 2 14 5 -1. <_> 12 2 7 5 2. <_> <_> 1 2 22 14 -1. <_> 1 2 11 14 2. <_> <_> 8 15 6 9 -1. <_> 10 15 2 9 3. <_> <_> 6 17 18 3 -1. <_> 6 18 18 1 3. <_> <_> 9 6 3 18 -1. <_> 9 12 3 6 3. <_> <_> 2 0 20 3 -1. <_> 2 1 20 1 3. <_> <_> 5 4 5 12 -1. <_> 5 8 5 4 3. <_> <_> 8 6 12 5 -1. <_> 12 6 4 5 3. <_> <_> 9 12 6 12 -1. <_> 9 12 3 6 2. <_> 12 18 3 6 2. <_> <_> 14 14 8 10 -1. <_> 18 14 4 5 2. <_> 14 19 4 5 2. <_> <_> 2 14 8 10 -1. <_> 2 14 4 5 2. <_> 6 19 4 5 2. <_> <_> 10 18 12 6 -1. <_> 16 18 6 3 2. <_> 10 21 6 3 2. <_> <_> 1 3 6 9 -1. <_> 1 6 6 3 3. <_> <_> 11 3 3 20 -1. <_> 12 3 1 20 3. <_> <_> 4 6 14 6 -1. <_> 4 6 7 3 2. <_> 11 9 7 3 2. <_> <_> 6 5 12 13 -1. <_> 10 5 4 13 3. <_> <_> 5 4 4 15 -1. <_> 5 9 4 5 3. <_> <_> 9 16 15 4 -1. <_> 14 16 5 4 3. <_> <_> 7 8 6 14 -1. <_> 7 8 3 7 2. <_> 10 15 3 7 2. <_> <_> 7 6 10 6 -1. <_> 7 8 10 2 3. <_> <_> 2 5 18 3 -1. <_> 2 6 18 1 3. <_> <_> 5 1 15 8 -1. <_> 5 5 15 4 2. <_> <_> 7 1 8 18 -1. <_> 7 10 8 9 2. <_> <_> 0 10 24 3 -1. <_> 0 11 24 1 3. <_> <_> 0 2 6 13 -1. <_> 2 2 2 13 3. <_> <_> 16 0 8 10 -1. <_> 20 0 4 5 2. <_> 16 5 4 5 2. <_> <_> 5 1 10 9 -1. <_> 5 4 10 3 3. <_> <_> 5 6 18 3 -1. <_> 5 7 18 1 3. <_> <_> 0 1 24 3 -1. <_> 0 2 24 1 3. <_> <_> 11 4 6 11 -1. <_> 13 4 2 11 3. <_> <_> 0 0 8 10 -1. <_> 0 0 4 5 2. <_> 4 5 4 5 2. <_> <_> 4 16 18 3 -1. <_> 4 17 18 1 3. <_> <_> 2 16 18 3 -1. <_> 2 17 18 1 3. <_> <_> 3 0 18 10 -1. <_> 12 0 9 5 2. <_> 3 5 9 5 2. <_> <_> 2 3 20 21 -1. <_> 12 3 10 21 2. <_> <_> 6 7 14 3 -1. <_> 6 7 7 3 2. <_> <_> 0 9 12 6 -1. <_> 0 9 6 3 2. <_> 6 12 6 3 2. <_> <_> 3 14 21 4 -1. <_> 10 14 7 4 3. <_> <_> 0 14 21 4 -1. <_> 7 14 7 4 3. <_> <_> 5 21 18 3 -1. <_> 11 21 6 3 3. <_> <_> 1 21 18 3 -1. <_> 7 21 6 3 3. <_> <_> 19 4 4 18 -1. <_> 21 4 2 9 2. <_> 19 13 2 9 2. <_> <_> 3 7 18 3 -1. <_> 3 8 18 1 3. <_> <_> 19 4 4 18 -1. <_> 21 4 2 9 2. <_> 19 13 2 9 2. <_> <_> 7 15 10 6 -1. <_> 7 17 10 2 3. <_> <_> 9 13 11 9 -1. <_> 9 16 11 3 3. <_> <_> 0 6 4 10 -1. <_> 0 11 4 5 2. <_> <_> 15 16 9 6 -1. <_> 15 18 9 2 3. <_> <_> 1 5 4 18 -1. <_> 1 5 2 9 2. <_> 3 14 2 9 2. <_> <_> 9 8 8 10 -1. <_> 13 8 4 5 2. <_> 9 13 4 5 2. <_> <_> 7 8 8 10 -1. <_> 7 8 4 5 2. <_> 11 13 4 5 2. <_> <_> 9 8 12 5 -1. <_> 13 8 4 5 3. <_> <_> 7 8 9 7 -1. <_> 10 8 3 7 3. <_> <_> 9 8 12 5 -1. <_> 13 8 4 5 3. <_> <_> 7 6 9 7 -1. <_> 10 6 3 7 3. <_> <_> 9 8 12 5 -1. <_> 13 8 4 5 3. <_> <_> 10 5 4 18 -1. <_> 10 11 4 6 3. <_> <_> 5 5 14 12 -1. <_> 5 11 14 6 2. <_> <_> 0 1 11 4 -1. <_> 0 3 11 2 2. <_> <_> 9 10 6 10 -1. <_> 11 10 2 10 3. <_> <_> 2 17 11 6 -1. <_> 2 19 11 2 3. <_> <_> 15 16 9 6 -1. <_> 15 18 9 2 3. <_> <_> 1 10 18 2 -1. <_> 1 11 18 1 2. <_> <_> 6 4 12 13 -1. <_> 10 4 4 13 3. <_> <_> 0 18 18 3 -1. <_> 0 19 18 1 3. <_> <_> 6 18 18 3 -1. <_> 6 19 18 1 3. <_> <_> 0 16 9 6 -1. <_> 0 18 9 2 3. <_> <_> 13 15 9 6 -1. <_> 13 17 9 2 3. <_> <_> 2 15 9 6 -1. <_> 2 17 9 2 3. <_> <_> 13 1 6 16 -1. <_> 13 1 3 16 2. <_> <_> 5 1 6 16 -1. <_> 8 1 3 16 2. <_> <_> 11 5 6 10 -1. <_> 13 5 2 10 3. <_> <_> 7 5 6 10 -1. <_> 9 5 2 10 3. <_> <_> 10 0 6 24 -1. <_> 12 0 2 24 3. <_> <_> 3 4 4 20 -1. <_> 3 4 2 10 2. <_> 5 14 2 10 2. <_> <_> 14 0 6 9 -1. <_> 16 0 2 9 3. <_> <_> 4 0 6 9 -1. <_> 6 0 2 9 3. <_> <_> 4 5 18 5 -1. <_> 10 5 6 5 3. <_> <_> 5 6 6 9 -1. <_> 7 6 2 9 3. <_> <_> 7 2 15 8 -1. <_> 12 2 5 8 3. <_> <_> 2 2 15 8 -1. <_> 7 2 5 8 3. <_> <_> 10 0 4 9 -1. <_> 10 0 2 9 2. <_> <_> 3 4 6 12 -1. <_> 3 4 3 6 2. <_> 6 10 3 6 2. <_> <_> 16 0 8 18 -1. <_> 16 0 4 18 2. <_> <_> 0 0 8 18 -1. <_> 4 0 4 18 2. <_> <_> 0 7 24 6 -1. <_> 0 9 24 2 3. <_> <_> 4 7 14 3 -1. <_> 11 7 7 3 2. <_> <_> 10 8 8 15 -1. <_> 10 8 4 15 2. <_> <_> 7 0 10 14 -1. <_> 12 0 5 14 2. <_> <_> 13 10 8 10 -1. <_> 17 10 4 5 2. <_> 13 15 4 5 2. <_> <_> 3 0 4 9 -1. <_> 5 0 2 9 2. <_> <_> 16 1 6 8 -1. <_> 16 1 3 8 2. <_> <_> 2 1 6 8 -1. <_> 5 1 3 8 2. <_> <_> 3 6 18 12 -1. <_> 3 10 18 4 3. <_> <_> 4 12 16 4 -1. <_> 4 14 16 2 2. <_> <_> 4 9 16 15 -1. <_> 4 14 16 5 3. <_> <_> 3 10 8 10 -1. <_> 3 10 4 5 2. <_> 7 15 4 5 2. <_> <_> 8 18 16 6 -1. <_> 16 18 8 3 2. <_> 8 21 8 3 2. <_> <_> 2 16 12 5 -1. <_> 6 16 4 5 3. <_> <_> 14 14 9 4 -1. <_> 14 16 9 2 2. <_> <_> 7 14 9 6 -1. <_> 7 16 9 2 3. <_> <_> 4 10 16 12 -1. <_> 4 14 16 4 3. <_> <_> 0 13 19 6 -1. <_> 0 15 19 2 3. <_> <_> 10 13 9 6 -1. <_> 10 15 9 2 3. <_> <_> 5 0 3 23 -1. <_> 6 0 1 23 3. <_> <_> 0 8 24 6 -1. <_> 0 10 24 2 3. <_> <_> 0 5 5 12 -1. <_> 0 9 5 4 3. <_> <_> 3 0 19 18 -1. <_> 3 9 19 9 2. <_> <_> 9 11 6 12 -1. <_> 9 11 3 6 2. <_> 12 17 3 6 2. <_> <_> 0 5 24 8 -1. <_> 12 5 12 4 2. <_> 0 9 12 4 2. <_> <_> 6 18 9 4 -1. <_> 6 20 9 2 2. <_> <_> 8 8 10 6 -1. <_> 8 10 10 2 3. <_> <_> 2 7 20 3 -1. <_> 2 8 20 1 3. <_> <_> 12 0 7 20 -1. <_> 12 10 7 10 2. <_> <_> 5 0 7 20 -1. <_> 5 10 7 10 2. <_> <_> 14 2 2 18 -1. <_> 14 11 2 9 2. <_> <_> 5 8 10 12 -1. <_> 10 8 5 12 2. <_> <_> 6 9 12 8 -1. <_> 12 9 6 4 2. <_> 6 13 6 4 2. <_> <_> 7 7 3 14 -1. <_> 7 14 3 7 2. <_> <_> 11 2 12 16 -1. <_> 17 2 6 8 2. <_> 11 10 6 8 2. <_> <_> 7 0 6 9 -1. <_> 9 0 2 9 3. <_> <_> 13 14 9 4 -1. <_> 13 16 9 2 2. <_> <_> 0 12 22 4 -1. <_> 0 12 11 2 2. <_> 11 14 11 2 2. <_> <_> 1 12 22 6 -1. <_> 12 12 11 3 2. <_> 1 15 11 3 2. <_> <_> 6 6 9 6 -1. <_> 9 6 3 6 3. <_> <_> 10 0 4 9 -1. <_> 10 0 2 9 2. <_> <_> 3 8 18 7 -1. <_> 9 8 6 7 3. <_> <_> 0 6 24 6 -1. <_> 0 8 24 2 3. <_> <_> 0 11 24 10 -1. <_> 8 11 8 10 3. <_> <_> 3 3 18 21 -1. <_> 9 3 6 21 3. <_> <_> 7 12 4 10 -1. <_> 9 12 2 10 2. <_> <_> 10 16 10 8 -1. <_> 15 16 5 4 2. <_> 10 20 5 4 2. <_> <_> 8 6 6 9 -1. <_> 10 6 2 9 3. <_> <_> 12 10 6 12 -1. <_> 15 10 3 6 2. <_> 12 16 3 6 2. <_> <_> 6 10 6 12 -1. <_> 6 10 3 6 2. <_> 9 16 3 6 2. <_> <_> 16 12 6 12 -1. <_> 19 12 3 6 2. <_> 16 18 3 6 2. <_> <_> 2 12 6 12 -1. <_> 2 12 3 6 2. <_> 5 18 3 6 2. <_> <_> 10 15 6 9 -1. <_> 12 15 2 9 3. <_> <_> 8 15 6 9 -1. <_> 10 15 2 9 3. <_> <_> 14 20 10 4 -1. <_> 14 20 5 4 2. <_> <_> 0 20 10 4 -1. <_> 5 20 5 4 2. <_> <_> 11 17 9 6 -1. <_> 11 19 9 2 3. <_> <_> 3 2 14 4 -1. <_> 3 4 14 2 2. <_> <_> 10 1 10 4 -1. <_> 10 3 10 2 2. <_> <_> 0 15 10 4 -1. <_> 5 15 5 4 2. <_> <_> 19 2 3 19 -1. <_> 20 2 1 19 3. <_> <_> 4 12 9 8 -1. <_> 7 12 3 8 3. <_> <_> 4 7 5 12 -1. <_> 4 11 5 4 3. <_> <_> 0 1 24 3 -1. <_> 8 1 8 3 3. <_> <_> 6 8 12 4 -1. <_> 6 10 12 2 2. <_> <_> 19 3 4 10 -1. <_> 19 3 2 10 2. <_> <_> 0 6 9 6 -1. <_> 3 6 3 6 3. <_> <_> 18 0 6 22 -1. <_> 20 0 2 22 3. <_> <_> 0 0 6 22 -1. <_> 2 0 2 22 3. <_> <_> 5 15 19 3 -1. <_> 5 16 19 1 3. <_> <_> 10 7 4 15 -1. <_> 10 12 4 5 3. <_> <_> 9 6 6 9 -1. <_> 11 6 2 9 3. <_> <_> 0 21 18 3 -1. <_> 0 22 18 1 3. <_> <_> 7 3 10 15 -1. <_> 7 8 10 5 3. <_> <_> 1 7 18 3 -1. <_> 1 8 18 1 3. <_> <_> 8 2 9 6 -1. <_> 11 2 3 6 3. <_> <_> 0 10 24 14 -1. <_> 0 17 24 7 2. <_> <_> 13 9 8 10 -1. <_> 17 9 4 5 2. <_> 13 14 4 5 2. <_> <_> 10 5 4 9 -1. <_> 12 5 2 9 2. <_> <_> 13 9 8 10 -1. <_> 17 9 4 5 2. <_> 13 14 4 5 2. <_> <_> 7 11 10 10 -1. <_> 7 11 5 5 2. <_> 12 16 5 5 2. <_> <_> 4 13 18 4 -1. <_> 13 13 9 2 2. <_> 4 15 9 2 2. <_> <_> 0 0 19 2 -1. <_> 0 1 19 1 2. <_> <_> 0 18 24 6 -1. <_> 8 18 8 6 3. <_> <_> 6 4 8 16 -1. <_> 6 12 8 8 2. <_> <_> 7 8 10 4 -1. <_> 7 10 10 2 2. <_> <_> 0 3 6 9 -1. <_> 0 6 6 3 3. <_> <_> 13 15 7 9 -1. <_> 13 18 7 3 3. <_> <_> 3 18 12 6 -1. <_> 3 18 6 3 2. <_> 9 21 6 3 2. <_> <_> 12 14 6 9 -1. <_> 12 17 6 3 3. <_> <_> 2 15 15 8 -1. <_> 2 19 15 4 2. <_> <_> 9 6 6 16 -1. <_> 9 14 6 8 2. <_> <_> 6 6 7 12 -1. <_> 6 10 7 4 3. <_> <_> 14 6 6 9 -1. <_> 14 9 6 3 3. <_> <_> 5 14 6 9 -1. <_> 5 17 6 3 3. <_> <_> 10 8 6 9 -1. <_> 12 8 2 9 3. <_> <_> 6 6 4 18 -1. <_> 6 6 2 9 2. <_> 8 15 2 9 2. <_> <_> 14 9 6 12 -1. <_> 17 9 3 6 2. <_> 14 15 3 6 2. <_> <_> 4 9 6 12 -1. <_> 4 9 3 6 2. <_> 7 15 3 6 2. <_> <_> 14 15 9 6 -1. <_> 14 17 9 2 3. <_> <_> 0 20 18 4 -1. <_> 0 20 9 2 2. <_> 9 22 9 2 2. <_> <_> 13 18 9 6 -1. <_> 13 20 9 2 3. <_> <_> 2 18 9 6 -1. <_> 2 20 9 2 3. <_> <_> 6 16 18 3 -1. <_> 6 17 18 1 3. <_> <_> 0 16 18 3 -1. <_> 0 17 18 1 3. <_> <_> 19 2 4 22 -1. <_> 21 2 2 11 2. <_> 19 13 2 11 2. <_> <_> 1 2 4 22 -1. <_> 1 2 2 11 2. <_> 3 13 2 11 2. <_> <_> 15 0 2 24 -1. <_> 15 0 1 24 2. <_> <_> 3 20 16 4 -1. <_> 11 20 8 4 2. <_> <_> 11 6 4 18 -1. <_> 13 6 2 9 2. <_> 11 15 2 9 2. <_> <_> 7 9 10 14 -1. <_> 7 9 5 7 2. <_> 12 16 5 7 2. <_> <_> 14 6 6 9 -1. <_> 14 9 6 3 3. <_> <_> 3 6 7 9 -1. <_> 3 9 7 3 3. <_> <_> 20 4 4 20 -1. <_> 22 4 2 10 2. <_> 20 14 2 10 2. <_> <_> 7 6 6 9 -1. <_> 7 9 6 3 3. <_> <_> 7 0 10 14 -1. <_> 12 0 5 7 2. <_> 7 7 5 7 2. <_> <_> 2 1 18 6 -1. <_> 11 1 9 6 2. <_> <_> 15 0 2 24 -1. <_> 15 0 1 24 2. <_> <_> 7 0 2 24 -1. <_> 8 0 1 24 2. <_> <_> 13 12 6 7 -1. <_> 13 12 3 7 2. <_> <_> 5 12 6 7 -1. <_> 8 12 3 7 2. <_> <_> 3 5 18 19 -1. <_> 9 5 6 19 3. <_> <_> 5 6 9 6 -1. <_> 8 6 3 6 3. <_> <_> 9 5 9 6 -1. <_> 12 5 3 6 3. <_> <_> 3 16 10 8 -1. <_> 3 16 5 4 2. <_> 8 20 5 4 2. <_> <_> 19 8 5 15 -1. <_> 19 13 5 5 3. <_> <_> 0 8 5 15 -1. <_> 0 13 5 5 3. <_> <_> 20 4 4 20 -1. <_> 22 4 2 10 2. <_> 20 14 2 10 2. <_> <_> 0 4 4 20 -1. <_> 0 4 2 10 2. <_> 2 14 2 10 2. <_> <_> 7 7 10 4 -1. <_> 7 7 5 4 2. <_> <_> 4 19 14 4 -1. <_> 11 19 7 4 2. <_> <_> 10 11 12 3 -1. <_> 10 11 6 3 2. <_> <_> 0 1 24 3 -1. <_> 0 2 24 1 3. <_> <_> 7 2 14 20 -1. <_> 14 2 7 10 2. <_> 7 12 7 10 2. <_> <_> 0 13 6 9 -1. <_> 2 13 2 9 3. <_> <_> 13 0 4 19 -1. <_> 13 0 2 19 2. <_> <_> 1 11 14 3 -1. <_> 8 11 7 3 2. <_> <_> 7 1 16 20 -1. <_> 15 1 8 10 2. <_> 7 11 8 10 2. <_> <_> 0 10 21 9 -1. <_> 7 10 7 9 3. <_> <_> 6 19 15 5 -1. <_> 11 19 5 5 3. <_> <_> 8 10 6 6 -1. <_> 11 10 3 6 2. <_> <_> 7 1 16 20 -1. <_> 15 1 8 10 2. <_> 7 11 8 10 2. <_> <_> 1 1 16 20 -1. <_> 1 1 8 10 2. <_> 9 11 8 10 2. <_> <_> 16 4 3 12 -1. <_> 16 10 3 6 2. <_> <_> 5 4 3 12 -1. <_> 5 10 3 6 2. <_> <_> 7 6 10 8 -1. <_> 12 6 5 4 2. <_> 7 10 5 4 2. <_> <_> 4 9 6 6 -1. <_> 4 12 6 3 2. <_> <_> 6 5 12 4 -1. <_> 6 7 12 2 2. <_> <_> 9 2 5 15 -1. <_> 9 7 5 5 3. <_> <_> 15 0 9 6 -1. <_> 15 2 9 2 3. <_> <_> 6 0 11 10 -1. <_> 6 5 11 5 2. <_> <_> 12 7 4 12 -1. <_> 12 13 4 6 2. <_> <_> 7 2 9 4 -1. <_> 7 4 9 2 2. <_> <_> 6 0 13 6 -1. <_> 6 2 13 2 3. <_> <_> 10 6 4 18 -1. <_> 10 6 2 9 2. <_> 12 15 2 9 2. <_> <_> 10 8 6 9 -1. <_> 12 8 2 9 3. <_> <_> 3 18 10 6 -1. <_> 3 20 10 2 3. <_> <_> 4 14 20 3 -1. <_> 4 15 20 1 3. <_> <_> 2 15 9 6 -1. <_> 2 17 9 2 3. <_> <_> 13 0 4 19 -1. <_> 13 0 2 19 2. <_> <_> 7 0 4 19 -1. <_> 9 0 2 19 2. <_> <_> 1 4 22 2 -1. <_> 1 5 22 1 2. <_> <_> 0 0 9 6 -1. <_> 0 2 9 2 3. <_> <_> 0 0 24 18 -1. <_> 0 9 24 9 2. <_> <_> 3 2 16 8 -1. <_> 3 6 16 4 2. <_> <_> 3 6 18 6 -1. <_> 3 8 18 2 3. <_> <_> 3 1 6 10 -1. <_> 5 1 2 10 3. <_> <_> 13 0 9 6 -1. <_> 16 0 3 6 3. <_> <_> 2 0 9 6 -1. <_> 5 0 3 6 3. <_> <_> 10 2 4 15 -1. <_> 10 7 4 5 3. <_> <_> 6 0 7 10 -1. <_> 6 5 7 5 2. <_> <_> 2 2 20 4 -1. <_> 12 2 10 2 2. <_> 2 4 10 2 2. <_> <_> 2 11 19 3 -1. <_> 2 12 19 1 3. <_> <_> 10 8 6 9 -1. <_> 12 8 2 9 3. <_> <_> 8 8 6 9 -1. <_> 10 8 2 9 3. <_> <_> 13 8 4 9 -1. <_> 13 8 2 9 2. <_> <_> 3 11 9 9 -1. <_> 6 11 3 9 3. <_> <_> 3 9 18 5 -1. <_> 9 9 6 5 3. <_> <_> 2 4 2 20 -1. <_> 2 14 2 10 2. <_> <_> 14 17 8 6 -1. <_> 14 20 8 3 2. <_> <_> 3 21 18 2 -1. <_> 3 22 18 1 2. <_> <_> 5 4 15 6 -1. <_> 10 4 5 6 3. <_> <_> 2 15 12 6 -1. <_> 2 17 12 2 3. <_> <_> 17 8 6 9 -1. <_> 17 11 6 3 3. <_> <_> 2 12 20 4 -1. <_> 2 12 10 2 2. <_> 12 14 10 2 2. <_> <_> 0 17 24 6 -1. <_> 0 19 24 2 3. <_> <_> 7 16 9 4 -1. <_> 7 18 9 2 2. <_> <_> 15 1 4 22 -1. <_> 17 1 2 11 2. <_> 15 12 2 11 2. <_> <_> 5 1 4 22 -1. <_> 5 1 2 11 2. <_> 7 12 2 11 2. <_> <_> 11 13 8 9 -1. <_> 11 16 8 3 3. <_> <_> 6 1 6 9 -1. <_> 8 1 2 9 3. <_> <_> 11 4 3 18 -1. <_> 11 10 3 6 3. <_> <_> 5 8 12 6 -1. <_> 5 8 6 3 2. <_> 11 11 6 3 2. <_> <_> 15 7 5 8 -1. <_> 15 11 5 4 2. <_> <_> 4 7 5 8 -1. <_> 4 11 5 4 2. <_> <_> 12 6 6 12 -1. <_> 15 6 3 6 2. <_> 12 12 3 6 2. <_> <_> 6 6 6 12 -1. <_> 6 6 3 6 2. <_> 9 12 3 6 2. <_> <_> 5 9 14 8 -1. <_> 12 9 7 4 2. <_> 5 13 7 4 2. <_> <_> 9 1 3 14 -1. <_> 9 8 3 7 2. <_> <_> 12 6 6 12 -1. <_> 12 10 6 4 3. <_> <_> 4 5 4 18 -1. <_> 4 5 2 9 2. <_> 6 14 2 9 2. <_> <_> 4 6 16 18 -1. <_> 4 12 16 6 3. <_> <_> 5 4 7 20 -1. <_> 5 14 7 10 2. <_> <_> 14 8 8 12 -1. <_> 14 14 8 6 2. <_> <_> 9 10 6 14 -1. <_> 9 10 3 7 2. <_> 12 17 3 7 2. <_> <_> 9 5 9 6 -1. <_> 12 5 3 6 3. <_> <_> 9 4 3 18 -1. <_> 10 4 1 18 3. <_> <_> 1 4 22 14 -1. <_> 12 4 11 7 2. <_> 1 11 11 7 2. <_> <_> 2 7 18 2 -1. <_> 2 8 18 1 2. <_> <_> 12 6 6 12 -1. <_> 12 10 6 4 3. <_> <_> 6 5 9 7 -1. <_> 9 5 3 7 3. <_> <_> 12 7 4 12 -1. <_> 12 13 4 6 2. <_> <_> 8 7 4 12 -1. <_> 8 13 4 6 2. <_> <_> 7 2 10 22 -1. <_> 7 13 10 11 2. <_> <_> 0 1 3 20 -1. <_> 1 1 1 20 3. <_> <_> 4 13 18 4 -1. <_> 13 13 9 2 2. <_> 4 15 9 2 2. <_> <_> 2 13 18 4 -1. <_> 2 13 9 2 2. <_> 11 15 9 2 2. <_> <_> 15 15 9 6 -1. <_> 15 17 9 2 3. <_> <_> 0 15 9 6 -1. <_> 0 17 9 2 3. <_> <_> 6 0 18 24 -1. <_> 15 0 9 12 2. <_> 6 12 9 12 2. <_> <_> 6 6 6 12 -1. <_> 6 10 6 4 3. <_> <_> 8 7 10 4 -1. <_> 8 9 10 2 2. <_> <_> 1 9 18 6 -1. <_> 1 9 9 3 2. <_> 10 12 9 3 2. <_> <_> 6 6 18 3 -1. <_> 6 7 18 1 3. <_> <_> 7 7 9 8 -1. <_> 10 7 3 8 3. <_> <_> 10 12 6 12 -1. <_> 12 12 2 12 3. <_> <_> 3 14 18 3 -1. <_> 3 15 18 1 3. <_> <_> 15 17 9 7 -1. <_> 18 17 3 7 3. <_> <_> 1 12 10 6 -1. <_> 1 14 10 2 3. <_> <_> 15 17 9 7 -1. <_> 18 17 3 7 3. <_> <_> 10 3 3 19 -1. <_> 11 3 1 19 3. <_> <_> 15 17 9 7 -1. <_> 18 17 3 7 3. <_> <_> 6 1 11 9 -1. <_> 6 4 11 3 3. <_> <_> 15 17 9 7 -1. <_> 18 17 3 7 3. <_> <_> 6 5 11 6 -1. <_> 6 8 11 3 2. <_> <_> 16 7 8 5 -1. <_> 16 7 4 5 2. <_> <_> 2 4 20 19 -1. <_> 12 4 10 19 2. <_> <_> 2 1 21 6 -1. <_> 9 1 7 6 3. <_> <_> 6 5 12 14 -1. <_> 6 5 6 7 2. <_> 12 12 6 7 2. <_> <_> 9 0 6 9 -1. <_> 11 0 2 9 3. <_> <_> 2 11 8 5 -1. <_> 6 11 4 5 2. <_> <_> 16 7 8 5 -1. <_> 16 7 4 5 2. <_> <_> 0 7 8 5 -1. <_> 4 7 4 5 2. <_> <_> 15 17 9 7 -1. <_> 18 17 3 7 3. <_> <_> 8 6 8 10 -1. <_> 8 6 4 5 2. <_> 12 11 4 5 2. <_> <_> 15 15 9 9 -1. <_> 18 15 3 9 3. <_> <_> 0 15 9 9 -1. <_> 3 15 3 9 3. <_> <_> 12 10 9 7 -1. <_> 15 10 3 7 3. <_> <_> 3 10 9 7 -1. <_> 6 10 3 7 3. <_> <_> 13 15 10 8 -1. <_> 18 15 5 4 2. <_> 13 19 5 4 2. <_> <_> 0 1 6 12 -1. <_> 0 1 3 6 2. <_> 3 7 3 6 2. <_> <_> 10 0 6 12 -1. <_> 13 0 3 6 2. <_> 10 6 3 6 2. <_> <_> 7 0 10 12 -1. <_> 7 0 5 6 2. <_> 12 6 5 6 2. <_> <_> 4 1 16 8 -1. <_> 4 1 8 8 2. <_> <_> 0 21 19 3 -1. <_> 0 22 19 1 3. <_> <_> 6 9 18 4 -1. <_> 15 9 9 2 2. <_> 6 11 9 2 2. <_> <_> 3 4 9 6 -1. <_> 3 6 9 2 3. <_> <_> 9 1 6 15 -1. <_> 9 6 6 5 3. <_> <_> 5 9 6 6 -1. <_> 8 9 3 6 2. <_> <_> 5 1 14 9 -1. <_> 5 4 14 3 3. <_> <_> 3 0 8 20 -1. <_> 3 0 4 10 2. <_> 7 10 4 10 2. <_> <_> 5 0 7 9 -1. <_> 5 3 7 3 3. <_> <_> 6 6 12 5 -1. <_> 10 6 4 5 3. <_> <_> 0 1 8 14 -1. <_> 4 1 4 14 2. <_> <_> 2 12 22 4 -1. <_> 2 14 22 2 2. <_> <_> 8 17 6 6 -1. <_> 8 20 6 3 2. <_> <_> 18 1 6 7 -1. <_> 18 1 3 7 2. <_> <_> 0 0 6 6 -1. <_> 3 0 3 6 2. <_> <_> 4 6 17 18 -1. <_> 4 12 17 6 3. <_> <_> 6 0 12 6 -1. <_> 6 0 6 3 2. <_> 12 3 6 3 2. <_> <_> 4 7 18 4 -1. <_> 13 7 9 2 2. <_> 4 9 9 2 2. <_> <_> 4 12 10 6 -1. <_> 4 14 10 2 3. <_> <_> 7 9 10 12 -1. <_> 12 9 5 6 2. <_> 7 15 5 6 2. <_> <_> 0 1 24 3 -1. <_> 8 1 8 3 3. <_> <_> 13 11 6 6 -1. <_> 13 11 3 6 2. <_> <_> 5 11 6 6 -1. <_> 8 11 3 6 2. <_> <_> 3 10 19 3 -1. <_> 3 11 19 1 3. <_> <_> 0 2 6 9 -1. <_> 0 5 6 3 3. <_> <_> 14 16 10 6 -1. <_> 14 18 10 2 3. <_> <_> 0 16 10 6 -1. <_> 0 18 10 2 3. <_> <_> 14 13 9 6 -1. <_> 14 15 9 2 3. <_> <_> 0 16 18 3 -1. <_> 0 17 18 1 3. <_> <_> 6 16 18 3 -1. <_> 6 17 18 1 3. <_> <_> 0 18 9 6 -1. <_> 0 20 9 2 3. <_> <_> 14 13 9 6 -1. <_> 14 15 9 2 3. <_> <_> 6 2 6 9 -1. <_> 8 2 2 9 3. <_> <_> 15 8 4 12 -1. <_> 15 8 2 12 2. <_> <_> 8 13 8 8 -1. <_> 8 17 8 4 2. <_> <_> 4 20 18 3 -1. <_> 10 20 6 3 3. <_> <_> 5 8 4 12 -1. <_> 7 8 2 12 2. <_> <_> 7 7 12 3 -1. <_> 7 7 6 3 2. <_> <_> 10 6 4 9 -1. <_> 12 6 2 9 2. <_> <_> 5 20 18 3 -1. <_> 11 20 6 3 3. <_> <_> 1 20 18 3 -1. <_> 7 20 6 3 3. <_> <_> 18 1 6 20 -1. <_> 21 1 3 10 2. <_> 18 11 3 10 2. <_> <_> 0 1 6 20 -1. <_> 0 1 3 10 2. <_> 3 11 3 10 2. <_> <_> 13 3 4 18 -1. <_> 15 3 2 9 2. <_> 13 12 2 9 2. <_> <_> 0 2 6 12 -1. <_> 0 6 6 4 3. <_> <_> 12 9 12 6 -1. <_> 18 9 6 3 2. <_> 12 12 6 3 2. <_> <_> 7 3 4 18 -1. <_> 7 3 2 9 2. <_> 9 12 2 9 2. <_> <_> 14 0 6 9 -1. <_> 16 0 2 9 3. <_> <_> 0 9 12 6 -1. <_> 0 9 6 3 2. <_> 6 12 6 3 2. <_> <_> 14 4 8 20 -1. <_> 18 4 4 10 2. <_> 14 14 4 10 2. <_> <_> 2 4 8 20 -1. <_> 2 4 4 10 2. <_> 6 14 4 10 2. <_> <_> 14 13 9 6 -1. <_> 14 15 9 2 3. <_> <_> 1 13 9 6 -1. <_> 1 15 9 2 3. <_> <_> 3 15 18 3 -1. <_> 9 15 6 3 3. <_> <_> 5 13 9 6 -1. <_> 5 15 9 2 3. <_> <_> 5 0 18 3 -1. <_> 5 1 18 1 3. <_> <_> 8 2 6 7 -1. <_> 11 2 3 7 2. <_> <_> 9 1 9 6 -1. <_> 12 1 3 6 3. <_> <_> 6 1 9 6 -1. <_> 9 1 3 6 3. <_> <_> 5 6 14 6 -1. <_> 12 6 7 3 2. <_> 5 9 7 3 2. <_> <_> 8 2 6 13 -1. <_> 10 2 2 13 3. <_> <_> 6 11 12 6 -1. <_> 12 11 6 3 2. <_> 6 14 6 3 2. <_> <_> 3 1 18 15 -1. <_> 9 1 6 15 3. <_> <_> 13 0 6 7 -1. <_> 13 0 3 7 2. <_> <_> 3 3 16 6 -1. <_> 3 6 16 3 2. <_> <_> 12 1 3 12 -1. <_> 12 7 3 6 2. <_> <_> 7 7 6 9 -1. <_> 9 7 2 9 3. <_> <_> 13 0 4 24 -1. <_> 13 0 2 24 2. <_> <_> 7 0 4 24 -1. <_> 9 0 2 24 2. <_> <_> 11 9 5 12 -1. <_> 11 13 5 4 3. <_> <_> 7 15 9 6 -1. <_> 7 17 9 2 3. <_> <_> 5 7 18 6 -1. <_> 5 9 18 2 3. <_> <_> 8 9 5 12 -1. <_> 8 13 5 4 3. <_> <_> 4 17 17 6 -1. <_> 4 19 17 2 3. <_> <_> 0 3 18 14 -1. <_> 0 3 9 7 2. <_> 9 10 9 7 2. <_> <_> 0 1 24 2 -1. <_> 0 2 24 1 2. <_> <_> 0 15 18 3 -1. <_> 0 16 18 1 3. <_> <_> 9 0 6 9 -1. <_> 11 0 2 9 3. <_> <_> 3 3 14 12 -1. <_> 3 9 14 6 2. <_> <_> 12 1 3 12 -1. <_> 12 7 3 6 2. <_> <_> 8 0 6 9 -1. <_> 10 0 2 9 3. <_> <_> 10 6 6 10 -1. <_> 12 6 2 10 3. <_> <_> 5 0 6 9 -1. <_> 7 0 2 9 3. <_> <_> 2 0 21 7 -1. <_> 9 0 7 7 3. <_> <_> 6 11 12 5 -1. <_> 10 11 4 5 3. <_> <_> 8 7 9 8 -1. <_> 11 7 3 8 3. <_> <_> 9 6 6 18 -1. <_> 9 6 3 9 2. <_> 12 15 3 9 2. <_> <_> 15 14 8 10 -1. <_> 19 14 4 5 2. <_> 15 19 4 5 2. <_> <_> 1 14 8 10 -1. <_> 1 14 4 5 2. <_> 5 19 4 5 2. <_> <_> 11 0 8 10 -1. <_> 15 0 4 5 2. <_> 11 5 4 5 2. <_> <_> 5 0 8 10 -1. <_> 5 0 4 5 2. <_> 9 5 4 5 2. <_> <_> 6 1 12 5 -1. <_> 6 1 6 5 2. <_> <_> 1 12 18 2 -1. <_> 10 12 9 2 2. <_> <_> 2 8 20 6 -1. <_> 12 8 10 3 2. <_> 2 11 10 3 2. <_> <_> 7 6 9 7 -1. <_> 10 6 3 7 3. <_> <_> 10 5 8 16 -1. <_> 14 5 4 8 2. <_> 10 13 4 8 2. <_> <_> 3 9 16 8 -1. <_> 3 9 8 4 2. <_> 11 13 8 4 2. <_> <_> 7 8 10 4 -1. <_> 7 8 5 4 2. <_> <_> 7 12 10 8 -1. <_> 7 12 5 4 2. <_> 12 16 5 4 2. <_> <_> 9 19 15 4 -1. <_> 14 19 5 4 3. <_> <_> 1 0 18 9 -1. <_> 7 0 6 9 3. <_> <_> 13 4 10 8 -1. <_> 18 4 5 4 2. <_> 13 8 5 4 2. <_> <_> 3 16 18 4 -1. <_> 9 16 6 4 3. <_> <_> 8 7 10 12 -1. <_> 13 7 5 6 2. <_> 8 13 5 6 2. <_> <_> 6 7 10 12 -1. <_> 6 7 5 6 2. <_> 11 13 5 6 2. <_> <_> 4 6 18 7 -1. <_> 10 6 6 7 3. <_> <_> 0 17 18 3 -1. <_> 0 18 18 1 3. <_> <_> 3 17 18 3 -1. <_> 3 18 18 1 3. <_> <_> 2 4 6 10 -1. <_> 4 4 2 10 3. <_> <_> 16 0 8 24 -1. <_> 16 0 4 24 2. <_> <_> 4 0 8 15 -1. <_> 8 0 4 15 2. <_> <_> 16 0 8 24 -1. <_> 16 0 4 24 2. <_> <_> 1 4 18 9 -1. <_> 7 4 6 9 3. <_> <_> 15 12 9 6 -1. <_> 15 14 9 2 3. <_> <_> 3 9 18 6 -1. <_> 3 9 9 3 2. <_> 12 12 9 3 2. <_> <_> 18 5 6 9 -1. <_> 18 8 6 3 3. <_> <_> 0 5 6 9 -1. <_> 0 8 6 3 3. <_> <_> 4 7 18 4 -1. <_> 13 7 9 2 2. <_> 4 9 9 2 2. <_> <_> 2 1 12 20 -1. <_> 2 1 6 10 2. <_> 8 11 6 10 2. <_> <_> 17 0 6 23 -1. <_> 17 0 3 23 2. <_> <_> 1 6 2 18 -1. <_> 1 15 2 9 2. <_> <_> 8 8 10 6 -1. <_> 8 10 10 2 3. <_> <_> 0 6 20 6 -1. <_> 0 6 10 3 2. <_> 10 9 10 3 2. <_> <_> 11 12 12 5 -1. <_> 15 12 4 5 3. <_> <_> 0 4 3 19 -1. <_> 1 4 1 19 3. <_> <_> 19 1 3 18 -1. <_> 20 1 1 18 3. <_> <_> 2 1 3 18 -1. <_> 3 1 1 18 3. <_> <_> 3 10 18 3 -1. <_> 9 10 6 3 3. <_> <_> 4 4 10 9 -1. <_> 9 4 5 9 2. <_> <_> 7 13 14 7 -1. <_> 7 13 7 7 2. <_> <_> 3 13 14 7 -1. <_> 10 13 7 7 2. <_> <_> 8 15 9 6 -1. <_> 11 15 3 6 3. <_> <_> 4 14 8 10 -1. <_> 4 14 4 5 2. <_> 8 19 4 5 2. <_> <_> 10 14 4 10 -1. <_> 10 19 4 5 2. <_> <_> 3 8 5 16 -1. <_> 3 16 5 8 2. <_> <_> 15 10 9 6 -1. <_> 15 12 9 2 3. <_> <_> 0 10 9 6 -1. <_> 0 12 9 2 3. <_> <_> 6 7 12 9 -1. <_> 6 10 12 3 3. <_> <_> 9 10 5 8 -1. <_> 9 14 5 4 2. <_> <_> 12 1 3 12 -1. <_> 12 7 3 6 2. <_> <_> 8 15 6 9 -1. <_> 10 15 2 9 3. <_> <_> 16 6 7 6 -1. <_> 16 9 7 3 2. <_> <_> 8 1 4 22 -1. <_> 10 1 2 22 2. <_> <_> 6 6 14 3 -1. <_> 6 6 7 3 2. <_> <_> 0 18 19 3 -1. <_> 0 19 19 1 3. <_> <_> 17 0 6 24 -1. <_> 17 0 3 24 2. <_> <_> 0 13 15 6 -1. <_> 5 13 5 6 3. <_> <_> 9 6 10 14 -1. <_> 14 6 5 7 2. <_> 9 13 5 7 2. <_> <_> 1 6 8 10 -1. <_> 1 6 4 5 2. <_> 5 11 4 5 2. <_> <_> 7 6 12 5 -1. <_> 7 6 6 5 2. <_> <_> 7 7 9 6 -1. <_> 10 7 3 6 3. <_> <_> 7 8 14 14 -1. <_> 14 8 7 7 2. <_> 7 15 7 7 2. <_> <_> 3 8 14 14 -1. <_> 3 8 7 7 2. <_> 10 15 7 7 2. <_> <_> 9 8 13 4 -1. <_> 9 10 13 2 2. <_> <_> 3 2 6 12 -1. <_> 3 2 3 6 2. <_> 6 8 3 6 2. <_> <_> 6 10 17 6 -1. <_> 6 13 17 3 2. <_> <_> 1 10 17 6 -1. <_> 1 13 17 3 2. <_> <_> 16 7 8 9 -1. <_> 16 10 8 3 3. <_> <_> 0 7 8 9 -1. <_> 0 10 8 3 3. <_> <_> 0 9 24 10 -1. <_> 12 9 12 5 2. <_> 0 14 12 5 2. <_> <_> 3 2 15 8 -1. <_> 8 2 5 8 3. <_> <_> 4 2 18 8 -1. <_> 10 2 6 8 3. <_> <_> 0 1 18 4 -1. <_> 0 1 9 2 2. <_> 9 3 9 2 2. <_> <_> 20 2 3 18 -1. <_> 21 2 1 18 3. <_> <_> 1 3 3 19 -1. <_> 2 3 1 19 3. <_> <_> 18 8 6 16 -1. <_> 20 8 2 16 3. <_> <_> 0 8 6 16 -1. <_> 2 8 2 16 3. <_> <_> 8 18 11 6 -1. <_> 8 20 11 2 3. <_> <_> 4 6 12 5 -1. <_> 8 6 4 5 3. <_> <_> 7 6 12 5 -1. <_> 11 6 4 5 3. <_> <_> 6 3 9 6 -1. <_> 9 3 3 6 3. <_> <_> 7 6 12 5 -1. <_> 7 6 6 5 2. <_> <_> 9 8 6 7 -1. <_> 12 8 3 7 2. <_> <_> 8 2 9 6 -1. <_> 11 2 3 6 3. <_> <_> 8 14 6 9 -1. <_> 8 17 6 3 3. <_> <_> 8 2 9 6 -1. <_> 11 2 3 6 3. <_> <_> 4 3 16 20 -1. <_> 4 3 8 10 2. <_> 12 13 8 10 2. <_> <_> 7 6 10 12 -1. <_> 12 6 5 6 2. <_> 7 12 5 6 2. <_> <_> 0 2 7 12 -1. <_> 0 6 7 4 3. <_> <_> 12 17 11 6 -1. <_> 12 19 11 2 3. <_> <_> 4 7 12 8 -1. <_> 4 7 6 4 2. <_> 10 11 6 4 2. <_> <_> 8 11 8 10 -1. <_> 12 11 4 5 2. <_> 8 16 4 5 2. <_> <_> 9 1 4 9 -1. <_> 11 1 2 9 2. <_> <_> 14 0 3 22 -1. <_> 15 0 1 22 3. <_> <_> 7 0 3 22 -1. <_> 8 0 1 22 3. <_> <_> 4 7 18 4 -1. <_> 13 7 9 2 2. <_> 4 9 9 2 2. <_> <_> 10 2 4 15 -1. <_> 10 7 4 5 3. <_> <_> 12 1 3 12 -1. <_> 12 7 3 6 2. <_> <_> 0 0 18 13 -1. <_> 9 0 9 13 2. <_> <_> 16 0 3 24 -1. <_> 17 0 1 24 3. <_> <_> 5 0 3 24 -1. <_> 6 0 1 24 3. <_> <_> 10 15 5 8 -1. <_> 10 19 5 4 2. <_> <_> 2 18 18 2 -1. <_> 2 19 18 1 2. <_> <_> 2 8 20 3 -1. <_> 2 9 20 1 3. <_> <_> 7 6 9 6 -1. <_> 7 8 9 2 3. <_> <_> 3 2 19 10 -1. <_> 3 7 19 5 2. <_> <_> 2 7 19 3 -1. <_> 2 8 19 1 3. <_> <_> 15 6 9 4 -1. <_> 15 8 9 2 2. <_> <_> 2 2 18 8 -1. <_> 8 2 6 8 3. <_> <_> 10 9 14 4 -1. <_> 10 9 7 4 2. <_> <_> 4 4 6 16 -1. <_> 7 4 3 16 2. <_> <_> 15 8 9 16 -1. <_> 18 8 3 16 3. <_> <_> 0 8 9 16 -1. <_> 3 8 3 16 3. <_> <_> 18 0 6 14 -1. <_> 20 0 2 14 3. <_> <_> 0 0 6 14 -1. <_> 2 0 2 14 3. <_> <_> 15 0 6 22 -1. <_> 17 0 2 22 3. <_> <_> 3 0 6 22 -1. <_> 5 0 2 22 3. <_> <_> 12 2 12 20 -1. <_> 16 2 4 20 3. <_> <_> 0 2 12 20 -1. <_> 4 2 4 20 3. <_> <_> 11 6 4 9 -1. <_> 11 6 2 9 2. <_> <_> 9 0 6 16 -1. <_> 12 0 3 16 2. <_> <_> 12 1 3 12 -1. <_> 12 7 3 6 2. <_> <_> 3 4 18 6 -1. <_> 3 4 9 3 2. <_> 12 7 9 3 2. <_> <_> 5 5 16 8 -1. <_> 13 5 8 4 2. <_> 5 9 8 4 2. <_> <_> 0 13 10 6 -1. <_> 0 15 10 2 3. <_> <_> 8 14 9 6 -1. <_> 8 16 9 2 3. <_> <_> 6 2 9 6 -1. <_> 9 2 3 6 3. <_> <_> 14 1 10 8 -1. <_> 19 1 5 4 2. <_> 14 5 5 4 2. <_> <_> 9 1 3 12 -1. <_> 9 7 3 6 2. <_> <_> 6 4 12 9 -1. <_> 6 7 12 3 3. <_> <_> 6 5 12 6 -1. <_> 10 5 4 6 3. <_> <_> 1 1 8 5 -1. <_> 5 1 4 5 2. <_> <_> 12 12 6 8 -1. <_> 12 16 6 4 2. <_> <_> 3 12 12 6 -1. <_> 3 14 12 2 3. <_> <_> 9 18 12 6 -1. <_> 15 18 6 3 2. <_> 9 21 6 3 2. <_> <_> 4 13 6 6 -1. <_> 4 16 6 3 2. <_> <_> 11 3 7 18 -1. <_> 11 12 7 9 2. <_> <_> 3 9 18 3 -1. <_> 9 9 6 3 3. <_> <_> 5 3 19 2 -1. <_> 5 4 19 1 2. <_> <_> 4 2 12 6 -1. <_> 4 2 6 3 2. <_> 10 5 6 3 2. <_> <_> 9 6 6 9 -1. <_> 11 6 2 9 3. <_> <_> 8 6 6 9 -1. <_> 10 6 2 9 3. <_> <_> 16 9 5 15 -1. <_> 16 14 5 5 3. <_> <_> 3 9 5 15 -1. <_> 3 14 5 5 3. <_> <_> 6 6 14 6 -1. <_> 13 6 7 3 2. <_> 6 9 7 3 2. <_> <_> 8 6 3 14 -1. <_> 8 13 3 7 2. <_> <_> 0 16 24 5 -1. <_> 8 16 8 5 3. <_> <_> 0 20 20 3 -1. <_> 10 20 10 3 2. <_> <_> 5 10 18 2 -1. <_> 5 11 18 1 2. <_> <_> 0 6 6 10 -1. <_> 2 6 2 10 3. <_> <_> 2 1 20 3 -1. <_> 2 2 20 1 3. <_> <_> 9 13 6 11 -1. <_> 11 13 2 11 3. <_> <_> 9 15 6 8 -1. <_> 9 19 6 4 2. <_> <_> 9 12 6 9 -1. <_> 9 15 6 3 3. <_> <_> 5 11 18 2 -1. <_> 5 12 18 1 2. <_> <_> 2 6 15 6 -1. <_> 2 8 15 2 3. <_> <_> 6 0 18 3 -1. <_> 6 1 18 1 3. <_> <_> 5 0 3 18 -1. <_> 6 0 1 18 3. <_> <_> 18 3 6 10 -1. <_> 20 3 2 10 3. <_> <_> 0 3 6 10 -1. <_> 2 3 2 10 3. <_> <_> 10 5 8 9 -1. <_> 10 5 4 9 2. <_> <_> 6 5 8 9 -1. <_> 10 5 4 9 2. <_> <_> 3 2 20 3 -1. <_> 3 3 20 1 3. <_> <_> 5 2 13 4 -1. <_> 5 4 13 2 2. <_> <_> 17 0 7 14 -1. <_> 17 7 7 7 2. <_> <_> 0 0 7 14 -1. <_> 0 7 7 7 2. <_> <_> 9 11 10 6 -1. <_> 9 11 5 6 2. <_> <_> 5 11 10 6 -1. <_> 10 11 5 6 2. <_> <_> 11 6 3 18 -1. <_> 11 12 3 6 3. <_> <_> 0 16 18 3 -1. <_> 0 17 18 1 3. <_> <_> 6 16 18 3 -1. <_> 6 17 18 1 3. <_> <_> 4 6 9 10 -1. <_> 4 11 9 5 2. <_> <_> 9 7 15 4 -1. <_> 9 9 15 2 2. <_> <_> 5 6 12 6 -1. <_> 5 6 6 3 2. <_> 11 9 6 3 2. <_> <_> 6 1 12 9 -1. <_> 6 4 12 3 3. <_> <_> 7 9 6 12 -1. <_> 7 9 3 6 2. <_> 10 15 3 6 2. <_> <_> 11 5 13 6 -1. <_> 11 7 13 2 3. <_> <_> 1 11 22 13 -1. <_> 12 11 11 13 2. <_> <_> 18 8 6 6 -1. <_> 18 11 6 3 2. <_> <_> 0 8 6 6 -1. <_> 0 11 6 3 2. <_> <_> 0 6 24 3 -1. <_> 0 7 24 1 3. <_> <_> 0 5 10 6 -1. <_> 0 7 10 2 3. <_> <_> 6 7 18 3 -1. <_> 6 8 18 1 3. <_> <_> 0 0 10 6 -1. <_> 0 2 10 2 3. <_> <_> 19 0 3 19 -1. <_> 20 0 1 19 3. <_> <_> 4 6 12 16 -1. <_> 4 6 6 8 2. <_> 10 14 6 8 2. <_> <_> 19 6 4 18 -1. <_> 21 6 2 9 2. <_> 19 15 2 9 2. <_> <_> 1 6 4 18 -1. <_> 1 6 2 9 2. <_> 3 15 2 9 2. <_> <_> 3 21 18 3 -1. <_> 3 22 18 1 3. <_> <_> 0 19 9 4 -1. <_> 0 21 9 2 2. <_> <_> 12 18 12 6 -1. <_> 18 18 6 3 2. <_> 12 21 6 3 2. <_> <_> 7 18 9 4 -1. <_> 7 20 9 2 2. <_> <_> 12 16 10 8 -1. <_> 17 16 5 4 2. <_> 12 20 5 4 2. <_> <_> 2 16 10 8 -1. <_> 2 16 5 4 2. <_> 7 20 5 4 2. <_> <_> 14 0 10 12 -1. <_> 19 0 5 6 2. <_> 14 6 5 6 2. <_> <_> 0 0 10 12 -1. <_> 0 0 5 6 2. <_> 5 6 5 6 2. <_> <_> 15 14 9 6 -1. <_> 15 16 9 2 3. <_> <_> 0 14 9 6 -1. <_> 0 16 9 2 3. <_> <_> 14 14 10 6 -1. <_> 14 16 10 2 3. <_> <_> 0 14 10 6 -1. <_> 0 16 10 2 3. <_> <_> 5 18 18 2 -1. <_> 5 19 18 1 2. <_> <_> 0 18 18 3 -1. <_> 0 19 18 1 3. <_> <_> 3 5 18 12 -1. <_> 12 5 9 6 2. <_> 3 11 9 6 2. <_> <_> 5 3 7 9 -1. <_> 5 6 7 3 3. <_> <_> 4 0 19 15 -1. <_> 4 5 19 5 3. <_> <_> 3 0 16 4 -1. <_> 3 2 16 2 2. <_> <_> 4 12 16 12 -1. <_> 4 12 8 12 2. <_> <_> 4 3 12 15 -1. <_> 10 3 6 15 2. <_> <_> 16 4 2 19 -1. <_> 16 4 1 19 2. <_> <_> 6 4 2 19 -1. <_> 7 4 1 19 2. <_> <_> 13 14 8 10 -1. <_> 17 14 4 5 2. <_> 13 19 4 5 2. <_> <_> 3 14 8 10 -1. <_> 3 14 4 5 2. <_> 7 19 4 5 2. <_> <_> 12 6 3 18 -1. <_> 12 12 3 6 3. <_> <_> 5 11 12 6 -1. <_> 5 11 6 3 2. <_> 11 14 6 3 2. <_> <_> 10 5 8 10 -1. <_> 14 5 4 5 2. <_> 10 10 4 5 2. <_> <_> 6 4 12 10 -1. <_> 6 4 6 5 2. <_> 12 9 6 5 2. <_> <_> 6 8 18 10 -1. <_> 15 8 9 5 2. <_> 6 13 9 5 2. <_> <_> 0 8 18 10 -1. <_> 0 8 9 5 2. <_> 9 13 9 5 2. <_> <_> 12 6 3 18 -1. <_> 12 12 3 6 3. <_> <_> 0 14 18 3 -1. <_> 0 15 18 1 3. <_> <_> 12 6 3 18 -1. <_> 12 12 3 6 3. <_> <_> 9 6 3 18 -1. <_> 9 12 3 6 3. <_> <_> 6 14 18 3 -1. <_> 6 15 18 1 3. <_> <_> 0 5 18 3 -1. <_> 0 6 18 1 3. <_> <_> 2 5 22 3 -1. <_> 2 6 22 1 3. <_> <_> 0 0 21 10 -1. <_> 7 0 7 10 3. <_> <_> 6 3 18 17 -1. <_> 12 3 6 17 3. <_> <_> 0 3 18 17 -1. <_> 6 3 6 17 3. <_> <_> 0 12 24 11 -1. <_> 8 12 8 11 3. <_> <_> 4 10 16 6 -1. <_> 4 13 16 3 2. <_> <_> 12 8 6 8 -1. <_> 12 12 6 4 2. <_> <_> 6 14 8 7 -1. <_> 10 14 4 7 2. <_> <_> 15 10 6 14 -1. <_> 18 10 3 7 2. <_> 15 17 3 7 2. <_> <_> 3 10 6 14 -1. <_> 3 10 3 7 2. <_> 6 17 3 7 2. <_> <_> 6 12 18 2 -1. <_> 6 13 18 1 2. <_> <_> 5 8 10 6 -1. <_> 5 10 10 2 3. <_> <_> 12 11 9 4 -1. <_> 12 13 9 2 2. <_> <_> 0 11 9 6 -1. <_> 0 13 9 2 3. <_> <_> 11 2 3 18 -1. <_> 12 2 1 18 3. <_> <_> 10 2 3 18 -1. <_> 11 2 1 18 3. <_> <_> 9 12 6 10 -1. <_> 11 12 2 10 3. <_> <_> 1 10 6 9 -1. <_> 1 13 6 3 3. <_> <_> 6 9 16 6 -1. <_> 14 9 8 3 2. <_> 6 12 8 3 2. <_> <_> 1 8 9 6 -1. <_> 1 10 9 2 3. <_> <_> 7 7 16 6 -1. <_> 7 9 16 2 3. <_> <_> 0 0 18 3 -1. <_> 0 1 18 1 3. <_> <_> 10 0 6 9 -1. <_> 12 0 2 9 3. <_> <_> 9 5 6 6 -1. <_> 12 5 3 6 2. <_> <_> 10 6 4 18 -1. <_> 12 6 2 9 2. <_> 10 15 2 9 2. <_> <_> 8 0 6 9 -1. <_> 10 0 2 9 3. <_> <_> 9 1 6 9 -1. <_> 9 4 6 3 3. <_> <_> 1 0 18 9 -1. <_> 1 3 18 3 3. <_> <_> 0 3 24 3 -1. <_> 0 4 24 1 3. <_> <_> 6 14 9 4 -1. <_> 6 16 9 2 2. <_> <_> 8 9 8 10 -1. <_> 12 9 4 5 2. <_> 8 14 4 5 2. <_> <_> 5 2 13 9 -1. <_> 5 5 13 3 3. <_> <_> 4 4 16 9 -1. <_> 4 7 16 3 3. <_> <_> 4 4 14 9 -1. <_> 4 7 14 3 3. <_> <_> 8 5 9 6 -1. <_> 8 7 9 2 3. <_> <_> 1 7 16 6 -1. <_> 1 9 16 2 3. <_> <_> 10 5 13 9 -1. <_> 10 8 13 3 3. <_> <_> 1 5 13 9 -1. <_> 1 8 13 3 3. <_> <_> 0 4 24 6 -1. <_> 12 4 12 3 2. <_> 0 7 12 3 2. <_> <_> 1 14 10 9 -1. <_> 1 17 10 3 3. <_> <_> 5 17 18 3 -1. <_> 5 18 18 1 3. <_> <_> 0 16 18 3 -1. <_> 0 17 18 1 3. <_> <_> 9 17 9 6 -1. <_> 9 19 9 2 3. <_> <_> 1 20 22 4 -1. <_> 1 20 11 2 2. <_> 12 22 11 2 2. <_> <_> 8 14 8 6 -1. <_> 8 17 8 3 2. <_> <_> 8 6 8 15 -1. <_> 8 11 8 5 3. <_> <_> 5 4 18 3 -1. <_> 5 5 18 1 3. <_> <_> 9 3 5 10 -1. <_> 9 8 5 5 2. <_> <_> 6 8 12 3 -1. <_> 6 8 6 3 2. <_> <_> 2 6 18 6 -1. <_> 2 6 9 3 2. <_> 11 9 9 3 2. <_> <_> 10 6 4 18 -1. <_> 12 6 2 9 2. <_> 10 15 2 9 2. <_> <_> 7 5 6 6 -1. <_> 10 5 3 6 2. <_> <_> 14 5 2 18 -1. <_> 14 14 2 9 2. <_> <_> 8 5 2 18 -1. <_> 8 14 2 9 2. <_> <_> 9 2 10 6 -1. <_> 9 2 5 6 2. <_> <_> 3 1 18 12 -1. <_> 12 1 9 12 2. <_> <_> 5 2 17 22 -1. <_> 5 13 17 11 2. <_> <_> 4 0 12 6 -1. <_> 4 2 12 2 3. <_> <_> 6 9 16 6 -1. <_> 14 9 8 3 2. <_> 6 12 8 3 2. <_> <_> 9 0 5 18 -1. <_> 9 9 5 9 2. <_> <_> 12 0 6 9 -1. <_> 14 0 2 9 3. <_> <_> 6 0 6 9 -1. <_> 8 0 2 9 3. <_> <_> 9 1 6 12 -1. <_> 11 1 2 12 3. <_> <_> 5 9 13 4 -1. <_> 5 11 13 2 2. <_> <_> 5 8 19 3 -1. <_> 5 9 19 1 3. <_> <_> 9 9 6 8 -1. <_> 9 13 6 4 2. <_> <_> 11 9 4 15 -1. <_> 11 14 4 5 3. <_> <_> 2 0 6 14 -1. <_> 2 0 3 7 2. <_> 5 7 3 7 2. <_> <_> 15 1 6 14 -1. <_> 18 1 3 7 2. <_> 15 8 3 7 2. <_> <_> 3 1 6 14 -1. <_> 3 1 3 7 2. <_> 6 8 3 7 2. <_> <_> 3 20 18 4 -1. <_> 12 20 9 2 2. <_> 3 22 9 2 2. <_> <_> 5 0 4 20 -1. <_> 5 0 2 10 2. <_> 7 10 2 10 2. <_> <_> 16 8 8 12 -1. <_> 20 8 4 6 2. <_> 16 14 4 6 2. <_> <_> 0 8 8 12 -1. <_> 0 8 4 6 2. <_> 4 14 4 6 2. <_> <_> 13 13 10 8 -1. <_> 18 13 5 4 2. <_> 13 17 5 4 2. <_> <_> 1 13 10 8 -1. <_> 1 13 5 4 2. <_> 6 17 5 4 2. <_> <_> 15 8 4 15 -1. <_> 15 13 4 5 3. <_> <_> 5 8 4 15 -1. <_> 5 13 4 5 3. <_> <_> 6 11 16 12 -1. <_> 6 15 16 4 3. <_> <_> 2 11 16 12 -1. <_> 2 15 16 4 3. <_> <_> 14 12 7 9 -1. <_> 14 15 7 3 3. <_> <_> 10 1 3 21 -1. <_> 10 8 3 7 3. <_> <_> 13 11 9 4 -1. <_> 13 13 9 2 2. <_> <_> 3 10 17 9 -1. <_> 3 13 17 3 3. <_> <_> 13 8 8 15 -1. <_> 13 13 8 5 3. <_> <_> 3 8 8 15 -1. <_> 3 13 8 5 3. <_> <_> 11 14 10 8 -1. <_> 16 14 5 4 2. <_> 11 18 5 4 2. <_> <_> 0 18 22 6 -1. <_> 0 18 11 3 2. <_> 11 21 11 3 2. <_> <_> 0 16 24 4 -1. <_> 0 16 12 4 2. <_> <_> 6 20 12 3 -1. <_> 12 20 6 3 2. <_> <_> 18 12 6 12 -1. <_> 21 12 3 6 2. <_> 18 18 3 6 2. <_> <_> 0 12 6 12 -1. <_> 0 12 3 6 2. <_> 3 18 3 6 2. <_> <_> 15 17 9 6 -1. <_> 15 19 9 2 3. <_> <_> 1 6 22 10 -1. <_> 1 6 11 5 2. <_> 12 11 11 5 2. <_> <_> 15 17 9 6 -1. <_> 15 19 9 2 3. <_> <_> 0 18 18 2 -1. <_> 0 19 18 1 2. <_> <_> 3 15 19 3 -1. <_> 3 16 19 1 3. <_> <_> 0 13 18 3 -1. <_> 0 14 18 1 3. <_> <_> 15 17 9 6 -1. <_> 15 19 9 2 3. <_> <_> 0 17 9 6 -1. <_> 0 19 9 2 3. <_> <_> 12 17 9 6 -1. <_> 12 19 9 2 3. <_> <_> 3 17 9 6 -1. <_> 3 19 9 2 3. <_> <_> 16 2 3 20 -1. <_> 17 2 1 20 3. <_> <_> 0 13 24 8 -1. <_> 0 17 24 4 2. <_> <_> 9 1 6 22 -1. <_> 12 1 3 11 2. <_> 9 12 3 11 2. ================================================ FILE: dnn.cpp ================================================ //go:build !gocv_specific_modules || (gocv_specific_modules && gocv_dnn) #include "dnn.h" Net Net_ReadNet(const char* model, const char* config) { try { Net n = new cv::dnn::Net(cv::dnn::readNet(model, config)); return n; } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } Net Net_ReadNetBytes(const char* framework, struct ByteArray model, struct ByteArray config) { try { std::vector modelv(model.data, model.data + model.length); std::vector configv(config.data, config.data + config.length); Net n = new cv::dnn::Net(cv::dnn::readNet(framework, modelv, configv)); return n; } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } Net Net_ReadNetFromCaffe(const char* prototxt, const char* caffeModel) { try { Net n = new cv::dnn::Net(cv::dnn::readNetFromCaffe(prototxt, caffeModel)); return n; } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } Net Net_ReadNetFromCaffeBytes(struct ByteArray prototxt, struct ByteArray caffeModel) { try { Net n = new cv::dnn::Net(cv::dnn::readNetFromCaffe(prototxt.data, prototxt.length, caffeModel.data, caffeModel.length)); return n; } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } Net Net_ReadNetFromTensorflow(const char* model) { try { Net n = new cv::dnn::Net(cv::dnn::readNetFromTensorflow(model)); return n; } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } Net Net_ReadNetFromTensorflowBytes(struct ByteArray model) { try { Net n = new cv::dnn::Net(cv::dnn::readNetFromTensorflow(model.data, model.length)); return n; } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } Net Net_ReadNetFromTorch(const char* model) { try { Net n = new cv::dnn::Net(cv::dnn::readNetFromTorch(model)); return n; } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } Net Net_ReadNetFromONNX(const char* model) { try { Net n = new cv::dnn::Net(cv::dnn::readNetFromONNX(model)); return n; } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } Net Net_ReadNetFromONNXBytes(struct ByteArray model) { try { Net n = new cv::dnn::Net(cv::dnn::readNetFromONNX(model.data, model.length)); return n; } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } void Net_Close(Net net) { delete net; } bool Net_Empty(Net net) { try { return net->empty(); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return false; } } void Net_SetInput(Net net, Mat blob, const char* name) { try { net->setInput(*blob, name); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); } } Mat Net_Forward(Net net, const char* outputName) { try { return new cv::Mat(net->forward(outputName)); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return new cv::Mat(); } } void Net_ForwardLayers(Net net, struct Mats* outputBlobs, struct CStrings outBlobNames) { try { std::vector< cv::Mat > blobs; std::vector< cv::String > names; for (int i = 0; i < outBlobNames.length; ++i) { names.push_back(cv::String(outBlobNames.strs[i])); } net->forward(blobs, names); // copy blobs into outputBlobs outputBlobs->mats = new Mat[blobs.size()]; for (size_t i = 0; i < blobs.size(); ++i) { outputBlobs->mats[i] = new cv::Mat(blobs[i]); } outputBlobs->length = (int)blobs.size(); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); } } void Net_SetPreferableBackend(Net net, int backend) { try { net->setPreferableBackend(backend); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); } } void Net_SetPreferableTarget(Net net, int target) { try { net->setPreferableTarget(target); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); } } int64_t Net_GetPerfProfile(Net net) { try { std::vector layersTimes; return net->getPerfProfile(layersTimes); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return 0; } } void Net_GetUnconnectedOutLayers(Net net, IntVector* res) { try { std::vector< int > cids(net->getUnconnectedOutLayers()); int* ids = new int[cids.size()]; for (size_t i = 0; i < cids.size(); ++i) { ids[i] = cids[i]; } res->length = cids.size(); res->val = ids; } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); } } void Net_GetLayerNames(Net net, CStrings* names) { try { std::vector< cv::String > cstrs(net->getLayerNames()); size_t totalStrLen = 0; for (cv::String str : cstrs) { totalStrLen += str.size(); } // Compute 1D buffer size required to store // 2D array of null-terminated strings size_t numStrings = cstrs.size(); size_t bufferLen = numStrings * sizeof(char*) + (totalStrLen + numStrings) * sizeof(char); const char **strs = (const char**)new char[bufferLen]; memset(strs, 0, bufferLen); char* it = (char*)(strs + cstrs.size()); const char* end = (char*)(strs) + bufferLen; for (size_t i = 0; i < numStrings; ++i, ++it) { strs[i] = it; size_t strlen = cstrs[i].size(); // Avoid buffer overrun if(end < it + strlen + 1) { break; } memcpy(it, cstrs[i].c_str(), strlen); it += strlen; } names->length = cstrs.size(); names->strs = strs; } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); } } struct Rect Net_BlobRectToImageRect(struct Rect rect, Size originalSize, double scalefactor, Size size, Scalar mean, bool swapRB, int ddepth, int dataLayout, int paddingMode, Scalar borderValue) { try { cv::Scalar sf(scalefactor); cv::Size sz(size.width, size.height); cv::Scalar cm(mean.val1, mean.val2, mean.val3, mean.val4); cv::dnn::DataLayout dl = static_cast(dataLayout); cv::dnn::ImagePaddingMode pm = static_cast(paddingMode); cv::Scalar bv(borderValue.val1, borderValue.val2, borderValue.val3, borderValue.val4); cv::dnn::Image2BlobParams params = cv::dnn::Image2BlobParams(sf, sz, cm, swapRB, ddepth, dl, pm, bv); cv::Rect bRect = params.blobRectToImageRect(cv::Rect(rect.x, rect.y, rect.width, rect.height), cv::Size(originalSize.width, originalSize.height)); Rect r = {bRect.x, bRect.y, bRect.width, bRect.height}; return r; } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); Rect r = {0, 0, 0, 0}; return r; } } struct Rects Net_BlobRectsToImageRects(struct Rects rects, Size originalSize, double scalefactor, Size size, Scalar mean, bool swapRB, int ddepth, int dataLayout, int paddingMode, Scalar borderValue) { try { std::vector _cRects; for (int i = 0; i < rects.length; ++i) { _cRects.push_back(cv::Rect( rects.rects[i].x, rects.rects[i].y, rects.rects[i].width, rects.rects[i].height )); } cv::Scalar sf(scalefactor); cv::Size sz(size.width, size.height); cv::Scalar cm(mean.val1, mean.val2, mean.val3, mean.val4); cv::dnn::DataLayout dl = static_cast(dataLayout); cv::dnn::ImagePaddingMode pm = static_cast(paddingMode); cv::Scalar bv(borderValue.val1, borderValue.val2, borderValue.val3, borderValue.val4); cv::dnn::Image2BlobParams params = cv::dnn::Image2BlobParams(sf, sz, cm, swapRB, ddepth, dl, pm, bv); std::vector detected; params.blobRectsToImageRects(_cRects, detected, cv::Size(originalSize.width, originalSize.height)); Rect* drects = new Rect[detected.size()]; for (size_t i = 0; i < detected.size(); ++i) { Rect r = {detected[i].x, detected[i].y, detected[i].width, detected[i].height}; drects[i] = r; } Rects ret = {drects, (int)detected.size()}; return ret; } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); Rects ret = {NULL, 0}; return ret; } } Mat Net_BlobFromImage(Mat image, double scalefactor, Size size, Scalar mean, bool swapRB, bool crop) { try { cv::Size sz(size.width, size.height); cv::Scalar cm(mean.val1, mean.val2, mean.val3, mean.val4); // use the default target ddepth here. return new cv::Mat(cv::dnn::blobFromImage(*image, scalefactor, sz, cm, swapRB, crop)); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return new cv::Mat(); } } Mat Net_BlobFromImageWithParams(Mat image, double scalefactor, Size size, Scalar mean, bool swapRB, int ddepth, int dataLayout, int paddingMode, Scalar borderValue) { try { cv::Scalar sf(scalefactor); cv::Size sz(size.width, size.height); cv::Scalar cm(mean.val1, mean.val2, mean.val3, mean.val4); cv::dnn::DataLayout dl = static_cast(dataLayout); cv::dnn::ImagePaddingMode pm = static_cast(paddingMode); cv::Scalar bv(borderValue.val1, borderValue.val2, borderValue.val3, borderValue.val4); cv::dnn::Image2BlobParams params = cv::dnn::Image2BlobParams(sf, sz, cm, swapRB, ddepth, dl, pm, bv); return new cv::Mat(cv::dnn::blobFromImageWithParams(*image, params)); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return new cv::Mat(); } } void Net_BlobFromImages(struct Mats images, Mat blob, double scalefactor, Size size, Scalar mean, bool swapRB, bool crop, int ddepth) { try { std::vector imgs; for (int i = 0; i < images.length; ++i) { imgs.push_back(*images.mats[i]); } cv::Size sz(size.width, size.height); cv::Scalar cm = cv::Scalar(mean.val1, mean.val2, mean.val3, mean.val4); // ignore the passed in ddepth, just use default. cv::dnn::blobFromImages(imgs, *blob, scalefactor, sz, cm, swapRB, crop); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); } } void Net_BlobFromImagesWithParams(struct Mats images, Mat blob, double scalefactor, Size size, Scalar mean, bool swapRB, int ddepth, int dataLayout, int paddingMode, Scalar borderValue) { try { std::vector imgs; for (int i = 0; i < images.length; ++i) { imgs.push_back(*images.mats[i]); } cv::Scalar sf(scalefactor); cv::Size sz(size.width, size.height); cv::Scalar cm(mean.val1, mean.val2, mean.val3, mean.val4); cv::dnn::DataLayout dl = static_cast(dataLayout); cv::dnn::ImagePaddingMode pm = static_cast(paddingMode); cv::Scalar bv(borderValue.val1, borderValue.val2, borderValue.val3, borderValue.val4); cv::dnn::Image2BlobParams params = cv::dnn::Image2BlobParams(sf, sz, cm, swapRB, ddepth, dl, pm, bv); cv::dnn::blobFromImagesWithParams(imgs, *blob, params); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); } } void Net_ImagesFromBlob(Mat blob_, struct Mats* images_) { try { std::vector imgs; cv::dnn::imagesFromBlob(*blob_, imgs); images_->mats = new Mat[imgs.size()]; for (size_t i = 0; i < imgs.size(); ++i) { images_->mats[i] = new cv::Mat(imgs[i]); } images_->length = (int) imgs.size(); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); } } Mat Net_GetBlobChannel(Mat blob, int imgidx, int chnidx) { size_t w = blob->size[3]; size_t h = blob->size[2]; return new cv::Mat(h, w, CV_32F, blob->ptr(imgidx, chnidx)); } Scalar Net_GetBlobSize(Mat blob) { Scalar scal = Scalar(); scal.val1 = blob->size[0]; scal.val2 = blob->size[1]; scal.val3 = blob->size[2]; scal.val4 = blob->size[3]; return scal; } Layer Net_GetLayer(Net net, int layerid) { try { return new cv::Ptr(net->getLayer(layerid)); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } void Layer_Close(Layer layer) { delete layer; } int Layer_InputNameToIndex(Layer layer, const char* name) { try { return (*layer)->inputNameToIndex(name); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return -1; } } int Layer_OutputNameToIndex(Layer layer, const char* name) { try { return (*layer)->outputNameToIndex(name); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return -1; } } const char* Layer_GetName(Layer layer) { try { return (*layer)->name.c_str(); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return ""; } } const char* Layer_GetType(Layer layer) { try { return (*layer)->type.c_str(); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return ""; } } void NMSBoxes(struct Rects bboxes, FloatVector scores, float score_threshold, float nms_threshold, IntVector* indices) { try { std::vector _bboxes; for (int i = 0; i < bboxes.length; ++i) { _bboxes.push_back(cv::Rect( bboxes.rects[i].x, bboxes.rects[i].y, bboxes.rects[i].width, bboxes.rects[i].height )); } std::vector _scores; float* f; int i; for (i = 0, f = scores.val; i < scores.length; ++f, ++i) { _scores.push_back(*f); } std::vector _indices(indices->length); cv::dnn::NMSBoxes(_bboxes, _scores, score_threshold, nms_threshold, _indices, 1.f, 0); int* ptr = new int[_indices.size()]; for (size_t i=0; i<_indices.size(); ++i) { ptr[i] = _indices[i]; } indices->length = _indices.size(); indices->val = ptr; } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); } } void NMSBoxesWithParams(struct Rects bboxes, FloatVector scores, const float score_threshold, const float nms_threshold, IntVector* indices, const float eta, const int top_k) { try { std::vector _bboxes; for (int i = 0; i < bboxes.length; ++i) { _bboxes.push_back(cv::Rect( bboxes.rects[i].x, bboxes.rects[i].y, bboxes.rects[i].width, bboxes.rects[i].height )); } std::vector _scores; float* f; int i; for (i = 0, f = scores.val; i < scores.length; ++f, ++i) { _scores.push_back(*f); } std::vector _indices(indices->length); cv::dnn::NMSBoxes(_bboxes, _scores, score_threshold, nms_threshold, _indices, eta, top_k); int* ptr = new int[_indices.size()]; for (size_t i=0; i<_indices.size(); ++i) { ptr[i] = _indices[i]; } indices->length = _indices.size(); indices->val = ptr; } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); } } ================================================ FILE: dnn.go ================================================ //go:build !gocv_specific_modules || (gocv_specific_modules && gocv_dnn) package gocv /* #include #include "dnn.h" */ import "C" import ( "image" "reflect" "unsafe" ) // Net allows you to create and manipulate comprehensive artificial neural networks. // // For further details, please see: // https://docs.opencv.org/master/db/d30/classcv_1_1dnn_1_1Net.html type Net struct { // C.Net p unsafe.Pointer } // NetBackendType is the type for the various different kinds of DNN backends. type NetBackendType int const ( // NetBackendDefault is the default backend. NetBackendDefault NetBackendType = 0 // NetBackendHalide is the Halide backend. NetBackendHalide NetBackendType = 1 // NetBackendOpenVINO is the OpenVINO backend. NetBackendOpenVINO NetBackendType = 2 // NetBackendOpenCV is the OpenCV backend. NetBackendOpenCV NetBackendType = 3 // NetBackendVKCOM is the Vulkan backend. NetBackendVKCOM NetBackendType = 4 // NetBackendCUDA is the Cuda backend. NetBackendCUDA NetBackendType = 5 ) // ParseNetBackend returns a valid NetBackendType given a string. Valid values are: // - halide // - openvino // - opencv // - vulkan // - cuda // - default func ParseNetBackend(backend string) NetBackendType { switch backend { case "halide": return NetBackendHalide case "openvino": return NetBackendOpenVINO case "opencv": return NetBackendOpenCV case "vulkan": return NetBackendVKCOM case "cuda": return NetBackendCUDA default: return NetBackendDefault } } // NetTargetType is the type for the various different kinds of DNN device targets. type NetTargetType int const ( // NetTargetCPU is the default CPU device target. NetTargetCPU NetTargetType = 0 // NetTargetFP32 is the 32-bit OpenCL target. NetTargetFP32 NetTargetType = 1 // NetTargetFP16 is the 16-bit OpenCL target. NetTargetFP16 NetTargetType = 2 // NetTargetVPU is the Movidius VPU target. NetTargetVPU NetTargetType = 3 // NetTargetVulkan is the NVIDIA Vulkan target. NetTargetVulkan NetTargetType = 4 // NetTargetFPGA is the FPGA target. NetTargetFPGA NetTargetType = 5 // NetTargetCUDA is the CUDA target. NetTargetCUDA NetTargetType = 6 // NetTargetCUDAFP16 is the CUDA target. NetTargetCUDAFP16 NetTargetType = 7 ) // ParseNetTarget returns a valid NetTargetType given a string. Valid values are: // - cpu // - fp32 // - fp16 // - vpu // - vulkan // - fpga // - cuda // - cudafp16 func ParseNetTarget(target string) NetTargetType { switch target { case "cpu": return NetTargetCPU case "fp32": return NetTargetFP32 case "fp16": return NetTargetFP16 case "vpu": return NetTargetVPU case "vulkan": return NetTargetVulkan case "fpga": return NetTargetFPGA case "cuda": return NetTargetCUDA case "cudafp16": return NetTargetCUDAFP16 default: return NetTargetCPU } } type DataLayoutType int const ( DataLayoutUnknown DataLayoutType = iota DataLayoutND DataLayoutNCHW DataLayoutNCDHW DataLayoutNHWC DataLayoutNDHWC DataLayoutPLANAR ) type PaddingModeType int const ( PaddingModeNull PaddingModeType = iota PaddingModeCropCenter PaddingModeLetterbox ) type ImageToBlobParams struct { ScaleFactor float64 Size image.Point Mean Scalar SwapRB bool Ddepth MatType DataLayout DataLayoutType PaddingMode PaddingModeType BorderValue Scalar } func NewImageToBlobParams(scale float64, size image.Point, mean Scalar, swapRB bool, ddepth MatType, dataLayout DataLayoutType, paddingMode PaddingModeType, border Scalar) ImageToBlobParams { return ImageToBlobParams{ ScaleFactor: scale, Size: size, Mean: mean, SwapRB: swapRB, Ddepth: ddepth, DataLayout: dataLayout, PaddingMode: paddingMode, BorderValue: border, } } // BlobRectToImageRect gets rectangle coordinates in original image system from rectangle in blob coordinates. // // For further details, please see: // https://docs.opencv.org/4.10.0/d9/d3c/structcv_1_1dnn_1_1Image2BlobParams.html#a40b2b5a731da82f042279650ffb3c3ee func (p *ImageToBlobParams) BlobRectToImageRect(rect image.Rectangle, size image.Point) image.Rectangle { cRect := C.struct_Rect{ x: C.int(rect.Min.X), y: C.int(rect.Min.Y), width: C.int(rect.Size().X), height: C.int(rect.Size().Y), } cSize := C.struct_Size{width: C.int(size.X), height: C.int(size.Y)} sz := C.struct_Size{ width: C.int(p.Size.X), height: C.int(p.Size.Y), } sMean := C.struct_Scalar{ val1: C.double(p.Mean.Val1), val2: C.double(p.Mean.Val2), val3: C.double(p.Mean.Val3), val4: C.double(p.Mean.Val4), } bv := C.struct_Scalar{ val1: C.double(p.BorderValue.Val1), val2: C.double(p.BorderValue.Val2), val3: C.double(p.BorderValue.Val3), val4: C.double(p.BorderValue.Val4), } return toRect(C.Net_BlobRectToImageRect(cRect, cSize, C.double(p.ScaleFactor), sz, sMean, C.bool(p.SwapRB), C.int(p.Ddepth), C.int(p.DataLayout), C.int(p.PaddingMode), bv)) } // BlobRectsToImageRects converts rectangle coordinates in original image system from rectangles in blob coordinates. // // For further details, please see: // https://docs.opencv.org/4.10.0/d9/d3c/structcv_1_1dnn_1_1Image2BlobParams.html#a822728804c0d35fc3b743644ee192f60 func (p *ImageToBlobParams) BlobRectsToImageRects(rects []image.Rectangle, size image.Point) []image.Rectangle { cRectArr := []C.struct_Rect{} for _, v := range rects { rect := C.struct_Rect{ x: C.int(v.Min.X), y: C.int(v.Min.Y), width: C.int(v.Size().X), height: C.int(v.Size().Y), } cRectArr = append(cRectArr, rect) } cRects := C.Rects{ rects: (*C.Rect)(&cRectArr[0]), length: C.int(len(rects)), } cSize := C.struct_Size{width: C.int(size.X), height: C.int(size.Y)} sz := C.struct_Size{ width: C.int(p.Size.X), height: C.int(p.Size.Y), } sMean := C.struct_Scalar{ val1: C.double(p.Mean.Val1), val2: C.double(p.Mean.Val2), val3: C.double(p.Mean.Val3), val4: C.double(p.Mean.Val4), } bv := C.struct_Scalar{ val1: C.double(p.BorderValue.Val1), val2: C.double(p.BorderValue.Val2), val3: C.double(p.BorderValue.Val3), val4: C.double(p.BorderValue.Val4), } return toRectangles(C.Net_BlobRectsToImageRects(cRects, cSize, C.double(p.ScaleFactor), sz, sMean, C.bool(p.SwapRB), C.int(p.Ddepth), C.int(p.DataLayout), C.int(p.PaddingMode), bv)) } // Close Net func (net *Net) Close() error { C.Net_Close((C.Net)(net.p)) net.p = nil return nil } // Empty returns true if there are no layers in the network. // // For further details, please see: // https://docs.opencv.org/master/db/d30/classcv_1_1dnn_1_1Net.html#a6a5778787d5b8770deab5eda6968e66c func (net *Net) Empty() bool { return bool(C.Net_Empty((C.Net)(net.p))) } // SetInput sets the new value for the layer output blob. // // For further details, please see: // https://docs.opencv.org/trunk/db/d30/classcv_1_1dnn_1_1Net.html#a672a08ae76444d75d05d7bfea3e4a328 func (net *Net) SetInput(blob Mat, name string) { cName := C.CString(name) defer C.free(unsafe.Pointer(cName)) C.Net_SetInput((C.Net)(net.p), blob.p, cName) } // Forward runs forward pass to compute output of layer with name outputName. // // For further details, please see: // https://docs.opencv.org/trunk/db/d30/classcv_1_1dnn_1_1Net.html#a98ed94cb6ef7063d3697259566da310b func (net *Net) Forward(outputName string) Mat { cName := C.CString(outputName) defer C.free(unsafe.Pointer(cName)) return newMat(C.Net_Forward((C.Net)(net.p), cName)) } // ForwardLayers forward pass to compute outputs of layers listed in outBlobNames. // // For further details, please see: // https://docs.opencv.org/3.4.1/db/d30/classcv_1_1dnn_1_1Net.html#adb34d7650e555264c7da3b47d967311b func (net *Net) ForwardLayers(outBlobNames []string) (blobs []Mat) { cMats := C.struct_Mats{} C.Net_ForwardLayers((C.Net)(net.p), &(cMats), toCStrings(outBlobNames)) blobs = make([]Mat, cMats.length) for i := C.int(0); i < cMats.length; i++ { blobs[i].p = C.Mats_get(cMats, i) addMatToProfile(blobs[i].p) } return } // SetPreferableBackend ask network to use specific computation backend. // // For further details, please see: // https://docs.opencv.org/3.4/db/d30/classcv_1_1dnn_1_1Net.html#a7f767df11386d39374db49cd8df8f59e func (net *Net) SetPreferableBackend(backend NetBackendType) error { C.Net_SetPreferableBackend((C.Net)(net.p), C.int(backend)) return nil } // SetPreferableTarget ask network to make computations on specific target device. // // For further details, please see: // https://docs.opencv.org/3.4/db/d30/classcv_1_1dnn_1_1Net.html#a9dddbefbc7f3defbe3eeb5dc3d3483f4 func (net *Net) SetPreferableTarget(target NetTargetType) error { C.Net_SetPreferableTarget((C.Net)(net.p), C.int(target)) return nil } // ReadNet reads a deep learning network represented in one of the supported formats. // // For further details, please see: // https://docs.opencv.org/3.4/d6/d0f/group__dnn.html#ga3b34fe7a29494a6a4295c169a7d32422 func ReadNet(model string, config string) Net { cModel := C.CString(model) defer C.free(unsafe.Pointer(cModel)) cConfig := C.CString(config) defer C.free(unsafe.Pointer(cConfig)) return Net{p: unsafe.Pointer(C.Net_ReadNet(cModel, cConfig))} } // ReadNetBytes reads a deep learning network represented in one of the supported formats. // // For further details, please see: // https://docs.opencv.org/master/d6/d0f/group__dnn.html#ga138439da76f26266fdefec9723f6c5cd func ReadNetBytes(framework string, model []byte, config []byte) (Net, error) { cFramework := C.CString(framework) defer C.free(unsafe.Pointer(cFramework)) bModel, err := toByteArray(model) if err != nil { return Net{}, err } var bConfig C.ByteArray if len(config) > 0 { pbConfig, err := toByteArray(config) if err != nil { return Net{}, err } bConfig = *pbConfig } return Net{p: unsafe.Pointer(C.Net_ReadNetBytes(cFramework, *bModel, bConfig))}, nil } // ReadNetFromCaffe reads a network model stored in Caffe framework's format. // // For further details, please see: // https://docs.opencv.org/master/d6/d0f/group__dnn.html#ga29d0ea5e52b1d1a6c2681e3f7d68473a func ReadNetFromCaffe(prototxt string, caffeModel string) Net { cprototxt := C.CString(prototxt) defer C.free(unsafe.Pointer(cprototxt)) cmodel := C.CString(caffeModel) defer C.free(unsafe.Pointer(cmodel)) return Net{p: unsafe.Pointer(C.Net_ReadNetFromCaffe(cprototxt, cmodel))} } // ReadNetFromCaffeBytes reads a network model stored in Caffe model in memory. // // For further details, please see: // https://docs.opencv.org/master/d6/d0f/group__dnn.html#ga946b342af1355185a7107640f868b64a func ReadNetFromCaffeBytes(prototxt []byte, caffeModel []byte) (Net, error) { bPrototxt, err := toByteArray(prototxt) if err != nil { return Net{}, err } bCaffeModel, err := toByteArray(caffeModel) if err != nil { return Net{}, err } return Net{p: unsafe.Pointer(C.Net_ReadNetFromCaffeBytes(*bPrototxt, *bCaffeModel))}, nil } // ReadNetFromTensorflow reads a network model stored in Tensorflow framework's format. // // For further details, please see: // https://docs.opencv.org/master/d6/d0f/group__dnn.html#gad820b280978d06773234ba6841e77e8d func ReadNetFromTensorflow(model string) Net { cmodel := C.CString(model) defer C.free(unsafe.Pointer(cmodel)) return Net{p: unsafe.Pointer(C.Net_ReadNetFromTensorflow(cmodel))} } // ReadNetFromTensorflowBytes reads a network model stored in Tensorflow framework's format. // // For further details, please see: // https://docs.opencv.org/master/d6/d0f/group__dnn.html#gacdba30a7c20db2788efbf5bb16a7884d func ReadNetFromTensorflowBytes(model []byte) (Net, error) { bModel, err := toByteArray(model) if err != nil { return Net{}, err } return Net{p: unsafe.Pointer(C.Net_ReadNetFromTensorflowBytes(*bModel))}, nil } // ReadNetFromTorch reads a network model stored in Torch framework's format (t7). // // check net.Empty() for read failure // // For further details, please see: // https://docs.opencv.org/master/d6/d0f/group__dnn.html#gaaaed8c8530e9e92fe6647700c13d961e func ReadNetFromTorch(model string) Net { cmodel := C.CString(model) defer C.free(unsafe.Pointer(cmodel)) return Net{p: unsafe.Pointer(C.Net_ReadNetFromTorch(cmodel))} } // ReadNetFromONNX reads a network model stored in ONNX framework's format. // // check net.Empty() for read failure // // For further details, please see: // https://docs.opencv.org/master/d6/d0f/group__dnn.html#ga7faea56041d10c71dbbd6746ca854197 func ReadNetFromONNX(model string) Net { cmodel := C.CString(model) defer C.free(unsafe.Pointer(cmodel)) return Net{p: unsafe.Pointer(C.Net_ReadNetFromONNX(cmodel))} } // ReadNetFromONNXBytes reads a network model stored in ONNX framework's format. // // For further details, please see: // https://docs.opencv.org/master/d6/d0f/group__dnn.html#ga9198ecaac7c32ddf0aa7a1bcbd359567 func ReadNetFromONNXBytes(model []byte) (Net, error) { bModel, err := toByteArray(model) if err != nil { return Net{}, err } return Net{p: unsafe.Pointer(C.Net_ReadNetFromONNXBytes(*bModel))}, nil } // BlobFromImage creates 4-dimensional blob from image. Optionally resizes and crops // image from center, subtract mean values, scales values by scalefactor, // swap Blue and Red channels. // // For further details, please see: // https://docs.opencv.org/trunk/d6/d0f/group__dnn.html#ga152367f253c81b53fe6862b299f5c5cd func BlobFromImage(img Mat, scaleFactor float64, size image.Point, mean Scalar, swapRB bool, crop bool) Mat { sz := C.struct_Size{ width: C.int(size.X), height: C.int(size.Y), } sMean := C.struct_Scalar{ val1: C.double(mean.Val1), val2: C.double(mean.Val2), val3: C.double(mean.Val3), val4: C.double(mean.Val4), } return newMat(C.Net_BlobFromImage(img.p, C.double(scaleFactor), sz, sMean, C.bool(swapRB), C.bool(crop))) } // BlobFromImageWithParams creates 4-dimensional blob from image. Optionally resizes and crops // image from center, subtract mean values, scales values by scalefactor, // swap Blue and Red channels. // // For further details, please see: // https://docs.opencv.org/4.10.0/d6/d0f/group__dnn.html#gadc12e5f4a801fd3c1d802f4c8c5d311c func BlobFromImageWithParams(img Mat, params ImageToBlobParams) Mat { sz := C.struct_Size{ width: C.int(params.Size.X), height: C.int(params.Size.Y), } sMean := C.struct_Scalar{ val1: C.double(params.Mean.Val1), val2: C.double(params.Mean.Val2), val3: C.double(params.Mean.Val3), val4: C.double(params.Mean.Val4), } bv := C.struct_Scalar{ val1: C.double(params.BorderValue.Val1), val2: C.double(params.BorderValue.Val2), val3: C.double(params.BorderValue.Val3), val4: C.double(params.BorderValue.Val4), } return newMat(C.Net_BlobFromImageWithParams(img.p, C.double(params.ScaleFactor), sz, sMean, C.bool(params.SwapRB), C.int(params.Ddepth), C.int(params.DataLayout), C.int(params.PaddingMode), bv)) } // BlobFromImages Creates 4-dimensional blob from series of images. // Optionally resizes and crops images from center, subtract mean values, // scales values by scalefactor, swap Blue and Red channels. // // For further details, please see: // https://docs.opencv.org/master/d6/d0f/group__dnn.html#ga2b89ed84432e4395f5a1412c2926293c func BlobFromImages(imgs []Mat, blob *Mat, scaleFactor float64, size image.Point, mean Scalar, swapRB bool, crop bool, ddepth MatType) { cMatArray := make([]C.Mat, len(imgs)) for i, r := range imgs { cMatArray[i] = r.p } cMats := C.struct_Mats{ mats: (*C.Mat)(&cMatArray[0]), length: C.int(len(imgs)), } sz := C.struct_Size{ width: C.int(size.X), height: C.int(size.Y), } sMean := C.struct_Scalar{ val1: C.double(mean.Val1), val2: C.double(mean.Val2), val3: C.double(mean.Val3), val4: C.double(mean.Val4), } C.Net_BlobFromImages(cMats, blob.p, C.double(scaleFactor), sz, sMean, C.bool(swapRB), C.bool(crop), C.int(ddepth)) } // BlobFromImagesWithParams Creates 4-dimensional blob from series of images. // Optionally resizes and crops images from center, subtract mean values, // scales values by scalefactor, swap Blue and Red channels. // // For further details, please see: // https://docs.opencv.org/master/d6/d0f/group__dnn.html#ga2b89ed84432e4395f5a1412c2926293c func BlobFromImagesWithParams(imgs []Mat, blob *Mat, params ImageToBlobParams) { cMatArray := make([]C.Mat, len(imgs)) for i, r := range imgs { cMatArray[i] = r.p } cMats := C.struct_Mats{ mats: (*C.Mat)(&cMatArray[0]), length: C.int(len(imgs)), } sz := C.struct_Size{ width: C.int(params.Size.X), height: C.int(params.Size.Y), } sMean := C.struct_Scalar{ val1: C.double(params.Mean.Val1), val2: C.double(params.Mean.Val2), val3: C.double(params.Mean.Val3), val4: C.double(params.Mean.Val4), } bv := C.struct_Scalar{ val1: C.double(params.BorderValue.Val1), val2: C.double(params.BorderValue.Val2), val3: C.double(params.BorderValue.Val3), val4: C.double(params.BorderValue.Val4), } C.Net_BlobFromImagesWithParams(cMats, blob.p, C.double(params.ScaleFactor), sz, sMean, C.bool(params.SwapRB), C.int(params.Ddepth), C.int(params.DataLayout), C.int(params.PaddingMode), bv) } // ImagesFromBlob Parse a 4D blob and output the images it contains as // 2D arrays through a simpler data structure (std::vector). // // For further details, please see: // https://docs.opencv.org/master/d6/d0f/group__dnn.html#ga4051b5fa2ed5f54b76c059a8625df9f5 func ImagesFromBlob(blob Mat, imgs []Mat) { cMats := C.struct_Mats{} C.Net_ImagesFromBlob(blob.p, &(cMats)) // mv = make([]Mat, cMats.length) for i := C.int(0); i < cMats.length; i++ { imgs[i].p = C.Mats_get(cMats, i) } } // GetBlobChannel extracts a single (2d)channel from a 4 dimensional blob structure // (this might e.g. contain the results of a SSD or YOLO detection, // // a bones structure from pose detection, or a color plane from Colorization) func GetBlobChannel(blob Mat, imgidx int, chnidx int) Mat { return newMat(C.Net_GetBlobChannel(blob.p, C.int(imgidx), C.int(chnidx))) } // GetBlobSize retrieves the 4 dimensional size information in (N,C,H,W) order func GetBlobSize(blob Mat) Scalar { s := C.Net_GetBlobSize(blob.p) return NewScalar(float64(s.val1), float64(s.val2), float64(s.val3), float64(s.val4)) } // Layer is a wrapper around the cv::dnn::Layer algorithm. type Layer struct { // C.Layer p unsafe.Pointer } // GetLayer returns pointer to layer with specified id from the network. // // For further details, please see: // https://docs.opencv.org/master/db/d30/classcv_1_1dnn_1_1Net.html#a70aec7f768f38c32b1ee25f3a56526df func (net *Net) GetLayer(layer int) Layer { return Layer{p: unsafe.Pointer(C.Net_GetLayer((C.Net)(net.p), C.int(layer)))} } // GetPerfProfile returns overall time for inference and timings (in ticks) for layers // // For further details, please see: // https://docs.opencv.org/master/db/d30/classcv_1_1dnn_1_1Net.html#a06ce946f675f75d1c020c5ddbc78aedc func (net *Net) GetPerfProfile() float64 { return float64(C.Net_GetPerfProfile((C.Net)(net.p))) } // GetUnconnectedOutLayers returns indexes of layers with unconnected outputs. // // For further details, please see: // https://docs.opencv.org/master/db/d30/classcv_1_1dnn_1_1Net.html#ae62a73984f62c49fd3e8e689405b056a func (net *Net) GetUnconnectedOutLayers() (ids []int) { cids := C.IntVector{} C.Net_GetUnconnectedOutLayers((C.Net)(net.p), &cids) defer C.free(unsafe.Pointer(cids.val)) h := &reflect.SliceHeader{ Data: uintptr(unsafe.Pointer(cids.val)), Len: int(cids.length), Cap: int(cids.length), } pcids := *(*[]C.int)(unsafe.Pointer(h)) for i := 0; i < int(cids.length); i++ { ids = append(ids, int(pcids[i])) } return } // GetLayerNames returns all layer names. // // For furtherdetails, please see: // https://docs.opencv.org/master/db/d30/classcv_1_1dnn_1_1Net.html#ae8be9806024a0d1d41aba687cce99e6b func (net *Net) GetLayerNames() (names []string) { cstrs := C.CStrings{} defer C.CStrings_Close(cstrs) C.Net_GetLayerNames((C.Net)(net.p), &cstrs) return toGoStrings(cstrs) } // Close Layer func (l *Layer) Close() error { C.Layer_Close((C.Layer)(l.p)) l.p = nil return nil } // GetName returns name for this layer. func (l *Layer) GetName() string { return C.GoString(C.Layer_GetName((C.Layer)(l.p))) } // GetType returns type for this layer. func (l *Layer) GetType() string { return C.GoString(C.Layer_GetType((C.Layer)(l.p))) } // InputNameToIndex returns index of input blob in input array. // // For further details, please see: // https://docs.opencv.org/master/d3/d6c/classcv_1_1dnn_1_1Layer.html#a60ffc8238f3fa26cd3f49daa7ac0884b func (l *Layer) InputNameToIndex(name string) int { cName := C.CString(name) defer C.free(unsafe.Pointer(cName)) return int(C.Layer_InputNameToIndex((C.Layer)(l.p), cName)) } // OutputNameToIndex returns index of output blob in output array. // // For further details, please see: // https://docs.opencv.org/master/d3/d6c/classcv_1_1dnn_1_1Layer.html#a60ffc8238f3fa26cd3f49daa7ac0884b func (l *Layer) OutputNameToIndex(name string) int { cName := C.CString(name) defer C.free(unsafe.Pointer(cName)) return int(C.Layer_OutputNameToIndex((C.Layer)(l.p), cName)) } // NMSBoxes performs non maximum suppression given boxes and corresponding scores. // // For futher details, please see: // https://docs.opencv.org/4.4.0/d6/d0f/group__dnn.html#ga9d118d70a1659af729d01b10233213ee func NMSBoxes(bboxes []image.Rectangle, scores []float32, scoreThreshold float32, nmsThreshold float32) (indices []int) { bboxesRectArr := []C.struct_Rect{} for _, v := range bboxes { bbox := C.struct_Rect{ x: C.int(v.Min.X), y: C.int(v.Min.Y), width: C.int(v.Size().X), height: C.int(v.Size().Y), } bboxesRectArr = append(bboxesRectArr, bbox) } bboxesRects := C.Rects{ rects: (*C.Rect)(&bboxesRectArr[0]), length: C.int(len(bboxes)), } scoresFloats := []C.float{} for _, v := range scores { scoresFloats = append(scoresFloats, C.float(v)) } scoresVector := C.struct_FloatVector{} scoresVector.val = (*C.float)(&scoresFloats[0]) scoresVector.length = (C.int)(len(scoresFloats)) indicesVector := C.IntVector{} C.NMSBoxes(bboxesRects, scoresVector, C.float(scoreThreshold), C.float(nmsThreshold), &indicesVector) defer C.free(unsafe.Pointer(indicesVector.val)) h := &reflect.SliceHeader{ Data: uintptr(unsafe.Pointer(indicesVector.val)), Len: int(indicesVector.length), Cap: int(indicesVector.length), } ptr := *(*[]C.int)(unsafe.Pointer(h)) indices = make([]int, indicesVector.length) for i := 0; i < int(indicesVector.length); i++ { indices[i] = int(ptr[i]) } return } // NMSBoxesWithParams performs non maximum suppression given boxes and corresponding scores. // // For futher details, please see: // https://docs.opencv.org/4.4.0/d6/d0f/group__dnn.html#ga9d118d70a1659af729d01b10233213ee func NMSBoxesWithParams(bboxes []image.Rectangle, scores []float32, scoreThreshold float32, nmsThreshold float32, eta float32, topK int) (indices []int) { bboxesRectArr := []C.struct_Rect{} for _, v := range bboxes { bbox := C.struct_Rect{ x: C.int(v.Min.X), y: C.int(v.Min.Y), width: C.int(v.Size().X), height: C.int(v.Size().Y), } bboxesRectArr = append(bboxesRectArr, bbox) } bboxesRects := C.Rects{ rects: (*C.Rect)(&bboxesRectArr[0]), length: C.int(len(bboxes)), } scoresFloats := []C.float{} for _, v := range scores { scoresFloats = append(scoresFloats, C.float(v)) } scoresVector := C.struct_FloatVector{} scoresVector.val = (*C.float)(&scoresFloats[0]) scoresVector.length = (C.int)(len(scoresFloats)) indicesVector := C.IntVector{} C.NMSBoxesWithParams(bboxesRects, scoresVector, C.float(scoreThreshold), C.float(nmsThreshold), &indicesVector, C.float(eta), C.int(topK)) defer C.free(unsafe.Pointer(indicesVector.val)) h := &reflect.SliceHeader{ Data: uintptr(unsafe.Pointer(indicesVector.val)), Len: int(indicesVector.length), Cap: int(indicesVector.length), } ptr := *(*[]C.int)(unsafe.Pointer(h)) indices = make([]int, indicesVector.length) for i := 0; i < int(indicesVector.length); i++ { indices[i] = int(ptr[i]) } return } ================================================ FILE: dnn.h ================================================ #ifndef _OPENCV3_DNN_H_ #define _OPENCV3_DNN_H_ #include #ifdef __cplusplus #include #include extern "C" { #endif #include "core.h" #ifdef __cplusplus typedef cv::dnn::Net* Net; typedef cv::Ptr* Layer; #else typedef void* Net; typedef void* Layer; #endif Net Net_ReadNet(const char* model, const char* config); Net Net_ReadNetBytes(const char* framework, struct ByteArray model, struct ByteArray config); Net Net_ReadNetFromCaffe(const char* prototxt, const char* caffeModel); Net Net_ReadNetFromCaffeBytes(struct ByteArray prototxt, struct ByteArray caffeModel); Net Net_ReadNetFromTensorflow(const char* model); Net Net_ReadNetFromTensorflowBytes(struct ByteArray model); Net Net_ReadNetFromTorch(const char* model); Net Net_ReadNetFromONNX(const char* model); Net Net_ReadNetFromONNXBytes(struct ByteArray model); struct Rect Net_BlobRectToImageRect(struct Rect rect, Size originalSize, double scalefactor, Size size, Scalar mean, bool swapRB, int ddepth, int dataLayout, int paddingMode, Scalar borderValue); struct Rects Net_BlobRectsToImageRects(struct Rects rects, Size originalSize, double scalefactor, Size size, Scalar mean, bool swapRB, int ddepth, int dataLayout, int paddingMode, Scalar borderValue); Mat Net_BlobFromImage(Mat image, double scalefactor, Size size, Scalar mean, bool swapRB, bool crop); Mat Net_BlobFromImageWithParams(Mat image, double scalefactor, Size size, Scalar mean, bool swapRB, int ddepth, int dataLayout, int paddingMode, Scalar borderValue); void Net_BlobFromImages(struct Mats images, Mat blob, double scalefactor, Size size, Scalar mean, bool swapRB, bool crop, int ddepth); void Net_BlobFromImagesWithParams(struct Mats images, Mat blob, double scalefactor, Size size, Scalar mean, bool swapRB, int ddepth, int dataLayout, int paddingMode, Scalar borderValue); void Net_ImagesFromBlob(Mat blob_, struct Mats* images_); void Net_Close(Net net); bool Net_Empty(Net net); void Net_SetInput(Net net, Mat blob, const char* name); Mat Net_Forward(Net net, const char* outputName); void Net_ForwardLayers(Net net, struct Mats* outputBlobs, struct CStrings outBlobNames); void Net_SetPreferableBackend(Net net, int backend); void Net_SetPreferableTarget(Net net, int target); int64_t Net_GetPerfProfile(Net net); void Net_GetUnconnectedOutLayers(Net net, IntVector* res); void Net_GetLayerNames(Net net, CStrings* names); Mat Net_GetBlobChannel(Mat blob, int imgidx, int chnidx); Scalar Net_GetBlobSize(Mat blob); Layer Net_GetLayer(Net net, int layerid); void Layer_Close(Layer layer); int Layer_InputNameToIndex(Layer layer, const char* name); int Layer_OutputNameToIndex(Layer layer, const char* name); const char* Layer_GetName(Layer layer); const char* Layer_GetType(Layer layer); void NMSBoxes(struct Rects bboxes, FloatVector scores, float score_threshold, float nms_threshold, IntVector* indices); void NMSBoxesWithParams(struct Rects bboxes, FloatVector scores, const float score_threshold, const float nms_threshold, IntVector* indices, const float eta, const int top_k); #ifdef __cplusplus } #endif #endif //_OPENCV3_DNN_H_ ================================================ FILE: dnn_async_openvino.go ================================================ //go:build openvino // +build openvino package gocv import ( "unsafe" ) /* #include #include "dnn.h" #include "asyncarray.h" */ import "C" // ForwardAsync runs forward pass to compute output of layer with name outputName. // // For further details, please see: // https://docs.opencv.org/trunk/db/d30/classcv_1_1dnn_1_1Net.html#a814890154ea9e10b132fec00b6f6ba30 func (net *Net) ForwardAsync(outputName string) AsyncArray { cName := C.CString(outputName) defer C.free(unsafe.Pointer(cName)) return newAsyncArray(C.Net_forwardAsync((C.Net)(net.p), cName)) } ================================================ FILE: dnn_ext.go ================================================ //go:build !gocv_specific_modules || (gocv_specific_modules && gocv_dnn) package gocv import ( "image" ) // FP16BlobFromImage is an extended helper function to convert an Image to a half-float blob, as used by // the Movidius Neural Compute Stick. func FP16BlobFromImage(img Mat, scaleFactor float32, size image.Point, mean float32, swapRB bool, crop bool) []byte { // resizes image so it maintains aspect ratio width := float32(img.Cols()) height := float32(img.Rows()) square := NewMatWithSize(size.Y, size.X, img.Type()) defer square.Close() maxDim := height var scale float32 = 1.0 if width > height { maxDim = width scale = float32(size.X) / float32(maxDim) } if width < height { scale = float32(size.Y) / float32(maxDim) } var roi image.Rectangle if width >= height { roi.Min.X = 0 roi.Min.Y = int(float32(size.Y)-height*scale) / 2 roi.Max.X = size.X roi.Max.Y = int(height * scale) } else { roi.Min.X = int(float32(size.X)-width*scale) / 2 roi.Min.Y = 0 roi.Max.X = int(width * scale) roi.Max.Y = size.Y } Resize(img, &square, roi.Max, 0, 0, InterpolationDefault) if swapRB { CvtColor(square, &square, ColorBGRToRGB) } fp32Image := NewMat() defer fp32Image.Close() square.ConvertTo(&fp32Image, MatTypeCV32F) if mean != 0 { // subtract mean fp32Image.SubtractFloat(mean) } if scaleFactor != 1.0 { // multiply by scale factor fp32Image.MultiplyFloat(scaleFactor) } fp16Blob := fp32Image.ConvertFp16() defer fp16Blob.Close() return fp16Blob.ToBytes() } ================================================ FILE: dnn_string.go ================================================ //go:build !gocv_specific_modules || (gocv_specific_modules && gocv_dnn) package gocv func (c NetBackendType) String() string { switch c { case NetBackendDefault: return "" case NetBackendHalide: return "halide" case NetBackendOpenVINO: return "openvino" case NetBackendOpenCV: return "opencv" case NetBackendVKCOM: return "vulkan" case NetBackendCUDA: return "cuda" } return "" } func (c NetTargetType) String() string { switch c { case NetTargetCPU: return "cpu" case NetTargetFP32: return "fp32" case NetTargetFP16: return "fp16" case NetTargetVPU: return "vpu" case NetTargetVulkan: return "vulkan" case NetTargetFPGA: return "fpga" case NetTargetCUDA: return "cuda" case NetTargetCUDAFP16: return "cudafp16" } return "" } ================================================ FILE: dnn_test.go ================================================ //go:build !gocv_specific_modules || (gocv_specific_modules && gocv_dnn) package gocv import ( "image" "os" "path/filepath" "testing" ) func TestReadNetDiskFromTensorflow(t *testing.T) { path := os.Getenv("GOCV_TENSORFLOW_TEST_FILES") if path == "" { t.Skip("Unable to locate Tensorflow model files for tests") } net := ReadNet(path+"/tensorflow_inception_graph.pb", "") if net.Empty() { t.Errorf("Unable to load Tensorflow model using ReadNet") } defer net.Close() checkTensorflowNet(t, net) } func TestReadNetMemoryFromTensorflow(t *testing.T) { path := os.Getenv("GOCV_TENSORFLOW_TEST_FILES") if path == "" { t.Skip("Unable to locate Tensorflow model files for tests") } bModel, err := os.ReadFile(path + "/tensorflow_inception_graph.pb") if err != nil { t.Errorf("Failed to load model from file: %v", err) } _, err = ReadNetBytes("tensorflow", nil, nil) if err == nil { t.Errorf("Should have error for reading nil model bytes") } net, err := ReadNetBytes("tensorflow", bModel, nil) if err != nil { t.Errorf("Failed to read net bytes: %v", err) } if net.Empty() { t.Errorf("Unable to load Tensorflow model using ReadNetBytes") } defer net.Close() checkTensorflowNet(t, net) } func TestReadNetDiskFromONNX(t *testing.T) { path := os.Getenv("GOCV_ONNX_TEST_FILES") if path == "" { t.Skip("Unable to locate ONNX model files for tests") } net := ReadNet(filepath.Join(path, "googlenet-9.onnx"), "") if net.Empty() { t.Errorf("Unable to load ONNX model using ReadNet") } defer net.Close() m := map[int]string{ 0: "onnx_node_output_0!conv1/7x7_s2_1", 10: "onnx_node_output_0!inception_3a/1x1_1", 20: "onnx_node_output_0!inception_3a/pool_1", 30: "onnx_node_output_0!inception_3b/5x5_reduce_1", 40: "onnx_node_output_0!inception_4a/1x1_2", 50: "onnx_node_output_0!inception_4a/pool_proj_1", 60: "onnx_node_output_0!inception_4b/5x5_reduce_2", 70: "onnx_node_output_0!inception_4c/3x3_reduce_2", 80: "onnx_node_output_0!inception_4c/output_1", 90: "onnx_node_output_0!inception_4d/5x5_2", 100: "onnx_node_output_0!inception_4e/3x3_2", 110: "onnx_node_output_0!inception_5a/1x1_1", 120: "onnx_node_output_0!inception_5a/pool_1", 130: "onnx_node_output_0!inception_5b/5x5_reduce_1", 140: "onnx_node_output_0!OC2_DUMMY_0"} checkONNXNet(t, net, m, 144) } func TestReadNetMemoryFromONNX(t *testing.T) { path := os.Getenv("GOCV_ONNX_TEST_FILES") if path == "" { t.Skip("Unable to locate ONNX model files for tests") } bModel, err := os.ReadFile(filepath.Join(path, "googlenet-9.onnx")) if err != nil { t.Errorf("Failed to load model from file: %v", err) } _, err = ReadNetBytes("onnx", nil, nil) if err == nil { t.Errorf("Should have error for reading nil model bytes") } net, err := ReadNetBytes("onnx", bModel, nil) if err != nil { t.Errorf("Failed to read net bytes: %v", err) } if net.Empty() { t.Errorf("Unable to load Caffe model using ReadNetBytes") } defer net.Close() m := map[int]string{ 0: "onnx_node_output_0!conv1/7x7_s2_1", 10: "onnx_node_output_0!inception_3a/1x1_1", 20: "onnx_node_output_0!inception_3a/pool_1", 30: "onnx_node_output_0!inception_3b/5x5_reduce_1", 40: "onnx_node_output_0!inception_4a/1x1_2", 50: "onnx_node_output_0!inception_4a/pool_proj_1", 60: "onnx_node_output_0!inception_4b/5x5_reduce_2", 70: "onnx_node_output_0!inception_4c/3x3_reduce_2", 80: "onnx_node_output_0!inception_4c/output_1", 90: "onnx_node_output_0!inception_4d/5x5_2", 100: "onnx_node_output_0!inception_4e/3x3_2", 110: "onnx_node_output_0!inception_5a/1x1_1", 120: "onnx_node_output_0!inception_5a/pool_1", 130: "onnx_node_output_0!inception_5b/5x5_reduce_1", 140: "onnx_node_output_0!OC2_DUMMY_0"} checkONNXNet(t, net, m, 144) } func checkTensorflowNet(t *testing.T, net Net) { img := IMRead("images/space_shuttle.jpg", IMReadColor) if img.Empty() { t.Error("Invalid Mat in Tensorflow test") } defer img.Close() blob := BlobFromImage(img, 1.0, image.Pt(224, 224), NewScalar(0, 0, 0, 0), true, false) if blob.Empty() { t.Error("Invalid blob in Tensorflow test") } defer blob.Close() net.SetInput(blob, "input") prob := net.Forward("softmax2") defer prob.Close() if prob.Empty() { t.Error("Invalid softmax2 in Tensorflow test") } probMat := prob.Reshape(1, 1) defer probMat.Close() _, maxVal, minLoc, maxLoc := MinMaxLoc(probMat) if round(float64(maxVal), 0.00005) != 1.0 { t.Errorf("Tensorflow maxVal incorrect: %v\n", round(float64(maxVal), 0.00005)) } if minLoc.X != 481 || minLoc.Y != 0 { t.Errorf("Tensorflow minLoc incorrect: %v\n", minLoc) } if maxLoc.X != 234 || maxLoc.Y != 0 { t.Errorf("Tensorflow maxLoc incorrect: %v\n", maxLoc) } } func TestTensorflowDisk(t *testing.T) { path := os.Getenv("GOCV_TENSORFLOW_TEST_FILES") if path == "" { t.Skip("Unable to locate Tensorflow model file for tests") } net := ReadNetFromTensorflow(path + "/tensorflow_inception_graph.pb") if net.Empty() { t.Errorf("Unable to load Tensorflow model") } defer net.Close() checkTensorflowNet(t, net) } func TestTensorflowMemory(t *testing.T) { path := os.Getenv("GOCV_TENSORFLOW_TEST_FILES") if path == "" { t.Skip("Unable to locate Tensorflow model file for tests") } b, err := os.ReadFile(path + "/tensorflow_inception_graph.pb") if err != nil { t.Errorf("Failed to load tensorflow model from file: %v", err) } net, err := ReadNetFromTensorflowBytes(b) if err != nil { t.Errorf("Failed to load Tensorflow model from bytes: %v", err) } if net.Empty() { t.Errorf("Unable to load Tensorflow model") } defer net.Close() checkTensorflowNet(t, net) } func TestOnnxMemory(t *testing.T) { path := os.Getenv("GOCV_ONNX_TEST_FILES") if path == "" { t.Skip("Unable to locate ONNX model file for tests") } b, err := os.ReadFile(filepath.Join(path, "googlenet-9.onnx")) if err != nil { t.Errorf("Failed to load ONNX from file: %v", err) } net, err := ReadNetFromONNXBytes(b) if err != nil { t.Errorf("Failed to load Tensorflow model from bytes: %v", err) } if net.Empty() { t.Errorf("Unable to load Tensorflow model") } defer net.Close() m := map[int]string{ 0: "onnx_node_output_0!conv1/7x7_s2_1", 10: "onnx_node_output_0!inception_3a/1x1_1", 20: "onnx_node_output_0!inception_3a/pool_1", 30: "onnx_node_output_0!inception_3b/5x5_reduce_1", 40: "onnx_node_output_0!inception_4a/1x1_2", 50: "onnx_node_output_0!inception_4a/pool_proj_1", 60: "onnx_node_output_0!inception_4b/5x5_reduce_2", 70: "onnx_node_output_0!inception_4c/3x3_reduce_2", 80: "onnx_node_output_0!inception_4c/output_1", 90: "onnx_node_output_0!inception_4d/5x5_2", 100: "onnx_node_output_0!inception_4e/3x3_2", 110: "onnx_node_output_0!inception_5a/1x1_1", 120: "onnx_node_output_0!inception_5a/pool_1", 130: "onnx_node_output_0!inception_5b/5x5_reduce_1", 140: "onnx_node_output_0!OC2_DUMMY_0"} checkONNXNet(t, net, m, 144) } func TestOnnxDisk(t *testing.T) { path := os.Getenv("GOCV_ONNX_TEST_FILES") if path == "" { t.Skip("Unable to locate ONNX model file for tests") } net := ReadNetFromONNX(filepath.Join(path, "googlenet-9.onnx")) if net.Empty() { t.Errorf("Unable to load ONNX model") } defer net.Close() m := map[int]string{ 0: "onnx_node_output_0!conv1/7x7_s2_1", 10: "onnx_node_output_0!inception_3a/1x1_1", 20: "onnx_node_output_0!inception_3a/pool_1", 30: "onnx_node_output_0!inception_3b/5x5_reduce_1", 40: "onnx_node_output_0!inception_4a/1x1_2", 50: "onnx_node_output_0!inception_4a/pool_proj_1", 60: "onnx_node_output_0!inception_4b/5x5_reduce_2", 70: "onnx_node_output_0!inception_4c/3x3_reduce_2", 80: "onnx_node_output_0!inception_4c/output_1", 90: "onnx_node_output_0!inception_4d/5x5_2", 100: "onnx_node_output_0!inception_4e/3x3_2", 110: "onnx_node_output_0!inception_5a/1x1_1", 120: "onnx_node_output_0!inception_5a/pool_1", 130: "onnx_node_output_0!inception_5b/5x5_reduce_1", 140: "onnx_node_output_0!OC2_DUMMY_0"} checkONNXNet(t, net, m, 144) } func checkONNXNet(t *testing.T, net Net, expectedLayers map[int]string, expectedLayerCount int) { img := IMRead("images/space_shuttle.jpg", IMReadColor) if img.Empty() { t.Error("Invalid Mat in ONNX test") } defer img.Close() blob := BlobFromImage(img, 1.0, image.Pt(224, 224), NewScalar(0, 0, 0, 0), true, false) if blob.Empty() { t.Error("Invalid blob in ONNX test") } defer blob.Close() lnames := net.GetLayerNames() if len(lnames) != expectedLayerCount { t.Errorf("Invalid len layer names in test: %d\n", len(lnames)) } m := expectedLayers for k, v := range m { if lnames[k] != v { t.Errorf("Invalid layer name in test: \"%s\" (expected=\"%s\")\n", lnames[k], v) } } net.SetInput(blob, "data_0") prob := net.Forward("prob_1") defer prob.Close() if prob.Empty() { t.Error("Invalid output in ONNX test") } probMat := prob.Reshape(1, 1) defer probMat.Close() _, maxVal, minLoc, maxLoc := MinMaxLoc(probMat) if round(float64(maxVal), 0.0005) != 0.9965 { t.Errorf("ONNX maxVal incorrect: %v\n", round(float64(maxVal), 0.0005)) } if minLoc.X != 955 || minLoc.Y != 0 { t.Errorf("ONNX minLoc incorrect: %v\n", minLoc) } if maxLoc.X != 812 || maxLoc.Y != 0 { t.Errorf("ONNX maxLoc incorrect: %v\n", maxLoc) } } func TestBlobFromImages(t *testing.T) { imgs := make([]Mat, 0) img := IMRead("images/space_shuttle.jpg", IMReadColor) if img.Empty() { t.Error("Invalid Mat in BlobFromImages test") } defer img.Close() imgs = append(imgs, img) imgs = append(imgs, img) blob := NewMat() BlobFromImages(imgs, &blob, 1.0, image.Pt(25, 25), NewScalar(0, 0, 0, 0), false, false, MatTypeCV32F) defer blob.Close() sz := GetBlobSize(blob) if sz.Val1 != 2 || sz.Val2 != 3 || sz.Val3 != 25 || sz.Val4 != 25 { t.Errorf("GetBlobSize in BlobFromImages retrieved wrong values") } } func TestBlobFromImageGreyscale(t *testing.T) { img := IMRead("images/space_shuttle.jpg", IMReadGrayScale) if img.Empty() { t.Error("Invalid Mat in TestBlobFromImageGreyscale test") } defer img.Close() blob := BlobFromImage(img, 1.0, image.Pt(100, 100), NewScalar(0, 0, 0, 0), false, false) defer blob.Close() if blob.Empty() { t.Errorf("BlobFromImageGreyscale failed to create blob") } } func TestBlobFromImageWithParams(t *testing.T) { img := IMRead("images/space_shuttle.jpg", IMReadColor) if img.Empty() { t.Error("Invalid Mat in BlobFromImages test") } defer img.Close() params := NewImageToBlobParams(1.0, image.Pt(25, 25), NewScalar(0, 0, 0, 0), false, MatTypeCV32F, DataLayoutNCHW, PaddingModeCropCenter, NewScalar(0, 0, 0, 0)) blob := BlobFromImageWithParams(img, params) defer blob.Close() sz := GetBlobSize(blob) if sz.Val1 != 1 || sz.Val2 != 3 || sz.Val3 != 25 || sz.Val4 != 25 { t.Errorf("GetBlobSize in BlobFromImagesWithParams retrieved wrong values: %v\n", sz) } } func TestBlobFromImagesWithParams(t *testing.T) { imgs := make([]Mat, 0) img := IMRead("images/space_shuttle.jpg", IMReadColor) if img.Empty() { t.Error("Invalid Mat in BlobFromImagesWithParams test") } defer img.Close() imgs = append(imgs, img) imgs = append(imgs, img) params := NewImageToBlobParams(1.0, image.Pt(25, 25), NewScalar(0, 0, 0, 0), false, MatTypeCV32F, DataLayoutNCHW, PaddingModeCropCenter, NewScalar(0, 0, 0, 0)) blob := NewMat() BlobFromImagesWithParams(imgs, &blob, params) defer blob.Close() sz := GetBlobSize(blob) if sz.Val1 != 2 || sz.Val2 != 3 || sz.Val3 != 25 || sz.Val4 != 25 { t.Errorf("GetBlobSize in BlobFromImagesWithParams retrieved wrong values: %v\n", sz) } } func TestImagesFromBlob(t *testing.T) { imgs := make([]Mat, 0) img := IMRead("images/space_shuttle.jpg", IMReadGrayScale) if img.Empty() { t.Error("Invalid Mat in BlobFromImages test") } defer img.Close() imgs = append(imgs, img) imgs = append(imgs, img) blob := NewMat() defer blob.Close() BlobFromImages(imgs, &blob, 1.0, image.Pt(img.Size()[0], img.Size()[1]), NewScalar(0, 0, 0, 0), false, false, MatTypeCV32F) imgsFromBlob := make([]Mat, len(imgs)) ImagesFromBlob(blob, imgsFromBlob) for i := 0; i < len(imgs); i++ { func() { imgFromBlob := NewMat() defer imgFromBlob.Close() imgsFromBlob[i].ConvertTo(&imgFromBlob, imgs[i].Type()) diff := NewMat() defer diff.Close() Compare(imgs[i], imgFromBlob, &diff, CompareNE) nz := CountNonZero(diff) if nz != 0 { t.Error("imgFromBlob is different from img!") } }() } } func TestGetBlobChannel(t *testing.T) { img := NewMatWithSize(100, 100, 5+16) defer img.Close() blob := BlobFromImage(img, 1.0, image.Pt(0, 0), NewScalar(0, 0, 0, 0), true, false) defer blob.Close() ch2 := GetBlobChannel(blob, 0, 1) defer ch2.Close() if ch2.Empty() { t.Errorf("GetBlobChannel failed to retrieve 2nd chan of a 3channel blob") } if ch2.Rows() != img.Rows() || ch2.Cols() != img.Cols() { t.Errorf("GetBlobChannel: retrieved image size does not match original") } } func TestGetBlobSize(t *testing.T) { img := NewMatWithSize(100, 100, 5+16) defer img.Close() blob := BlobFromImage(img, 1.0, image.Pt(0, 0), NewScalar(0, 0, 0, 0), true, false) defer blob.Close() sz := GetBlobSize(blob) if sz.Val1 != 1 || sz.Val2 != 3 || sz.Val3 != 100 || sz.Val4 != 100 { t.Errorf("GetBlobSize retrieved wrong values") } } func TestParseNetBackend(t *testing.T) { val := ParseNetBackend("halide") if val != NetBackendHalide { t.Errorf("ParseNetBackend invalid") } val = ParseNetBackend("openvino") if val != NetBackendOpenVINO { t.Errorf("ParseNetBackend invalid") } val = ParseNetBackend("opencv") if val != NetBackendOpenCV { t.Errorf("ParseNetBackend invalid") } val = ParseNetBackend("vulkan") if val != NetBackendVKCOM { t.Errorf("ParseNetBackend invalid") } val = ParseNetBackend("cuda") if val != NetBackendCUDA { t.Errorf("ParseNetBackend invalid") } val = ParseNetBackend("crazytrain") if val != NetBackendDefault { t.Errorf("ParseNetBackend invalid") } } func TestParseNetTarget(t *testing.T) { val := ParseNetTarget("cpu") if val != NetTargetCPU { t.Errorf("ParseNetTarget invalid") } val = ParseNetTarget("fp32") if val != NetTargetFP32 { t.Errorf("ParseNetTarget invalid") } val = ParseNetTarget("fp16") if val != NetTargetFP16 { t.Errorf("ParseNetTarget invalid") } val = ParseNetTarget("vpu") if val != NetTargetVPU { t.Errorf("ParseNetTarget invalid") } val = ParseNetTarget("cuda") if val != NetTargetCUDA { t.Errorf("ParseNetTarget invalid") } val = ParseNetTarget("vulkan") if val != NetTargetVulkan { t.Errorf("ParseNetTarget invalid") } val = ParseNetTarget("fpga") if val != NetTargetFPGA { t.Errorf("ParseNetTarget invalid") } val = ParseNetTarget("cudafp16") if val != NetTargetCUDAFP16 { t.Errorf("ParseNetTarget invalid") } val = ParseNetTarget("idk") if val != NetTargetCPU { t.Errorf("ParseNetTarget invalid") } } func TestFP16BlobFromImage(t *testing.T) { img := NewMatWithSize(100, 100, 5+16) defer img.Close() data := FP16BlobFromImage(img, 1.0, image.Pt(100, 100), 0, false, false) if len(data) != 60000 { t.Errorf("FP16BlobFromImage incorrect length: %v\n", len(data)) } img2 := NewMatWithSize(100, 50, 5+16) defer img2.Close() data = FP16BlobFromImage(img2, 2.0, image.Pt(50, 100), -0.1, true, false) if len(data) != 30000 { t.Errorf("FP16BlobFromImage incorrect length: %v\n", len(data)) } } func TestNMSBoxes(t *testing.T) { img := IMRead("images/face.jpg", IMReadColor) if img.Empty() { t.Error("Invalid Mat in NMSBoxes test") } defer img.Close() img.ConvertTo(&img, MatTypeCV32F) bboxes := []image.Rectangle{ image.Rect(53, 47, 589, 451), image.Rect(118, 54, 618, 450), image.Rect(53, 66, 605, 480), image.Rect(111, 65, 630, 480), image.Rect(156, 51, 640, 480), } scores := []float32{0.82094115, 0.7998236, 0.9809663, 0.99717456, 0.89628726} scoreThreshold := float32(0.5) nmsThreshold := float32(0.4) indices := NMSBoxes(bboxes, scores, scoreThreshold, nmsThreshold) if indices[0] != 3 { t.Errorf("Invalid NMSBoxes test indices: %v", indices) } } func TestNMSBoxesWithParams(t *testing.T) { img := IMRead("images/face.jpg", IMReadColor) if img.Empty() { t.Error("Invalid Mat in NMSBoxesWithParams test") } defer img.Close() img.ConvertTo(&img, MatTypeCV32F) bboxes := []image.Rectangle{ image.Rect(53, 47, 589, 451), image.Rect(118, 54, 618, 450), image.Rect(53, 66, 605, 480), image.Rect(111, 65, 630, 480), image.Rect(156, 51, 640, 480), } scores := []float32{0.82094115, 0.7998236, 0.9809663, 0.99717456, 0.89628726} scoreThreshold := float32(0.5) nmsThreshold := float32(0.4) indices := NMSBoxesWithParams(bboxes, scores, scoreThreshold, nmsThreshold, float32(1.0), 0) if indices[0] != 3 { t.Errorf("Invalid NMSBoxesWithParams test indices: %v", indices) } } ================================================ FILE: env.cmd ================================================ ECHO This script is no longer necessary and has been deprecated. ECHO See the Custom Environment section of the README if you need to customize your environment. ================================================ FILE: env.sh ================================================ echo "This script is no longer necessary and has been deprecated." echo "See the Custom Environment section of the README if you need to customize your environment." ================================================ FILE: features2d.cpp ================================================ //go:build !gocv_specific_modules || (gocv_specific_modules && gocv_features2d) #include "features2d.h" AKAZE AKAZE_Create() { try { return new cv::Ptr(cv::AKAZE::create()); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } AKAZE AKAZE_CreateWithParams(int descriptor_type, int descriptor_size, int descriptor_channels, float threshold, int nOctaves, int nOctaveLayers, int diffusivity) { try { cv::AKAZE::DescriptorType type = static_cast(descriptor_type); return new cv::Ptr(cv::AKAZE::create(type, descriptor_size, descriptor_channels,threshold, nOctaves, nOctaveLayers, static_cast(diffusivity))); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } void AKAZE_Close(AKAZE a) { delete a; } struct KeyPoints AKAZE_Detect(AKAZE a, Mat src) { try { std::vector detected; (*a)->detect(*src, detected); KeyPoint* kps = new KeyPoint[detected.size()]; for (size_t i = 0; i < detected.size(); ++i) { KeyPoint k = {detected[i].pt.x, detected[i].pt.y, detected[i].size, detected[i].angle, detected[i].response, detected[i].octave, detected[i].class_id }; kps[i] = k; } KeyPoints ret = {kps, (int)detected.size()}; return ret; } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); KeyPoint* kps = new KeyPoint[0]; KeyPoints ret = {kps, 0}; return ret; } } struct KeyPoints AKAZE_Compute(AKAZE a, Mat src, struct KeyPoints kp, Mat desc) { try { std::vector computed; for (size_t i = 0; i < kp.length; i++) { cv::KeyPoint k = cv::KeyPoint(kp.keypoints[i].x, kp.keypoints[i].y, kp.keypoints[i].size, kp.keypoints[i].angle, kp.keypoints[i].response, kp.keypoints[i].octave, kp.keypoints[i].classID); computed.push_back(k); } (*a)->compute(*src, computed, *desc); KeyPoint* kps = new KeyPoint[computed.size()]; for (size_t i = 0; i < computed.size(); ++i) { KeyPoint k = {computed[i].pt.x, computed[i].pt.y, computed[i].size, computed[i].angle, computed[i].response, computed[i].octave, computed[i].class_id }; kps[i] = k; } KeyPoints ret = {kps, (int)computed.size()}; return ret; } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); KeyPoint* kps = new KeyPoint[0]; KeyPoints ret = {kps, 0}; return ret; } } struct KeyPoints AKAZE_DetectAndCompute(AKAZE a, Mat src, Mat mask, Mat desc) { try { std::vector detected; (*a)->detectAndCompute(*src, *mask, detected, *desc); KeyPoint* kps = new KeyPoint[detected.size()]; for (size_t i = 0; i < detected.size(); ++i) { KeyPoint k = {detected[i].pt.x, detected[i].pt.y, detected[i].size, detected[i].angle, detected[i].response, detected[i].octave, detected[i].class_id }; kps[i] = k; } KeyPoints ret = {kps, (int)detected.size()}; return ret; } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); KeyPoint* kps = new KeyPoint[0]; KeyPoints ret = {kps, 0}; return ret; } } AgastFeatureDetector AgastFeatureDetector_Create() { try { return new cv::Ptr(cv::AgastFeatureDetector::create()); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } AgastFeatureDetector AgastFeatureDetector_CreateWithParams(int threshold, bool nonmaxSuppression, int type) { try { cv::AgastFeatureDetector::DetectorType detectorType = static_cast(type); return new cv::Ptr(cv::AgastFeatureDetector::create(threshold, nonmaxSuppression, detectorType)); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } void AgastFeatureDetector_Close(AgastFeatureDetector a) { delete a; } struct KeyPoints AgastFeatureDetector_Detect(AgastFeatureDetector a, Mat src) { try { std::vector detected; (*a)->detect(*src, detected); KeyPoint* kps = new KeyPoint[detected.size()]; for (size_t i = 0; i < detected.size(); ++i) { KeyPoint k = {detected[i].pt.x, detected[i].pt.y, detected[i].size, detected[i].angle, detected[i].response, detected[i].octave, detected[i].class_id }; kps[i] = k; } KeyPoints ret = {kps, (int)detected.size()}; return ret; } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); KeyPoint* kps = new KeyPoint[0]; KeyPoints ret = {kps, 0}; return ret; } } BRISK BRISK_Create() { try { return new cv::Ptr(cv::BRISK::create()); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } BRISK BRISK_CreateWithParams(int thresh, int octaves, float patternScale) { try { return new cv::Ptr(cv::BRISK::create(thresh, octaves, patternScale)); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } void BRISK_Close(BRISK b) { delete b; } struct KeyPoints BRISK_Detect(BRISK b, Mat src) { try { std::vector detected; (*b)->detect(*src, detected); KeyPoint* kps = new KeyPoint[detected.size()]; for (size_t i = 0; i < detected.size(); ++i) { KeyPoint k = {detected[i].pt.x, detected[i].pt.y, detected[i].size, detected[i].angle, detected[i].response, detected[i].octave, detected[i].class_id }; kps[i] = k; } KeyPoints ret = {kps, (int)detected.size()}; return ret; } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); KeyPoint* kps = new KeyPoint[0]; KeyPoints ret = {kps, 0}; return ret; } } struct KeyPoints BRISK_Compute(BRISK b, Mat src, struct KeyPoints kp, Mat desc) { try { std::vector computed; for (size_t i = 0; i < kp.length; i++) { cv::KeyPoint k = cv::KeyPoint(kp.keypoints[i].x, kp.keypoints[i].y, kp.keypoints[i].size, kp.keypoints[i].angle, kp.keypoints[i].response, kp.keypoints[i].octave, kp.keypoints[i].classID); computed.push_back(k); } (*b)->compute(*src, computed, *desc); KeyPoint* kps = new KeyPoint[computed.size()]; for (size_t i = 0; i < computed.size(); ++i) { KeyPoint k = {computed[i].pt.x, computed[i].pt.y, computed[i].size, computed[i].angle, computed[i].response, computed[i].octave, computed[i].class_id }; kps[i] = k; } KeyPoints ret = {kps, (int)computed.size()}; return ret; } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); KeyPoint* kps = new KeyPoint[0]; KeyPoints ret = {kps, 0}; return ret; } } struct KeyPoints BRISK_DetectAndCompute(BRISK b, Mat src, Mat mask, Mat desc) { try { std::vector detected; (*b)->detectAndCompute(*src, *mask, detected, *desc); KeyPoint* kps = new KeyPoint[detected.size()]; for (size_t i = 0; i < detected.size(); ++i) { KeyPoint k = {detected[i].pt.x, detected[i].pt.y, detected[i].size, detected[i].angle, detected[i].response, detected[i].octave, detected[i].class_id }; kps[i] = k; } KeyPoints ret = {kps, (int)detected.size()}; return ret; } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); KeyPoint* kps = new KeyPoint[0]; KeyPoints ret = {kps, 0}; return ret; } } GFTTDetector GFTTDetector_Create() { try { return new cv::Ptr(cv::GFTTDetector::create()); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } GFTTDetector GFTTDetector_Create_WithParams(const GFTTDetectorParams* params) { try { // Create the GFTTDetector and return it wrapped in a smart pointer return new cv::Ptr(cv::GFTTDetector::create(params->maxCorners, params->qualityLevel, params->minDistance, params->blockSize, params->useHarrisDetector, params->k)); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } void GFTTDetector_Close(GFTTDetector a) { delete a; } struct KeyPoints GFTTDetector_Detect(GFTTDetector a, Mat src) { try { std::vector detected; (*a)->detect(*src, detected); KeyPoint* kps = new KeyPoint[detected.size()]; for (size_t i = 0; i < detected.size(); ++i) { KeyPoint k = {detected[i].pt.x, detected[i].pt.y, detected[i].size, detected[i].angle, detected[i].response, detected[i].octave, detected[i].class_id }; kps[i] = k; } KeyPoints ret = {kps, (int)detected.size()}; return ret; } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); KeyPoint* kps = new KeyPoint[0]; KeyPoints ret = {kps, 0}; return ret; } } KAZE KAZE_Create() { try { return new cv::Ptr(cv::KAZE::create()); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } KAZE KAZE_CreateWithParams(bool extended, bool upright, float threshold, int nOctaves, int nOctaveLayers, int diffusivity) { try { return new cv::Ptr(cv::KAZE::create(extended, upright, threshold, nOctaves, nOctaveLayers, static_cast(diffusivity))); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } void KAZE_Close(KAZE a) { delete a; } struct KeyPoints KAZE_Detect(KAZE a, Mat src) { try { std::vector detected; (*a)->detect(*src, detected); KeyPoint* kps = new KeyPoint[detected.size()]; for (size_t i = 0; i < detected.size(); ++i) { KeyPoint k = {detected[i].pt.x, detected[i].pt.y, detected[i].size, detected[i].angle, detected[i].response, detected[i].octave, detected[i].class_id }; kps[i] = k; } KeyPoints ret = {kps, (int)detected.size()}; return ret; } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); KeyPoint* kps = new KeyPoint[0]; KeyPoints ret = {kps, 0}; return ret; } } struct KeyPoints KAZE_Compute(KAZE a, Mat src, struct KeyPoints kp, Mat desc) { try { std::vector computed; for (size_t i = 0; i < kp.length; i++) { cv::KeyPoint k = cv::KeyPoint(kp.keypoints[i].x, kp.keypoints[i].y, kp.keypoints[i].size, kp.keypoints[i].angle, kp.keypoints[i].response, kp.keypoints[i].octave, kp.keypoints[i].classID); computed.push_back(k); } (*a)->compute(*src, computed, *desc); KeyPoint* kps = new KeyPoint[computed.size()]; for (size_t i = 0; i < computed.size(); ++i) { KeyPoint k = {computed[i].pt.x, computed[i].pt.y, computed[i].size, computed[i].angle, computed[i].response, computed[i].octave, computed[i].class_id }; kps[i] = k; } KeyPoints ret = {kps, (int)computed.size()}; return ret; } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); KeyPoint* kps = new KeyPoint[0]; KeyPoints ret = {kps, 0}; return ret; } } struct KeyPoints KAZE_DetectAndCompute(KAZE a, Mat src, Mat mask, Mat desc) { try { std::vector detected; (*a)->detectAndCompute(*src, *mask, detected, *desc); KeyPoint* kps = new KeyPoint[detected.size()]; for (size_t i = 0; i < detected.size(); ++i) { KeyPoint k = {detected[i].pt.x, detected[i].pt.y, detected[i].size, detected[i].angle, detected[i].response, detected[i].octave, detected[i].class_id }; kps[i] = k; } KeyPoints ret = {kps, (int)detected.size()}; return ret; } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); KeyPoint* kps = new KeyPoint[0]; KeyPoints ret = {kps, 0}; return ret; } } MSER MSER_Create() { try { return new cv::Ptr(cv::MSER::create()); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } MSER MSER_CreateWithParams(int delta, int min_area, int max_area, double max_variation, double min_diversity, int max_evolution, double area_threshold, double min_margin, int edge_blur_size) { try { return new cv::Ptr(cv::MSER::create(delta, min_area, max_area, max_variation, min_diversity, max_evolution, area_threshold, min_margin, edge_blur_size)); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } void MSER_Close(MSER a) { delete a; } struct KeyPoints MSER_Detect(MSER a, Mat src) { try { std::vector detected; (*a)->detect(*src, detected); KeyPoint* kps = new KeyPoint[detected.size()]; for (size_t i = 0; i < detected.size(); ++i) { KeyPoint k = {detected[i].pt.x, detected[i].pt.y, detected[i].size, detected[i].angle, detected[i].response, detected[i].octave, detected[i].class_id }; kps[i] = k; } KeyPoints ret = {kps, (int)detected.size()}; return ret; } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); KeyPoint* kps = new KeyPoint[0]; KeyPoints ret = {kps, 0}; return ret; } } FastFeatureDetector FastFeatureDetector_Create() { try { return new cv::Ptr(cv::FastFeatureDetector::create()); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } void FastFeatureDetector_Close(FastFeatureDetector f) { delete f; } FastFeatureDetector FastFeatureDetector_CreateWithParams(int threshold, bool nonmaxSuppression, int type) { try { return new cv::Ptr(cv::FastFeatureDetector::create(threshold,nonmaxSuppression,static_cast(type))); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } struct KeyPoints FastFeatureDetector_Detect(FastFeatureDetector f, Mat src) { try { std::vector detected; (*f)->detect(*src, detected); KeyPoint* kps = new KeyPoint[detected.size()]; for (size_t i = 0; i < detected.size(); ++i) { KeyPoint k = {detected[i].pt.x, detected[i].pt.y, detected[i].size, detected[i].angle, detected[i].response, detected[i].octave, detected[i].class_id }; kps[i] = k; } KeyPoints ret = {kps, (int)detected.size()}; return ret; } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); KeyPoint* kps = new KeyPoint[0]; KeyPoints ret = {kps, 0}; return ret; } } ORB ORB_Create() { try { return new cv::Ptr(cv::ORB::create()); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } ORB ORB_CreateWithParams(int nfeatures, float scaleFactor, int nlevels, int edgeThreshold, int firstLevel, int WTA_K, int scoreType, int patchSize, int fastThreshold) { try { return new cv::Ptr(cv::ORB::create(nfeatures, scaleFactor, nlevels, edgeThreshold, firstLevel, WTA_K, static_cast(scoreType), patchSize, fastThreshold)); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } void ORB_Close(ORB o) { delete o; } struct KeyPoints ORB_Detect(ORB o, Mat src) { try { std::vector detected; (*o)->detect(*src, detected); KeyPoint* kps = new KeyPoint[detected.size()]; for (size_t i = 0; i < detected.size(); ++i) { KeyPoint k = {detected[i].pt.x, detected[i].pt.y, detected[i].size, detected[i].angle, detected[i].response, detected[i].octave, detected[i].class_id }; kps[i] = k; } KeyPoints ret = {kps, (int)detected.size()}; return ret; } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); KeyPoint* kps = new KeyPoint[0]; KeyPoints ret = {kps, 0}; return ret; } } struct KeyPoints ORB_Compute(ORB o, Mat src, struct KeyPoints kp, Mat desc) { try { std::vector computed; for (size_t i = 0; i < kp.length; i++) { cv::KeyPoint k = cv::KeyPoint(kp.keypoints[i].x, kp.keypoints[i].y, kp.keypoints[i].size, kp.keypoints[i].angle, kp.keypoints[i].response, kp.keypoints[i].octave, kp.keypoints[i].classID); computed.push_back(k); } (*o)->compute(*src, computed, *desc); KeyPoint* kps = new KeyPoint[computed.size()]; for (size_t i = 0; i < computed.size(); ++i) { KeyPoint k = {computed[i].pt.x, computed[i].pt.y, computed[i].size, computed[i].angle, computed[i].response, computed[i].octave, computed[i].class_id }; kps[i] = k; } KeyPoints ret = {kps, (int)computed.size()}; return ret; } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); KeyPoint* kps = new KeyPoint[0]; KeyPoints ret = {kps, 0}; return ret; } } struct KeyPoints ORB_DetectAndCompute(ORB o, Mat src, Mat mask, Mat desc) { try { std::vector detected; (*o)->detectAndCompute(*src, *mask, detected, *desc); KeyPoint* kps = new KeyPoint[detected.size()]; for (size_t i = 0; i < detected.size(); ++i) { KeyPoint k = {detected[i].pt.x, detected[i].pt.y, detected[i].size, detected[i].angle, detected[i].response, detected[i].octave, detected[i].class_id }; kps[i] = k; } KeyPoints ret = {kps, (int)detected.size()}; return ret; } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); KeyPoint* kps = new KeyPoint[0]; KeyPoints ret = {kps, 0}; return ret; } } cv::SimpleBlobDetector::Params ConvertCParamsToCPPParams(SimpleBlobDetectorParams params) { cv::SimpleBlobDetector::Params converted; converted.blobColor = params.blobColor; converted.filterByArea = params.filterByArea; converted.filterByCircularity = params.filterByCircularity; converted.filterByColor = params.filterByColor; converted.filterByConvexity = params.filterByConvexity; converted.filterByInertia = params.filterByInertia; converted.maxArea = params.maxArea; converted.maxCircularity = params.maxCircularity; converted.maxConvexity = params.maxConvexity; converted.maxInertiaRatio = params.maxInertiaRatio; converted.maxThreshold = params.maxThreshold; converted.minArea = params.minArea; converted.minCircularity = params.minCircularity; converted.minConvexity = params.minConvexity; converted.minDistBetweenBlobs = params.minDistBetweenBlobs; converted.minInertiaRatio = params.minInertiaRatio; converted.minRepeatability = params.minRepeatability; converted.minThreshold = params.minThreshold; converted.thresholdStep = params.thresholdStep; return converted; } SimpleBlobDetectorParams ConvertCPPParamsToCParams(cv::SimpleBlobDetector::Params params) { SimpleBlobDetectorParams converted; converted.blobColor = params.blobColor; converted.filterByArea = params.filterByArea; converted.filterByCircularity = params.filterByCircularity; converted.filterByColor = params.filterByColor; converted.filterByConvexity = params.filterByConvexity; converted.filterByInertia = params.filterByInertia; converted.maxArea = params.maxArea; converted.maxCircularity = params.maxCircularity; converted.maxConvexity = params.maxConvexity; converted.maxInertiaRatio = params.maxInertiaRatio; converted.maxThreshold = params.maxThreshold; converted.minArea = params.minArea; converted.minCircularity = params.minCircularity; converted.minConvexity = params.minConvexity; converted.minDistBetweenBlobs = params.minDistBetweenBlobs; converted.minInertiaRatio = params.minInertiaRatio; converted.minRepeatability = params.minRepeatability; converted.minThreshold = params.minThreshold; converted.thresholdStep = params.thresholdStep; return converted; } SimpleBlobDetector SimpleBlobDetector_Create_WithParams(SimpleBlobDetectorParams params){ try { cv::SimpleBlobDetector::Params actualParams; return new cv::Ptr(cv::SimpleBlobDetector::create(ConvertCParamsToCPPParams(params))); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } SimpleBlobDetector SimpleBlobDetector_Create() { try { return new cv::Ptr(cv::SimpleBlobDetector::create()); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } SimpleBlobDetectorParams SimpleBlobDetectorParams_Create() { try { return ConvertCPPParamsToCParams(cv::SimpleBlobDetector::Params()); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return SimpleBlobDetectorParams(); } } void SimpleBlobDetector_Close(SimpleBlobDetector b) { delete b; } struct KeyPoints SimpleBlobDetector_Detect(SimpleBlobDetector b, Mat src) { try { std::vector detected; (*b)->detect(*src, detected); KeyPoint* kps = new KeyPoint[detected.size()]; for (size_t i = 0; i < detected.size(); ++i) { KeyPoint k = {detected[i].pt.x, detected[i].pt.y, detected[i].size, detected[i].angle, detected[i].response, detected[i].octave, detected[i].class_id }; kps[i] = k; } KeyPoints ret = {kps, (int)detected.size()}; return ret; } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); KeyPoint* kps = new KeyPoint[0]; KeyPoints ret = {kps, 0}; return ret; } } BFMatcher BFMatcher_Create() { try { return new cv::Ptr(cv::BFMatcher::create()); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } BFMatcher BFMatcher_CreateWithParams(int normType, bool crossCheck) { try { return new cv::Ptr(cv::BFMatcher::create(normType, crossCheck)); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } void BFMatcher_Close(BFMatcher b) { delete b; } struct DMatches BFMatcher_Match(BFMatcher b, Mat query, Mat train) { try { std::vector matches; (*b)->match(*query, *train, matches); DMatch *dmatches = new DMatch[matches.size()]; for (size_t i = 0; i < matches.size(); ++i) { DMatch dmatch = {matches[i].queryIdx, matches[i].trainIdx, matches[i].imgIdx, matches[i].distance}; dmatches[i] = dmatch; } DMatches ret = {dmatches, (int) matches.size()}; return ret; } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); DMatch *dmatches = new DMatch[0]; DMatches ret = {dmatches, 0}; return ret; } } struct MultiDMatches BFMatcher_KnnMatch(BFMatcher b, Mat query, Mat train, int k) { try { std::vector< std::vector > matches; (*b)->knnMatch(*query, *train, matches, k); DMatches *dms = new DMatches[matches.size()]; for (size_t i = 0; i < matches.size(); ++i) { DMatch *dmatches = new DMatch[matches[i].size()]; for (size_t j = 0; j < matches[i].size(); ++j) { DMatch dmatch = {matches[i][j].queryIdx, matches[i][j].trainIdx, matches[i][j].imgIdx, matches[i][j].distance}; dmatches[j] = dmatch; } dms[i] = {dmatches, (int) matches[i].size()}; } MultiDMatches ret = {dms, (int) matches.size()}; return ret; } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); DMatch *dmatches = new DMatch[0]; DMatches *dms = new DMatches[0]; MultiDMatches ret = {dms, 0}; return ret; } } struct MultiDMatches BFMatcher_KnnMatchWithParams(BFMatcher b, Mat query, Mat train, int k, Mat mask, bool compactResult) { try { std::vector< std::vector > matches; (*b)->knnMatch(*query, *train, matches, k, *mask, compactResult); DMatches *dms = new DMatches[matches.size()]; for (size_t i = 0; i < matches.size(); ++i) { DMatch *dmatches = new DMatch[matches[i].size()]; for (size_t j = 0; j < matches[i].size(); ++j) { DMatch dmatch = {matches[i][j].queryIdx, matches[i][j].trainIdx, matches[i][j].imgIdx, matches[i][j].distance}; dmatches[j] = dmatch; } dms[i] = {dmatches, (int) matches[i].size()}; } MultiDMatches ret = {dms, (int) matches.size()}; return ret; } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); DMatch *dmatches = new DMatch[0]; DMatches *dms = new DMatches[0]; MultiDMatches ret = {dms, 0}; return ret; } } FlannBasedMatcher FlannBasedMatcher_Create() { try { return new cv::Ptr(cv::FlannBasedMatcher::create()); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } void FlannBasedMatcher_Close(FlannBasedMatcher f) { delete f; } struct MultiDMatches FlannBasedMatcher_KnnMatch(FlannBasedMatcher f, Mat query, Mat train, int k) { try { std::vector< std::vector > matches; (*f)->knnMatch(*query, *train, matches, k); DMatches *dms = new DMatches[matches.size()]; for (size_t i = 0; i < matches.size(); ++i) { DMatch *dmatches = new DMatch[matches[i].size()]; for (size_t j = 0; j < matches[i].size(); ++j) { DMatch dmatch = {matches[i][j].queryIdx, matches[i][j].trainIdx, matches[i][j].imgIdx, matches[i][j].distance}; dmatches[j] = dmatch; } dms[i] = {dmatches, (int) matches[i].size()}; } MultiDMatches ret = {dms, (int) matches.size()}; return ret; } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); DMatch *dmatches = new DMatch[0]; DMatches *dms = new DMatches[0]; MultiDMatches ret = {dms, 0}; return ret; } } struct MultiDMatches FlannBasedMatcher_KnnMatchWithParams(FlannBasedMatcher f, Mat query, Mat train, int k, Mat mask, bool compactResult) { try { std::vector< std::vector > matches; (*f)->knnMatch(*query, *train, matches, k, *mask, compactResult); DMatches *dms = new DMatches[matches.size()]; for (size_t i = 0; i < matches.size(); ++i) { DMatch *dmatches = new DMatch[matches[i].size()]; for (size_t j = 0; j < matches[i].size(); ++j) { DMatch dmatch = {matches[i][j].queryIdx, matches[i][j].trainIdx, matches[i][j].imgIdx, matches[i][j].distance}; dmatches[j] = dmatch; } dms[i] = {dmatches, (int) matches[i].size()}; } MultiDMatches ret = {dms, (int) matches.size()}; return ret; } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); DMatch *dmatches = new DMatch[0]; DMatches *dms = new DMatches[0]; MultiDMatches ret = {dms, 0}; return ret; } } void DrawKeyPoints(Mat src, struct KeyPoints kp, Mat dst, Scalar s, int flags) { try { std::vector keypts; cv::KeyPoint keypt; for (int i = 0; i < kp.length; ++i) { keypt = cv::KeyPoint(kp.keypoints[i].x, kp.keypoints[i].y, kp.keypoints[i].size, kp.keypoints[i].angle, kp.keypoints[i].response, kp.keypoints[i].octave, kp.keypoints[i].classID); keypts.push_back(keypt); } cv::Scalar color = cv::Scalar(s.val1, s.val2, s.val3, s.val4); cv::drawKeypoints(*src, keypts, *dst, color, static_cast(flags)); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); } } SIFT SIFT_Create() { try { return new cv::Ptr(cv::SIFT::create()); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } SIFT SIFT_CreateWithParams(int nfeatures, int nOctaveLayers, double contrastThreshold, double edgeThreshold, double sigma) { try { return new cv::Ptr(cv::SIFT::create(nfeatures, nOctaveLayers, contrastThreshold, edgeThreshold, sigma)); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } void SIFT_Close(SIFT d) { delete d; } struct KeyPoints SIFT_Detect(SIFT d, Mat src) { try { std::vector detected; (*d)->detect(*src, detected); KeyPoint* kps = new KeyPoint[detected.size()]; for (size_t i = 0; i < detected.size(); ++i) { KeyPoint k = {detected[i].pt.x, detected[i].pt.y, detected[i].size, detected[i].angle, detected[i].response, detected[i].octave, detected[i].class_id }; kps[i] = k; } KeyPoints ret = {kps, (int)detected.size()}; return ret; } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); KeyPoint* kps = new KeyPoint[0]; KeyPoints ret = {kps, 0}; return ret; } } struct KeyPoints SIFT_Compute(SIFT d, Mat src, struct KeyPoints kp, Mat desc) { try { std::vector computed; for (size_t i = 0; i < kp.length; i++) { cv::KeyPoint k = cv::KeyPoint(kp.keypoints[i].x, kp.keypoints[i].y, kp.keypoints[i].size, kp.keypoints[i].angle, kp.keypoints[i].response, kp.keypoints[i].octave, kp.keypoints[i].classID); computed.push_back(k); } (*d)->compute(*src, computed, *desc); KeyPoint* kps = new KeyPoint[computed.size()]; for (size_t i = 0; i < computed.size(); ++i) { KeyPoint k = {computed[i].pt.x, computed[i].pt.y, computed[i].size, computed[i].angle, computed[i].response, computed[i].octave, computed[i].class_id }; kps[i] = k; } KeyPoints ret = {kps, (int)computed.size()}; return ret; } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); KeyPoint* kps = new KeyPoint[0]; KeyPoints ret = {kps, 0}; return ret; } } struct KeyPoints SIFT_DetectAndCompute(SIFT d, Mat src, Mat mask, Mat desc) { try { std::vector detected; (*d)->detectAndCompute(*src, *mask, detected, *desc); KeyPoint* kps = new KeyPoint[detected.size()]; for (size_t i = 0; i < detected.size(); ++i) { KeyPoint k = {detected[i].pt.x, detected[i].pt.y, detected[i].size, detected[i].angle, detected[i].response, detected[i].octave, detected[i].class_id }; kps[i] = k; } KeyPoints ret = {kps, (int)detected.size()}; return ret; } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); KeyPoint* kps = new KeyPoint[0]; KeyPoints ret = {kps, 0}; return ret; } } void DrawMatches(Mat img1, struct KeyPoints kp1, Mat img2, struct KeyPoints kp2, struct DMatches matches1to2, Mat outImg, const Scalar matchesColor, const Scalar pointColor, struct ByteArray matchesMask, int flags) { try { std::vector kp1vec, kp2vec; cv::KeyPoint keypt; for (int i = 0; i < kp1.length; ++i) { keypt = cv::KeyPoint(kp1.keypoints[i].x, kp1.keypoints[i].y, kp1.keypoints[i].size, kp1.keypoints[i].angle, kp1.keypoints[i].response, kp1.keypoints[i].octave, kp1.keypoints[i].classID); kp1vec.push_back(keypt); } for (int i = 0; i < kp2.length; ++i) { keypt = cv::KeyPoint(kp2.keypoints[i].x, kp2.keypoints[i].y, kp2.keypoints[i].size, kp2.keypoints[i].angle, kp2.keypoints[i].response, kp2.keypoints[i].octave, kp2.keypoints[i].classID); kp2vec.push_back(keypt); } cv::Scalar cvmatchescolor = cv::Scalar(matchesColor.val1, matchesColor.val2, matchesColor.val3, matchesColor.val4); cv::Scalar cvpointcolor = cv::Scalar(pointColor.val1, pointColor.val2, pointColor.val3, pointColor.val4); std::vector dmatchvec; cv::DMatch dm; for (int i = 0; i < matches1to2.length; i++) { dm = cv::DMatch(matches1to2.dmatches[i].queryIdx, matches1to2.dmatches[i].trainIdx, matches1to2.dmatches[i].imgIdx, matches1to2.dmatches[i].distance); dmatchvec.push_back(dm); } std::vector maskvec; for (int i = 0; i < matchesMask.length; i++) { maskvec.push_back(matchesMask.data[i]); } cv::drawMatches(*img1, kp1vec, *img2, kp2vec, dmatchvec, *outImg, cvmatchescolor, cvpointcolor, maskvec, static_cast(flags)); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); } } ================================================ FILE: features2d.go ================================================ //go:build !gocv_specific_modules || (gocv_specific_modules && gocv_features2d) package gocv /* #include #include "features2d.h" */ import "C" import ( "image/color" "io" "reflect" "unsafe" ) type Feature2DDetector interface { Detect(src Mat) []KeyPoint } type Feature2DComputer interface { Compute(src Mat, mask Mat, kps []KeyPoint) ([]KeyPoint, Mat) } type Feature2DDetectComputer interface { DetectAndCompute(src Mat, mask Mat) ([]KeyPoint, Mat) } type Feature2D interface { io.Closer Feature2DDetector Feature2DComputer Feature2DDetectComputer } // AKAZE is a wrapper around the cv::AKAZE algorithm. type AKAZE struct { // C.AKAZE p unsafe.Pointer } var _ Feature2D = (*AKAZE)(nil) // NewAKAZE returns a new AKAZE algorithm // // For further details, please see: // https://docs.opencv.org/master/d8/d30/classcv_1_1AKAZE.html func NewAKAZE() AKAZE { return AKAZE{p: unsafe.Pointer(C.AKAZE_Create())} } // NewAKAZEWithParams creates a new AKAZE detector with custom parameters. func NewAKAZEWithParams(descriptorType, descriptorSize, descriptorChannels int, threshold float32, nOctaves, nOctaveLayers, diffusivity int) AKAZE { ptr := C.AKAZE_CreateWithParams( C.int(descriptorType), C.int(descriptorSize), C.int(descriptorChannels), C.float(threshold), C.int(nOctaves), C.int(nOctaveLayers), C.int(diffusivity)) return AKAZE{p: unsafe.Pointer(ptr)} } // Close AKAZE. func (a *AKAZE) Close() error { C.AKAZE_Close((C.AKAZE)(a.p)) a.p = nil return nil } // Detect keypoints in an image using AKAZE. // // For further details, please see: // https://docs.opencv.org/master/d0/d13/classcv_1_1Feature2D.html#aa4e9a7082ec61ebc108806704fbd7887 func (a *AKAZE) Detect(src Mat) []KeyPoint { ret := C.AKAZE_Detect((C.AKAZE)(a.p), src.p) defer C.KeyPoints_Close(ret) return getKeyPoints(ret) } // Compute keypoints in an image using AKAZE. // // For further details, please see: // https://docs.opencv.org/4.x/d0/d13/classcv_1_1Feature2D.html#ab3cce8d56f4fc5e1d530b5931e1e8dc0 func (a *AKAZE) Compute(src Mat, mask Mat, kps []KeyPoint) ([]KeyPoint, Mat) { desc := NewMat() kp2arr := make([]C.struct_KeyPoint, len(kps)) for i, kp := range kps { kp2arr[i].x = C.double(kp.X) kp2arr[i].y = C.double(kp.Y) kp2arr[i].size = C.double(kp.Size) kp2arr[i].angle = C.double(kp.Angle) kp2arr[i].response = C.double(kp.Response) kp2arr[i].octave = C.int(kp.Octave) kp2arr[i].classID = C.int(kp.ClassID) } cKeyPoints := C.struct_KeyPoints{ keypoints: (*C.struct_KeyPoint)(&kp2arr[0]), length: (C.int)(len(kps)), } ret := C.AKAZE_Compute((C.AKAZE)(a.p), src.p, cKeyPoints, desc.p) defer C.KeyPoints_Close(ret) return getKeyPoints(ret), desc } // DetectAndCompute keypoints and compute in an image using AKAZE. // // For further details, please see: // https://docs.opencv.org/master/d0/d13/classcv_1_1Feature2D.html#a8be0d1c20b08eb867184b8d74c15a677 func (a *AKAZE) DetectAndCompute(src Mat, mask Mat) ([]KeyPoint, Mat) { desc := NewMat() ret := C.AKAZE_DetectAndCompute((C.AKAZE)(a.p), src.p, mask.p, desc.p) defer C.KeyPoints_Close(ret) return getKeyPoints(ret), desc } // AgastFeatureDetector is a wrapper around the cv::AgastFeatureDetector. type AgastFeatureDetector struct { // C.AgastFeatureDetector p unsafe.Pointer } // NewAgastFeatureDetector returns a new AgastFeatureDetector algorithm // // For further details, please see: // https://docs.opencv.org/master/d7/d19/classcv_1_1AgastFeatureDetector.html func NewAgastFeatureDetector() AgastFeatureDetector { return AgastFeatureDetector{p: unsafe.Pointer(C.AgastFeatureDetector_Create())} } // NewAgastFeatureDetectorWithParams creates a new AGAST feature detector with custom parameters. func NewAgastFeatureDetectorWithParams(threshold int, nonmaxSuppression bool, detectorType int) AgastFeatureDetector { return AgastFeatureDetector{ p: unsafe.Pointer(C.AgastFeatureDetector_CreateWithParams( C.int(threshold), C.bool(nonmaxSuppression), C.int(detectorType), )), } } // Close AgastFeatureDetector. func (a *AgastFeatureDetector) Close() error { C.AgastFeatureDetector_Close((C.AgastFeatureDetector)(a.p)) a.p = nil return nil } // Detect keypoints in an image using AgastFeatureDetector. // // For further details, please see: // https://docs.opencv.org/master/d0/d13/classcv_1_1Feature2D.html#aa4e9a7082ec61ebc108806704fbd7887 func (a *AgastFeatureDetector) Detect(src Mat) []KeyPoint { ret := C.AgastFeatureDetector_Detect((C.AgastFeatureDetector)(a.p), src.p) defer C.KeyPoints_Close(ret) return getKeyPoints(ret) } // BRISK is a wrapper around the cv::BRISK algorithm. type BRISK struct { // C.BRISK p unsafe.Pointer } var _ Feature2D = (*BRISK)(nil) // NewBRISK returns a new BRISK algorithm // // For further details, please see: // https://docs.opencv.org/4.x/de/dbf/classcv_1_1BRISK.html func NewBRISK() BRISK { return BRISK{p: unsafe.Pointer(C.BRISK_Create())} } // NewBRISKWithParams returns a new BRISK algorithm with parameters // // For further details, please see: // https://docs.opencv.org/4.x/de/dbf/classcv_1_1BRISK.html func NewBRISKWithParams(thresh int, octaves int, patternScale float32) BRISK { return BRISK{p: unsafe.Pointer(C.BRISK_CreateWithParams(C.int(thresh), C.int(octaves), C.float(patternScale)))} } // Close BRISK. func (b *BRISK) Close() error { C.BRISK_Close((C.BRISK)(b.p)) b.p = nil return nil } // Detect keypoints in an image using BRISK. // // For further details, please see: // https://docs.opencv.org/master/d0/d13/classcv_1_1Feature2D.html#aa4e9a7082ec61ebc108806704fbd7887 func (b *BRISK) Detect(src Mat) []KeyPoint { ret := C.BRISK_Detect((C.BRISK)(b.p), src.p) defer C.KeyPoints_Close(ret) return getKeyPoints(ret) } // Compute keypoints in an image using BRISK. // // For further details, please see: // https://docs.opencv.org/4.x/d0/d13/classcv_1_1Feature2D.html#ab3cce8d56f4fc5e1d530b5931e1e8dc0 func (b *BRISK) Compute(src Mat, mask Mat, kps []KeyPoint) ([]KeyPoint, Mat) { desc := NewMat() kp2arr := make([]C.struct_KeyPoint, len(kps)) for i, kp := range kps { kp2arr[i].x = C.double(kp.X) kp2arr[i].y = C.double(kp.Y) kp2arr[i].size = C.double(kp.Size) kp2arr[i].angle = C.double(kp.Angle) kp2arr[i].response = C.double(kp.Response) kp2arr[i].octave = C.int(kp.Octave) kp2arr[i].classID = C.int(kp.ClassID) } cKeyPoints := C.struct_KeyPoints{ keypoints: (*C.struct_KeyPoint)(&kp2arr[0]), length: (C.int)(len(kps)), } ret := C.BRISK_Compute((C.BRISK)(b.p), src.p, cKeyPoints, desc.p) defer C.KeyPoints_Close(ret) return getKeyPoints(ret), desc } // DetectAndCompute keypoints and compute in an image using BRISK. // // For further details, please see: // https://docs.opencv.org/master/d0/d13/classcv_1_1Feature2D.html#a8be0d1c20b08eb867184b8d74c15a677 func (b *BRISK) DetectAndCompute(src Mat, mask Mat) ([]KeyPoint, Mat) { desc := NewMat() ret := C.BRISK_DetectAndCompute((C.BRISK)(b.p), src.p, mask.p, desc.p) defer C.KeyPoints_Close(ret) return getKeyPoints(ret), desc } // FastFeatureDetectorType defines the detector type // // For further details, please see: // https://docs.opencv.org/master/df/d74/classcv_1_1FastFeatureDetector.html#a4654f6fb0aa4b8e9123b223bfa0e2a08 type FastFeatureDetectorType int const ( //FastFeatureDetectorType58 is an alias of FastFeatureDetector::TYPE_5_8 FastFeatureDetectorType58 FastFeatureDetectorType = 0 //FastFeatureDetectorType712 is an alias of FastFeatureDetector::TYPE_7_12 FastFeatureDetectorType712 FastFeatureDetectorType = 1 //FastFeatureDetectorType916 is an alias of FastFeatureDetector::TYPE_9_16 FastFeatureDetectorType916 FastFeatureDetectorType = 2 ) // FastFeatureDetector is a wrapper around the cv::FastFeatureDetector. type FastFeatureDetector struct { // C.FastFeatureDetector p unsafe.Pointer } // NewFastFeatureDetector returns a new FastFeatureDetector algorithm // // For further details, please see: // https://docs.opencv.org/master/df/d74/classcv_1_1FastFeatureDetector.html func NewFastFeatureDetector() FastFeatureDetector { return FastFeatureDetector{p: unsafe.Pointer(C.FastFeatureDetector_Create())} } // NewFastFeatureDetectorWithParams returns a new FastFeatureDetector algorithm with parameters // // For further details, please see: // https://docs.opencv.org/master/df/d74/classcv_1_1FastFeatureDetector.html#ab986f2ff8f8778aab1707e2642bc7f8e func NewFastFeatureDetectorWithParams(threshold int, nonmaxSuppression bool, typ FastFeatureDetectorType) FastFeatureDetector { return FastFeatureDetector{p: unsafe.Pointer(C.FastFeatureDetector_CreateWithParams(C.int(threshold), C.bool(nonmaxSuppression), C.int(typ)))} } // Close FastFeatureDetector. func (f *FastFeatureDetector) Close() error { C.FastFeatureDetector_Close((C.FastFeatureDetector)(f.p)) f.p = nil return nil } // Detect keypoints in an image using FastFeatureDetector. // // For further details, please see: // https://docs.opencv.org/master/d0/d13/classcv_1_1Feature2D.html#aa4e9a7082ec61ebc108806704fbd7887 func (f *FastFeatureDetector) Detect(src Mat) []KeyPoint { ret := C.FastFeatureDetector_Detect((C.FastFeatureDetector)(f.p), src.p) defer C.KeyPoints_Close(ret) return getKeyPoints(ret) } // GFTTDetector is a wrapper around the cv::GFTTDetector algorithm. type GFTTDetector struct { // C.GFTTDetector p unsafe.Pointer } // GFTTDetectorParams holds parameters to create a GFTTDetector type GFTTDetectorParams struct { MaxCorners int QualityLevel float64 MinDistance float64 BlockSize int UseHarrisDetector bool K float64 } // NewGFTTDetector returns a new GFTTDetector algorithm // // For further details, please see: // https://docs.opencv.org/master/df/d21/classcv_1_1GFTTDetector.html func NewGFTTDetector() GFTTDetector { return GFTTDetector{p: unsafe.Pointer(C.GFTTDetector_Create())} } // NewGFTTDetectorWithParams returns a new GFTTDetector algorithm with custom parameters // // For further details, please see: // https://docs.opencv.org/master/df/d21/classcv_1_1GFTTDetector.html func NewGFTTDetectorWithParams(params GFTTDetectorParams) GFTTDetector { cParams := C.GFTTDetectorParams{ maxCorners: C.int(params.MaxCorners), qualityLevel: C.double(params.QualityLevel), minDistance: C.double(params.MinDistance), blockSize: C.int(params.BlockSize), useHarrisDetector: C.bool(params.UseHarrisDetector), k: C.double(params.K), } return GFTTDetector{p: unsafe.Pointer(C.GFTTDetector_Create_WithParams(&cParams))} } // Close GFTTDetector. func (a *GFTTDetector) Close() error { C.GFTTDetector_Close((C.GFTTDetector)(a.p)) a.p = nil return nil } // Detect keypoints in an image using GFTTDetector. // // For further details, please see: // https://docs.opencv.org/master/d0/d13/classcv_1_1Feature2D.html#aa4e9a7082ec61ebc108806704fbd7887 func (a *GFTTDetector) Detect(src Mat) []KeyPoint { ret := C.GFTTDetector_Detect((C.GFTTDetector)(a.p), src.p) defer C.KeyPoints_Close(ret) return getKeyPoints(ret) } // KAZE is a wrapper around the cv::KAZE algorithm. type KAZE struct { // C.KAZE p unsafe.Pointer } var _ Feature2D = (*KAZE)(nil) // NewKAZE returns a new KAZE algorithm // // For further details, please see: // https://docs.opencv.org/master/d3/d61/classcv_1_1KAZE.html func NewKAZE() KAZE { return KAZE{p: unsafe.Pointer(C.KAZE_Create())} } // NewKazeWithParams returns a new KAZE algorithm with the specified parameters. func NewKazeWithParams(extended bool, upright bool, threshold float32, nOctaves int, nOctaveLayers int, diffusivity int) KAZE { cExtended := C.bool(extended) cUpright := C.bool(upright) cThreshold := C.float(threshold) cNOctaves := C.int(nOctaves) cNOctaveLayers := C.int(nOctaveLayers) cDiffusivity := C.int(diffusivity) return KAZE{p: unsafe.Pointer(C.KAZE_CreateWithParams(cExtended, cUpright, cThreshold, cNOctaves, cNOctaveLayers, cDiffusivity))} } // Close KAZE. func (a *KAZE) Close() error { C.KAZE_Close((C.KAZE)(a.p)) a.p = nil return nil } // Detect keypoints in an image using KAZE. // // For further details, please see: // https://docs.opencv.org/master/d0/d13/classcv_1_1Feature2D.html#aa4e9a7082ec61ebc108806704fbd7887 func (a *KAZE) Detect(src Mat) []KeyPoint { ret := C.KAZE_Detect((C.KAZE)(a.p), src.p) defer C.KeyPoints_Close(ret) return getKeyPoints(ret) } // Compute keypoints in an image using KAZE. // // For further details, please see: // https://docs.opencv.org/4.x/d0/d13/classcv_1_1Feature2D.html#ab3cce8d56f4fc5e1d530b5931e1e8dc0 func (a *KAZE) Compute(src Mat, mask Mat, kps []KeyPoint) ([]KeyPoint, Mat) { desc := NewMat() kp2arr := make([]C.struct_KeyPoint, len(kps)) for i, kp := range kps { kp2arr[i].x = C.double(kp.X) kp2arr[i].y = C.double(kp.Y) kp2arr[i].size = C.double(kp.Size) kp2arr[i].angle = C.double(kp.Angle) kp2arr[i].response = C.double(kp.Response) kp2arr[i].octave = C.int(kp.Octave) kp2arr[i].classID = C.int(kp.ClassID) } cKeyPoints := C.struct_KeyPoints{ keypoints: (*C.struct_KeyPoint)(&kp2arr[0]), length: (C.int)(len(kps)), } ret := C.KAZE_Compute((C.KAZE)(a.p), src.p, cKeyPoints, desc.p) defer C.KeyPoints_Close(ret) return getKeyPoints(ret), desc } // DetectAndCompute keypoints and compute in an image using KAZE. // // For further details, please see: // https://docs.opencv.org/master/d0/d13/classcv_1_1Feature2D.html#a8be0d1c20b08eb867184b8d74c15a677 func (a *KAZE) DetectAndCompute(src Mat, mask Mat) ([]KeyPoint, Mat) { desc := NewMat() ret := C.KAZE_DetectAndCompute((C.KAZE)(a.p), src.p, mask.p, desc.p) defer C.KeyPoints_Close(ret) return getKeyPoints(ret), desc } // MSER is a wrapper around the cv::MSER algorithm. type MSER struct { // C.MSER p unsafe.Pointer } // NewMSER returns a new MSER algorithm // // For further details, please see: // https://docs.opencv.org/master/d3/d28/classcv_1_1MSER.html func NewMSER() MSER { return MSER{p: unsafe.Pointer(C.MSER_Create())} } // NewMSERWithParams returns a new MSER algorithm with the specified parameters. func NewMSERWithParams(delta int, minArea int, maxArea int, maxVariation float64, minDiversity float64, maxEvolution int, areaThreshold float64, minMargin float64, edgeBlurSize int) MSER { cDelta := C.int(delta) cMinArea := C.int(minArea) cMaxArea := C.int(maxArea) cMaxVariation := C.double(maxVariation) cMinDiversity := C.double(minDiversity) cMaxEvolution := C.int(maxEvolution) cAreaThreshold := C.double(areaThreshold) cMinMargin := C.double(minMargin) cEdgeBlurSize := C.int(edgeBlurSize) return MSER{p: unsafe.Pointer(C.MSER_CreateWithParams(cDelta, cMinArea, cMaxArea, cMaxVariation, cMinDiversity, cMaxEvolution, cAreaThreshold, cMinMargin, cEdgeBlurSize))} } // Close MSER. func (a *MSER) Close() error { C.MSER_Close((C.MSER)(a.p)) a.p = nil return nil } // Detect keypoints in an image using MSER. // // For further details, please see: // https://docs.opencv.org/master/d0/d13/classcv_1_1Feature2D.html#aa4e9a7082ec61ebc108806704fbd7887 func (a *MSER) Detect(src Mat) []KeyPoint { ret := C.MSER_Detect((C.MSER)(a.p), src.p) defer C.KeyPoints_Close(ret) return getKeyPoints(ret) } // ORB is a wrapper around the cv::ORB. type ORB struct { // C.ORB p unsafe.Pointer } var _ Feature2D = (*ORB)(nil) // NewORB returns a new ORB algorithm // // For further details, please see: // https://docs.opencv.org/master/db/d95/classcv_1_1ORB.html func NewORB() ORB { return ORB{p: unsafe.Pointer(C.ORB_Create())} } // NewORBWithParams returns a new ORB algorithm with parameters // // For further details, please see: // https://docs.opencv.org/master/db/d95/classcv_1_1ORB.html#aeff0cbe668659b7ca14bb85ff1c4073b func NewORBWithParams(nFeatures int, scaleFactor float32, nLevels int, edgeThreshold int, firstLevel int, WTAK int, scoreType ORBScoreType, patchSize int, fastThreshold int) ORB { return ORB{p: unsafe.Pointer(C.ORB_CreateWithParams( C.int(nFeatures), C.float(scaleFactor), C.int(nLevels), C.int(edgeThreshold), C.int(firstLevel), C.int(WTAK), C.int(scoreType), C.int(patchSize), C.int(fastThreshold), ))} } type ORBScoreType int const ( ORBScoreTypeHarris ORBScoreType = 0 ORBScoreTypeFAST ORBScoreType = 1 ) // Close ORB. func (o *ORB) Close() error { C.ORB_Close((C.ORB)(o.p)) o.p = nil return nil } // Detect keypoints in an image using ORB. // // For further details, please see: // https://docs.opencv.org/master/d0/d13/classcv_1_1Feature2D.html#aa4e9a7082ec61ebc108806704fbd7887 func (o *ORB) Detect(src Mat) []KeyPoint { ret := C.ORB_Detect((C.ORB)(o.p), src.p) defer C.KeyPoints_Close(ret) return getKeyPoints(ret) } // Compute keypoints in an image using ORB. // // For further details, please see: // https://docs.opencv.org/4.x/d0/d13/classcv_1_1Feature2D.html#ab3cce8d56f4fc5e1d530b5931e1e8dc0 func (o *ORB) Compute(src Mat, mask Mat, kps []KeyPoint) ([]KeyPoint, Mat) { desc := NewMat() kp2arr := make([]C.struct_KeyPoint, len(kps)) for i, kp := range kps { kp2arr[i].x = C.double(kp.X) kp2arr[i].y = C.double(kp.Y) kp2arr[i].size = C.double(kp.Size) kp2arr[i].angle = C.double(kp.Angle) kp2arr[i].response = C.double(kp.Response) kp2arr[i].octave = C.int(kp.Octave) kp2arr[i].classID = C.int(kp.ClassID) } cKeyPoints := C.struct_KeyPoints{ keypoints: (*C.struct_KeyPoint)(&kp2arr[0]), length: (C.int)(len(kps)), } ret := C.ORB_Compute((C.ORB)(o.p), src.p, cKeyPoints, desc.p) defer C.KeyPoints_Close(ret) return getKeyPoints(ret), desc } // DetectAndCompute detects keypoints and computes from an image using ORB. // // For further details, please see: // https://docs.opencv.org/master/d0/d13/classcv_1_1Feature2D.html#a8be0d1c20b08eb867184b8d74c15a677 func (o *ORB) DetectAndCompute(src Mat, mask Mat) ([]KeyPoint, Mat) { desc := NewMat() ret := C.ORB_DetectAndCompute((C.ORB)(o.p), src.p, mask.p, desc.p) defer C.KeyPoints_Close(ret) return getKeyPoints(ret), desc } // SimpleBlobDetector is a wrapper around the cv::SimpleBlobDetector. type SimpleBlobDetector struct { // C.SimpleBlobDetector p unsafe.Pointer } // SimpleBlobDetector_Params is a wrapper around the cv::SimpleBlobdetector::Params type SimpleBlobDetectorParams struct { p C.SimpleBlobDetectorParams } // NewSimpleBlobDetector returns a new SimpleBlobDetector algorithm // // For further details, please see: // https://docs.opencv.org/master/d0/d7a/classcv_1_1SimpleBlobDetector.html func NewSimpleBlobDetector() SimpleBlobDetector { return SimpleBlobDetector{p: unsafe.Pointer(C.SimpleBlobDetector_Create())} } // NewSimpleBlobDetectorWithParams returns a new SimpleBlobDetector with custom parameters // // For further details, please see: // https://docs.opencv.org/master/d0/d7a/classcv_1_1SimpleBlobDetector.html func NewSimpleBlobDetectorWithParams(params SimpleBlobDetectorParams) SimpleBlobDetector { return SimpleBlobDetector{p: unsafe.Pointer(C.SimpleBlobDetector_Create_WithParams(params.p))} } // Close SimpleBlobDetector. func (b *SimpleBlobDetector) Close() error { C.SimpleBlobDetector_Close((C.SimpleBlobDetector)(b.p)) b.p = nil return nil } // NewSimpleBlobDetectorParams returns the default parameters for the SimpleBobDetector func NewSimpleBlobDetectorParams() SimpleBlobDetectorParams { return SimpleBlobDetectorParams{p: C.SimpleBlobDetectorParams_Create()} } // SetBlobColor sets the blobColor field func (p *SimpleBlobDetectorParams) SetBlobColor(blobColor int) { p.p.blobColor = C.uchar(blobColor) } // GetBlobColor gets the blobColor field func (p *SimpleBlobDetectorParams) GetBlobColor() int { return int(p.p.blobColor) } // SetFilterByArea sets the filterByArea field func (p *SimpleBlobDetectorParams) SetFilterByArea(filterByArea bool) { p.p.filterByArea = C.bool(filterByArea) } // GetFilterByArea gets the filterByArea field func (p *SimpleBlobDetectorParams) GetFilterByArea() bool { return bool(p.p.filterByArea) } // SetFilterByCircularity sets the filterByCircularity field func (p *SimpleBlobDetectorParams) SetFilterByCircularity(filterByCircularity bool) { p.p.filterByCircularity = C.bool(filterByCircularity) } // GetFilterByCircularity gets the filterByCircularity field func (p *SimpleBlobDetectorParams) GetFilterByCircularity() bool { return bool(p.p.filterByCircularity) } // SetFilterByColor sets the filterByColor field func (p *SimpleBlobDetectorParams) SetFilterByColor(filterByColor bool) { p.p.filterByColor = C.bool(filterByColor) } // GetFilterByColor gets the filterByColor field func (p *SimpleBlobDetectorParams) GetFilterByColor() bool { return bool(p.p.filterByColor) } // SetFilterByConvexity sets the filterByConvexity field func (p *SimpleBlobDetectorParams) SetFilterByConvexity(filterByConvexity bool) { p.p.filterByConvexity = C.bool(filterByConvexity) } // GetFilterByConvexity gets the filterByConvexity field func (p *SimpleBlobDetectorParams) GetFilterByConvexity() bool { return bool(p.p.filterByConvexity) } // SetFilterByInertia sets the filterByInertia field func (p *SimpleBlobDetectorParams) SetFilterByInertia(filterByInertia bool) { p.p.filterByInertia = C.bool(filterByInertia) } // GetFilterByInertia gets the filterByInertia field func (p *SimpleBlobDetectorParams) GetFilterByInertia() bool { return bool(p.p.filterByInertia) } // SetMaxArea sets the maxArea parameter for SimpleBlobDetector_Params func (p *SimpleBlobDetectorParams) SetMaxArea(maxArea float64) { p.p.maxArea = C.float(maxArea) } // GetMaxArea sets the maxArea parameter for SimpleBlobDetector_Params func (p *SimpleBlobDetectorParams) GetMaxArea() float64 { return float64(p.p.maxArea) } // SetMaxCircularity sets the maxCircularity parameter for SimpleBlobDetector_Params func (p *SimpleBlobDetectorParams) SetMaxCircularity(maxCircularity float64) { p.p.maxCircularity = C.float(maxCircularity) } // GetMaxCircularity sets the maxCircularity parameter for SimpleBlobDetector_Params func (p *SimpleBlobDetectorParams) GetMaxCircularity() float64 { return float64(p.p.maxCircularity) } // SetMaxConvexity sets the maxConvexity parameter for SimpleBlobDetector_Params func (p *SimpleBlobDetectorParams) SetMaxConvexity(maxConvexity float64) { p.p.maxConvexity = C.float(maxConvexity) } // GetMaxConvexity sets the maxConvexity parameter for SimpleBlobDetector_Params func (p *SimpleBlobDetectorParams) GetMaxConvexity() float64 { return float64(p.p.maxConvexity) } // SetMaxInertiaRatio sets the maxInertiaRatio parameter for SimpleBlobDetector_Params func (p *SimpleBlobDetectorParams) SetMaxInertiaRatio(maxInertiaRatio float64) { p.p.maxInertiaRatio = C.float(maxInertiaRatio) } // GetMaxInertiaRatio sets the maxCConvexity parameter for SimpleBlobDetector_Params func (p *SimpleBlobDetectorParams) GetMaxInertiaRatio() float64 { return float64(p.p.maxInertiaRatio) } // SetMaxThreshold sets the maxThreshold parameter for SimpleBlobDetector_Params func (p *SimpleBlobDetectorParams) SetMaxThreshold(maxThreshold float64) { p.p.maxThreshold = C.float(maxThreshold) } // GetMaxThreshold sets the maxCConvexity parameter for SimpleBlobDetector_Params func (p *SimpleBlobDetectorParams) GetMaxThreshold() float64 { return float64(p.p.maxThreshold) } // SetMinArea sets the minArea parameter for SimpleBlobDetector_Params func (p *SimpleBlobDetectorParams) SetMinArea(minArea float64) { p.p.minArea = C.float(minArea) } // GetMinArea sets theinArea parameter for SimpleBlobDetector_Params func (p *SimpleBlobDetectorParams) GetMinArea() float64 { return float64(p.p.minArea) } // SetMinCircularity sets the minCircularity parameter for SimpleBlobDetector_Params func (p *SimpleBlobDetectorParams) SetMinCircularity(minCircularity float64) { p.p.minCircularity = C.float(minCircularity) } // GetMinCircularity sets the minCircularity parameter for SimpleBlobDetector_Params func (p *SimpleBlobDetectorParams) GetMinCircularity() float64 { return float64(p.p.minCircularity) } // SetMinConvexity sets the minConvexity parameter for SimpleBlobDetector_Params func (p *SimpleBlobDetectorParams) SetMinConvexity(minConvexity float64) { p.p.minConvexity = C.float(minConvexity) } // GetMinConvexity sets the minConvexity parameter for SimpleBlobDetector_Params func (p *SimpleBlobDetectorParams) GetMinConvexity() float64 { return float64(p.p.minConvexity) } // SetMinDistBetweenBlobs sets the minDistBetweenBlobs parameter for SimpleBlobDetector_Params func (p *SimpleBlobDetectorParams) SetMinDistBetweenBlobs(minDistBetweenBlobs float64) { p.p.minDistBetweenBlobs = C.float(minDistBetweenBlobs) } // GetMinDistBetweenBlobs sets the minDistBetweenBlobs parameter for SimpleBlobDetector_Params func (p *SimpleBlobDetectorParams) GetMinDistBetweenBlobs() float64 { return float64(p.p.minDistBetweenBlobs) } // SetMinInertiaRatio sets the minInertiaRatio parameter for SimpleBlobDetector_Params func (p *SimpleBlobDetectorParams) SetMinInertiaRatio(minInertiaRatio float64) { p.p.minInertiaRatio = C.float(minInertiaRatio) } // GetMinInertiaRatio sets the minInertiaRatio parameter for SimpleBlobDetector_Params func (p *SimpleBlobDetectorParams) GetMinInertiaRatio() float64 { return float64(p.p.minInertiaRatio) } // SetMinRepeatability sets the minRepeatability parameter for SimpleBlobDetector_Params func (p *SimpleBlobDetectorParams) SetMinRepeatability(minRepeatability int) { p.p.minRepeatability = C.size_t(minRepeatability) } // GetMinInertiaRatio sets the minRepeatability parameter for SimpleBlobDetector_Params func (p *SimpleBlobDetectorParams) GetMinRepeatability() int { return int(p.p.minRepeatability) } // SetMinThreshold sets the minThreshold parameter for SimpleBlobDetector_Params func (p *SimpleBlobDetectorParams) SetMinThreshold(minThreshold float64) { p.p.minThreshold = C.float(minThreshold) } // GetMinThreshold sets the minInertiaRatio parameter for SimpleBlobDetector_Params func (p *SimpleBlobDetectorParams) GetMinThreshold() float64 { return float64(p.p.minThreshold) } // SetMinThreshold sets the minThreshold parameter for SimpleBlobDetector_Params func (p *SimpleBlobDetectorParams) SetThresholdStep(thresholdStep float64) { p.p.thresholdStep = C.float(thresholdStep) } // GetMinThreshold sets the minInertiaRatio parameter for SimpleBlobDetector_Params func (p *SimpleBlobDetectorParams) GetThresholdStep() float64 { return float64(p.p.thresholdStep) } // Detect keypoints in an image using SimpleBlobDetector. // // For further details, please see: // https://docs.opencv.org/master/d0/d13/classcv_1_1Feature2D.html#aa4e9a7082ec61ebc108806704fbd7887 func (b *SimpleBlobDetector) Detect(src Mat) []KeyPoint { ret := C.SimpleBlobDetector_Detect((C.SimpleBlobDetector)(b.p), src.p) defer C.KeyPoints_Close(ret) return getKeyPoints(ret) } // getKeyPoints returns a slice of KeyPoint given a pointer to a C.KeyPoints func getKeyPoints(ret C.KeyPoints) []KeyPoint { cArray := ret.keypoints length := int(ret.length) hdr := reflect.SliceHeader{ Data: uintptr(unsafe.Pointer(cArray)), Len: length, Cap: length, } s := *(*[]C.KeyPoint)(unsafe.Pointer(&hdr)) keys := make([]KeyPoint, length) for i, r := range s { keys[i] = KeyPoint{float64(r.x), float64(r.y), float64(r.size), float64(r.angle), float64(r.response), int(r.octave), int(r.classID)} } return keys } // BFMatcher is a wrapper around the the cv::BFMatcher algorithm type BFMatcher struct { // C.BFMatcher p unsafe.Pointer } // NewBFMatcher returns a new BFMatcher // // For further details, please see: // https://docs.opencv.org/master/d3/da1/classcv_1_1BFMatcher.html#abe0bb11749b30d97f60d6ade665617bd func NewBFMatcher() BFMatcher { return BFMatcher{p: unsafe.Pointer(C.BFMatcher_Create())} } // NewBFMatcherWithParams creates a new BFMatchers but allows setting parameters // to values other than just the defaults. // // For further details, please see: // https://docs.opencv.org/master/d3/da1/classcv_1_1BFMatcher.html#abe0bb11749b30d97f60d6ade665617bd func NewBFMatcherWithParams(normType NormType, crossCheck bool) BFMatcher { return BFMatcher{p: unsafe.Pointer(C.BFMatcher_CreateWithParams(C.int(normType), C.bool(crossCheck)))} } // Close BFMatcher func (b *BFMatcher) Close() error { C.BFMatcher_Close((C.BFMatcher)(b.p)) b.p = nil return nil } // Match Finds the best match for each descriptor from a query set. // // For further details, please see: // https://docs.opencv.org/4.x/db/d39/classcv_1_1DescriptorMatcher.html#a0f046f47b68ec7074391e1e85c750cba func (b *BFMatcher) Match(query, train Mat) []DMatch { ret := C.BFMatcher_Match((C.BFMatcher)(b.p), query.p, train.p) defer C.DMatches_Close(ret) return getDMatches(ret) } // KnnMatch Finds the k best matches for each descriptor from a query set. // // For further details, please see: // https://docs.opencv.org/master/db/d39/classcv_1_1DescriptorMatcher.html#aa880f9353cdf185ccf3013e08210483a func (b *BFMatcher) KnnMatch(query, train Mat, k int) [][]DMatch { ret := C.BFMatcher_KnnMatch((C.BFMatcher)(b.p), query.p, train.p, C.int(k)) defer C.MultiDMatches_Close(ret) return getMultiDMatches(ret) } // FlannBasedMatcher is a wrapper around the the cv::FlannBasedMatcher algorithm type FlannBasedMatcher struct { // C.FlannBasedMatcher p unsafe.Pointer } // NewFlannBasedMatcher returns a new FlannBasedMatcher // // For further details, please see: // https://docs.opencv.org/master/dc/de2/classcv_1_1FlannBasedMatcher.html#ab9114a6471e364ad221f89068ca21382 func NewFlannBasedMatcher() FlannBasedMatcher { return FlannBasedMatcher{p: unsafe.Pointer(C.FlannBasedMatcher_Create())} } // Close FlannBasedMatcher func (f *FlannBasedMatcher) Close() error { C.FlannBasedMatcher_Close((C.FlannBasedMatcher)(f.p)) f.p = nil return nil } // KnnMatch Finds the k best matches for each descriptor from a query set. // // For further details, please see: // https://docs.opencv.org/master/db/d39/classcv_1_1DescriptorMatcher.html#aa880f9353cdf185ccf3013e08210483a func (f *FlannBasedMatcher) KnnMatch(query, train Mat, k int) [][]DMatch { ret := C.FlannBasedMatcher_KnnMatch((C.FlannBasedMatcher)(f.p), query.p, train.p, C.int(k)) defer C.MultiDMatches_Close(ret) return getMultiDMatches(ret) } func getMultiDMatches(ret C.MultiDMatches) [][]DMatch { cArray := ret.dmatches length := int(ret.length) hdr := reflect.SliceHeader{ Data: uintptr(unsafe.Pointer(cArray)), Len: length, Cap: length, } s := *(*[]C.DMatches)(unsafe.Pointer(&hdr)) keys := make([][]DMatch, length) for i := range s { keys[i] = getDMatches(C.MultiDMatches_get(ret, C.int(i))) } return keys } func getDMatches(ret C.DMatches) []DMatch { cArray := ret.dmatches length := int(ret.length) hdr := reflect.SliceHeader{ Data: uintptr(unsafe.Pointer(cArray)), Len: length, Cap: length, } s := *(*[]C.DMatch)(unsafe.Pointer(&hdr)) keys := make([]DMatch, length) for i, r := range s { keys[i] = DMatch{int(r.queryIdx), int(r.trainIdx), int(r.imgIdx), float64(r.distance)} } return keys } // DrawMatchesFlag are the flags setting drawing feature // // For further details please see: // https://docs.opencv.org/master/de/d30/structcv_1_1DrawMatchesFlags.html type DrawMatchesFlag int const ( // DrawDefault creates new image and for each keypoint only the center point will be drawn DrawDefault DrawMatchesFlag = 0 // DrawOverOutImg draws matches on existing content of image DrawOverOutImg DrawMatchesFlag = 1 // NotDrawSinglePoints will not draw single points NotDrawSinglePoints DrawMatchesFlag = 2 // DrawRichKeyPoints draws the circle around each keypoint with keypoint size and orientation DrawRichKeyPoints DrawMatchesFlag = 3 ) // DrawKeyPoints draws keypoints // // For further details please see: // https://docs.opencv.org/master/d4/d5d/group__features2d__draw.html#gab958f8900dd10f14316521c149a60433 func DrawKeyPoints(src Mat, keyPoints []KeyPoint, dst *Mat, color color.RGBA, flag DrawMatchesFlag) { cKeyPointArray := make([]C.struct_KeyPoint, len(keyPoints)) for i, kp := range keyPoints { cKeyPointArray[i].x = C.double(kp.X) cKeyPointArray[i].y = C.double(kp.Y) cKeyPointArray[i].size = C.double(kp.Size) cKeyPointArray[i].angle = C.double(kp.Angle) cKeyPointArray[i].response = C.double(kp.Response) cKeyPointArray[i].octave = C.int(kp.Octave) cKeyPointArray[i].classID = C.int(kp.ClassID) } cKeyPoints := C.struct_KeyPoints{ keypoints: (*C.struct_KeyPoint)(&cKeyPointArray[0]), length: (C.int)(len(keyPoints)), } scalar := C.struct_Scalar{ val1: C.double(color.B), val2: C.double(color.G), val3: C.double(color.R), val4: C.double(color.A), } C.DrawKeyPoints(src.p, cKeyPoints, dst.p, scalar, C.int(flag)) } // SIFT is a wrapper around the cv::SIFT algorithm. // Due to the patent having expired, this is now in the main OpenCV code modules. type SIFT struct { // C.SIFT p unsafe.Pointer } var _ Feature2D = (*SIFT)(nil) // NewSIFT returns a new SIFT algorithm. // // For further details, please see: // https://docs.opencv.org/master/d5/d3c/classcv_1_1xfeatures2d_1_1SIFT.html func NewSIFT() SIFT { return SIFT{p: unsafe.Pointer(C.SIFT_Create())} } func NewSIFTWithParams(nfeatures *int, nOctaveLayers *int, contrastThreshold *float64, edgeThreshold *float64, sigma *float64) SIFT { numFeatures := 0 if nfeatures != nil { numFeatures = *nfeatures } numOctaveLayers := 3 if nOctaveLayers != nil { numOctaveLayers = *nOctaveLayers } var numContrastThreshold float64 = 0.04 if contrastThreshold != nil { numContrastThreshold = *contrastThreshold } var numEdgeThreshold float64 = 10 if edgeThreshold != nil { numEdgeThreshold = *edgeThreshold } var numSigma float64 = 1.6 if sigma != nil { numSigma = *sigma } return SIFT{p: unsafe.Pointer(C.SIFT_CreateWithParams(C.int(numFeatures), C.int(numOctaveLayers), C.double(numContrastThreshold), C.double(numEdgeThreshold), C.double(numSigma)))} } // Close SIFT. func (d *SIFT) Close() error { C.SIFT_Close((C.SIFT)(d.p)) d.p = nil return nil } // Detect keypoints in an image using SIFT. // // For further details, please see: // https://docs.opencv.org/master/d0/d13/classcv_1_1Feature2D.html#aa4e9a7082ec61ebc108806704fbd7887 func (d *SIFT) Detect(src Mat) []KeyPoint { ret := C.SIFT_Detect((C.SIFT)(d.p), C.Mat(src.Ptr())) defer C.KeyPoints_Close(ret) return getKeyPoints(ret) } // Compute keypoints in an image using SIFT. // // For further details, please see: // https://docs.opencv.org/4.x/d0/d13/classcv_1_1Feature2D.html#ab3cce8d56f4fc5e1d530b5931e1e8dc0 func (d *SIFT) Compute(src Mat, mask Mat, kps []KeyPoint) ([]KeyPoint, Mat) { desc := NewMat() kp2arr := make([]C.struct_KeyPoint, len(kps)) for i, kp := range kps { kp2arr[i].x = C.double(kp.X) kp2arr[i].y = C.double(kp.Y) kp2arr[i].size = C.double(kp.Size) kp2arr[i].angle = C.double(kp.Angle) kp2arr[i].response = C.double(kp.Response) kp2arr[i].octave = C.int(kp.Octave) kp2arr[i].classID = C.int(kp.ClassID) } cKeyPoints := C.struct_KeyPoints{ keypoints: (*C.struct_KeyPoint)(&kp2arr[0]), length: (C.int)(len(kps)), } ret := C.SIFT_Compute((C.SIFT)(d.p), src.p, cKeyPoints, desc.p) defer C.KeyPoints_Close(ret) return getKeyPoints(ret), desc } // DetectAndCompute detects and computes keypoints in an image using SIFT. // // For further details, please see: // https://docs.opencv.org/master/d0/d13/classcv_1_1Feature2D.html#a8be0d1c20b08eb867184b8d74c15a677 func (d *SIFT) DetectAndCompute(src Mat, mask Mat) ([]KeyPoint, Mat) { desc := NewMat() ret := C.SIFT_DetectAndCompute((C.SIFT)(d.p), C.Mat(src.Ptr()), C.Mat(mask.Ptr()), C.Mat(desc.Ptr())) defer C.KeyPoints_Close(ret) return getKeyPoints(ret), desc } // DrawMatches draws matches on combined train and querry images. // // For further details, please see: // https://docs.opencv.org/master/d4/d5d/group__features2d__draw.html#gad8f463ccaf0dc6f61083abd8717c261a func DrawMatches(img1 Mat, kp1 []KeyPoint, img2 Mat, kp2 []KeyPoint, matches1to2 []DMatch, outImg *Mat, matchColor color.RGBA, singlePointColor color.RGBA, matchesMask []byte, flags DrawMatchesFlag) { kp1arr := make([]C.struct_KeyPoint, len(kp1)) kp2arr := make([]C.struct_KeyPoint, len(kp2)) for i, kp := range kp1 { kp1arr[i].x = C.double(kp.X) kp1arr[i].y = C.double(kp.Y) kp1arr[i].size = C.double(kp.Size) kp1arr[i].angle = C.double(kp.Angle) kp1arr[i].response = C.double(kp.Response) kp1arr[i].octave = C.int(kp.Octave) kp1arr[i].classID = C.int(kp.ClassID) } for i, kp := range kp2 { kp2arr[i].x = C.double(kp.X) kp2arr[i].y = C.double(kp.Y) kp2arr[i].size = C.double(kp.Size) kp2arr[i].angle = C.double(kp.Angle) kp2arr[i].response = C.double(kp.Response) kp2arr[i].octave = C.int(kp.Octave) kp2arr[i].classID = C.int(kp.ClassID) } cKeyPoints1 := C.struct_KeyPoints{ keypoints: (*C.struct_KeyPoint)(&kp1arr[0]), length: (C.int)(len(kp1)), } cKeyPoints2 := C.struct_KeyPoints{ keypoints: (*C.struct_KeyPoint)(&kp2arr[0]), length: (C.int)(len(kp2)), } dMatchArr := make([]C.struct_DMatch, len(matches1to2)) for i, dm := range matches1to2 { dMatchArr[i].queryIdx = C.int(dm.QueryIdx) dMatchArr[i].trainIdx = C.int(dm.TrainIdx) dMatchArr[i].imgIdx = C.int(dm.ImgIdx) dMatchArr[i].distance = C.float(dm.Distance) } cDMatches := C.struct_DMatches{ dmatches: (*C.struct_DMatch)(&dMatchArr[0]), length: (C.int)(len(matches1to2)), } scalarMatchColor := C.struct_Scalar{ val1: C.double(matchColor.R), val2: C.double(matchColor.G), val3: C.double(matchColor.B), val4: C.double(matchColor.A), } scalarPointColor := C.struct_Scalar{ val1: C.double(singlePointColor.B), val2: C.double(singlePointColor.G), val3: C.double(singlePointColor.R), val4: C.double(singlePointColor.A), } mask := make([]C.char, len(matchesMask)) cByteArray := C.struct_ByteArray{ length: (C.int)(len(matchesMask)), } if len(matchesMask) > 0 { cByteArray = C.struct_ByteArray{ data: (*C.char)(&mask[0]), length: (C.int)(len(matchesMask)), } } C.DrawMatches(img1.p, cKeyPoints1, img2.p, cKeyPoints2, cDMatches, outImg.p, scalarMatchColor, scalarPointColor, cByteArray, C.int(flags)) } ================================================ FILE: features2d.h ================================================ #ifndef _OPENCV3_FEATURES2D_H_ #define _OPENCV3_FEATURES2D_H_ #ifdef __cplusplus #include extern "C" { #endif #include "core.h" #ifdef __cplusplus typedef cv::Ptr* AKAZE; typedef cv::Ptr* AgastFeatureDetector; typedef cv::Ptr* BRISK; typedef cv::Ptr* FastFeatureDetector; typedef cv::Ptr* GFTTDetector; typedef cv::Ptr* KAZE; typedef cv::Ptr* MSER; typedef cv::Ptr* ORB; typedef cv::Ptr* SimpleBlobDetector; typedef cv::Ptr* BFMatcher; typedef cv::Ptr* FlannBasedMatcher; typedef cv::Ptr* SIFT; #else typedef void* AKAZE; typedef void* AgastFeatureDetector; typedef void* BRISK; typedef void* FastFeatureDetector; typedef void* GFTTDetector; typedef void* KAZE; typedef void* MSER; typedef void* ORB; typedef void* SimpleBlobDetector; typedef void* BFMatcher; typedef void* FlannBasedMatcher; typedef void* SIFT; #endif AKAZE AKAZE_Create(); AKAZE AKAZE_CreateWithParams(int descriptor_type, int descriptor_size, int descriptor_channels, float threshold, int nOctaves, int nOctaveLayers, int diffusivity); void AKAZE_Close(AKAZE a); struct KeyPoints AKAZE_Detect(AKAZE a, Mat src); struct KeyPoints AKAZE_Compute(AKAZE a, Mat src, struct KeyPoints kp, Mat desc); struct KeyPoints AKAZE_DetectAndCompute(AKAZE a, Mat src, Mat mask, Mat desc); AgastFeatureDetector AgastFeatureDetector_Create(); AgastFeatureDetector AgastFeatureDetector_CreateWithParams(int threshold, bool nonmaxSuppression, int type); void AgastFeatureDetector_Close(AgastFeatureDetector a); struct KeyPoints AgastFeatureDetector_Detect(AgastFeatureDetector a, Mat src); BRISK BRISK_Create(); BRISK BRISK_CreateWithParams(int thresh, int octaves, float patternScale); void BRISK_Close(BRISK b); struct KeyPoints BRISK_Detect(BRISK b, Mat src); struct KeyPoints BRISK_Compute(BRISK b, Mat src, struct KeyPoints kp, Mat desc); struct KeyPoints BRISK_DetectAndCompute(BRISK b, Mat src, Mat mask, Mat desc); FastFeatureDetector FastFeatureDetector_Create(); FastFeatureDetector FastFeatureDetector_CreateWithParams(int threshold, bool nonmaxSuppression, int type); void FastFeatureDetector_Close(FastFeatureDetector f); struct KeyPoints FastFeatureDetector_Detect(FastFeatureDetector f, Mat src); GFTTDetector GFTTDetector_Create(); GFTTDetector GFTTDetector_Create_WithParams(const struct GFTTDetectorParams* params); void GFTTDetector_Close(GFTTDetector a); struct KeyPoints GFTTDetector_Detect(GFTTDetector a, Mat src); KAZE KAZE_Create(); KAZE KAZE_CreateWithParams(bool extended, bool upright, float threshold, int nOctaves, int nOctaveLayers, int diffusivity); void KAZE_Close(KAZE a); struct KeyPoints KAZE_Detect(KAZE a, Mat src); struct KeyPoints KAZE_Compute(KAZE a, Mat src, struct KeyPoints kp, Mat desc); struct KeyPoints KAZE_DetectAndCompute(KAZE a, Mat src, Mat mask, Mat desc); MSER MSER_Create(); MSER MSER_CreateWithParams(int delta, int min_area, int max_area, double max_variation, double min_diversity, int max_evolution, double area_threshold, double min_margin, int edge_blur_size); void MSER_Close(MSER a); struct KeyPoints MSER_Detect(MSER a, Mat src); ORB ORB_Create(); ORB ORB_CreateWithParams(int nfeatures, float scaleFactor, int nlevels, int edgeThreshold, int firstLevel, int WTA_K, int scoreType, int patchSize, int fastThreshold); void ORB_Close(ORB o); struct KeyPoints ORB_Detect(ORB o, Mat src); struct KeyPoints ORB_Compute(ORB o, Mat src, struct KeyPoints kp, Mat desc); struct KeyPoints ORB_DetectAndCompute(ORB o, Mat src, Mat mask, Mat desc); SimpleBlobDetector SimpleBlobDetector_Create(); SimpleBlobDetector SimpleBlobDetector_Create_WithParams(SimpleBlobDetectorParams params); void SimpleBlobDetector_Close(SimpleBlobDetector b); struct KeyPoints SimpleBlobDetector_Detect(SimpleBlobDetector b, Mat src); SimpleBlobDetectorParams SimpleBlobDetectorParams_Create(); BFMatcher BFMatcher_Create(); BFMatcher BFMatcher_CreateWithParams(int normType, bool crossCheck); void BFMatcher_Close(BFMatcher b); struct DMatches BFMatcher_Match(BFMatcher b, Mat query, Mat train); struct MultiDMatches BFMatcher_KnnMatch(BFMatcher b, Mat query, Mat train, int k); FlannBasedMatcher FlannBasedMatcher_Create(); void FlannBasedMatcher_Close(FlannBasedMatcher f); struct MultiDMatches FlannBasedMatcher_KnnMatch(FlannBasedMatcher f, Mat query, Mat train, int k); void DrawKeyPoints(Mat src, struct KeyPoints kp, Mat dst, const Scalar s, int flags); SIFT SIFT_Create(); SIFT SIFT_CreateWithParams(int nfeatures, int nOctaveLayers, double contrastThreshold, double edgeThreshold, double sigma); void SIFT_Close(SIFT f); struct KeyPoints SIFT_Detect(SIFT f, Mat src); struct KeyPoints SIFT_Compute(SIFT f, Mat src, struct KeyPoints kp, Mat desc); struct KeyPoints SIFT_DetectAndCompute(SIFT f, Mat src, Mat mask, Mat desc); void DrawMatches(Mat img1, struct KeyPoints kp1, Mat img2, struct KeyPoints kp2, struct DMatches matches1to2, Mat outImg, const Scalar matchesColor, const Scalar pointColor, struct ByteArray matchesMask, int flags); #ifdef __cplusplus } #endif #endif //_OPENCV3_FEATURES2D_H_ ================================================ FILE: features2d_string.go ================================================ //go:build !gocv_specific_modules || (gocv_specific_modules && gocv_features2d) package gocv /* #include #include "features2d.h" */ import "C" func (c FastFeatureDetectorType) String() string { switch c { case FastFeatureDetectorType58: return "fast-feature-detector-type-58" case FastFeatureDetectorType712: return "fast-feature-detector-type-712" case FastFeatureDetectorType916: return "fast-feature-detector-type-916" } return "" } func (c DrawMatchesFlag) String() string { switch c { case DrawDefault: return "draw-default" case DrawOverOutImg: return "draw-over-out-imt" case NotDrawSinglePoints: return "draw-single-points" case DrawRichKeyPoints: return "draw-rich-key-points" } return "" } ================================================ FILE: features2d_test.go ================================================ //go:build !gocv_specific_modules || (gocv_specific_modules && gocv_features2d) package gocv import ( "image/color" "runtime" "testing" ) func TestAKAZE(t *testing.T) { img := IMRead("images/face.jpg", IMReadColor) if img.Empty() { t.Error("Invalid Mat in AKAZE test") } defer img.Close() dst := NewMat() defer dst.Close() ak := NewAKAZE() defer ak.Close() kp := ak.Detect(img) if len(kp) < 512 { t.Errorf("Invalid KeyPoint array in AKAZE test: %d", len(kp)) } mask := NewMat() defer mask.Close() kpc, desc := ak.Compute(img, mask, kp) defer desc.Close() if len(kpc) < 512 { t.Errorf("Invalid KeyPoint array in AKAZE Compute: %d", len(kpc)) } if desc.Empty() { t.Error("Invalid Mat desc in AKAZE Compute") } kpdc, desc2 := ak.DetectAndCompute(img, mask) defer desc2.Close() if len(kpdc) < 512 { t.Errorf("Invalid KeyPoint array in AKAZE DetectAndCompute: %d", len(kpdc)) } if desc2.Empty() { t.Error("Invalid Mat desc in AKAZE DetectAndCompute") } } func TestAKAZEWithParams(t *testing.T) { img := IMRead("images/face.jpg", IMReadColor) if img.Empty() { t.Error("Invalid Mat in AKAZE test") } defer img.Close() dst := NewMat() defer dst.Close() ak := NewAKAZEWithParams(3, 0, 3, 0.001, 4, 4, 1) defer ak.Close() // Test Detect method kp := ak.Detect(img) if len(kp) < 473 { t.Errorf("Invalid KeyPoint array in AKAZE test: %d", len(kp)) } mask := NewMat() defer mask.Close() kpc, desc := ak.Compute(img, mask, kp) defer desc.Close() if len(kpc) < 473 { t.Errorf("Invalid KeyPoint array in AKAZE Compute: %d", len(kpc)) } if desc.Empty() { t.Error("Invalid Mat desc in AKAZE Compute") } kpdc, desc2 := ak.DetectAndCompute(img, mask) defer desc2.Close() if len(kpdc) < 473 { t.Errorf("Invalid KeyPoint array in AKAZE DetectAndCompute: %d", len(kpdc)) } if desc2.Empty() { t.Error("Invalid Mat desc in AKAZE DetectAndCompute") } } func TestAgastFeatureDetector(t *testing.T) { img := IMRead("images/face.jpg", IMReadColor) if img.Empty() { t.Error("Invalid Mat in AgastFeatureDetector test") } defer img.Close() dst := NewMat() defer dst.Close() ad := NewAgastFeatureDetector() defer ad.Close() kp := ad.Detect(img) if len(kp) < 2800 { t.Errorf("Invalid KeyPoint array in AgastFeatureDetector test: %d", len(kp)) } } func TestAgastFeatureDetectorWithParams(t *testing.T) { img := IMRead("images/face.jpg", IMReadColor) if img.Empty() { t.Error("Invalid Mat in AgastFeatureDetector test") } defer img.Close() dst := NewMat() defer dst.Close() ad := NewAgastFeatureDetectorWithParams(10, true, 0) defer ad.Close() kp := ad.Detect(img) if len(kp) < 2137 { t.Errorf("Invalid KeyPoint array in AgastFeatureDetector test: %d", len(kp)) } } func TestBRISK(t *testing.T) { img := IMRead("images/face.jpg", IMReadColor) if img.Empty() { t.Error("Invalid Mat in BRISK test") } defer img.Close() dst := NewMat() defer dst.Close() br := NewBRISK() defer br.Close() kp := br.Detect(img) if len(kp) < 513 { t.Errorf("Invalid KeyPoint array in BRISK Detect: %d", len(kp)) } mask := NewMat() defer mask.Close() kpc, desc := br.Compute(img, mask, kp) defer desc.Close() if len(kpc) < 512 { t.Errorf("Invalid KeyPoint array in BRISK Compute: %d", len(kpc)) } if desc.Empty() { t.Error("Invalid Mat desc in BRISK Compute") } kpdc, desc2 := br.DetectAndCompute(img, mask) defer desc2.Close() if len(kpdc) < 512 { t.Errorf("Invalid KeyPoint array in BRISK DetectAndCompute: %d", len(kpdc)) } if desc2.Empty() { t.Error("Invalid Mat desc in BRISK DetectAndCompute") } } func TestBRISKWithParams(t *testing.T) { img := IMRead("images/face.jpg", IMReadColor) if img.Empty() { t.Error("Invalid Mat in BRISK test") } defer img.Close() dst := NewMat() defer dst.Close() // Create BRISK with custom parameters (e.g., threshold = 30, octaves = 3, patternScale = 1.0) br := NewBRISKWithParams(30, 3, 1.0) defer br.Close() kp := br.Detect(img) if len(kp) < 513 { t.Errorf("Invalid KeyPoint array in BRISK Detect: %d", len(kp)) } mask := NewMat() defer mask.Close() kpc, desc := br.Compute(img, mask, kp) defer desc.Close() if len(kpc) < 512 { t.Errorf("Invalid KeyPoint array in BRISK Compute: %d", len(kpc)) } if desc.Empty() { t.Error("Invalid Mat desc in BRISK Compute") } kpdc, desc2 := br.DetectAndCompute(img, mask) defer desc2.Close() if len(kpdc) < 512 { t.Errorf("Invalid KeyPoint array in BRISK DetectAndCompute: %d", len(kpdc)) } if desc2.Empty() { t.Error("Invalid Mat desc in BRISK DetectAndCompute") } } func TestFastFeatureDetector(t *testing.T) { img := IMRead("images/face.jpg", IMReadColor) if img.Empty() { t.Error("Invalid Mat in FastFeatureDetector test") } defer img.Close() dst := NewMat() defer dst.Close() fd := NewFastFeatureDetector() defer fd.Close() kp := fd.Detect(img) if len(kp) < 2690 { t.Errorf("Invalid KeyPoint array in FastFeatureDetector test: %d", len(kp)) } } func TestFastFeatureDetectorWithParams(t *testing.T) { img := IMRead("images/face.jpg", IMReadColor) if img.Empty() { t.Error("Invalid Mat in FastFeatureDetector test") } defer img.Close() dst := NewMat() defer dst.Close() fd := NewFastFeatureDetectorWithParams(10, true, FastFeatureDetectorType916) defer fd.Close() kp := fd.Detect(img) if len(kp) < 2690 { t.Errorf("Invalid KeyPoint array in FastFeatureDetector test: %d", len(kp)) } } func TestGFTTDetector(t *testing.T) { img := IMRead("images/face.jpg", IMReadColor) if img.Empty() { t.Error("Invalid Mat in GFTTDetector test") } defer img.Close() dst := NewMat() defer dst.Close() gft := NewGFTTDetector() defer gft.Close() kp := gft.Detect(img) if len(kp) < 512 { t.Errorf("Invalid KeyPoint array in GFTTDetector test: %d", len(kp)) } } func TestGFTTDetectorWithParams(t *testing.T) { img := IMRead("images/face.jpg", IMReadColor) if img.Empty() { t.Error("Invalid Mat in GFTTDetector test") } defer img.Close() dst := NewMat() defer dst.Close() params := GFTTDetectorParams{ MaxCorners: 500, QualityLevel: 0.01, MinDistance: 10, BlockSize: 3, UseHarrisDetector: false, K: 0.04, } gft := NewGFTTDetectorWithParams(params) defer gft.Close() kp := gft.Detect(img) if len(kp) < 323 { t.Errorf("Invalid KeyPoint array in GFTTDetector test: %d", len(kp)) } } func TestKAZE(t *testing.T) { img := IMRead("images/face.jpg", IMReadColor) if img.Empty() { t.Error("Invalid Mat in KAZE test") } defer img.Close() dst := NewMat() defer dst.Close() k := NewKAZE() defer k.Close() kp := k.Detect(img) if len(kp) < 512 { t.Errorf("Invalid KeyPoint array in KAZE test: %d", len(kp)) } mask := NewMat() defer mask.Close() kpc, desc := k.Compute(img, mask, kp) defer desc.Close() if len(kpc) < 512 { t.Errorf("Invalid KeyPoint array in KAZE Compute: %d", len(kpc)) } if desc.Empty() { t.Error("Invalid Mat desc in KAZE Compute") } kpdc, desc2 := k.DetectAndCompute(img, mask) defer desc2.Close() if len(kpdc) < 512 { t.Errorf("Invalid KeyPoint array in KAZE DetectAndCompute: %d", len(kpdc)) } if desc2.Empty() { t.Error("Invalid Mat desc in KAZE DetectAndCompute") } } func TestKAZEWithParams(t *testing.T) { // Load the image for testing img := IMRead("images/face.jpg", IMReadColor) if img.Empty() { t.Error("Invalid Mat in KAZE With Params test") } defer img.Close() // Create a destination matrix dst := NewMat() defer dst.Close() // Set up the parameters for KAZE with the function NewKazeWithParams extended := true upright := false threshold := float32(0.001) nOctaves := 4 nOctaveLayers := 4 diffusivity := 1 // Based on your input parameter options (e.g., 1 could be for `cv::KAZE::DIFF_PM_G2`) // Create a KAZE object with the specified parameters k := NewKazeWithParams(extended, upright, threshold, nOctaves, nOctaveLayers, diffusivity) defer k.Close() // Detect keypoints kp := k.Detect(img) if len(kp) < 512 { t.Errorf("Invalid KeyPoint array in KAZE With Params test: %d", len(kp)) } // Create a mask (optional) mask := NewMat() defer mask.Close() // Compute descriptors for the keypoints kpc, desc := k.Compute(img, mask, kp) defer desc.Close() if len(kpc) < 512 { t.Errorf("Invalid KeyPoint array in KAZE With Params Compute: %d", len(kpc)) } if desc.Empty() { t.Error("Invalid Mat desc in KAZE With Params Compute") } // Perform DetectAndCompute kpdc, desc2 := k.DetectAndCompute(img, mask) defer desc2.Close() if len(kpdc) < 512 { t.Errorf("Invalid KeyPoint array in KAZE With Params DetectAndCompute: %d", len(kpdc)) } if desc2.Empty() { t.Error("Invalid Mat desc in KAZE With Params DetectAndCompute") } } func TestMSER(t *testing.T) { img := IMRead("images/face.jpg", IMReadColor) if img.Empty() { t.Error("Invalid Mat in MSER test") } defer img.Close() dst := NewMat() defer dst.Close() mser := NewMSER() defer mser.Close() kp := mser.Detect(img) if len(kp) == 0 { t.Errorf("Invalid KeyPoint array in MSER test: %d", len(kp)) } } func TestMSERWithParams(t *testing.T) { img := IMRead("images/face.jpg", IMReadColor) if img.Empty() { t.Error("Invalid Mat in MSER With Params test") } defer img.Close() dst := NewMat() defer dst.Close() delta := 5 minArea := 60 maxArea := 14400 maxVariation := 0.25 minDiversity := 0.2 maxEvolution := 200 areaThreshold := 1.01 minMargin := 0.003 edgeBlurSize := 5 mser := NewMSERWithParams(delta, minArea, maxArea, maxVariation, minDiversity, maxEvolution, areaThreshold, minMargin, edgeBlurSize) defer mser.Close() regions := mser.Detect(img) if len(regions) == 0 { t.Errorf("Invalid region detection in MSER With Params test: %d", len(regions)) } } func TestORB(t *testing.T) { img := IMRead("images/face.jpg", IMReadColor) if img.Empty() { t.Error("Invalid Mat in AgastFeatureDetector test") } defer img.Close() dst := NewMat() defer dst.Close() od := NewORB() defer od.Close() kp := od.Detect(img) if len(kp) != 500 { t.Errorf("Invalid KeyPoint array in ORB test: %d", len(kp)) } mask := NewMat() defer mask.Close() kpc, desc := od.Compute(img, mask, kp) defer desc.Close() if len(kpc) < 500 { t.Errorf("Invalid KeyPoint array in ORB Compute: %d", len(kpc)) } if desc.Empty() { t.Error("Invalid Mat desc in ORB Compute") } kpdc, desc2 := od.DetectAndCompute(img, mask) defer desc2.Close() if len(kpdc) < 500 { t.Errorf("Invalid KeyPoint array in ORB DetectAndCompute: %d", len(kpdc)) } if desc2.Empty() { t.Error("Invalid Mat desc in ORB DetectAndCompute") } } func TestSimpleBlobDetector(t *testing.T) { img := IMRead("images/face.jpg", IMReadColor) if img.Empty() { t.Error("Invalid Mat in SimpleBlobDetector test") } defer img.Close() dst := NewMat() defer dst.Close() bd := NewSimpleBlobDetector() defer bd.Close() kp := bd.Detect(img) if len(kp) != 2 { t.Errorf("Invalid KeyPoint array in SimpleBlobDetector test: %d", len(kp)) } } func TestSimpleBlobDetectorWithParams(t *testing.T) { img := IMRead("images/circles.jpg", IMReadColor) if img.Empty() { t.Error("Invalid Mat in SimpleBlobDetector test") } defer img.Close() params := NewSimpleBlobDetectorParams() params.SetMaxArea(27500.0) bdp := NewSimpleBlobDetectorWithParams(params) defer bdp.Close() kp := bdp.Detect(img) if len(kp) != 4 { t.Errorf("Invalid KeyPoint array in SimpleBlobDetector test: %d", len(kp)) } } func TestSimpleBlobDetectorParams(t *testing.T) { float64EqualityThreshold := 1e-5 knownBlobColor := 235 knownFilterByArea := false knownFilterByCircularity := true knownFilterByColor := false knownFilterByConvexity := false knownFilterByInertia := false knownMaxArea := 20000.0 knownMaxCircularity := 0.99 knownMaxConvexity := 0.98 knownMaxInertiaRatio := 0.97 knownMaxThreshold := 233.0 knownMinArea := 230.0 knownMinCircularity := 0.9 knownMinConvexity := 0.89 knownMinDistBetweenBlobs := 15.5 knownMinInertiaRatio := 0.88 knownMinRepeatability := 5 knownMinThreshold := 200.0 knownThresholdStep := 2.0 params := NewSimpleBlobDetectorParams() params.SetBlobColor(knownBlobColor) params.SetFilterByArea(knownFilterByArea) params.SetFilterByCircularity(knownFilterByCircularity) params.SetFilterByColor(knownFilterByColor) params.SetFilterByConvexity(knownFilterByConvexity) params.SetFilterByInertia(knownFilterByInertia) params.SetMaxArea(knownMaxArea) params.SetMaxCircularity(knownMaxCircularity) params.SetMaxConvexity(knownMaxConvexity) params.SetMaxInertiaRatio(knownMaxInertiaRatio) params.SetMaxThreshold(knownMaxThreshold) params.SetMinArea(knownMinArea) params.SetMinCircularity(knownMinCircularity) params.SetMinConvexity(knownMinConvexity) params.SetMinDistBetweenBlobs(knownMinDistBetweenBlobs) params.SetMinInertiaRatio(knownMinInertiaRatio) params.SetMinRepeatability(knownMinRepeatability) params.SetMinThreshold(knownMinThreshold) params.SetThresholdStep(knownThresholdStep) if params.GetBlobColor() != knownBlobColor { t.Error("BlobColor incorrect in SimpleBlobDetectorParams test") } if params.GetFilterByArea() != knownFilterByArea { t.Error("FilterByArea incorrect in SimpleBlobDetectorParams test") } if params.GetFilterByCircularity() != knownFilterByCircularity { t.Error("FilterByCircularity incorrect in SimpleBlobDetectorParams test") } if params.GetFilterByColor() != knownFilterByColor { t.Error("FilterByColor incorrect in SimpleBlobDetectorParams test") } if params.GetFilterByConvexity() != knownFilterByConvexity { t.Error("FilterByConvexity incorrect in SimpleBlobDetectorParams test") } if params.GetFilterByInertia() != knownFilterByInertia { t.Error("FilterByInertia incorrect in SimpleBlobDetectorParams test") } if params.GetMaxArea() != knownMaxArea { t.Error("MaxArea incorrect in SimpleBlobDetectorParams test") } diffMaxCircularity := params.GetMaxCircularity() - knownMaxCircularity if diffMaxCircularity > float64EqualityThreshold { t.Errorf("DiffMaxCircularity greater than float64EqualityThreshold in SimpleBlobDetectorParams test. Diff: %f", diffMaxCircularity) } diffMaxConvexity := params.GetMaxConvexity() - knownMaxConvexity if diffMaxConvexity > float64EqualityThreshold { t.Errorf("DiffMaxConvexity greater than float64EqualityThreshold in SimpleBlobDetectorParams test. Diff: %f", diffMaxConvexity) } diffMaxInertiaRatio := params.GetMaxInertiaRatio() - knownMaxInertiaRatio if diffMaxInertiaRatio > float64EqualityThreshold { t.Errorf("DiffMaxInertiaRatio greater than float64EqualityThreshold in SimpleBlobDetectorParams test. Diff: %f", diffMaxInertiaRatio) } if params.GetMaxThreshold() != knownMaxThreshold { t.Error("MaxThreshold incorrect in SimpleBlobDetectorParams test") } if params.GetMinArea() != knownMinArea { t.Error("MinArea incorrect in SimpleBlobDetectorParams test") } diffMinCircularity := params.GetMinCircularity() - knownMinCircularity if diffMinCircularity > float64EqualityThreshold { t.Errorf("DiffMinCircularity greater than float64EqualityThreshold in SimpleBlobDetectorParams test. Diff %f", diffMinCircularity) } diffMinConvexity := params.GetMinConvexity() - knownMinConvexity if diffMinConvexity > float64EqualityThreshold { t.Errorf("DiffMinConvexity greater than float64EqualityThreshold in SimpleBlobDetectorParams test. Diff: %f", diffMinConvexity) } if params.GetMinDistBetweenBlobs() != knownMinDistBetweenBlobs { t.Error("MinDistBetweenBlobs incorrect in SimpleBlobDetectorParams test") } diffMinInertiaRatio := params.GetMinInertiaRatio() - knownMinInertiaRatio if diffMinInertiaRatio > float64EqualityThreshold { t.Errorf("DiffMinInertiaRatio greater than float64EqualityThreshold in SimpleBlobDetectorParams test. Diff: %f", diffMinInertiaRatio) } if params.GetMinRepeatability() != knownMinRepeatability { t.Error("MinRepeatability incorrect in SimpleBlobDetectorParams test") } if params.GetMinThreshold() != knownMinThreshold { t.Error("MinThreshold incorrect in SimpleBlobDetectorParams test") } if params.GetThresholdStep() != knownThresholdStep { t.Error("ThresholdStep incorrect in SimpleBlobDetectorParams test") } } func TestBFMatcher(t *testing.T) { descriptorFile := "images/sift_descriptor.png" desc1 := IMRead(descriptorFile, IMReadGrayScale) if desc1.Empty() { t.Error("descriptor one is empty in BFMatcher test") } defer desc1.Close() desc2 := IMRead(descriptorFile, IMReadGrayScale) if desc2.Empty() { t.Error("descriptor two is empty in BFMatcher test") } defer desc2.Close() bf := NewBFMatcher() defer bf.Close() k := 2 dMatches := bf.KnnMatch(desc1, desc2, k) if len(dMatches) < 1 { t.Errorf("DMatches was excepted to have at least one element") } for i := range dMatches { if len(dMatches[i]) != k { t.Errorf("Length does not match k cluster amount in BFMatcher") } } matches := bf.Match(desc1, desc2) if len(matches) != 890 { t.Errorf("Matches was excepted to have 890 elements, but it has %d", len(matches)) } bfParams := NewBFMatcherWithParams(NormHamming, false) defer bfParams.Close() dMatches = bfParams.KnnMatch(desc1, desc2, k) if len(dMatches) < 1 { t.Errorf("DMatches was excepted to have at least one element") } for i := range dMatches { if len(dMatches[i]) != k { t.Errorf("Length does not match k cluster amount in BFMatcher") } } } func TestFlannBasedMatcher(t *testing.T) { descriptorFile := "images/sift_descriptor.png" desc1 := IMRead(descriptorFile, IMReadGrayScale) if desc1.Empty() { t.Error("descriptor one is empty in FlannBasedMatcher test") } defer desc1.Close() desc1.ConvertTo(&desc1, MatTypeCV32F) desc2 := IMRead(descriptorFile, IMReadGrayScale) if desc2.Empty() { t.Error("descriptor two is empty in FlannBasedMatcher test") } defer desc2.Close() desc2.ConvertTo(&desc2, MatTypeCV32F) f := NewFlannBasedMatcher() defer f.Close() k := 2 dMatches := f.KnnMatch(desc1, desc2, k) if len(dMatches) < 1 { t.Errorf("DMatches was excepted to have at least one element") } for i := range dMatches { if len(dMatches[i]) != k { t.Errorf("Length does not match k cluster amount in FlannBasedMatcher") } } } func TestDrawKeyPoints(t *testing.T) { keypointsFile := "images/simple.jpg" img := IMRead(keypointsFile, IMReadColor) if img.Empty() { t.Error("keypoints file is empty in DrawKeyPoints test") } defer img.Close() ffd := NewFastFeatureDetector() kp := ffd.Detect(img) simpleKP := NewMat() defer simpleKP.Close() DrawKeyPoints(img, kp, &simpleKP, color.RGBA{255, 0, 0, 0}, DrawDefault) if simpleKP.Rows() != img.Rows() || simpleKP.Cols() != img.Cols() { t.Error("Invalid DrawKeyPoints test") } } func TestDrawMatches(t *testing.T) { if runtime.GOOS == "darwin" { t.Skip("skipping test on macos") } queryFile := "images/box.png" trainFile := "images/box_in_scene.png" query := IMRead(queryFile, IMReadGrayScale) train := IMRead(trainFile, IMReadGrayScale) if query.Empty() || train.Empty() { t.Error("at least one of files is empty in DrawMatches test") } defer query.Close() defer train.Close() sift := NewSIFT() defer sift.Close() m1 := NewMat() m2 := NewMat() defer m1.Close() defer m2.Close() kp1, des1 := sift.DetectAndCompute(query, m1) kp2, des2 := sift.DetectAndCompute(train, m2) defer des1.Close() defer des2.Close() bf := NewBFMatcher() defer bf.Close() matches := bf.KnnMatch(des1, des2, 2) if len(matches) == 0 { t.Error("no matches found in DrawMatches test") } var good []DMatch for _, m := range matches { if len(m) > 1 { if m[0].Distance < 0.75*m[1].Distance { good = append(good, m[0]) } } } c := color.RGBA{ R: 255, G: 0, B: 0, A: 0, } mask := make([]byte, 0) out := NewMat() defer out.Close() DrawMatches(query, kp1, train, kp2, good, &out, c, c, mask, DrawDefault) if out.Cols() != (query.Cols()+train.Cols()) || out.Rows() < train.Rows() || out.Rows() < query.Rows() { t.Error("Invalid DrawMatches test") } mask = make([]byte, len(good)) smoke := NewMat() defer smoke.Close() DrawMatches(query, kp1, train, kp2, good, &smoke, c, c, mask, DrawDefault) } func TestSIFT(t *testing.T) { if runtime.GOOS == "darwin" { t.Skip("skipping test on macos") } img := IMRead("./images/face.jpg", IMReadGrayScale) if img.Empty() { t.Error("Invalid Mat in SIFT test") } defer img.Close() dst := NewMat() defer dst.Close() si := NewSIFT() defer si.Close() kp := si.Detect(img) if len(kp) == 512 { t.Errorf("Invalid KeyPoint array in SIFT test: %d", len(kp)) } mask := NewMat() defer mask.Close() kpc, desc := si.Compute(img, mask, kp) defer desc.Close() if len(kpc) < 512 { t.Errorf("Invalid KeyPoint array in SIFT Compute: %d", len(kpc)) } if desc.Empty() { t.Error("Invalid Mat desc in SIFT Compute") } kpdc, desc2 := si.DetectAndCompute(img, mask) defer desc2.Close() if len(kpdc) < 512 { t.Errorf("Invalid KeyPoint array in SIFT DetectAndCompute: %d", len(kpdc)) } if desc2.Empty() { t.Error("Invalid Mat desc in SIFT DetectAndCompute") } } func TestSIFTWithParams(t *testing.T) { if runtime.GOOS == "darwin" { t.Skip("skipping test on macos") } img := IMRead("./images/face.jpg", IMReadGrayScale) if img.Empty() { t.Error("Invalid Mat in SIFT test") } defer img.Close() dst := NewMat() defer dst.Close() nFeatures := 256 nOctaveLayers := 3 contrastThreshold := 0.039 var edgeThreshold float64 = 11 sigma := 1.55 si := NewSIFTWithParams(&nFeatures, &nOctaveLayers, &contrastThreshold, &edgeThreshold, &sigma) defer si.Close() kp := si.Detect(img) if len(kp) != 256 { t.Errorf("Invalid KeyPoint array in SIFT test: %d", len(kp)) } mask := NewMat() defer mask.Close() kpc, desc := si.Compute(img, mask, kp) defer desc.Close() if len(kpc) != 256 { t.Errorf("Invalid KeyPoint array in SIFT Compute: %d", len(kpc)) } if desc.Empty() { t.Error("Invalid Mat desc in SIFT Compute") } kpdc, desc2 := si.DetectAndCompute(img, mask) defer desc2.Close() if len(kpdc) != 256 { t.Errorf("Invalid KeyPoint array in SIFT DetectAndCompute: %d", len(kpdc)) } if desc2.Empty() { t.Error("Invalid Mat desc in SIFT DetectAndCompute") } } ================================================ FILE: go.mod ================================================ module gocv.io/x/gocv go 1.21 require ( github.com/hybridgroup/mjpeg v0.0.0-20140228234708-4680f319790e github.com/pascaldekloe/goe v0.1.0 github.com/subeshb1/wasm-go-image-to-ascii v0.0.0-20200725121413-d828986df340 ) require ( github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59 // indirect github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect ) ================================================ FILE: go.sum ================================================ github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59 h1:WWB576BN5zNSZc/M9d/10pqEx5VHNhaQ/yOVAkmj5Yo= github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59/go.mod h1:q/89r3U2H7sSsE2t6Kca0lfwTK8JdoNGS/yzM/4iH5I= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/hybridgroup/mjpeg v0.0.0-20140228234708-4680f319790e h1:xCcwD5FOXul+j1dn8xD16nbrhJkkum/Cn+jTd/u1LhY= github.com/hybridgroup/mjpeg v0.0.0-20140228234708-4680f319790e/go.mod h1:eagM805MRKrioHYuU7iKLUyFPVKqVV6um5DAvCkUtXs= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ= github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/shurcooL/go v0.0.0-20200502201357-93f07166e636/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.3.0 h1:NGXK3lHquSN08v5vWalVI/L8XU9hdzE/G6xsrze47As= github.com/stretchr/objx v0.3.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/subeshb1/wasm-go-image-to-ascii v0.0.0-20200725121413-d828986df340 h1:EN1NUPDAdhpWv9zNNdbovzqfJaRmnrwWaq0huRzQp9I= github.com/subeshb1/wasm-go-image-to-ascii v0.0.0-20200725121413-d828986df340/go.mod h1:A2X7CsJFb8jEdYaWeCbs2HydXC69J4Iaw4DM+bly5iw= github.com/wayneashleyberry/terminal-dimensions v1.0.0/go.mod h1:PW2XrtV6KmKOPhuf7wbtcmw1/IFnC39mryRET2XbxeE= golang.org/x/sys v0.0.0-20181019160139-8e24a49d80f8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= ================================================ FILE: gocv.go ================================================ // Package gocv is a wrapper around the OpenCV 4.x computer vision library. // It provides a Go language interface to the latest version of OpenCV. // // OpenCV (Open Source Computer Vision Library: http://opencv.org) is an // open-source BSD-licensed library that includes several hundreds of // computer vision algorithms. // // For further details, please see: // http://docs.opencv.org/master/d1/dfb/intro.html package gocv // import "gocv.io/x/gocv" ================================================ FILE: helpers_test.go ================================================ package gocv import "math" var eps = 0.00000001 func floatEquals(a, b float64) bool { if math.Abs(a-b) < eps { return true } return false } // round helper from https://stackoverflow.com/questions/39544571/golang-round-to-nearest-0-05 func round(x, unit float64) float64 { return float64(int64(x/unit+0.5)) * unit } ================================================ FILE: highgui.cpp ================================================ //go:build !gocv_specific_modules || (gocv_specific_modules && gocv_highgui) #include "highgui_gocv.h" void Window_SetMouseCallback(char* winname, mouse_callback on_mouse) { try { cv::setMouseCallback(winname, on_mouse, (void*)winname); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); } } // Window void Window_New(const char* winname, int flags) { try { cv::namedWindow(winname, flags); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); } } void Window_Close(const char* winname) { try { cv::destroyWindow(winname); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); } } OpenCVResult Window_IMShow(const char* winname, Mat mat) { try { cv::imshow(winname, *mat); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } double Window_GetProperty(const char* winname, int flag) { try { return cv::getWindowProperty(winname, flag); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return 0.0; } } OpenCVResult Window_SetProperty(const char* winname, int flag, double value) { try { cv::setWindowProperty(winname, flag, value); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Window_SetTitle(const char* winname, const char* title) { try { cv::setWindowTitle(winname, title); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } int Window_WaitKey(int delay = 0) { try { return cv::waitKey(delay); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return -1; } } int Window_WaitKeyEx(int delay = 0) { try { return cv::waitKeyEx(delay); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return -1; } } int Window_PollKey(void) { try { return cv::pollKey(); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return -1; } } OpenCVResult Window_Move(const char* winname, int x, int y) { try { cv::moveWindow(winname, x, y); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Window_Resize(const char* winname, int width, int height) { try { cv::resizeWindow(winname, width, height); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } struct Rect Window_SelectROI(const char* winname, Mat img) { try { cv::Rect bRect = cv::selectROI(winname, *img); Rect r = {bRect.x, bRect.y, bRect.width, bRect.height}; return r; } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); Rect r = {0, 0, 0, 0}; return r; } } struct Rects Window_SelectROIs(const char* winname, Mat img) { try { std::vector rois; cv::selectROIs(winname, *img, rois); Rect* rects = new Rect[rois.size()]; for (size_t i = 0; i < rois.size(); ++i) { Rect r = {rois[i].x, rois[i].y, rois[i].width, rois[i].height}; rects[i] = r; } Rects ret = {rects, (int)rois.size()}; return ret; } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); Rects ret = {NULL, 0}; return ret; } } // Trackbar void Trackbar_Create(const char* winname, const char* trackname, int max) { try { cv::createTrackbar(trackname, winname, NULL, max); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); } } void Trackbar_CreateWithValue(const char* winname, const char* trackname, int* value, int max) { try { cv::createTrackbar(trackname, winname, value, max); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); } } int Trackbar_GetPos(const char* winname, const char* trackname) { try { return cv::getTrackbarPos(trackname, winname); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return -1; } } void Trackbar_SetPos(const char* winname, const char* trackname, int pos) { try { cv::setTrackbarPos(trackname, winname, pos); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); } } void Trackbar_SetMin(const char* winname, const char* trackname, int pos) { try { cv::setTrackbarMin(trackname, winname, pos); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); } } void Trackbar_SetMax(const char* winname, const char* trackname, int pos) { try { cv::setTrackbarMax(trackname, winname, pos); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); } } ================================================ FILE: highgui.go ================================================ //go:build !gocv_specific_modules || (gocv_specific_modules && gocv_highgui) package gocv /* #include #include "highgui_gocv.h" void go_onmouse_dispatcher(int event, int x, int y, int flags, void *userdata); */ import "C" import ( "image" "runtime" "unsafe" ) type MouseHandlerFunc func(event int, x int, y int, flags int, userdata interface{}) type mouseHandlerInfo struct { c_name_ptr *C.char fn MouseHandlerFunc userdata interface{} } var ( onMouseHandlers = map[string]mouseHandlerInfo{} ) // Window is a wrapper around OpenCV's "HighGUI" named windows. // While OpenCV was designed for use in full-scale applications and can be used // within functionally rich UI frameworks (such as Qt*, WinForms*, or Cocoa*) // or without any UI at all, sometimes there it is required to try functionality // quickly and visualize the results. This is what the HighGUI module has been designed for. // // For further details, please see: // http://docs.opencv.org/master/d7/dfc/group__highgui.html type Window struct { name string open bool } // NewWindow creates a new named OpenCV window // // For further details, please see: // http://docs.opencv.org/master/d7/dfc/group__highgui.html#ga5afdf8410934fd099df85c75b2e0888b func NewWindow(name string) *Window { runtime.LockOSThread() cName := C.CString(name) defer C.free(unsafe.Pointer(cName)) C.Window_New(cName, 0) return &Window{name: name, open: true} } // Close closes and deletes a named OpenCV Window. // // For further details, please see: // http://docs.opencv.org/master/d7/dfc/group__highgui.html#ga851ccdd6961022d1d5b4c4f255dbab34 func (w *Window) Close() error { cName := C.CString(w.name) defer C.free(unsafe.Pointer(cName)) mcbInfo, exists := onMouseHandlers[w.name] if exists { mcbInfo.fn = nil mcbInfo.userdata = nil C.free(unsafe.Pointer(mcbInfo.c_name_ptr)) delete(onMouseHandlers, w.name) } C.Window_Close(cName) w.open = false runtime.UnlockOSThread() return nil } // IsOpen checks to see if the Window seems to be open. func (w *Window) IsOpen() bool { return w.open } // WindowFlag value for SetWindowProperty / GetWindowProperty. type WindowFlag float32 const ( // WindowNormal indicates a normal window. WindowNormal WindowFlag = 0x00000000 // WindowAutosize indicates a window sized based on the contents. WindowAutosize WindowFlag = 0x00000001 // WindowFullscreen indicates a full-screen window. WindowFullscreen WindowFlag = 1 // WindowFreeRatio indicates allow the user to resize without maintaining aspect ratio. WindowFreeRatio WindowFlag = 0x00000100 // WindowKeepRatio indicates always maintain an aspect ratio that matches the contents. WindowKeepRatio WindowFlag = 0x00000000 ) // WindowPropertyFlag flags for SetWindowProperty / GetWindowProperty. type WindowPropertyFlag int const ( // WindowPropertyFullscreen fullscreen property // (can be WINDOW_NORMAL or WINDOW_FULLSCREEN). WindowPropertyFullscreen WindowPropertyFlag = 0 // WindowPropertyAutosize is autosize property // (can be WINDOW_NORMAL or WINDOW_AUTOSIZE). WindowPropertyAutosize WindowPropertyFlag = 1 // WindowPropertyAspectRatio window's aspect ration // (can be set to WINDOW_FREERATIO or WINDOW_KEEPRATIO). WindowPropertyAspectRatio WindowPropertyFlag = 2 // WindowPropertyOpenGL opengl support. WindowPropertyOpenGL WindowPropertyFlag = 3 // WindowPropertyVisible or not. WindowPropertyVisible WindowPropertyFlag = 4 ) // GetWindowProperty returns properties of a window. // // For further details, please see: // https://docs.opencv.org/master/d7/dfc/group__highgui.html#gaaf9504b8f9cf19024d9d44a14e461656 func (w *Window) GetWindowProperty(flag WindowPropertyFlag) float64 { cName := C.CString(w.name) defer C.free(unsafe.Pointer(cName)) return float64(C.Window_GetProperty(cName, C.int(flag))) } // SetWindowProperty changes parameters of a window dynamically. // // For further details, please see: // https://docs.opencv.org/master/d7/dfc/group__highgui.html#ga66e4a6db4d4e06148bcdfe0d70a5df27 func (w *Window) SetWindowProperty(flag WindowPropertyFlag, value WindowFlag) error { cName := C.CString(w.name) defer C.free(unsafe.Pointer(cName)) return OpenCVResult(C.Window_SetProperty(cName, C.int(flag), C.double(value))) } // SetWindowTitle updates window title. // // For further details, please see: // https://docs.opencv.org/master/d7/dfc/group__highgui.html#ga56f8849295fd10d0c319724ddb773d96 func (w *Window) SetWindowTitle(title string) error { cName := C.CString(w.name) defer C.free(unsafe.Pointer(cName)) cTitle := C.CString(title) defer C.free(unsafe.Pointer(cTitle)) return OpenCVResult(C.Window_SetTitle(cName, cTitle)) } // IMShow displays an image Mat in the specified window. // This function should be followed by the WaitKey function which displays // the image for specified milliseconds. Otherwise, it won't display the image. // // For further details, please see: // http://docs.opencv.org/master/d7/dfc/group__highgui.html#ga453d42fe4cb60e5723281a89973ee563 func (w *Window) IMShow(img Mat) error { cName := C.CString(w.name) defer C.free(unsafe.Pointer(cName)) return OpenCVResult(C.Window_IMShow(cName, img.p)) } // WaitKey waits for a pressed key. // This function is the only method in OpenCV's HighGUI that can fetch // and handle events, so it needs to be called periodically // for normal event processing // // For further details, please see: // http://docs.opencv.org/master/d7/dfc/group__highgui.html#ga5628525ad33f52eab17feebcfba38bd7 func (w *Window) WaitKey(delay int) int { return int(C.Window_WaitKey(C.int(delay))) } // WaitKeyEx Similar to waitKey, but returns full key code. // Note // Key code is implementation specific and depends on used backend: QT/GTK/Win32/etc // // For further details, please see: // https://docs.opencv.org/4.x/d7/dfc/group__highgui.html#gafa15c0501e0ddd90918f17aa071d3dd0 func (w *Window) WaitKeyEx(delay int) int { return int(C.Window_WaitKey(C.int(delay))) } // PollKey polls for a pressed key. // The function pollKey polls for a key event without waiting. // It returns the code of the pressed key or -1 if no key was pressed since // the last invocation. To wait until a key was pressed, use waitKey. // // The functions waitKey and pollKey are the only methods in HighGUI that can // fetch and handle GUI events, so one of them needs to be called periodically // for normal event processing unless HighGUI is used within an environment that // takes care of event processing. // The function only works if there is at least one HighGUI window created and // the window is active. If there are several HighGUI windows, any of them can // be active. // // For further details, please see: // https://docs.opencv.org/4.x/d7/dfc/group__highgui.html#ga6d20fbd3100ec3badc1eaa653aff99d7 func (w *Window) PollKey() int { return int(C.Window_PollKey()) } // MoveWindow moves window to the specified position. // // For further details, please see: // https://docs.opencv.org/master/d7/dfc/group__highgui.html#ga8d86b207f7211250dbe6e28f76307ffb func (w *Window) MoveWindow(x, y int) error { cName := C.CString(w.name) defer C.free(unsafe.Pointer(cName)) return OpenCVResult(C.Window_Move(cName, C.int(x), C.int(y))) } // ResizeWindow resizes window to the specified size. // // For further details, please see: // https://docs.opencv.org/master/d7/dfc/group__highgui.html#ga9e80e080f7ef33f897e415358aee7f7e func (w *Window) ResizeWindow(width, height int) error { cName := C.CString(w.name) defer C.free(unsafe.Pointer(cName)) return OpenCVResult(C.Window_Resize(cName, C.int(width), C.int(height))) } // SelectROI selects a Region Of Interest (ROI) on the given image. // It creates a window and allows user to select a ROI using mouse. // // Controls: // use space or enter to finish selection, // use key c to cancel selection (function will return a zero Rect). // // For further details, please see: // https://docs.opencv.org/master/d7/dfc/group__highgui.html#ga8daf4730d3adf7035b6de9be4c469af5 func (w *Window) SelectROI(img Mat) image.Rectangle { cName := C.CString(w.name) defer C.free(unsafe.Pointer(cName)) r := C.Window_SelectROI(cName, img.p) rect := image.Rect(int(r.x), int(r.y), int(r.x+r.width), int(r.y+r.height)) return rect } // SelectROIs selects multiple Regions Of Interest (ROI) on the given image. // It creates a window and allows user to select ROIs using mouse. // // Controls: // use space or enter to finish current selection and start a new one // use esc to terminate multiple ROI selection process // // For further details, please see: // https://docs.opencv.org/master/d7/dfc/group__highgui.html#ga0f11fad74a6432b8055fb21621a0f893 func (w *Window) SelectROIs(img Mat) []image.Rectangle { cName := C.CString(w.name) defer C.free(unsafe.Pointer(cName)) ret := C.Window_SelectROIs(cName, img.p) defer C.Rects_Close(ret) return toRectangles(ret) } // Deprecated: use Window.SelectROI instead func SelectROI(name string, img Mat) image.Rectangle { cName := C.CString(name) defer C.free(unsafe.Pointer(cName)) r := C.Window_SelectROI(cName, img.p) rect := image.Rect(int(r.x), int(r.y), int(r.x+r.width), int(r.y+r.height)) return rect } // Deprecated: use Window.SelectROIs instead func SelectROIs(name string, img Mat) []image.Rectangle { cName := C.CString(name) defer C.free(unsafe.Pointer(cName)) ret := C.Window_SelectROIs(cName, img.p) defer C.Rects_Close(ret) return toRectangles(ret) } // WaitKey that is not attached to a specific Window. // Only use when no Window exists in your application, e.g. command line app. func WaitKey(delay int) int { return int(C.Window_WaitKey(C.int(delay))) } // Trackbar is a wrapper around OpenCV's "HighGUI" window Trackbars. type Trackbar struct { name string parent *Window } // CreateTrackbar creates a trackbar and attaches it to the specified window. // // For further details, please see: // https://docs.opencv.org/master/d7/dfc/group__highgui.html#gaf78d2155d30b728fc413803745b67a9b func (w *Window) CreateTrackbar(name string, max int) *Trackbar { cName := C.CString(w.name) defer C.free(unsafe.Pointer(cName)) tName := C.CString(name) defer C.free(unsafe.Pointer(tName)) C.Trackbar_Create(cName, tName, C.int(max)) return &Trackbar{name: name, parent: w} } // CreateTrackbarWithValue works like CreateTrackbar but also assigns a // variable value to be a position synchronized with the trackbar. // // For further details, please see: // https://docs.opencv.org/master/d7/dfc/group__highgui.html#gaf78d2155d30b728fc413803745b67a9b func (w *Window) CreateTrackbarWithValue(name string, value *int, max int) *Trackbar { cName := C.CString(w.name) defer C.free(unsafe.Pointer(cName)) tName := C.CString(name) defer C.free(unsafe.Pointer(tName)) C.Trackbar_CreateWithValue(cName, tName, (*C.int)(unsafe.Pointer(value)), C.int(max)) return &Trackbar{name: name, parent: w} } // GetPos returns the trackbar position. // // For further details, please see: // https://docs.opencv.org/master/d7/dfc/group__highgui.html#ga122632e9e91b9ec06943472c55d9cda8 func (t *Trackbar) GetPos() int { cName := C.CString(t.parent.name) defer C.free(unsafe.Pointer(cName)) tName := C.CString(t.name) defer C.free(unsafe.Pointer(tName)) return int(C.Trackbar_GetPos(cName, tName)) } // SetPos sets the trackbar position. // // For further details, please see: // https://docs.opencv.org/master/d7/dfc/group__highgui.html#ga67d73c4c9430f13481fd58410d01bd8d func (t *Trackbar) SetPos(pos int) { cName := C.CString(t.parent.name) defer C.free(unsafe.Pointer(cName)) tName := C.CString(t.name) defer C.free(unsafe.Pointer(tName)) C.Trackbar_SetPos(cName, tName, C.int(pos)) } // SetMin sets the trackbar minimum position. // // For further details, please see: // https://docs.opencv.org/master/d7/dfc/group__highgui.html#gabe26ffe8d2b60cc678895595a581b7aa func (t *Trackbar) SetMin(pos int) { cName := C.CString(t.parent.name) defer C.free(unsafe.Pointer(cName)) tName := C.CString(t.name) defer C.free(unsafe.Pointer(tName)) C.Trackbar_SetMin(cName, tName, C.int(pos)) } // SetMax sets the trackbar maximum position. // // For further details, please see: // https://docs.opencv.org/master/d7/dfc/group__highgui.html#ga7e5437ccba37f1154b65210902fc4480 func (t *Trackbar) SetMax(pos int) { cName := C.CString(t.parent.name) defer C.free(unsafe.Pointer(cName)) tName := C.CString(t.name) defer C.free(unsafe.Pointer(tName)) C.Trackbar_SetMax(cName, tName, C.int(pos)) } //export go_onmouse_dispatcher func go_onmouse_dispatcher(event C.int, x C.int, y C.int, flags C.int, userdata unsafe.Pointer) { c_winname := (*C.char)(unsafe.Pointer(userdata)) winName := C.GoString(c_winname) info, exists := onMouseHandlers[winName] if !exists { return } info.fn(int(event), int(x), int(y), int(flags), info.userdata) } func (w *Window) SetMouseHandler(onMOuse MouseHandlerFunc, userdata interface{}) { c_winname := C.CString(w.name) onMouseHandlers[w.name] = mouseHandlerInfo{ c_name_ptr: c_winname, fn: onMOuse, userdata: userdata, } C.Window_SetMouseCallback(c_winname, C.mouse_callback(C.go_onmouse_dispatcher)) } ================================================ FILE: highgui_gocv.h ================================================ #ifndef _OPENCV3_HIGHGUI_H_ #define _OPENCV3_HIGHGUI_H_ #ifdef __cplusplus #include extern "C" { #endif #include "core.h" typedef void(*mouse_callback) (int event, int x, int y, int flags, void *userdata); /* typedef struct mouse_callback_userdata { char* winname; void* userdata; } mouse_callback_userdata; */ void Window_SetMouseCallback(char* winname, mouse_callback on_mouse); // Window void Window_New(const char* winname, int flags); void Window_Close(const char* winname); OpenCVResult Window_IMShow(const char* winname, Mat mat); double Window_GetProperty(const char* winname, int flag); OpenCVResult Window_SetProperty(const char* winname, int flag, double value); OpenCVResult Window_SetTitle(const char* winname, const char* title); int Window_WaitKey(int); int Window_WaitKeyEx(int); int Window_PollKey(void); OpenCVResult Window_Move(const char* winname, int x, int y); OpenCVResult Window_Resize(const char* winname, int width, int height); struct Rect Window_SelectROI(const char* winname, Mat img); struct Rects Window_SelectROIs(const char* winname, Mat img); // Trackbar void Trackbar_Create(const char* winname, const char* trackname, int max); void Trackbar_CreateWithValue(const char* winname, const char* trackname, int* value, int max); int Trackbar_GetPos(const char* winname, const char* trackname); void Trackbar_SetPos(const char* winname, const char* trackname, int pos); void Trackbar_SetMin(const char* winname, const char* trackname, int pos); void Trackbar_SetMax(const char* winname, const char* trackname, int pos); #ifdef __cplusplus } #endif #endif //_OPENCV3_HIGHGUI_H_ ================================================ FILE: highgui_onmouse_test.go ================================================ // Do not run these tests on mac OS X. They fail with errors suggesting the GUI // should only be touched from the main thread. //go:build !darwin && (!gocv_specific_modules || (gocv_specific_modules && gocv_highgui)) package gocv import ( "testing" ) type mouseHandlerUserData struct { name string } func mouseHandler(event int, x int, y int, flags int, userdata interface{}) {} func TestMouseHandler(t *testing.T) { windowName := "mouse" w := NewWindow(windowName) defer w.Close() udata := mouseHandlerUserData{ name: "gocv", } w.SetMouseHandler(mouseHandler, &udata) } ================================================ FILE: highgui_string.go ================================================ //go:build !gocv_specific_modules || (gocv_specific_modules && gocv_highgui) package gocv /* #include #include "highgui_gocv.h" */ import "C" func (c WindowFlag) String() string { switch c { case WindowNormal: return "window-normal" case WindowFullscreen: return "window-fullscreen" case WindowFreeRatio: return "window-free-ratio" } return "" } func (c WindowPropertyFlag) String() string { switch c { case WindowPropertyFullscreen: return "window-property-fullscreen" case WindowPropertyAutosize: return "window-property-autosize" case WindowPropertyAspectRatio: return "window-property-aspect-ratio" case WindowPropertyOpenGL: return "window-property-opengl" case WindowPropertyVisible: return "window-property-visible" } return "" } ================================================ FILE: highgui_test.go ================================================ // Do not run these tests on mac OS X. They fail with errors suggesting the GUI // should only be touched from the main thread. //go:build !darwin && (!gocv_specific_modules || (gocv_specific_modules && gocv_highgui)) package gocv import ( "testing" ) func TestWindow(t *testing.T) { window := NewWindow("test") if window == nil { t.Error("Unable to create Window") } if window.name != "test" { t.Error("Invalid Window name") } val := window.WaitKey(1) if val != -1 { t.Error("Invalid WaitKey") } if !window.IsOpen() { t.Error("Window should have been open") } window.SetWindowProperty(WindowPropertyFullscreen, WindowFullscreen) prop := WindowFlag(window.GetWindowProperty(WindowPropertyFullscreen)) if prop != WindowFullscreen { t.Error("Window property should have been fullscreen") } window.SetWindowTitle("My new title") window.MoveWindow(100, 100) window.ResizeWindow(100, 100) window.Close() if window.IsOpen() { t.Error("Window should have been closed") } } func TestIMShow(t *testing.T) { window := NewWindow("imshow") if window == nil { t.Error("Unable to create IMShow Window") } img := IMRead("images/face-detect.jpg", IMReadColor) if img.Empty() { t.Error("Invalid Mat in IMShow") } defer img.Close() // TODO: some way to determine if the call succeeded window.IMShow(img) val := WaitKey(1) if val != -1 { t.Error("Invalid for IMShow") } window.Close() if window.IsOpen() { t.Error("IMShow window should have been closed") } } func TestSelectROI(t *testing.T) { t.Skip("TODO: figure out how to implement a test that can exercise the GUI") } func TestSelectROIs(t *testing.T) { t.Skip("TODO: figure out how to implement a test that can exercise the GUI") } func TestTrackbar(t *testing.T) { window := NewWindow("trackbar") defer window.Close() tracker := window.CreateTrackbar("trackme", 100) if tracker.GetPos() != 0 { t.Error("Trackbar pos should have been 0") } tracker.SetMin(10) tracker.SetMax(150) tracker.SetPos(50) if tracker.GetPos() != 50 { t.Error("Trackbar pos should have been 50") } } func TestTrackbarWithValue(t *testing.T) { window := NewWindow("trackbar") defer window.Close() value := 20 tracker := window.CreateTrackbarWithValue("trackme", &value, 100) if tracker.GetPos() != 20 { t.Error("Trackbar pos should have been 20") } tracker.SetPos(50) if value != 50 { t.Error("Trackbar pos should have been 50") } } func TestPollKey(t *testing.T) { w := NewWindow("polly") defer w.Close() if v := w.PollKey(); v != -1 { t.Errorf("got %d want -1", v) } } func TestWaitKeyEx(t *testing.T) { w := NewWindow("wait") defer w.Close() if w.WaitKeyEx(1) != -1 { t.Error("WaitKeyEx failed!") } } ================================================ FILE: imgcodecs.cpp ================================================ #include #include "imgcodecs.h" // Image Mat Image_IMRead(const char* filename, int flags) { try { cv::Mat img = cv::imread(filename, flags); return new cv::Mat(img); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return new cv::Mat(); } } Mats Image_IMReadMulti(const char* filename, int flags) { try { std::vector dst; Mats m = Mats(); bool b = cv::imreadmulti(filename, dst, flags); if (b) { m.mats = new Mat[dst.size()]; for (size_t i = 0; i < dst.size(); ++i) { m.mats[i] = new cv::Mat(dst[i]); } m.length = (int)dst.size(); } return m; } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return Mats(); } } Mats Image_IMReadMulti_WithParams(const char* filename, int start, int count, int flags) { try { std::vector dst; auto m = Mats(); auto b = cv::imreadmulti(filename, dst, start, count, flags); if (b) { m.mats = new Mat[dst.size()]; for (size_t i = 0; i < dst.size(); ++i) { m.mats[i] = new cv::Mat(dst[i]); } m.length = (int)dst.size(); } return m; } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return Mats(); } } bool Image_IMWrite(const char* filename, Mat img) { try { return cv::imwrite(filename, *img); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return false; } } bool Image_IMWrite_WithParams(const char* filename, Mat img, IntVector params) { try { std::vector compression_params; for (int i = 0, *v = params.val; i < params.length; ++v, ++i) { compression_params.push_back(*v); } return cv::imwrite(filename, *img, compression_params); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return false; } } OpenCVResult Image_IMEncode(const char* fileExt, Mat img, void* vector) { try { auto vectorPtr = reinterpret_cast *>(vector); cv::imencode(fileExt, *img, *vectorPtr); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Image_IMEncode_WithParams(const char* fileExt, Mat img, IntVector params, void* vector) { try { auto vectorPtr = reinterpret_cast *>(vector); std::vector compression_params; for (int i = 0, *v = params.val; i < params.length; ++v, ++i) { compression_params.push_back(*v); } cv::imencode(fileExt, *img, *vectorPtr, compression_params); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } Mat Image_IMDecode(ByteArray buf, int flags) { try { std::vector data(buf.data, buf.data + buf.length); cv::Mat img = cv::imdecode(data, flags); return new cv::Mat(img); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return new cv::Mat(); } } OpenCVResult Image_IMDecodeIntoMat(ByteArray buf, int flags, Mat dest) { try { std::vector data(buf.data, buf.data + buf.length); cv::imdecode(data, flags, dest); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } ================================================ FILE: imgcodecs.go ================================================ package gocv /* #include #include "imgcodecs.h" */ import "C" import ( "unsafe" ) // IMReadFlag is one of the valid flags to use for the IMRead function. type IMReadFlag int const ( // IMReadUnchanged return the loaded image as is (with alpha channel, // otherwise it gets cropped). IMReadUnchanged IMReadFlag = -1 // IMReadGrayScale always convert image to the single channel // grayscale image. IMReadGrayScale IMReadFlag = 0 // IMReadColor always converts image to the 3 channel BGR color image. IMReadColor IMReadFlag = 1 // IMReadAnyDepth returns 16-bit/32-bit image when the input has the corresponding // depth, otherwise convert it to 8-bit. IMReadAnyDepth IMReadFlag = 2 // IMReadAnyColor the image is read in any possible color format. IMReadAnyColor IMReadFlag = 4 // IMReadLoadGDAL uses the gdal driver for loading the image. IMReadLoadGDAL IMReadFlag = 8 // IMReadReducedGrayscale2 always converts image to the single channel grayscale image // and the image size reduced 1/2. IMReadReducedGrayscale2 IMReadFlag = 16 // IMReadReducedColor2 always converts image to the 3 channel BGR color image and the // image size reduced 1/2. IMReadReducedColor2 IMReadFlag = 17 // IMReadReducedGrayscale4 always converts image to the single channel grayscale image and // the image size reduced 1/4. IMReadReducedGrayscale4 IMReadFlag = 32 // IMReadReducedColor4 always converts image to the 3 channel BGR color image and // the image size reduced 1/4. IMReadReducedColor4 IMReadFlag = 33 // IMReadReducedGrayscale8 always convert image to the single channel grayscale image and // the image size reduced 1/8. IMReadReducedGrayscale8 IMReadFlag = 64 // IMReadReducedColor8 always convert image to the 3 channel BGR color image and the // image size reduced 1/8. IMReadReducedColor8 IMReadFlag = 65 // IMReadIgnoreOrientation do not rotate the image according to EXIF's orientation flag. IMReadIgnoreOrientation IMReadFlag = 128 ) // TODO: Define IMWriteFlag type? const ( //IMWriteJpegQuality is the quality from 0 to 100 for JPEG (the higher is the better). Default value is 95. IMWriteJpegQuality = 1 // IMWriteJpegProgressive enables JPEG progressive feature, 0 or 1, default is False. IMWriteJpegProgressive = 2 // IMWriteJpegOptimize enables JPEG optimization, 0 or 1, default is False. IMWriteJpegOptimize = 3 // IMWriteJpegRstInterval is the JPEG restart interval, 0 - 65535, default is 0 - no restart. IMWriteJpegRstInterval = 4 // IMWriteJpegLumaQuality separates luma quality level, 0 - 100, default is 0 - don't use. IMWriteJpegLumaQuality = 5 // IMWriteJpegChromaQuality separates chroma quality level, 0 - 100, default is 0 - don't use. IMWriteJpegChromaQuality = 6 // IMWritePngCompression is the compression level from 0 to 9 for PNG. A // higher value means a smaller size and longer compression time. // If specified, strategy is changed to IMWRITE_PNG_STRATEGY_DEFAULT (Z_DEFAULT_STRATEGY). // Default value is 1 (best speed setting). IMWritePngCompression = 16 // IMWritePngStrategy is one of cv::IMWritePNGFlags, default is IMWRITE_PNG_STRATEGY_RLE. IMWritePngStrategy = 17 // IMWritePngBilevel is the binary level PNG, 0 or 1, default is 0. IMWritePngBilevel = 18 // IMWritePxmBinary for PPM, PGM, or PBM can be a binary format flag, 0 or 1. Default value is 1. IMWritePxmBinary = 32 // IMWriteWebpQuality is the quality from 1 to 100 for WEBP (the higher is // the better). By default (without any parameter) and for quality above // 100 the lossless compression is used. IMWriteWebpQuality = 64 // IMWritePamTupletype sets the TUPLETYPE field to the corresponding string // value that is defined for the format. IMWritePamTupletype = 128 // IMWritePngStrategyDefault is the value to use for normal data. IMWritePngStrategyDefault = 0 // IMWritePngStrategyFiltered is the value to use for data produced by a // filter (or predictor). Filtered data consists mostly of small values // with a somewhat random distribution. In this case, the compression // algorithm is tuned to compress them better. IMWritePngStrategyFiltered = 1 // IMWritePngStrategyHuffmanOnly forces Huffman encoding only (no string match). IMWritePngStrategyHuffmanOnly = 2 // IMWritePngStrategyRle is the value to use to limit match distances to // one (run-length encoding). IMWritePngStrategyRle = 3 // IMWritePngStrategyFixed is the value to prevent the use of dynamic // Huffman codes, allowing for a simpler decoder for special applications. IMWritePngStrategyFixed = 4 ) // IMRead reads an image from a file into a Mat. // The flags param is one of the IMReadFlag flags. // If the image cannot be read (because of missing file, improper permissions, // unsupported or invalid format), the function returns an empty Mat. // // For further details, please see: // http://docs.opencv.org/master/d4/da8/group__imgcodecs.html#ga288b8b3da0892bd651fce07b3bbd3a56 func IMRead(name string, flags IMReadFlag) Mat { cName := C.CString(name) defer C.free(unsafe.Pointer(cName)) return newMat(C.Image_IMRead(cName, C.int(flags))) } // IMReadMulti reads multi-page image from a file into a []Mat. // The flags param is one of the IMReadFlag flags. // If the image cannot be read (because of missing file, improper permissions, // unsupported or invalid format), the function returns an empty []Mat. // // For further details, please see: // https://docs.opencv.org/4.x/d4/da8/group__imgcodecs.html#gaaeb5e219c706fd6aa1ec6cf17b172080 func IMReadMulti(name string, flags IMReadFlag) []Mat { var mats []Mat multiRead := C.struct_Mats{} cName := C.CString(name) defer C.free(unsafe.Pointer(cName)) multiRead = C.Image_IMReadMulti(cName, C.int(flags)) defer C.Mats_Close(multiRead) if multiRead.length > C.int(0) { mats = make([]Mat, multiRead.length) for i := 0; i < int(multiRead.length); i++ { mats[i].p = C.Mats_get(multiRead, C.int(i)) } } return mats } // IMReadMulti reads multi-page image from a file into a []Mat. // The flags param is one of the IMReadFlag flags. // If the image cannot be read (because of missing file, improper permissions, // unsupported or invalid format), the function returns an empty []Mat. // // For further details, please see: // https://docs.opencv.org/4.x/d4/da8/group__imgcodecs.html#ga55e88dc40b65807cfbe2c62d27f7fdf9 func IMReadMulti_WithParams(name string, start int, count int, flags IMReadFlag) []Mat { var mats []Mat multiRead := C.struct_Mats{} cName := C.CString(name) defer C.free(unsafe.Pointer(cName)) multiRead = C.Image_IMReadMulti_WithParams(cName, C.int(start), C.int(count), C.int(flags)) defer C.Mats_Close(multiRead) if multiRead.length > C.int(0) { mats = make([]Mat, multiRead.length) for i := 0; i < int(multiRead.length); i++ { mats[i].p = C.Mats_get(multiRead, C.int(i)) } } return mats } // IMWrite writes a Mat to an image file. // // For further details, please see: // http://docs.opencv.org/master/d4/da8/group__imgcodecs.html#gabbc7ef1aa2edfaa87772f1202d67e0ce func IMWrite(name string, img Mat) bool { cName := C.CString(name) defer C.free(unsafe.Pointer(cName)) return bool(C.Image_IMWrite(cName, img.p)) } // IMWriteWithParams writes a Mat to an image file. With that func you can // pass compression parameters. // // For further details, please see: // http://docs.opencv.org/master/d4/da8/group__imgcodecs.html#gabbc7ef1aa2edfaa87772f1202d67e0ce func IMWriteWithParams(name string, img Mat, params []int) bool { cName := C.CString(name) defer C.free(unsafe.Pointer(cName)) cparams := []C.int{} for _, v := range params { cparams = append(cparams, C.int(v)) } paramsVector := C.struct_IntVector{} paramsVector.val = (*C.int)(&cparams[0]) paramsVector.length = (C.int)(len(cparams)) return bool(C.Image_IMWrite_WithParams(cName, img.p, paramsVector)) } // FileExt represents a file extension. type FileExt string const ( // PNGFileExt is the file extension for PNG. PNGFileExt FileExt = ".png" // JPEGFileExt is the file extension for JPEG. JPEGFileExt FileExt = ".jpg" // GIFFileExt is the file extension for GIF. GIFFileExt FileExt = ".gif" ) // IMEncode encodes an image Mat into a memory buffer. // This function compresses the image and stores it in the returned memory buffer, // using the image format passed in in the form of a file extension string. // // For further details, please see: // http://docs.opencv.org/master/d4/da8/group__imgcodecs.html#ga461f9ac09887e47797a54567df3b8b63 func IMEncode(fileExt FileExt, img Mat) (buf *NativeByteBuffer, err error) { cfileExt := C.CString(string(fileExt)) defer C.free(unsafe.Pointer(cfileExt)) buffer := newNativeByteBuffer() res := C.Image_IMEncode(cfileExt, img.Ptr(), buffer.nativePointer()) return buffer, OpenCVResult(res) } // IMEncodeWithParams encodes an image Mat into a memory buffer. // This function compresses the image and stores it in the returned memory buffer, // using the image format passed in in the form of a file extension string. // // Usage example: // // buffer, err := gocv.IMEncodeWithParams(gocv.JPEGFileExt, img, []int{gocv.IMWriteJpegQuality, quality}) // // For further details, please see: // http://docs.opencv.org/master/d4/da8/group__imgcodecs.html#ga461f9ac09887e47797a54567df3b8b63 func IMEncodeWithParams(fileExt FileExt, img Mat, params []int) (buf *NativeByteBuffer, err error) { cfileExt := C.CString(string(fileExt)) defer C.free(unsafe.Pointer(cfileExt)) cparams := []C.int{} for _, v := range params { cparams = append(cparams, C.int(v)) } paramsVector := C.struct_IntVector{} paramsVector.val = (*C.int)(&cparams[0]) paramsVector.length = (C.int)(len(cparams)) b := newNativeByteBuffer() res := C.Image_IMEncode_WithParams(cfileExt, img.Ptr(), paramsVector, b.nativePointer()) return b, OpenCVResult(res) } // IMDecode reads an image from a buffer in memory. // The function IMDecode reads an image from the specified buffer in memory. // If the buffer is too short or contains invalid data, the function // returns an empty matrix. // // For further details, please see: // https://docs.opencv.org/master/d4/da8/group__imgcodecs.html#ga26a67788faa58ade337f8d28ba0eb19e func IMDecode(buf []byte, flags IMReadFlag) (Mat, error) { data, err := toByteArray(buf) if err != nil { return Mat{}, err } return newMat(C.Image_IMDecode(*data, C.int(flags))), LastExceptionError() } // IMDecodeIntoMat reads an image from a buffer in memory into a matrix. // The function IMDecodeIntoMat reads an image from the specified buffer in memory. // If the buffer is too short or contains invalid data, the function // returns an error // // For further details, please see: // https://docs.opencv.org/4.x/d4/da8/group__imgcodecs.html#ga5a0acefe5cbe0a81e904e452ec7ca733 func IMDecodeIntoMat(buf []byte, flags IMReadFlag, dest *Mat) error { data, err := toByteArray(buf) if err != nil { return err } return OpenCVResult(C.Image_IMDecodeIntoMat(*data, C.int(flags), dest.p)) } ================================================ FILE: imgcodecs.h ================================================ #ifndef _OPENCV3_IMGCODECS_H_ #define _OPENCV3_IMGCODECS_H_ #include #ifdef __cplusplus #include extern "C" { #endif #include "core.h" Mat Image_IMRead(const char* filename, int flags); Mats Image_IMReadMulti(const char* filename, int flags); Mats Image_IMReadMulti_WithParams(const char* filename, int start, int count, int flags); bool Image_IMWrite(const char* filename, Mat img); bool Image_IMWrite_WithParams(const char* filename, Mat img, IntVector params); OpenCVResult Image_IMEncode(const char* fileExt, Mat img, void* vector); OpenCVResult Image_IMEncode_WithParams(const char* fileExt, Mat img, IntVector params, void* vector); Mat Image_IMDecode(ByteArray buf, int flags); OpenCVResult Image_IMDecodeIntoMat(ByteArray buf, int flag, Mat dest); #ifdef __cplusplus } #endif #endif //_OPENCV3_IMGCODECS_H_ ================================================ FILE: imgcodecs_test.go ================================================ package gocv import ( "fmt" "io" "io/ioutil" "log" "net/http" "os" "path" "path/filepath" "strconv" "testing" ) func TestIMRead(t *testing.T) { img := IMRead("images/face-detect.jpg", IMReadColor) defer img.Close() if img.Empty() { t.Error("Invalid Mat in IMRead") } } func TestIMWrite(t *testing.T) { dir, _ := ioutil.TempDir("", "gocvtests") tmpfn := filepath.Join(dir, "test.jpg") img := IMRead("images/face-detect.jpg", IMReadColor) defer img.Close() if img.Empty() { t.Error("Invalid read of Mat in IMWrite test") } result := IMWrite(tmpfn, img) if !result { t.Error("Invalid write of Mat in IMWrite test") } } func TestIMWriteWithParams(t *testing.T) { dir, _ := ioutil.TempDir("", "gocvtests") tmpfn := filepath.Join(dir, "test.jpg") img := IMRead("images/face-detect.jpg", IMReadColor) defer img.Close() if img.Empty() { t.Error("Invalid read of Mat in IMWrite test") } result := IMWriteWithParams(tmpfn, img, []int{IMWriteJpegQuality, 60}) if !result { t.Error("Invalid write of Mat in IMWrite test") } } func TestIMEncode(t *testing.T) { img := IMRead("images/face-detect.jpg", IMReadColor) defer img.Close() if img.Empty() { t.Error("Invalid Mat in IMEncode test") } buf, err := IMEncode(PNGFileExt, img) if err != nil { t.Error(err) } defer buf.Close() bytes := buf.GetBytes() if len(bytes) < 43000 { t.Errorf("Wrong buffer size in IMEncode test. Should have been %v\n", len(bytes)) } } func ExampleIMEncodeWithParams() { img := IMRead(path.Join(os.Getenv("GOPATH"), "src/gocv.io/x/gocv/images/face-detect.jpg"), IMReadColor) if img.Empty() { log.Fatal("Invalid Mat") } imgHandler := func(w http.ResponseWriter, req *http.Request) { quality := 75 if q, err := strconv.Atoi(req.URL.Query().Get("q")); err == nil { quality = q } buffer, err := IMEncodeWithParams(JPEGFileExt, img, []int{IMWriteJpegQuality, quality}) if err != nil { w.WriteHeader(http.StatusInternalServerError) io.WriteString(w, err.Error()) return } defer buffer.Close() w.Header().Set("Content-Type", "image/jpeg") w.WriteHeader(http.StatusOK) w.Write(buffer.GetBytes()) } http.HandleFunc("/img", imgHandler) fmt.Println("Open in browser http://127.0.0.1:8080/img?q=10 where q is a JPEG quality parameter") log.Fatal(http.ListenAndServe("127.0.0.1:8080", nil)) } func TestIMEncodeWithParams(t *testing.T) { img := IMRead("images/face-detect.jpg", IMReadColor) defer img.Close() if img.Empty() { t.Error("Invalid Mat in IMEncode test") } buf, err := IMEncodeWithParams(JPEGFileExt, img, []int{IMWriteJpegQuality, 75}) if err != nil { t.Error(err) } defer buf.Close() if buf.Len() < 18000 { t.Errorf("Wrong buffer size in IMEncode test. Should have been %v\n", buf.Len()) } buf2, err := IMEncodeWithParams(JPEGFileExt, img, []int{IMWriteJpegQuality, 100}) if err != nil { t.Error(err) } defer buf2.Close() if buf2.Len() < 18000 { t.Errorf("Wrong buffer size in IMEncode test. Should have been %v\n", buf2.Len()) } if buf.Len() >= buf2.Len() { t.Errorf("Jpeg quality parameter does not work correctly\n") } } func TestIMDecode(t *testing.T) { content, err := ioutil.ReadFile("images/face-detect.jpg") if err != nil { t.Error("Invalid ReadFile in IMDecode") } dec, err := IMDecode(content, IMReadColor) if err != nil { t.Error(err.Error()) } if dec.Empty() { t.Error("Invalid Mat in IMDecode") } dec.Close() dec, err = IMDecode([]byte{}, IMReadColor) if err == nil { t.Error("Should not decode empty array") } } func TestIMDecodeIntoMat(t *testing.T) { mat := NewMat() defer mat.Close() content, err := ioutil.ReadFile("images/face-detect.jpg") if err != nil { t.Error("Invalid ReadFile in IMDecode") } err = IMDecodeIntoMat(content, IMReadColor, &mat) if err != nil { t.Error(err.Error()) } if mat.Empty() { t.Error("Invalid Mat in IMDecode") } } func TestIMDecodeWebp(t *testing.T) { content, err := ioutil.ReadFile("images/sample.webp") if err != nil { t.Error("Invalid ReadFile in IMDecodeWebp") } dec, err := IMDecode(content, IMReadColor) if err != nil { t.Error(err.Error()) } if dec.Empty() { t.Error("Invalid Mat in IMDecodeWebp") } dec.Close() } func TestIMReadMulti(t *testing.T) { mats := IMReadMulti("images/multipage.tif", IMReadAnyColor) for i, page := range mats { if page.Empty() { t.Errorf("page %d empty", i) } } } func TestIMReadMulti_WithParams(t *testing.T) { mats := IMReadMulti_WithParams("images/multipage.tif", 2, 3, IMReadAnyColor) for i, page := range mats { if page.Empty() { t.Errorf("page %d empty", i) } } } ================================================ FILE: imgproc.cpp ================================================ #include "imgproc.h" double ArcLength(PointVector curve, bool is_closed) { try { return cv::arcLength(*curve, is_closed); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return 0.0; } } PointVector ApproxPolyDP(PointVector curve, double epsilon, bool closed) { try { PointVector approxCurvePts = new std::vector; cv::approxPolyDP(*curve, *approxCurvePts, epsilon, closed); return approxCurvePts; } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } OpenCVResult CvtColor(Mat src, Mat dst, int code) { try { cv::cvtColor(*src, *dst, code); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Demosaicing(Mat src, Mat dst, int code) { try { cv::demosaicing(*src, *dst, code); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult EqualizeHist(Mat src, Mat dst) { try { cv::equalizeHist(*src, *dst); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult CalcHist(struct Mats mats, IntVector chans, Mat mask, Mat hist, IntVector sz, FloatVector rng, bool acc) { std::vector images; for (int i = 0; i < mats.length; ++i) { images.push_back(*mats.mats[i]); } std::vector channels; for (int i = 0, *v = chans.val; i < chans.length; ++v, ++i) { channels.push_back(*v); } std::vector histSize; for (int i = 0, *v = sz.val; i < sz.length; ++v, ++i) { histSize.push_back(*v); } std::vector ranges; float* f; int i; for (i = 0, f = rng.val; i < rng.length; ++f, ++i) { ranges.push_back(*f); } try { cv::calcHist(images, channels, *mask, *hist, histSize, ranges, acc); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult CalcBackProject(struct Mats mats, IntVector chans, Mat hist, Mat backProject, FloatVector rng, bool uniform){ std::vector images; for (int i = 0; i < mats.length; ++i) { images.push_back(*mats.mats[i]); } std::vector channels; for (int i = 0, *v = chans.val; i < chans.length; ++v, ++i) { channels.push_back(*v); } std::vector ranges; float* f; int i; for (i = 0, f = rng.val; i < rng.length; ++f, ++i) { ranges.push_back(*f); } try { cv::calcBackProject(images, channels, *hist, *backProject, ranges, uniform); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } double CompareHist(Mat hist1, Mat hist2, int method) { try { return cv::compareHist(*hist1, *hist2, method); } catch(const cv::Exception& e) { setExceptionInfo(e.code, e.what()); return 0.0; } } float EMD(Mat sig1, Mat sig2, int distType) { try { return cv::EMD(*sig1, *sig2, distType); } catch(const cv::Exception& e) { setExceptionInfo(e.code, e.what()); return 0.0; } } struct RotatedRect FitEllipse(PointVector pts) { cv::RotatedRect bRect; try { bRect = cv::fitEllipse(*pts); } catch(const cv::Exception& e) { setExceptionInfo(e.code, e.what()); RotatedRect emptyRect; return emptyRect; } Rect r = {bRect.boundingRect().x, bRect.boundingRect().y, bRect.boundingRect().width, bRect.boundingRect().height}; Point centrpt = {int(lroundf(bRect.center.x)), int(lroundf(bRect.center.y))}; Size szsz = {int(lroundf(bRect.size.width)), int(lroundf(bRect.size.height))}; cv::Point2f* pts4 = new cv::Point2f[4]; bRect.points(pts4); Point* rpts = new Point[4]; for (size_t j = 0; j < 4; j++) { Point pt = {int(lroundf(pts4[j].x)), int(lroundf(pts4[j].y))}; rpts[j] = pt; } delete[] pts4; RotatedRect rotRect = {Points{rpts, 4}, r, centrpt, szsz, bRect.angle}; return rotRect; } OpenCVResult ConvexHull(PointVector points, Mat hull, bool clockwise, bool returnPoints) { try { cv::convexHull(*points, *hull, clockwise, returnPoints); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult ConvexityDefects(PointVector points, Mat hull, Mat result) { try { cv::convexityDefects(*points, *hull, *result); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult BilateralFilter(Mat src, Mat dst, int d, double sc, double ss) { try { cv::bilateralFilter(*src, *dst, d, sc, ss); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Blur(Mat src, Mat dst, Size ps) { try { cv::Size sz(ps.width, ps.height); cv::blur(*src, *dst, sz); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult BoxFilter(Mat src, Mat dst, int ddepth, Size ps) { try { cv::Size sz(ps.width, ps.height); cv::boxFilter(*src, *dst, ddepth, sz); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult SqBoxFilter(Mat src, Mat dst, int ddepth, Size ps) { try { cv::Size sz(ps.width, ps.height); cv::sqrBoxFilter(*src, *dst, ddepth, sz); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Dilate(Mat src, Mat dst, Mat kernel) { try { cv::dilate(*src, *dst, *kernel); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult DilateWithParams(Mat src, Mat dst, Mat kernel, Point anchor, int iterations, int borderType, Scalar borderValue) { try { cv::Point pt1(anchor.x, anchor.y); cv::Scalar c = cv::Scalar(borderValue.val1, borderValue.val2, borderValue.val3, borderValue.val4); cv::dilate(*src, *dst, *kernel, pt1, iterations, borderType, c); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult DistanceTransform(Mat src, Mat dst, Mat labels, int distanceType, int maskSize, int labelType) { try { cv::distanceTransform(*src, *dst, *labels, distanceType, maskSize, labelType); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Erode(Mat src, Mat dst, Mat kernel) { try { cv::erode(*src, *dst, *kernel); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult ErodeWithParams(Mat src, Mat dst, Mat kernel, Point anchor, int iterations, int borderType) { try { cv::Point pt1(anchor.x, anchor.y); cv::erode(*src, *dst, *kernel, pt1, iterations, borderType, cv::morphologyDefaultBorderValue()); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult ErodeWithParamsAndBorderValue(Mat src, Mat dst, Mat kernel, Point anchor, int iterations, int borderType, Scalar borderValue) { try { cv::Point pt1(anchor.x, anchor.y); cv::Scalar c = cv::Scalar(borderValue.val1, borderValue.val2, borderValue.val3, borderValue.val4); cv::erode(*src, *dst, *kernel, pt1, iterations, borderType, c); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult MatchTemplate(Mat image, Mat templ, Mat result, int method, Mat mask) { try { cv::matchTemplate(*image, *templ, *result, method, *mask); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } struct Moment Moments(Mat src, bool binaryImage) { try { cv::Moments m = cv::moments(*src, binaryImage); Moment mom = {m.m00, m.m10, m.m01, m.m20, m.m11, m.m02, m.m30, m.m21, m.m12, m.m03, m.mu20, m.mu11, m.mu02, m.mu30, m.mu21, m.mu12, m.mu03, m.nu20, m.nu11, m.nu02, m.nu30, m.nu21, m.nu12, m.nu03 }; return mom; } catch(const cv::Exception& e) { setExceptionInfo(e.code, e.what()); Moment mom; return mom; } } OpenCVResult PyrDown(Mat src, Mat dst, Size size, int borderType) { try { cv::Size cvSize(size.width, size.height); cv::pyrDown(*src, *dst, cvSize, borderType); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult PyrUp(Mat src, Mat dst, Size size, int borderType) { try { cv::Size cvSize(size.width, size.height); cv::pyrUp(*src, *dst, cvSize, borderType); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } struct Rect BoundingRect(PointVector pts) { cv::Rect bRect; try { bRect = cv::boundingRect(*pts); Rect r = {bRect.x, bRect.y, bRect.width, bRect.height}; return r; } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); Rect r; return r; } } OpenCVResult BoxPoints(RotatedRect rect, Mat boxPts){ try { cv::Point2f centerPt(rect.center.x , rect.center.y); cv::Size2f rSize(rect.size.width, rect.size.height); cv::RotatedRect rotatedRectangle(centerPt, rSize, rect.angle); cv::boxPoints(rotatedRectangle, *boxPts); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult BoxPoints2f(RotatedRect2f rect, Mat boxPts){ try { cv::Point2f centerPt(rect.center.x , rect.center.y); cv::Size2f rSize(rect.size.width, rect.size.height); cv::RotatedRect rotatedRectangle(centerPt, rSize, rect.angle); cv::boxPoints(rotatedRectangle, *boxPts); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } double ContourArea(PointVector pts) { try { return cv::contourArea(*pts); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return 0.0; } } struct RotatedRect MinAreaRect(PointVector pts){ try { cv::RotatedRect cvrect = cv::minAreaRect(*pts); Point* rpts = new Point[4]; cv::Point2f* pts4 = new cv::Point2f[4]; cvrect.points(pts4); for (size_t j = 0; j < 4; j++) { Point pt = {int(lroundf(pts4[j].x)), int(lroundf(pts4[j].y))}; rpts[j] = pt; } delete[] pts4; cv::Rect bRect = cvrect.boundingRect(); Rect r = {bRect.x, bRect.y, bRect.width, bRect.height}; Point centrpt = {int(lroundf(cvrect.center.x)), int(lroundf(cvrect.center.y))}; Size szsz = {int(lroundf(cvrect.size.width)), int(lroundf(cvrect.size.height))}; RotatedRect retrect = {(Contour){rpts, 4}, r, centrpt, szsz, cvrect.angle}; return retrect; } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); RotatedRect retrect; return retrect; } } struct RotatedRect2f MinAreaRect2f(PointVector pts){ try { cv::RotatedRect cvrect = cv::minAreaRect(*pts); Point2f* rpts = new Point2f[4]; cv::Point2f* pts4 = new cv::Point2f[4]; cvrect.points(pts4); for (size_t j = 0; j < 4; j++) { Point2f pt = {pts4[j].x, pts4[j].y}; rpts[j] = pt; } delete[] pts4; cv::Rect bRect = cvrect.boundingRect(); Rect r = {bRect.x, bRect.y, bRect.width, bRect.height}; Point2f centrpt = {cvrect.center.x, cvrect.center.y}; Size2f szsz = {cvrect.size.width, cvrect.size.height}; RotatedRect2f retrect = {(Contour2f){rpts, 4}, r, centrpt, szsz, cvrect.angle}; return retrect; } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); RotatedRect2f retrect; return retrect; } } OpenCVResult MinEnclosingCircle(PointVector pts, Point2f* center, float* radius){ try { cv::Point2f center2f; cv::minEnclosingCircle(*pts, center2f, *radius); center->x = center2f.x; center->y = center2f.y; return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } PointsVector FindContours(Mat src, Mat hierarchy, int mode, int method) { try { PointsVector contours = new std::vector >; cv::findContours(*src, *contours, *hierarchy, mode, method); return contours; } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } double PointPolygonTest(PointVector pts, Point pt, bool measureDist) { try { cv::Point2f pt1(pt.x, pt.y); return cv::pointPolygonTest(*pts, pt1, measureDist); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return 0.0; } } int ConnectedComponents(Mat src, Mat labels, int connectivity, int ltype, int ccltype){ try { return cv::connectedComponents(*src, *labels, connectivity, ltype, ccltype); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return 0; } } int ConnectedComponentsWithStats(Mat src, Mat labels, Mat stats, Mat centroids, int connectivity, int ltype, int ccltype) { try { return cv::connectedComponentsWithStats(*src, *labels, *stats, *centroids, connectivity, ltype, ccltype); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return 0; } } Mat GetStructuringElement(int shape, Size ksize) { try { cv::Size sz(ksize.width, ksize.height); return new cv::Mat(cv::getStructuringElement(shape, sz)); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return new cv::Mat(); } } Scalar MorphologyDefaultBorderValue(){ try { cv::Scalar cs = cv::morphologyDefaultBorderValue(); return (Scalar){cs[0],cs[1],cs[2],cs[3]}; } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); Scalar scal = Scalar(); return scal; } } OpenCVResult MorphologyEx(Mat src, Mat dst, int op, Mat kernel) { try { cv::morphologyEx(*src, *dst, op, *kernel); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult MorphologyExWithParams(Mat src, Mat dst, int op, Mat kernel, Point pt, int iterations, int borderType) { try { cv::Point pt1(pt.x, pt.y); cv::morphologyEx(*src, *dst, op, *kernel, pt1, iterations, borderType); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult GaussianBlur(Mat src, Mat dst, Size ps, double sX, double sY, int bt) { try { cv::Size sz(ps.width, ps.height); cv::GaussianBlur(*src, *dst, sz, sX, sY, bt); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } Mat GetGaussianKernel(int ksize, double sigma, int ktype){ try { return new cv::Mat(cv::getGaussianKernel(ksize, sigma, ktype)); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return new cv::Mat(); } } OpenCVResult Laplacian(Mat src, Mat dst, int dDepth, int kSize, double scale, double delta, int borderType) { try { cv::Laplacian(*src, *dst, dDepth, kSize, scale, delta, borderType); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Scharr(Mat src, Mat dst, int dDepth, int dx, int dy, double scale, double delta, int borderType) { try { cv::Scharr(*src, *dst, dDepth, dx, dy, scale, delta, borderType); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult MedianBlur(Mat src, Mat dst, int ksize) { try { cv::medianBlur(*src, *dst, ksize); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Canny(Mat src, Mat edges, double t1, double t2) { try { cv::Canny(*src, *edges, t1, t2); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult CornerSubPix(Mat img, Mat corners, Size winSize, Size zeroZone, TermCriteria criteria) { try { cv::Size wsz(winSize.width, winSize.height); cv::Size zsz(zeroZone.width, zeroZone.height); cv::cornerSubPix(*img, *corners, wsz, zsz, *criteria); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult GoodFeaturesToTrack(Mat img, Mat corners, int maxCorners, double quality, double minDist) { try { cv::goodFeaturesToTrack(*img, *corners, maxCorners, quality, minDist); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult GrabCut(Mat img, Mat mask, Rect r, Mat bgdModel, Mat fgdModel, int iterCount, int mode) { try { cv::Rect cvRect = cv::Rect(r.x, r.y, r.width, r.height); cv::grabCut(*img, *mask, cvRect, *bgdModel, *fgdModel, iterCount, mode); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult HoughCircles(Mat src, Mat circles, int method, double dp, double minDist) { try { cv::HoughCircles(*src, *circles, method, dp, minDist); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult HoughCirclesWithParams(Mat src, Mat circles, int method, double dp, double minDist, double param1, double param2, int minRadius, int maxRadius) { try { cv::HoughCircles(*src, *circles, method, dp, minDist, param1, param2, minRadius, maxRadius); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult HoughLines(Mat src, Mat lines, double rho, double theta, int threshold) { try { cv::HoughLines(*src, *lines, rho, theta, threshold); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult HoughLinesP(Mat src, Mat lines, double rho, double theta, int threshold) { try { cv::HoughLinesP(*src, *lines, rho, theta, threshold); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult HoughLinesPWithParams(Mat src, Mat lines, double rho, double theta, int threshold, double minLineLength, double maxLineGap) { try { cv::HoughLinesP(*src, *lines, rho, theta, threshold, minLineLength, maxLineGap); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult HoughLinesPointSet(Mat points, Mat lines, int linesMax, int threshold, double minRho, double maxRho, double rhoStep, double minTheta, double maxTheta, double thetaStep) { try { cv::HoughLinesPointSet(*points, *lines, linesMax, threshold, minRho, maxRho, rhoStep, minTheta, maxTheta, thetaStep ); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Integral(Mat src, Mat sum, Mat sqsum, Mat tilted) { try { cv::integral(*src, *sum, *sqsum, *tilted); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } double Threshold(Mat src, Mat dst, double thresh, double maxvalue, int typ) { try { return cv::threshold(*src, *dst, thresh, maxvalue, typ); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return 0.0; } } OpenCVResult AdaptiveThreshold(Mat src, Mat dst, double maxValue, int adaptiveMethod, int thresholdType, int blockSize, double c) { try { cv::adaptiveThreshold(*src, *dst, maxValue, adaptiveMethod, thresholdType, blockSize, c); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult ArrowedLine(Mat img, Point pt1, Point pt2, Scalar color, int thickness) { try { cv::Point p1(pt1.x, pt1.y); cv::Point p2(pt2.x, pt2.y); cv::Scalar c = cv::Scalar(color.val1, color.val2, color.val3, color.val4); cv::arrowedLine(*img, p1, p2, c, thickness); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } bool ClipLine(Size imgSize, Point pt1, Point pt2) { try { cv::Size sz(imgSize.width, imgSize.height); cv::Point p1(pt1.x, pt1.y); cv::Point p2(pt2.x, pt2.y); return cv::clipLine(sz, p1, p2); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return false; } } OpenCVResult Circle(Mat img, Point center, int radius, Scalar color, int thickness) { try { cv::Point p1(center.x, center.y); cv::Scalar c = cv::Scalar(color.val1, color.val2, color.val3, color.val4); cv::circle(*img, p1, radius, c, thickness); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult CircleWithParams(Mat img, Point center, int radius, Scalar color, int thickness, int lineType, int shift) { try { cv::Point p1(center.x, center.y); cv::Scalar c = cv::Scalar(color.val1, color.val2, color.val3, color.val4); cv::circle(*img, p1, radius, c, thickness, lineType, shift); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Ellipse(Mat img, Point center, Point axes, double angle, double startAngle, double endAngle, Scalar color, int thickness) { try { cv::Point p1(center.x, center.y); cv::Point p2(axes.x, axes.y); cv::Scalar c = cv::Scalar(color.val1, color.val2, color.val3, color.val4); cv::ellipse(*img, p1, p2, angle, startAngle, endAngle, c, thickness); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult EllipseWithParams(Mat img, Point center, Point axes, double angle, double startAngle, double endAngle, Scalar color, int thickness, int lineType, int shift) { try { cv::Point p1(center.x, center.y); cv::Point p2(axes.x, axes.y); cv::Scalar c = cv::Scalar(color.val1, color.val2, color.val3, color.val4); cv::ellipse(*img, p1, p2, angle, startAngle, endAngle, c, thickness, lineType, shift); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Line(Mat img, Point pt1, Point pt2, Scalar color, int thickness) { try { cv::Point p1(pt1.x, pt1.y); cv::Point p2(pt2.x, pt2.y); cv::Scalar c = cv::Scalar(color.val1, color.val2, color.val3, color.val4); cv::line(*img, p1, p2, c, thickness); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Rectangle(Mat img, Rect r, Scalar color, int thickness) { try { cv::Scalar c = cv::Scalar(color.val1, color.val2, color.val3, color.val4); cv::rectangle( *img, cv::Point(r.x, r.y), cv::Point(r.x + r.width, r.y + r.height), c, thickness, cv::LINE_AA ); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult RectangleWithParams(Mat img, Rect r, Scalar color, int thickness, int lineType, int shift) { try { cv::Scalar c = cv::Scalar(color.val1, color.val2, color.val3, color.val4); cv::rectangle( *img, cv::Point(r.x, r.y), cv::Point(r.x + r.width, r.y + r.height), c, thickness, lineType, shift ); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult FillPoly(Mat img, PointsVector pts, Scalar color) { try { cv::Scalar c = cv::Scalar(color.val1, color.val2, color.val3, color.val4); cv::fillPoly(*img, *pts, c); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult FillPolyWithParams(Mat img, PointsVector pts, Scalar color, int lineType, int shift, Point offset) { try { cv::Scalar c = cv::Scalar(color.val1, color.val2, color.val3, color.val4); cv::fillPoly(*img, *pts, c, lineType, shift, cv::Point(offset.x, offset.y)); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Polylines(Mat img, PointsVector pts, bool isClosed, Scalar color,int thickness) { try { cv::Scalar c = cv::Scalar(color.val1, color.val2, color.val3, color.val4); cv::polylines(*img, *pts, isClosed, c, thickness); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } struct Size GetTextSize(const char* text, int fontFace, double fontScale, int thickness) { try { return GetTextSizeWithBaseline(text, fontFace, fontScale, thickness, NULL); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); Size size = {0, 0}; return size; } } struct Size GetTextSizeWithBaseline(const char* text, int fontFace, double fontScale, int thickness, int* baesline) { try { cv::Size sz = cv::getTextSize(text, fontFace, fontScale, thickness, baesline); Size size = {sz.width, sz.height}; return size; } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); Size size = {0, 0}; return size; } } OpenCVResult PutText(Mat img, const char* text, Point org, int fontFace, double fontScale, Scalar color, int thickness) { try { cv::Point pt(org.x, org.y); cv::Scalar c = cv::Scalar(color.val1, color.val2, color.val3, color.val4); cv::putText(*img, text, pt, fontFace, fontScale, c, thickness); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult PutTextWithParams(Mat img, const char* text, Point org, int fontFace, double fontScale, Scalar color, int thickness, int lineType, bool bottomLeftOrigin) { try { cv::Point pt(org.x, org.y); cv::Scalar c = cv::Scalar(color.val1, color.val2, color.val3, color.val4); cv::putText(*img, text, pt, fontFace, fontScale, c, thickness, lineType, bottomLeftOrigin); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Resize(Mat src, Mat dst, Size dsize, double fx, double fy, int interp) { try { cv::Size sz(dsize.width, dsize.height); cv::resize(*src, *dst, sz, fx, fy, interp); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult GetRectSubPix(Mat src, Size patchSize, Point center, Mat dst) { try { cv::Size sz(patchSize.width, patchSize.height); cv::Point pt(center.x, center.y); cv::getRectSubPix(*src, sz, pt, *dst); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } Mat GetRotationMatrix2D(Point center, double angle, double scale) { try { cv::Point pt(center.x, center.y); return new cv::Mat(cv::getRotationMatrix2D(pt, angle, scale)); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return new cv::Mat(); } } OpenCVResult WarpAffine(Mat src, Mat dst, Mat m, Size dsize) { try { cv::Size sz(dsize.width, dsize.height); cv::warpAffine(*src, *dst, *m, sz); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult WarpAffineWithParams(Mat src, Mat dst, Mat rot_mat, Size dsize, int flags, int borderMode, Scalar borderValue) { try { cv::Size sz(dsize.width, dsize.height); cv::Scalar c = cv::Scalar(borderValue.val1, borderValue.val2, borderValue.val3, borderValue.val4); cv::warpAffine(*src, *dst, *rot_mat, sz, flags, borderMode, c); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult WarpPerspective(Mat src, Mat dst, Mat m, Size dsize) { try { cv::Size sz(dsize.width, dsize.height); cv::warpPerspective(*src, *dst, *m, sz); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult WarpPerspectiveWithParams(Mat src, Mat dst, Mat rot_mat, Size dsize, int flags, int borderMode, Scalar borderValue) { try { cv::Size sz(dsize.width, dsize.height); cv::Scalar c = cv::Scalar(borderValue.val1, borderValue.val2, borderValue.val3, borderValue.val4); cv::warpPerspective(*src, *dst, *rot_mat, sz, flags, borderMode, c); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Watershed(Mat image, Mat markers) { try { cv::watershed(*image, *markers); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult ApplyColorMap(Mat src, Mat dst, int colormap) { try { cv::applyColorMap(*src, *dst, colormap); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult ApplyCustomColorMap(Mat src, Mat dst, Mat colormap) { try { cv::applyColorMap(*src, *dst, *colormap); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } Mat GetPerspectiveTransform(PointVector src, PointVector dst) { try { std::vector src_pts; copyPointVectorToPoint2fVector(src, &src_pts); std::vector dst_pts; copyPointVectorToPoint2fVector(dst, &dst_pts); return new cv::Mat(cv::getPerspectiveTransform(src_pts, dst_pts)); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return new cv::Mat(); } } Mat GetPerspectiveTransform2f(Point2fVector src, Point2fVector dst) { try { return new cv::Mat(cv::getPerspectiveTransform(*src, *dst)); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return new cv::Mat(); } } Mat GetAffineTransform(PointVector src, PointVector dst) { try { std::vector src_pts; copyPointVectorToPoint2fVector(src, &src_pts); std::vector dst_pts; copyPointVectorToPoint2fVector(dst, &dst_pts); return new cv::Mat(cv::getAffineTransform(src_pts, dst_pts)); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return new cv::Mat(); } } Mat GetAffineTransform2f(Point2fVector src, Point2fVector dst) { try { return new cv::Mat(cv::getAffineTransform(*src, *dst)); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return new cv::Mat(); } } OpenCVResult DrawContours(Mat src, PointsVector contours, int contourIdx, Scalar color, int thickness) { try { cv::Scalar c = cv::Scalar(color.val1, color.val2, color.val3, color.val4); cv::drawContours(*src, *contours, contourIdx, c, thickness); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult DrawContoursWithParams(Mat src, PointsVector contours, int contourIdx, Scalar color, int thickness, int lineType, Mat hierarchy, int maxLevel, Point offset) { try { cv::Scalar c = cv::Scalar(color.val1, color.val2, color.val3, color.val4); cv::Point offsetPt(offset.x, offset.y); std::vector vecHierarchy; if (hierarchy->empty() == 0) { for (int j = 0; j < hierarchy->cols; ++j) { vecHierarchy.push_back(hierarchy->at(0, j)); } } cv::drawContours(*src, *contours, contourIdx, c, thickness, lineType, vecHierarchy, maxLevel, offsetPt); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Sobel(Mat src, Mat dst, int ddepth, int dx, int dy, int ksize, double scale, double delta, int borderType) { try { cv::Sobel(*src, *dst, ddepth, dx, dy, ksize, scale, delta, borderType); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult SpatialGradient(Mat src, Mat dx, Mat dy, int ksize, int borderType) { try { cv::spatialGradient(*src, *dx, *dy, ksize, borderType); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Remap(Mat src, Mat dst, Mat map1, Mat map2, int interpolation, int borderMode, Scalar borderValue) { try { cv::Scalar c = cv::Scalar(borderValue.val1, borderValue.val2, borderValue.val3, borderValue.val4); cv::remap(*src, *dst, *map1, *map2, interpolation, borderMode, c); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Filter2D(Mat src, Mat dst, int ddepth, Mat kernel, Point anchor, double delta, int borderType) { try { cv::Point anchorPt(anchor.x, anchor.y); cv::filter2D(*src, *dst, ddepth, *kernel, anchorPt, delta, borderType); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult SepFilter2D(Mat src, Mat dst, int ddepth, Mat kernelX, Mat kernelY, Point anchor, double delta, int borderType) { try { cv::Point anchorPt(anchor.x, anchor.y); cv::sepFilter2D(*src, *dst, ddepth, *kernelX, *kernelY, anchorPt, delta, borderType); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult LogPolar(Mat src, Mat dst, Point center, double m, int flags) { try { cv::Point2f centerPt(center.x, center.y); cv::logPolar(*src, *dst, centerPt, m, flags); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult FitLine(PointVector pts, Mat line, int distType, double param, double reps, double aeps) { try { cv::fitLine(*pts, *line, distType, param, reps, aeps); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult LinearPolar(Mat src, Mat dst, Point center, double maxRadius, int flags) { try { cv::Point2f centerPt(center.x, center.y); cv::linearPolar(*src, *dst, centerPt, maxRadius, flags); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } double MatchShapes(PointVector contour1, PointVector contour2, int method, double parameter) { try { return cv::matchShapes(*contour1, *contour2, method, parameter); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return 0.0; } } CLAHE CLAHE_Create() { try { return new cv::Ptr(cv::createCLAHE()); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } CLAHE CLAHE_CreateWithParams(double clipLimit, Size tileGridSize) { try { cv::Size sz(tileGridSize.width, tileGridSize.height); return new cv::Ptr(cv::createCLAHE(clipLimit, sz)); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } void CLAHE_Close(CLAHE c) { delete c; } OpenCVResult CLAHE_Apply(CLAHE c, Mat src, Mat dst) { try { (*c)->apply(*src, *dst); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult InvertAffineTransform(Mat src, Mat dst) { try { cv::invertAffineTransform(*src, *dst); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } Point2f PhaseCorrelate(Mat src1, Mat src2, Mat window, double* response) { try { cv::Point2d result = cv::phaseCorrelate(*src1, *src2, *window, response); Point2f result2f = { .x = float(result.x), .y = float(result.y), }; return result2f; } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); Point2f result2f = { .x = 0.0, .y = 0.0, }; return result2f; } } OpenCVResult CreateHanningWindow(Mat dst, Size size, int typ) { try { cv::Size sz(size.width, size.height); cv::createHanningWindow(*dst, sz, typ); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Mat_Accumulate(Mat src, Mat dst) { try { cv::accumulate(*src, *dst); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Mat_AccumulateWithMask(Mat src, Mat dst, Mat mask) { try { cv::accumulate(*src, *dst, *mask); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Mat_AccumulateSquare(Mat src, Mat dst) { try { cv::accumulateSquare(*src, *dst); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Mat_AccumulateSquareWithMask(Mat src, Mat dst, Mat mask) { try { cv::accumulateSquare(*src, *dst, *mask); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Mat_AccumulateProduct(Mat src1, Mat src2, Mat dst) { try { cv::accumulateProduct(*src1, *src2, *dst); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Mat_AccumulateProductWithMask(Mat src1, Mat src2, Mat dst, Mat mask) { try { cv::accumulateProduct(*src1, *src2, *dst, *mask); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Mat_AccumulatedWeighted(Mat src, Mat dst, double alpha) { try { cv::accumulateWeighted(*src, *dst, alpha); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Mat_AccumulatedWeightedWithMask(Mat src, Mat dst, double alpha, Mat mask) { try { cv::accumulateWeighted(*src, *dst, alpha, *mask); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } ================================================ FILE: imgproc.go ================================================ package gocv /* #include #include "imgproc.h" */ import "C" import ( "errors" "image" "image/color" "reflect" "unsafe" ) // ArcLength calculates a contour perimeter or a curve length. // // For further details, please see: // // https://docs.opencv.org/master/d3/dc0/group__imgproc__shape.html#ga8d26483c636be6b35c3ec6335798a47c func ArcLength(curve PointVector, isClosed bool) float64 { return float64(C.ArcLength(curve.p, C.bool(isClosed))) } // ApproxPolyDP approximates a polygonal curve(s) with the specified precision. // // For further details, please see: // // https://docs.opencv.org/master/d3/dc0/group__imgproc__shape.html#ga0012a5fdaea70b8a9970165d98722b4c func ApproxPolyDP(curve PointVector, epsilon float64, closed bool) PointVector { return PointVector{p: C.ApproxPolyDP(curve.p, C.double(epsilon), C.bool(closed))} } // ConvexHull finds the convex hull of a point set. // // For further details, please see: // https://docs.opencv.org/master/d3/dc0/group__imgproc__shape.html#ga014b28e56cb8854c0de4a211cb2be656 func ConvexHull(points PointVector, hull *Mat, clockwise bool, returnPoints bool) error { return OpenCVResult(C.ConvexHull(points.p, hull.p, C.bool(clockwise), C.bool(returnPoints))) } // ConvexityDefects finds the convexity defects of a contour. // // For further details, please see: // https://docs.opencv.org/master/d3/dc0/group__imgproc__shape.html#gada4437098113fd8683c932e0567f47ba func ConvexityDefects(contour PointVector, hull Mat, result *Mat) error { return OpenCVResult(C.ConvexityDefects(contour.p, hull.p, result.p)) } // CvtColor converts an image from one color space to another. // It converts the src Mat image to the dst Mat using the // code param containing the desired ColorConversionCode color space. // // For further details, please see: // http://docs.opencv.org/master/d7/d1b/group__imgproc__misc.html#ga4e0972be5de079fed4e3a10e24ef5ef0 func CvtColor(src Mat, dst *Mat, code ColorConversionCode) error { return OpenCVResult(C.CvtColor(src.p, dst.p, C.int(code))) } // Demosaicing converts an image from Bayer pattern to RGB or grayscale. // It converts the src Mat image to the dst Mat using the // code param containing the desired ColorConversionCode color space. // // For further details, please see: // https://docs.opencv.org/master/d7/d1b/group__imgproc__color__conversions.html#ga57261f12fccf872a2b2d66daf29d5bd0 func Demosaicing(src Mat, dst *Mat, code ColorConversionCode) error { return OpenCVResult(C.Demosaicing(src.p, dst.p, C.int(code))) } // EqualizeHist normalizes the brightness and increases the contrast of the image. // // For further details, please see: // https://docs.opencv.org/master/d6/dc7/group__imgproc__hist.html#ga7e54091f0c937d49bf84152a16f76d6e func EqualizeHist(src Mat, dst *Mat) error { return OpenCVResult(C.EqualizeHist(src.p, dst.p)) } // CalcHist Calculates a histogram of a set of images // // For futher details, please see: // https://docs.opencv.org/master/d6/dc7/group__imgproc__hist.html#ga6ca1876785483836f72a77ced8ea759a func CalcHist(src []Mat, channels []int, mask Mat, hist *Mat, size []int, ranges []float64, acc bool) error { cMatArray := make([]C.Mat, len(src)) for i, r := range src { cMatArray[i] = r.p } cMats := C.struct_Mats{ mats: (*C.Mat)(&cMatArray[0]), length: C.int(len(src)), } chansInts := []C.int{} for _, v := range channels { chansInts = append(chansInts, C.int(v)) } chansVector := C.struct_IntVector{} chansVector.val = (*C.int)(&chansInts[0]) chansVector.length = (C.int)(len(chansInts)) sizeInts := []C.int{} for _, v := range size { sizeInts = append(sizeInts, C.int(v)) } sizeVector := C.struct_IntVector{} sizeVector.val = (*C.int)(&sizeInts[0]) sizeVector.length = (C.int)(len(sizeInts)) rangeFloats := []C.float{} for _, v := range ranges { rangeFloats = append(rangeFloats, C.float(v)) } rangeVector := C.struct_FloatVector{} rangeVector.val = (*C.float)(&rangeFloats[0]) rangeVector.length = (C.int)(len(rangeFloats)) return OpenCVResult(C.CalcHist(cMats, chansVector, mask.p, hist.p, sizeVector, rangeVector, C.bool(acc))) } // CalcBackProject calculates the back projection of a histogram. // // For futher details, please see: // https://docs.opencv.org/3.4/d6/dc7/group__imgproc__hist.html#ga3a0af640716b456c3d14af8aee12e3ca func CalcBackProject(src []Mat, channels []int, hist Mat, backProject *Mat, ranges []float64, uniform bool) error { cMatArray := make([]C.Mat, len(src)) for i, r := range src { cMatArray[i] = r.p } cMats := C.struct_Mats{ mats: (*C.Mat)(&cMatArray[0]), length: C.int(len(src)), } chansInts := []C.int{} for _, v := range channels { chansInts = append(chansInts, C.int(v)) } chansVector := C.struct_IntVector{} chansVector.val = (*C.int)(&chansInts[0]) chansVector.length = (C.int)(len(chansInts)) rangeFloats := []C.float{} for _, v := range ranges { rangeFloats = append(rangeFloats, C.float(v)) } rangeVector := C.struct_FloatVector{} rangeVector.val = (*C.float)(&rangeFloats[0]) rangeVector.length = (C.int)(len(rangeFloats)) return OpenCVResult(C.CalcBackProject(cMats, chansVector, hist.p, backProject.p, rangeVector, C.bool(uniform))) } // HistCompMethod is the method for Histogram comparison // For more information, see https://docs.opencv.org/master/d6/dc7/group__imgproc__hist.html#ga994f53817d621e2e4228fc646342d386 type HistCompMethod int const ( // HistCmpCorrel calculates the Correlation HistCmpCorrel HistCompMethod = 0 // HistCmpChiSqr calculates the Chi-Square HistCmpChiSqr HistCompMethod = 1 // HistCmpIntersect calculates the Intersection HistCmpIntersect HistCompMethod = 2 // HistCmpBhattacharya applies the HistCmpBhattacharya by calculating the Bhattacharya distance. HistCmpBhattacharya HistCompMethod = 3 // HistCmpHellinger applies the HistCmpBhattacharya comparison. It is a synonym to HistCmpBhattacharya. HistCmpHellinger = HistCmpBhattacharya // HistCmpChiSqrAlt applies the Alternative Chi-Square (regularly used for texture comparsion). HistCmpChiSqrAlt HistCompMethod = 4 // HistCmpKlDiv applies the Kullback-Liebler divergence comparison. HistCmpKlDiv HistCompMethod = 5 ) // CompareHist Compares two histograms. // // For further details, please see: // https://docs.opencv.org/master/d6/dc7/group__imgproc__hist.html#gaf4190090efa5c47cb367cf97a9a519bd func CompareHist(hist1 Mat, hist2 Mat, method HistCompMethod) float32 { return float32(C.CompareHist(hist1.p, hist2.p, C.int(method))) } // EMD Computes the "minimal work" distance between two weighted point configurations. // // For further details, please see: // https://docs.opencv.org/4.x/d6/dc7/group__imgproc__hist.html#ga902b8e60cc7075c8947345489221e0e0 func EMD(signature1, signature2 Mat, typ DistanceTypes) float32 { return float32(C.EMD(signature1.p, signature2.p, C.int(typ))) } // ClipLine clips the line against the image rectangle. // For further details, please see: // https://docs.opencv.org/master/d6/d6e/group__imgproc__draw.html#gaf483cb46ad6b049bc35ec67052ef1c2c func ClipLine(imgSize image.Point, pt1 image.Point, pt2 image.Point) bool { pSize := C.struct_Size{ width: C.int(imgSize.X), height: C.int(imgSize.Y), } rPt1 := C.struct_Point{ x: C.int(pt1.X), y: C.int(pt1.Y), } rPt2 := C.struct_Point{ x: C.int(pt2.X), y: C.int(pt2.Y), } return bool(C.ClipLine(pSize, rPt1, rPt2)) } // BilateralFilter applies a bilateral filter to an image. // // Bilateral filtering is described here: // http://www.dai.ed.ac.uk/CVonline/LOCAL_COPIES/MANDUCHI1/Bilateral_Filtering.html // // BilateralFilter can reduce unwanted noise very well while keeping edges // fairly sharp. However, it is very slow compared to most filters. // // For further details, please see: // https://docs.opencv.org/master/d4/d86/group__imgproc__filter.html#ga9d7064d478c95d60003cf839430737ed func BilateralFilter(src Mat, dst *Mat, diameter int, sigmaColor float64, sigmaSpace float64) error { return OpenCVResult(C.BilateralFilter(src.p, dst.p, C.int(diameter), C.double(sigmaColor), C.double(sigmaSpace))) } // Blur blurs an image Mat using a normalized box filter. // // For further details, please see: // https://docs.opencv.org/master/d4/d86/group__imgproc__filter.html#ga8c45db9afe636703801b0b2e440fce37 func Blur(src Mat, dst *Mat, ksize image.Point) error { pSize := C.struct_Size{ width: C.int(ksize.X), height: C.int(ksize.Y), } return OpenCVResult(C.Blur(src.p, dst.p, pSize)) } // BoxFilter blurs an image using the box filter. // // For further details, please see: // https://docs.opencv.org/master/d4/d86/group__imgproc__filter.html#gad533230ebf2d42509547d514f7d3fbc3 func BoxFilter(src Mat, dst *Mat, depth int, ksize image.Point) error { pSize := C.struct_Size{ height: C.int(ksize.X), width: C.int(ksize.Y), } return OpenCVResult(C.BoxFilter(src.p, dst.p, C.int(depth), pSize)) } // SqBoxFilter calculates the normalized sum of squares of the pixel values overlapping the filter. // // For further details, please see: // https://docs.opencv.org/master/d4/d86/group__imgproc__filter.html#ga045028184a9ef65d7d2579e5c4bff6c0 func SqBoxFilter(src Mat, dst *Mat, depth int, ksize image.Point) error { pSize := C.struct_Size{ height: C.int(ksize.X), width: C.int(ksize.Y), } return OpenCVResult(C.SqBoxFilter(src.p, dst.p, C.int(depth), pSize)) } // Dilate dilates an image by using a specific structuring element. // // For further details, please see: // https://docs.opencv.org/master/d4/d86/group__imgproc__filter.html#ga4ff0f3318642c4f469d0e11f242f3b6c func Dilate(src Mat, dst *Mat, kernel Mat) error { return OpenCVResult(C.Dilate(src.p, dst.p, kernel.p)) } // DilateWithParams dilates an image by using a specific structuring element. // // For further details, please see: // https://docs.opencv.org/master/d4/d86/group__imgproc__filter.html#ga4ff0f3318642c4f469d0e11f242f3b6c func DilateWithParams(src Mat, dst *Mat, kernel Mat, anchor image.Point, iterations int, borderType BorderType, borderValue color.RGBA) error { cAnchor := C.struct_Point{ x: C.int(anchor.X), y: C.int(anchor.Y), } bv := C.struct_Scalar{ val1: C.double(borderValue.B), val2: C.double(borderValue.G), val3: C.double(borderValue.R), val4: C.double(borderValue.A), } return OpenCVResult(C.DilateWithParams(src.p, dst.p, kernel.p, cAnchor, C.int(iterations), C.int(borderType), bv)) } // DistanceTransformLabelTypes are the types of the DistanceTransform algorithm flag type DistanceTransformLabelTypes int const ( // DistanceLabelCComp assigns the same label to each connected component of zeros in the source image // (as well as all the non-zero pixels closest to the connected component). DistanceLabelCComp DistanceTransformLabelTypes = 0 // DistanceLabelPixel assigns its own label to each zero pixel (and all the non-zero pixels closest to it). DistanceLabelPixel ) // DistanceTransformMasks are the marsk sizes for distance transform type DistanceTransformMasks int const ( // DistanceMask3 is a mask of size 3 DistanceMask3 DistanceTransformMasks = 0 // DistanceMask5 is a mask of size 3 DistanceMask5 // DistanceMaskPrecise is not currently supported DistanceMaskPrecise ) // DistanceTransform Calculates the distance to the closest zero pixel for each pixel of the source image. // // For further details, please see: // https://docs.opencv.org/master/d7/d1b/group__imgproc__misc.html#ga8a0b7fdfcb7a13dde018988ba3a43042 func DistanceTransform(src Mat, dst *Mat, labels *Mat, distType DistanceTypes, maskSize DistanceTransformMasks, labelType DistanceTransformLabelTypes) error { return OpenCVResult(C.DistanceTransform(src.p, dst.p, labels.p, C.int(distType), C.int(maskSize), C.int(labelType))) } // Erode erodes an image by using a specific structuring element. // // For further details, please see: // https://docs.opencv.org/master/d4/d86/group__imgproc__filter.html#gaeb1e0c1033e3f6b891a25d0511362aeb func Erode(src Mat, dst *Mat, kernel Mat) error { return OpenCVResult(C.Erode(src.p, dst.p, kernel.p)) } // ErodeWithParams erodes an image by using a specific structuring element. // // For further details, please see: // https://docs.opencv.org/master/d4/d86/group__imgproc__filter.html#gaeb1e0c1033e3f6b891a25d0511362aeb func ErodeWithParams(src Mat, dst *Mat, kernel Mat, anchor image.Point, iterations int, borderType BorderType) error { cAnchor := C.struct_Point{ x: C.int(anchor.X), y: C.int(anchor.Y), } return OpenCVResult(C.ErodeWithParams(src.p, dst.p, kernel.p, cAnchor, C.int(iterations), C.int(borderType))) } // ErodeWithParamsAndBorderValue erodes an image by using a specific structuring // element. Same as ErodeWithParams but requires an additional borderValue // parameter. // // For further details, please see: // https://docs.opencv.org/master/d4/d86/group__imgproc__filter.html#gaeb1e0c1033e3f6b891a25d0511362aeb func ErodeWithParamsAndBorderValue(src Mat, dst *Mat, kernel Mat, anchor image.Point, iterations int, borderType BorderType, borderValue Scalar) error { cAnchor := C.struct_Point{ x: C.int(anchor.X), y: C.int(anchor.Y), } bv := C.struct_Scalar{ val1: C.double(borderValue.Val1), val2: C.double(borderValue.Val2), val3: C.double(borderValue.Val3), val4: C.double(borderValue.Val4), } return OpenCVResult(C.ErodeWithParamsAndBorderValue(src.p, dst.p, kernel.p, cAnchor, C.int(iterations), C.int(borderType), bv)) } // RetrievalMode is the mode of the contour retrieval algorithm. type RetrievalMode int const ( // RetrievalExternal retrieves only the extreme outer contours. // It sets `hierarchy[i][2]=hierarchy[i][3]=-1` for all the contours. RetrievalExternal RetrievalMode = 0 // RetrievalList retrieves all of the contours without establishing // any hierarchical relationships. RetrievalList RetrievalMode = 1 // RetrievalCComp retrieves all of the contours and organizes them into // a two-level hierarchy. At the top level, there are external boundaries // of the components. At the second level, there are boundaries of the holes. // If there is another contour inside a hole of a connected component, it // is still put at the top level. RetrievalCComp RetrievalMode = 2 // RetrievalTree retrieves all of the contours and reconstructs a full // hierarchy of nested contours. RetrievalTree RetrievalMode = 3 // RetrievalFloodfill lacks a description in the original header. RetrievalFloodfill RetrievalMode = 4 ) // ContourApproximationMode is the mode of the contour approximation algorithm. type ContourApproximationMode int const ( // ChainApproxNone stores absolutely all the contour points. That is, // any 2 subsequent points (x1,y1) and (x2,y2) of the contour will be // either horizontal, vertical or diagonal neighbors, that is, // max(abs(x1-x2),abs(y2-y1))==1. ChainApproxNone ContourApproximationMode = 1 // ChainApproxSimple compresses horizontal, vertical, and diagonal segments // and leaves only their end points. // For example, an up-right rectangular contour is encoded with 4 points. ChainApproxSimple ContourApproximationMode = 2 // ChainApproxTC89L1 applies one of the flavors of the Teh-Chin chain // approximation algorithms. ChainApproxTC89L1 ContourApproximationMode = 3 // ChainApproxTC89KCOS applies one of the flavors of the Teh-Chin chain // approximation algorithms. ChainApproxTC89KCOS ContourApproximationMode = 4 ) // BoundingRect calculates the up-right bounding rectangle of a point set. // // For further details, please see: // https://docs.opencv.org/3.3.0/d3/dc0/group__imgproc__shape.html#gacb413ddce8e48ff3ca61ed7cf626a366 func BoundingRect(contour PointVector) image.Rectangle { r := C.BoundingRect(contour.p) rect := image.Rect(int(r.x), int(r.y), int(r.x+r.width), int(r.y+r.height)) return rect } // BoxPoints finds the four vertices of a rotated rect. Useful to draw the rotated rectangle. // // For further Details, please see: // https://docs.opencv.org/3.3.0/d3/dc0/group__imgproc__shape.html#gaf78d467e024b4d7936cf9397185d2f5c func BoxPoints(rect RotatedRect, pts *Mat) error { rPoints := toCPoints(rect.Points) rRect := C.struct_Rect{ x: C.int(rect.BoundingRect.Min.X), y: C.int(rect.BoundingRect.Min.Y), width: C.int(rect.BoundingRect.Max.X - rect.BoundingRect.Min.X), height: C.int(rect.BoundingRect.Max.Y - rect.BoundingRect.Min.Y), } rCenter := C.struct_Point{ x: C.int(rect.Center.X), y: C.int(rect.Center.Y), } rSize := C.struct_Size{ width: C.int(rect.Width), height: C.int(rect.Height), } r := C.struct_RotatedRect{ pts: rPoints, boundingRect: rRect, center: rCenter, size: rSize, angle: C.double(rect.Angle), } return OpenCVResult(C.BoxPoints(r, pts.p)) } // BoxPoints finds the four vertices of a rotated rect. Useful to draw the rotated rectangle. // // For further Details, please see: // https://docs.opencv.org/3.3.0/d3/dc0/group__imgproc__shape.html#gaf78d467e024b4d7936cf9397185d2f5c func BoxPoints2f(rect RotatedRect2f, pts *Mat) error { rPoints := toCPoints2f(rect.Points) rRect := C.struct_Rect{ x: C.int(rect.BoundingRect.Min.X), y: C.int(rect.BoundingRect.Min.Y), width: C.int(rect.BoundingRect.Max.X - rect.BoundingRect.Min.X), height: C.int(rect.BoundingRect.Max.Y - rect.BoundingRect.Min.Y), } rCenter := C.struct_Point2f{ x: C.float(rect.Center.X), y: C.float(rect.Center.Y), } rSize := C.struct_Size2f{ width: C.float(rect.Width), height: C.float(rect.Height), } r := C.struct_RotatedRect2f{ pts: rPoints, boundingRect: rRect, center: rCenter, size: rSize, angle: C.double(rect.Angle), } return OpenCVResult(C.BoxPoints2f(r, pts.p)) } // ContourArea calculates a contour area. // // For further details, please see: // https://docs.opencv.org/3.3.0/d3/dc0/group__imgproc__shape.html#ga2c759ed9f497d4a618048a2f56dc97f1 func ContourArea(contour PointVector) float64 { result := C.ContourArea(contour.p) return float64(result) } type RotatedRect struct { Points []image.Point BoundingRect image.Rectangle Center image.Point Width int Height int Angle float64 } type RotatedRect2f struct { Points []Point2f BoundingRect image.Rectangle Center Point2f Width float32 Height float32 Angle float64 } // toPoints converts C.Contour to []image.Points func toPoints(points C.Contour) []image.Point { pArray := points.points pLength := int(points.length) pHdr := reflect.SliceHeader{ Data: uintptr(unsafe.Pointer(pArray)), Len: pLength, Cap: pLength, } sPoints := *(*[]C.Point)(unsafe.Pointer(&pHdr)) points4 := make([]image.Point, pLength) for j, pt := range sPoints { points4[j] = image.Pt(int(pt.x), int(pt.y)) } return points4 } // toPoints2f converts C.Contour2f to []Point2f func toPoints2f(points C.Contour2f) []Point2f { pArray := points.points pLength := int(points.length) pHdr := reflect.SliceHeader{ Data: uintptr(unsafe.Pointer(pArray)), Len: pLength, Cap: pLength, } sPoints := *(*[]C.Point)(unsafe.Pointer(&pHdr)) points4 := make([]Point2f, pLength) for j, pt := range sPoints { points4[j] = NewPoint2f(float32(pt.x), float32(pt.y)) } return points4 } // MinAreaRect finds a rotated rectangle of the minimum area enclosing the input 2D point set. // // For further details, please see: // https://docs.opencv.org/master/d3/dc0/group__imgproc__shape.html#ga3d476a3417130ae5154aea421ca7ead9 func MinAreaRect(points PointVector) RotatedRect { result := C.MinAreaRect(points.p) defer C.Points_Close(result.pts) return RotatedRect{ Points: toPoints(result.pts), BoundingRect: image.Rect(int(result.boundingRect.x), int(result.boundingRect.y), int(result.boundingRect.x)+int(result.boundingRect.width), int(result.boundingRect.y)+int(result.boundingRect.height)), Center: image.Pt(int(result.center.x), int(result.center.y)), Width: int(result.size.width), Height: int(result.size.height), Angle: float64(result.angle), } } // MinAreaRect finds a rotated rectangle of the minimum area enclosing the input 2D point set. // // For further details, please see: // https://docs.opencv.org/master/d3/dc0/group__imgproc__shape.html#ga3d476a3417130ae5154aea421ca7ead9 func MinAreaRect2f(points PointVector) RotatedRect2f { result := C.MinAreaRect2f(points.p) defer C.Points2f_Close(result.pts) return RotatedRect2f{ Points: toPoints2f(result.pts), BoundingRect: image.Rect(int(result.boundingRect.x), int(result.boundingRect.y), int(result.boundingRect.x)+int(result.boundingRect.width), int(result.boundingRect.y)+int(result.boundingRect.height)), Center: NewPoint2f(float32(result.center.x), float32(result.center.y)), Width: float32(result.size.width), Height: float32(result.size.height), Angle: float64(result.angle), } } // FitEllipse Fits an ellipse around a set of 2D points. // // For further details, please see: // https://docs.opencv.org/master/d3/dc0/group__imgproc__shape.html#gaf259efaad93098103d6c27b9e4900ffa func FitEllipse(pts PointVector) RotatedRect { cRect := C.FitEllipse(pts.p) defer C.Points_Close(cRect.pts) return RotatedRect{ Points: toPoints(cRect.pts), BoundingRect: image.Rect(int(cRect.boundingRect.x), int(cRect.boundingRect.y), int(cRect.boundingRect.x)+int(cRect.boundingRect.width), int(cRect.boundingRect.y)+int(cRect.boundingRect.height)), Center: image.Pt(int(cRect.center.x), int(cRect.center.y)), Width: int(cRect.size.width), Height: int(cRect.size.height), Angle: float64(cRect.angle), } } // MinEnclosingCircle finds a circle of the minimum area enclosing the input 2D point set. // // For further details, please see: // https://docs.opencv.org/3.4/d3/dc0/group__imgproc__shape.html#ga8ce13c24081bbc7151e9326f412190f1 func MinEnclosingCircle(pts PointVector) (x, y, radius float32) { cCenterPoint := C.struct_Point2f{} var cRadius C.float C.MinEnclosingCircle(pts.p, &cCenterPoint, &cRadius) x, y = float32(cCenterPoint.x), float32(cCenterPoint.y) radius = float32(cRadius) return x, y, radius } // FindContours finds contours in a binary image. // // For further details, please see: // https://docs.opencv.org/master/d3/dc0/group__imgproc__shape.html#ga95f5b48d01abc7c2e0732db24689837b func FindContours(src Mat, mode RetrievalMode, method ContourApproximationMode) PointsVector { hierarchy := NewMat() defer hierarchy.Close() return FindContoursWithParams(src, &hierarchy, mode, method) } // FindContoursWithParams finds contours in a binary image. // // For further details, please see: // https://docs.opencv.org/master/d3/dc0/group__imgproc__shape.html#ga17ed9f5d79ae97bd4c7cf18403e1689a func FindContoursWithParams(src Mat, hierarchy *Mat, mode RetrievalMode, method ContourApproximationMode) PointsVector { return PointsVector{p: C.FindContours(src.p, hierarchy.p, C.int(mode), C.int(method))} } // PointPolygonTest performs a point-in-contour test. // // For further details, please see: // https://docs.opencv.org/master/d3/dc0/group__imgproc__shape.html#ga1a539e8db2135af2566103705d7a5722 func PointPolygonTest(pts PointVector, pt image.Point, measureDist bool) float64 { cp := C.struct_Point{ x: C.int(pt.X), y: C.int(pt.Y), } return float64(C.PointPolygonTest(pts.p, cp, C.bool(measureDist))) } // ConnectedComponentsAlgorithmType specifies the type for ConnectedComponents type ConnectedComponentsAlgorithmType int const ( // SAUF algorithm for 8-way connectivity, SAUF algorithm for 4-way connectivity. CCL_WU ConnectedComponentsAlgorithmType = 0 // BBDT algorithm for 8-way connectivity, SAUF algorithm for 4-way connectivity. CCL_DEFAULT ConnectedComponentsAlgorithmType = 1 // BBDT algorithm for 8-way connectivity, SAUF algorithm for 4-way connectivity CCL_GRANA ConnectedComponentsAlgorithmType = 2 ) // ConnectedComponents computes the connected components labeled image of boolean image. // // For further details, please see: // https://docs.opencv.org/master/d3/dc0/group__imgproc__shape.html#gaedef8c7340499ca391d459122e51bef5 func ConnectedComponents(src Mat, labels *Mat) int { return int(C.ConnectedComponents(src.p, labels.p, C.int(8), C.int(MatTypeCV32S), C.int(CCL_DEFAULT))) } // ConnectedComponents computes the connected components labeled image of boolean image. // // For further details, please see: // https://docs.opencv.org/master/d3/dc0/group__imgproc__shape.html#gaedef8c7340499ca391d459122e51bef5 func ConnectedComponentsWithParams(src Mat, labels *Mat, conn int, ltype MatType, ccltype ConnectedComponentsAlgorithmType) int { return int(C.ConnectedComponents(src.p, labels.p, C.int(conn), C.int(ltype), C.int(ccltype))) } // ConnectedComponentsTypes are the connected components algorithm output formats type ConnectedComponentsTypes int const ( //The leftmost (x) coordinate which is the inclusive start of the bounding box in the horizontal direction. CC_STAT_LEFT ConnectedComponentsTypes = 0 //The topmost (y) coordinate which is the inclusive start of the bounding box in the vertical direction. CC_STAT_TOP ConnectedComponentsTypes = 1 // The horizontal size of the bounding box. CC_STAT_WIDTH ConnectedComponentsTypes = 2 // The vertical size of the bounding box. CC_STAT_HEIGHT ConnectedComponentsTypes = 3 // The total area (in pixels) of the connected component. CC_STAT_AREA ConnectedComponentsTypes = 4 CC_STAT_MAX ConnectedComponentsTypes = 5 ) // ConnectedComponentsWithStats computes the connected components labeled image of boolean // image and also produces a statistics output for each label. // // For further details, please see: // https://docs.opencv.org/master/d3/dc0/group__imgproc__shape.html#ga107a78bf7cd25dec05fb4dfc5c9e765f func ConnectedComponentsWithStats(src Mat, labels *Mat, stats *Mat, centroids *Mat) int { return int(C.ConnectedComponentsWithStats(src.p, labels.p, stats.p, centroids.p, C.int(8), C.int(MatTypeCV32S), C.int(CCL_DEFAULT))) } // ConnectedComponentsWithStats computes the connected components labeled image of boolean // image and also produces a statistics output for each label. // // For further details, please see: // https://docs.opencv.org/master/d3/dc0/group__imgproc__shape.html#ga107a78bf7cd25dec05fb4dfc5c9e765f func ConnectedComponentsWithStatsWithParams(src Mat, labels *Mat, stats *Mat, centroids *Mat, conn int, ltype MatType, ccltype ConnectedComponentsAlgorithmType) int { return int(C.ConnectedComponentsWithStats(src.p, labels.p, stats.p, centroids.p, C.int(conn), C.int(ltype), C.int(ccltype))) } // TemplateMatchMode is the type of the template matching operation. type TemplateMatchMode int const ( // TmSqdiff maps to TM_SQDIFF TmSqdiff TemplateMatchMode = 0 // TmSqdiffNormed maps to TM_SQDIFF_NORMED TmSqdiffNormed TemplateMatchMode = 1 // TmCcorr maps to TM_CCORR TmCcorr TemplateMatchMode = 2 // TmCcorrNormed maps to TM_CCORR_NORMED TmCcorrNormed TemplateMatchMode = 3 // TmCcoeff maps to TM_CCOEFF TmCcoeff TemplateMatchMode = 4 // TmCcoeffNormed maps to TM_CCOEFF_NORMED TmCcoeffNormed TemplateMatchMode = 5 ) // MatchTemplate compares a template against overlapped image regions. // // For further details, please see: // https://docs.opencv.org/master/df/dfb/group__imgproc__object.html#ga586ebfb0a7fb604b35a23d85391329be func MatchTemplate(image Mat, templ Mat, result *Mat, method TemplateMatchMode, mask Mat) error { return OpenCVResult(C.MatchTemplate(image.p, templ.p, result.p, C.int(method), mask.p)) } // Moments calculates all of the moments up to the third order of a polygon // or rasterized shape. // // For further details, please see: // https://docs.opencv.org/master/d3/dc0/group__imgproc__shape.html#ga556a180f43cab22649c23ada36a8a139 func Moments(src Mat, binaryImage bool) map[string]float64 { r := C.Moments(src.p, C.bool(binaryImage)) result := make(map[string]float64) result["m00"] = float64(r.m00) result["m10"] = float64(r.m10) result["m01"] = float64(r.m01) result["m20"] = float64(r.m20) result["m11"] = float64(r.m11) result["m02"] = float64(r.m02) result["m30"] = float64(r.m30) result["m21"] = float64(r.m21) result["m12"] = float64(r.m12) result["m03"] = float64(r.m03) result["mu20"] = float64(r.mu20) result["mu11"] = float64(r.mu11) result["mu02"] = float64(r.mu02) result["mu30"] = float64(r.mu30) result["mu21"] = float64(r.mu21) result["mu12"] = float64(r.mu12) result["mu03"] = float64(r.mu03) result["nu20"] = float64(r.nu20) result["nu11"] = float64(r.nu11) result["nu02"] = float64(r.nu02) result["nu30"] = float64(r.nu30) result["nu21"] = float64(r.nu21) result["nu12"] = float64(r.nu12) result["nu03"] = float64(r.nu03) return result } // PyrDown blurs an image and downsamples it. // // For further details, please see: // https://docs.opencv.org/master/d4/d86/group__imgproc__filter.html#gaf9bba239dfca11654cb7f50f889fc2ff func PyrDown(src Mat, dst *Mat, ksize image.Point, borderType BorderType) error { pSize := C.struct_Size{ height: C.int(ksize.X), width: C.int(ksize.Y), } return OpenCVResult(C.PyrDown(src.p, dst.p, pSize, C.int(borderType))) } // PyrUp upsamples an image and then blurs it. // // For further details, please see: // https://docs.opencv.org/master/d4/d86/group__imgproc__filter.html#gada75b59bdaaca411ed6fee10085eb784 func PyrUp(src Mat, dst *Mat, ksize image.Point, borderType BorderType) error { pSize := C.struct_Size{ height: C.int(ksize.X), width: C.int(ksize.Y), } return OpenCVResult(C.PyrUp(src.p, dst.p, pSize, C.int(borderType))) } // MorphologyDefaultBorder returns "magic" border value for erosion and dilation. // It is automatically transformed to Scalar::all(-DBL_MAX) for dilation. // // For further details, please see: // https://docs.opencv.org/master/d4/d86/group__imgproc__filter.html#ga94756fad83d9d24d29c9bf478558c40a func MorphologyDefaultBorderValue() Scalar { var scalar C.Scalar = C.MorphologyDefaultBorderValue() return NewScalar(float64(scalar.val1), float64(scalar.val2), float64(scalar.val3), float64(scalar.val4)) } // MorphologyEx performs advanced morphological transformations. // // For further details, please see: // https://docs.opencv.org/master/d4/d86/group__imgproc__filter.html#ga67493776e3ad1a3df63883829375201f func MorphologyEx(src Mat, dst *Mat, op MorphType, kernel Mat) error { return OpenCVResult(C.MorphologyEx(src.p, dst.p, C.int(op), kernel.p)) } // MorphologyExWithParams performs advanced morphological transformations. // // For further details, please see: // https://docs.opencv.org/master/d4/d86/group__imgproc__filter.html#ga67493776e3ad1a3df63883829375201f func MorphologyExWithParams(src Mat, dst *Mat, op MorphType, kernel Mat, iterations int, borderType BorderType) error { pt := C.struct_Point{ x: C.int(-1), y: C.int(-1), } return OpenCVResult(C.MorphologyExWithParams(src.p, dst.p, C.int(op), kernel.p, pt, C.int(iterations), C.int(borderType))) } // MorphShape is the shape of the structuring element used for Morphing operations. type MorphShape int const ( // MorphRect is the rectangular morph shape. MorphRect MorphShape = 0 // MorphCross is the cross morph shape. MorphCross MorphShape = 1 // MorphEllipse is the ellipse morph shape. MorphEllipse MorphShape = 2 ) // GetStructuringElement returns a structuring element of the specified size // and shape for morphological operations. // // For further details, please see: // https://docs.opencv.org/master/d4/d86/group__imgproc__filter.html#gac342a1bb6eabf6f55c803b09268e36dc func GetStructuringElement(shape MorphShape, ksize image.Point) Mat { sz := C.struct_Size{ width: C.int(ksize.X), height: C.int(ksize.Y), } return newMat(C.GetStructuringElement(C.int(shape), sz)) } // MorphType type of morphological operation. type MorphType int const ( // MorphErode operation MorphErode MorphType = 0 // MorphDilate operation MorphDilate MorphType = 1 // MorphOpen operation MorphOpen MorphType = 2 // MorphClose operation MorphClose MorphType = 3 // MorphGradient operation MorphGradient MorphType = 4 // MorphTophat operation MorphTophat MorphType = 5 // MorphBlackhat operation MorphBlackhat MorphType = 6 // MorphHitmiss operation MorphHitmiss MorphType = 7 ) // BorderType type of border. type BorderType int const ( // BorderConstant border type BorderConstant BorderType = 0 // BorderReplicate border type BorderReplicate BorderType = 1 // BorderReflect border type BorderReflect BorderType = 2 // BorderWrap border type BorderWrap BorderType = 3 // BorderReflect101 border type BorderReflect101 BorderType = 4 // BorderTransparent border type BorderTransparent BorderType = 5 // BorderDefault border type BorderDefault = BorderReflect101 // BorderIsolated border type BorderIsolated BorderType = 16 ) // GaussianBlur blurs an image Mat using a Gaussian filter. // The function convolves the src Mat image into the dst Mat using // the specified Gaussian kernel params. // // For further details, please see: // http://docs.opencv.org/master/d4/d86/group__imgproc__filter.html#gaabe8c836e97159a9193fb0b11ac52cf1 func GaussianBlur(src Mat, dst *Mat, ksize image.Point, sigmaX float64, sigmaY float64, borderType BorderType) error { pSize := C.struct_Size{ width: C.int(ksize.X), height: C.int(ksize.Y), } return OpenCVResult(C.GaussianBlur(src.p, dst.p, pSize, C.double(sigmaX), C.double(sigmaY), C.int(borderType))) } // GetGaussianKernel returns Gaussian filter coefficients. // // For further details, please see: // https://docs.opencv.org/master/d4/d86/group__imgproc__filter.html#gac05a120c1ae92a6060dd0db190a61afa func GetGaussianKernel(ksize int, sigma float64) Mat { return newMat(C.GetGaussianKernel(C.int(ksize), C.double(sigma), C.int(MatTypeCV64F))) } // GetGaussianKernelWithParams returns Gaussian filter coefficients. // // For further details, please see: // https://docs.opencv.org/master/d4/d86/group__imgproc__filter.html#gac05a120c1ae92a6060dd0db190a61afa func GetGaussianKernelWithParams(ksize int, sigma float64, ktype MatType) Mat { return newMat(C.GetGaussianKernel(C.int(ksize), C.double(sigma), C.int(ktype))) } // Sobel calculates the first, second, third, or mixed image derivatives using an extended Sobel operator // // For further details, please see: // https://docs.opencv.org/master/d4/d86/group__imgproc__filter.html#gacea54f142e81b6758cb6f375ce782c8d func Sobel(src Mat, dst *Mat, ddepth MatType, dx, dy, ksize int, scale, delta float64, borderType BorderType) error { return OpenCVResult(C.Sobel(src.p, dst.p, C.int(ddepth), C.int(dx), C.int(dy), C.int(ksize), C.double(scale), C.double(delta), C.int(borderType))) } // SpatialGradient calculates the first order image derivative in both x and y using a Sobel operator. // // For further details, please see: // https://docs.opencv.org/master/d4/d86/group__imgproc__filter.html#ga405d03b20c782b65a4daf54d233239a2 func SpatialGradient(src Mat, dx, dy *Mat, ksize MatType, borderType BorderType) error { return OpenCVResult(C.SpatialGradient(src.p, dx.p, dy.p, C.int(ksize), C.int(borderType))) } // Laplacian calculates the Laplacian of an image. // // For further details, please see: // https://docs.opencv.org/master/d4/d86/group__imgproc__filter.html#gad78703e4c8fe703d479c1860d76429e6 func Laplacian(src Mat, dst *Mat, dDepth MatType, size int, scale float64, delta float64, borderType BorderType) error { return OpenCVResult(C.Laplacian(src.p, dst.p, C.int(dDepth), C.int(size), C.double(scale), C.double(delta), C.int(borderType))) } // Scharr calculates the first x- or y- image derivative using Scharr operator. // // For further details, please see: // https://docs.opencv.org/master/d4/d86/group__imgproc__filter.html#gaa13106761eedf14798f37aa2d60404c9 func Scharr(src Mat, dst *Mat, dDepth MatType, dx int, dy int, scale float64, delta float64, borderType BorderType) error { return OpenCVResult(C.Scharr(src.p, dst.p, C.int(dDepth), C.int(dx), C.int(dy), C.double(scale), C.double(delta), C.int(borderType))) } // MedianBlur blurs an image using the median filter. // // For further details, please see: // https://docs.opencv.org/master/d4/d86/group__imgproc__filter.html#ga564869aa33e58769b4469101aac458f9 func MedianBlur(src Mat, dst *Mat, ksize int) error { return OpenCVResult(C.MedianBlur(src.p, dst.p, C.int(ksize))) } // Canny finds edges in an image using the Canny algorithm. // The function finds edges in the input image image and marks // them in the output map edges using the Canny algorithm. // The smallest value between threshold1 and threshold2 is used // for edge linking. The largest value is used to // find initial segments of strong edges. // See http://en.wikipedia.org/wiki/Canny_edge_detector // // For further details, please see: // http://docs.opencv.org/master/dd/d1a/group__imgproc__feature.html#ga04723e007ed888ddf11d9ba04e2232de func Canny(src Mat, edges *Mat, t1 float32, t2 float32) error { return OpenCVResult(C.Canny(src.p, edges.p, C.double(t1), C.double(t2))) } // CornerSubPix Refines the corner locations. The function iterates to find // the sub-pixel accurate location of corners or radial saddle points. // // For further details, please see: // https://docs.opencv.org/master/dd/d1a/group__imgproc__feature.html#ga354e0d7c86d0d9da75de9b9701a9a87e func CornerSubPix(img Mat, corners *Mat, winSize image.Point, zeroZone image.Point, criteria TermCriteria) error { winSz := C.struct_Size{ width: C.int(winSize.X), height: C.int(winSize.Y), } zeroSz := C.struct_Size{ width: C.int(zeroZone.X), height: C.int(zeroZone.Y), } return OpenCVResult(C.CornerSubPix(img.p, corners.p, winSz, zeroSz, criteria.p)) } // GoodFeaturesToTrack determines strong corners on an image. The function // finds the most prominent corners in the image or in the specified image region. // // For further details, please see: // https://docs.opencv.org/master/dd/d1a/group__imgproc__feature.html#ga1d6bb77486c8f92d79c8793ad995d541 func GoodFeaturesToTrack(img Mat, corners *Mat, maxCorners int, quality float64, minDist float64) error { return OpenCVResult(C.GoodFeaturesToTrack(img.p, corners.p, C.int(maxCorners), C.double(quality), C.double(minDist))) } // GrabCutMode is the flag for GrabCut algorithm. type GrabCutMode int const ( // GCInitWithRect makes the function initialize the state and the mask using the provided rectangle. // After that it runs the itercount iterations of the algorithm. GCInitWithRect GrabCutMode = 0 // GCInitWithMask makes the function initialize the state using the provided mask. // GCInitWithMask and GCInitWithRect can be combined. // Then all the pixels outside of the ROI are automatically initialized with GC_BGD. GCInitWithMask GrabCutMode = 1 // GCEval means that the algorithm should just resume. GCEval GrabCutMode = 2 // GCEvalFreezeModel means that the algorithm should just run a single iteration of the GrabCut algorithm // with the fixed model GCEvalFreezeModel GrabCutMode = 3 ) // Grabcut runs the GrabCut algorithm. // The function implements the GrabCut image segmentation algorithm. // For further details, please see: // https://docs.opencv.org/master/d7/d1b/group__imgproc__misc.html#ga909c1dda50efcbeaa3ce126be862b37f func GrabCut(img Mat, mask *Mat, r image.Rectangle, bgdModel *Mat, fgdModel *Mat, iterCount int, mode GrabCutMode) error { cRect := C.struct_Rect{ x: C.int(r.Min.X), y: C.int(r.Min.Y), width: C.int(r.Size().X), height: C.int(r.Size().Y), } return OpenCVResult(C.GrabCut(img.p, mask.p, cRect, bgdModel.p, fgdModel.p, C.int(iterCount), C.int(mode))) } // HoughMode is the type for Hough transform variants. type HoughMode int const ( // HoughStandard is the classical or standard Hough transform. HoughStandard HoughMode = 0 // HoughProbabilistic is the probabilistic Hough transform (more efficient // in case if the picture contains a few long linear segments). HoughProbabilistic HoughMode = 1 // HoughMultiScale is the multi-scale variant of the classical Hough // transform. HoughMultiScale HoughMode = 2 // HoughGradient is basically 21HT, described in: HK Yuen, John Princen, // John Illingworth, and Josef Kittler. Comparative study of hough // transform methods for circle finding. Image and Vision Computing, // 8(1):71–77, 1990. HoughGradient HoughMode = 3 ) // HoughCircles finds circles in a grayscale image using the Hough transform. // The only "method" currently supported is HoughGradient. If you want to pass // more parameters, please see `HoughCirclesWithParams`. // // For further details, please see: // https://docs.opencv.org/master/dd/d1a/group__imgproc__feature.html#ga47849c3be0d0406ad3ca45db65a25d2d func HoughCircles(src Mat, circles *Mat, method HoughMode, dp, minDist float64) error { return OpenCVResult(C.HoughCircles(src.p, circles.p, C.int(method), C.double(dp), C.double(minDist))) } // HoughCirclesWithParams finds circles in a grayscale image using the Hough // transform. The only "method" currently supported is HoughGradient. // // For further details, please see: // https://docs.opencv.org/master/dd/d1a/group__imgproc__feature.html#ga47849c3be0d0406ad3ca45db65a25d2d func HoughCirclesWithParams(src Mat, circles *Mat, method HoughMode, dp, minDist, param1, param2 float64, minRadius, maxRadius int) error { return OpenCVResult(C.HoughCirclesWithParams(src.p, circles.p, C.int(method), C.double(dp), C.double(minDist), C.double(param1), C.double(param2), C.int(minRadius), C.int(maxRadius))) } // HoughLines implements the standard or standard multi-scale Hough transform // algorithm for line detection. For a good explanation of Hough transform, see: // http://homepages.inf.ed.ac.uk/rbf/HIPR2/hough.htm // // For further details, please see: // http://docs.opencv.org/master/dd/d1a/group__imgproc__feature.html#ga46b4e588934f6c8dfd509cc6e0e4545a func HoughLines(src Mat, lines *Mat, rho float32, theta float32, threshold int) error { return OpenCVResult(C.HoughLines(src.p, lines.p, C.double(rho), C.double(theta), C.int(threshold))) } // HoughLinesP implements the probabilistic Hough transform // algorithm for line detection. For a good explanation of Hough transform, see: // http://homepages.inf.ed.ac.uk/rbf/HIPR2/hough.htm // // For further details, please see: // http://docs.opencv.org/master/dd/d1a/group__imgproc__feature.html#ga8618180a5948286384e3b7ca02f6feeb func HoughLinesP(src Mat, lines *Mat, rho float32, theta float32, threshold int) error { return OpenCVResult(C.HoughLinesP(src.p, lines.p, C.double(rho), C.double(theta), C.int(threshold))) } func HoughLinesPWithParams(src Mat, lines *Mat, rho float32, theta float32, threshold int, minLineLength float32, maxLineGap float32) error { return OpenCVResult(C.HoughLinesPWithParams(src.p, lines.p, C.double(rho), C.double(theta), C.int(threshold), C.double(minLineLength), C.double(maxLineGap))) } // HoughLinesPointSet implements the Hough transform algorithm for line // detection on a set of points. For a good explanation of Hough transform, see: // http://homepages.inf.ed.ac.uk/rbf/HIPR2/hough.htm // // For further details, please see: // https://docs.opencv.org/master/dd/d1a/group__imgproc__feature.html#ga2858ef61b4e47d1919facac2152a160e func HoughLinesPointSet(points Mat, lines *Mat, linesMax int, threshold int, minRho float32, maxRho float32, rhoStep float32, minTheta float32, maxTheta float32, thetaStep float32) error { return OpenCVResult(C.HoughLinesPointSet(points.p, lines.p, C.int(linesMax), C.int(threshold), C.double(minRho), C.double(maxRho), C.double(rhoStep), C.double(minTheta), C.double(maxTheta), C.double(thetaStep))) } // Integral calculates one or more integral images for the source image. // For further details, please see: // https://docs.opencv.org/master/d7/d1b/group__imgproc__misc.html#ga97b87bec26908237e8ba0f6e96d23e28 func Integral(src Mat, sum *Mat, sqsum *Mat, tilted *Mat) error { return OpenCVResult(C.Integral(src.p, sum.p, sqsum.p, tilted.p)) } // ThresholdType type of threshold operation. type ThresholdType int const ( // ThresholdBinary threshold type ThresholdBinary ThresholdType = 0 // ThresholdBinaryInv threshold type ThresholdBinaryInv ThresholdType = 1 // ThresholdTrunc threshold type ThresholdTrunc ThresholdType = 2 // ThresholdToZero threshold type ThresholdToZero ThresholdType = 3 // ThresholdToZeroInv threshold type ThresholdToZeroInv ThresholdType = 4 // ThresholdMask threshold type ThresholdMask ThresholdType = 7 // ThresholdOtsu threshold type ThresholdOtsu ThresholdType = 8 // ThresholdTriangle threshold type ThresholdTriangle ThresholdType = 16 ) // Threshold applies a fixed-level threshold to each array element. // // For further details, please see: // https://docs.opencv.org/3.3.0/d7/d1b/group__imgproc__misc.html#gae8a4a146d1ca78c626a53577199e9c57 func Threshold(src Mat, dst *Mat, thresh float32, maxvalue float32, typ ThresholdType) (threshold float32) { return float32(C.Threshold(src.p, dst.p, C.double(thresh), C.double(maxvalue), C.int(typ))) } // AdaptiveThresholdType type of adaptive threshold operation. type AdaptiveThresholdType int const ( // AdaptiveThresholdMean threshold type AdaptiveThresholdMean AdaptiveThresholdType = 0 // AdaptiveThresholdGaussian threshold type AdaptiveThresholdGaussian AdaptiveThresholdType = 1 ) // AdaptiveThreshold applies a fixed-level threshold to each array element. // // For further details, please see: // https://docs.opencv.org/master/d7/d1b/group__imgproc__misc.html#ga72b913f352e4a1b1b397736707afcde3 func AdaptiveThreshold(src Mat, dst *Mat, maxValue float32, adaptiveTyp AdaptiveThresholdType, typ ThresholdType, blockSize int, c float32) error { return OpenCVResult(C.AdaptiveThreshold(src.p, dst.p, C.double(maxValue), C.int(adaptiveTyp), C.int(typ), C.int(blockSize), C.double(c))) } // ArrowedLine draws a arrow segment pointing from the first point // to the second one. // // For further details, please see: // https://docs.opencv.org/master/d6/d6e/group__imgproc__draw.html#ga0a165a3ca093fd488ac709fdf10c05b2 func ArrowedLine(img *Mat, pt1 image.Point, pt2 image.Point, c color.RGBA, thickness int) error { sp1 := C.struct_Point{ x: C.int(pt1.X), y: C.int(pt1.Y), } sp2 := C.struct_Point{ x: C.int(pt2.X), y: C.int(pt2.Y), } sColor := C.struct_Scalar{ val1: C.double(c.B), val2: C.double(c.G), val3: C.double(c.R), val4: C.double(c.A), } return OpenCVResult(C.ArrowedLine(img.p, sp1, sp2, sColor, C.int(thickness))) } // Circle draws a circle. // // For further details, please see: // https://docs.opencv.org/master/d6/d6e/group__imgproc__draw.html#gaf10604b069374903dbd0f0488cb43670 func Circle(img *Mat, center image.Point, radius int, c color.RGBA, thickness int) error { pc := C.struct_Point{ x: C.int(center.X), y: C.int(center.Y), } sColor := C.struct_Scalar{ val1: C.double(c.B), val2: C.double(c.G), val3: C.double(c.R), val4: C.double(c.A), } return OpenCVResult(C.Circle(img.p, pc, C.int(radius), sColor, C.int(thickness))) } // CircleWithParams draws a circle. // // For further details, please see: // https://docs.opencv.org/master/d6/d6e/group__imgproc__draw.html#gaf10604b069374903dbd0f0488cb43670 func CircleWithParams(img *Mat, center image.Point, radius int, c color.RGBA, thickness int, lineType LineType, shift int) error { pc := C.struct_Point{ x: C.int(center.X), y: C.int(center.Y), } sColor := C.struct_Scalar{ val1: C.double(c.B), val2: C.double(c.G), val3: C.double(c.R), val4: C.double(c.A), } return OpenCVResult(C.CircleWithParams(img.p, pc, C.int(radius), sColor, C.int(thickness), C.int(lineType), C.int(shift))) } // Ellipse draws a simple or thick elliptic arc or fills an ellipse sector. // // For further details, please see: // https://docs.opencv.org/master/d6/d6e/group__imgproc__draw.html#ga28b2267d35786f5f890ca167236cbc69 func Ellipse(img *Mat, center, axes image.Point, angle, startAngle, endAngle float64, c color.RGBA, thickness int) error { pc := C.struct_Point{ x: C.int(center.X), y: C.int(center.Y), } pa := C.struct_Point{ x: C.int(axes.X), y: C.int(axes.Y), } sColor := C.struct_Scalar{ val1: C.double(c.B), val2: C.double(c.G), val3: C.double(c.R), val4: C.double(c.A), } return OpenCVResult(C.Ellipse(img.p, pc, pa, C.double(angle), C.double(startAngle), C.double(endAngle), sColor, C.int(thickness))) } // Ellipse draws a simple or thick elliptic arc or fills an ellipse sector. // // For further details, please see: // https://docs.opencv.org/master/d6/d6e/group__imgproc__draw.html#ga28b2267d35786f5f890ca167236cbc69 func EllipseWithParams(img *Mat, center, axes image.Point, angle, startAngle, endAngle float64, c color.RGBA, thickness int, lineType LineType, shift int) error { pc := C.struct_Point{ x: C.int(center.X), y: C.int(center.Y), } pa := C.struct_Point{ x: C.int(axes.X), y: C.int(axes.Y), } sColor := C.struct_Scalar{ val1: C.double(c.B), val2: C.double(c.G), val3: C.double(c.R), val4: C.double(c.A), } return OpenCVResult(C.EllipseWithParams(img.p, pc, pa, C.double(angle), C.double(startAngle), C.double(endAngle), sColor, C.int(thickness), C.int(lineType), C.int(shift))) } // Line draws a line segment connecting two points. // // For further details, please see: // https://docs.opencv.org/master/d6/d6e/group__imgproc__draw.html#ga7078a9fae8c7e7d13d24dac2520ae4a2 func Line(img *Mat, pt1 image.Point, pt2 image.Point, c color.RGBA, thickness int) error { sp1 := C.struct_Point{ x: C.int(pt1.X), y: C.int(pt1.Y), } sp2 := C.struct_Point{ x: C.int(pt2.X), y: C.int(pt2.Y), } sColor := C.struct_Scalar{ val1: C.double(c.B), val2: C.double(c.G), val3: C.double(c.R), val4: C.double(c.A), } return OpenCVResult(C.Line(img.p, sp1, sp2, sColor, C.int(thickness))) } // Rectangle draws a simple, thick, or filled up-right rectangle. // It renders a rectangle with the desired characteristics to the target Mat image. // // For further details, please see: // http://docs.opencv.org/master/d6/d6e/group__imgproc__draw.html#ga346ac30b5c74e9b5137576c9ee9e0e8c func Rectangle(img *Mat, r image.Rectangle, c color.RGBA, thickness int) error { cRect := C.struct_Rect{ x: C.int(r.Min.X), y: C.int(r.Min.Y), width: C.int(r.Size().X), height: C.int(r.Size().Y), } sColor := C.struct_Scalar{ val1: C.double(c.B), val2: C.double(c.G), val3: C.double(c.R), val4: C.double(c.A), } return OpenCVResult(C.Rectangle(img.p, cRect, sColor, C.int(thickness))) } // RectangleWithParams draws a simple, thick, or filled up-right rectangle. // It renders a rectangle with the desired characteristics to the target Mat image. // // For further details, please see: // http://docs.opencv.org/master/d6/d6e/group__imgproc__draw.html#ga346ac30b5c74e9b5137576c9ee9e0e8c func RectangleWithParams(img *Mat, r image.Rectangle, c color.RGBA, thickness int, lineType LineType, shift int) error { cRect := C.struct_Rect{ x: C.int(r.Min.X), y: C.int(r.Min.Y), width: C.int(r.Size().X), height: C.int(r.Size().Y), } sColor := C.struct_Scalar{ val1: C.double(c.B), val2: C.double(c.G), val3: C.double(c.R), val4: C.double(c.A), } return OpenCVResult(C.RectangleWithParams(img.p, cRect, sColor, C.int(thickness), C.int(lineType), C.int(shift))) } // FillPoly fills the area bounded by one or more polygons. // // For more information, see: // https://docs.opencv.org/master/d6/d6e/group__imgproc__draw.html#gaf30888828337aa4c6b56782b5dfbd4b7 func FillPoly(img *Mat, pts PointsVector, c color.RGBA) error { sColor := C.struct_Scalar{ val1: C.double(c.B), val2: C.double(c.G), val3: C.double(c.R), val4: C.double(c.A), } return OpenCVResult(C.FillPoly(img.p, pts.p, sColor)) } // FillPolyWithParams fills the area bounded by one or more polygons. // // For more information, see: // https://docs.opencv.org/master/d6/d6e/group__imgproc__draw.html#gaf30888828337aa4c6b56782b5dfbd4b7 func FillPolyWithParams(img *Mat, pts PointsVector, c color.RGBA, lineType LineType, shift int, offset image.Point) error { offsetP := C.struct_Point{ x: C.int(offset.X), y: C.int(offset.Y), } sColor := C.struct_Scalar{ val1: C.double(c.B), val2: C.double(c.G), val3: C.double(c.R), val4: C.double(c.A), } return OpenCVResult(C.FillPolyWithParams(img.p, pts.p, sColor, C.int(lineType), C.int(shift), offsetP)) } // Polylines draws several polygonal curves. // // For more information, see: // https://docs.opencv.org/master/d6/d6e/group__imgproc__draw.html#ga1ea127ffbbb7e0bfc4fd6fd2eb64263c func Polylines(img *Mat, pts PointsVector, isClosed bool, c color.RGBA, thickness int) error { sColor := C.struct_Scalar{ val1: C.double(c.B), val2: C.double(c.G), val3: C.double(c.R), val4: C.double(c.A), } return OpenCVResult(C.Polylines(img.p, pts.p, C.bool(isClosed), sColor, C.int(thickness))) } // HersheyFont are the font libraries included in OpenCV. // Only a subset of the available Hershey fonts are supported by OpenCV. // // For more information, see: // http://sources.isc.org/utils/misc/hershey-font.txt type HersheyFont int const ( // FontHersheySimplex is normal size sans-serif font. FontHersheySimplex HersheyFont = 0 // FontHersheyPlain issmall size sans-serif font. FontHersheyPlain HersheyFont = 1 // FontHersheyDuplex normal size sans-serif font // (more complex than FontHersheySIMPLEX). FontHersheyDuplex HersheyFont = 2 // FontHersheyComplex i a normal size serif font. FontHersheyComplex HersheyFont = 3 // FontHersheyTriplex is a normal size serif font // (more complex than FontHersheyCOMPLEX). FontHersheyTriplex HersheyFont = 4 // FontHersheyComplexSmall is a smaller version of FontHersheyCOMPLEX. FontHersheyComplexSmall HersheyFont = 5 // FontHersheyScriptSimplex is a hand-writing style font. FontHersheyScriptSimplex HersheyFont = 6 // FontHersheyScriptComplex is a more complex variant of FontHersheyScriptSimplex. FontHersheyScriptComplex HersheyFont = 7 // FontItalic is the flag for italic font. FontItalic HersheyFont = 16 ) // LineType are the line libraries included in OpenCV. // // For more information, see: // https://vovkos.github.io/doxyrest-showcase/opencv/sphinx_rtd_theme/enum_cv_LineTypes.html type LineType int const ( // Filled line Filled LineType = -1 // Line4 4-connected line Line4 LineType = 4 // Line8 8-connected line Line8 LineType = 8 // LineAA antialiased line LineAA LineType = 16 ) // GetTextSize calculates the width and height of a text string. // It returns an image.Point with the size required to draw text using // a specific font face, scale, and thickness. // // For further details, please see: // http://docs.opencv.org/master/d6/d6e/group__imgproc__draw.html#ga3d2abfcb995fd2db908c8288199dba82 func GetTextSize(text string, fontFace HersheyFont, fontScale float64, thickness int) image.Point { cText := C.CString(text) defer C.free(unsafe.Pointer(cText)) sz := C.GetTextSize(cText, C.int(fontFace), C.double(fontScale), C.int(thickness)) return image.Pt(int(sz.width), int(sz.height)) } // GetTextSizeWithBaseline calculates the width and height of a text string including the basline of the text. // It returns an image.Point with the size required to draw text using // a specific font face, scale, and thickness as well as its baseline. // // For further details, please see: // http://docs.opencv.org/master/d6/d6e/group__imgproc__draw.html#ga3d2abfcb995fd2db908c8288199dba82 func GetTextSizeWithBaseline(text string, fontFace HersheyFont, fontScale float64, thickness int) (image.Point, int) { cText := C.CString(text) defer C.free(unsafe.Pointer(cText)) cBaseline := C.int(0) sz := C.GetTextSizeWithBaseline(cText, C.int(fontFace), C.double(fontScale), C.int(thickness), &cBaseline) return image.Pt(int(sz.width), int(sz.height)), int(cBaseline) } // PutText draws a text string. // It renders the specified text string into the img Mat at the location // passed in the "org" param, using the desired font face, font scale, // color, and line thinkness. // // For further details, please see: // http://docs.opencv.org/master/d6/d6e/group__imgproc__draw.html#ga5126f47f883d730f633d74f07456c576 func PutText(img *Mat, text string, org image.Point, fontFace HersheyFont, fontScale float64, c color.RGBA, thickness int) error { cText := C.CString(text) defer C.free(unsafe.Pointer(cText)) pOrg := C.struct_Point{ x: C.int(org.X), y: C.int(org.Y), } sColor := C.struct_Scalar{ val1: C.double(c.B), val2: C.double(c.G), val3: C.double(c.R), val4: C.double(c.A), } return OpenCVResult(C.PutText(img.p, cText, pOrg, C.int(fontFace), C.double(fontScale), sColor, C.int(thickness))) } // PutTextWithParams draws a text string. // It renders the specified text string into the img Mat at the location // passed in the "org" param, using the desired font face, font scale, // color, and line thinkness. // // For further details, please see: // http://docs.opencv.org/master/d6/d6e/group__imgproc__draw.html#ga5126f47f883d730f633d74f07456c576 func PutTextWithParams(img *Mat, text string, org image.Point, fontFace HersheyFont, fontScale float64, c color.RGBA, thickness int, lineType LineType, bottomLeftOrigin bool) error { cText := C.CString(text) defer C.free(unsafe.Pointer(cText)) pOrg := C.struct_Point{ x: C.int(org.X), y: C.int(org.Y), } sColor := C.struct_Scalar{ val1: C.double(c.B), val2: C.double(c.G), val3: C.double(c.R), val4: C.double(c.A), } return OpenCVResult(C.PutTextWithParams(img.p, cText, pOrg, C.int(fontFace), C.double(fontScale), sColor, C.int(thickness), C.int(lineType), C.bool(bottomLeftOrigin))) } // InterpolationFlags are bit flags that control the interpolation algorithm // that is used. type InterpolationFlags int const ( // InterpolationNearestNeighbor is nearest neighbor. (fast but low quality) InterpolationNearestNeighbor InterpolationFlags = 0 // InterpolationLinear is bilinear interpolation. InterpolationLinear InterpolationFlags = 1 // InterpolationCubic is bicube interpolation. InterpolationCubic InterpolationFlags = 2 // InterpolationArea uses pixel area relation. It is preferred for image // decimation as it gives moire-free results. InterpolationArea InterpolationFlags = 3 // InterpolationLanczos4 is Lanczos interpolation over 8x8 neighborhood. InterpolationLanczos4 InterpolationFlags = 4 // InterpolationDefault is an alias for InterpolationLinear. InterpolationDefault = InterpolationLinear // InterpolationMax indicates use maximum interpolation. InterpolationMax InterpolationFlags = 7 // WarpFillOutliers fills all of the destination image pixels. If some of them correspond to outliers in the source image, they are set to zero. WarpFillOutliers = 8 // WarpInverseMap, inverse transformation. WarpInverseMap = 16 ) // Resize resizes an image. // It resizes the image src down to or up to the specified size, storing the // result in dst. Note that src and dst may be the same image. If you wish to // scale by factor, an empty sz may be passed and non-zero fx and fy. Likewise, // if you wish to scale to an explicit size, a non-empty sz may be passed with // zero for both fx and fy. // // For further details, please see: // https://docs.opencv.org/master/da/d54/group__imgproc__transform.html#ga47a974309e9102f5f08231edc7e7529d func Resize(src Mat, dst *Mat, sz image.Point, fx, fy float64, interp InterpolationFlags) error { pSize := C.struct_Size{ width: C.int(sz.X), height: C.int(sz.Y), } return OpenCVResult(C.Resize(src.p, dst.p, pSize, C.double(fx), C.double(fy), C.int(interp))) } // GetRectSubPix retrieves a pixel rectangle from an image with sub-pixel accuracy. // // For further details, please see: // https://docs.opencv.org/master/da/d54/group__imgproc__transform.html#ga77576d06075c1a4b6ba1a608850cd614 func GetRectSubPix(src Mat, patchSize image.Point, center image.Point, dst *Mat) error { sz := C.struct_Size{ width: C.int(patchSize.X), height: C.int(patchSize.Y), } pt := C.struct_Point{ x: C.int(center.X), y: C.int(center.Y), } return OpenCVResult(C.GetRectSubPix(src.p, sz, pt, dst.p)) } // GetRotationMatrix2D calculates an affine matrix of 2D rotation. // // For further details, please see: // https://docs.opencv.org/master/da/d54/group__imgproc__transform.html#gafbbc470ce83812914a70abfb604f4326 func GetRotationMatrix2D(center image.Point, angle, scale float64) Mat { pc := C.struct_Point{ x: C.int(center.X), y: C.int(center.Y), } return newMat(C.GetRotationMatrix2D(pc, C.double(angle), C.double(scale))) } // WarpAffine applies an affine transformation to an image. For more parameters please check WarpAffineWithParams // // For further details, please see: // https://docs.opencv.org/master/da/d54/group__imgproc__transform.html#ga0203d9ee5fcd28d40dbc4a1ea4451983 func WarpAffine(src Mat, dst *Mat, m Mat, sz image.Point) error { pSize := C.struct_Size{ width: C.int(sz.X), height: C.int(sz.Y), } return OpenCVResult(C.WarpAffine(src.p, dst.p, m.p, pSize)) } // WarpAffineWithParams applies an affine transformation to an image. // // For further details, please see: // https://docs.opencv.org/master/da/d54/group__imgproc__transform.html#ga0203d9ee5fcd28d40dbc4a1ea4451983 func WarpAffineWithParams(src Mat, dst *Mat, m Mat, sz image.Point, flags InterpolationFlags, borderType BorderType, borderValue color.RGBA) error { pSize := C.struct_Size{ width: C.int(sz.X), height: C.int(sz.Y), } bv := C.struct_Scalar{ val1: C.double(borderValue.B), val2: C.double(borderValue.G), val3: C.double(borderValue.R), val4: C.double(borderValue.A), } return OpenCVResult(C.WarpAffineWithParams(src.p, dst.p, m.p, pSize, C.int(flags), C.int(borderType), bv)) } // WarpPerspective applies a perspective transformation to an image. // For more parameters please check WarpPerspectiveWithParams. // // For further details, please see: // https://docs.opencv.org/master/da/d54/group__imgproc__transform.html#gaf73673a7e8e18ec6963e3774e6a94b87 func WarpPerspective(src Mat, dst *Mat, m Mat, sz image.Point) error { pSize := C.struct_Size{ width: C.int(sz.X), height: C.int(sz.Y), } return OpenCVResult(C.WarpPerspective(src.p, dst.p, m.p, pSize)) } // WarpPerspectiveWithParams applies a perspective transformation to an image. // // For further details, please see: // https://docs.opencv.org/master/da/d54/group__imgproc__transform.html#gaf73673a7e8e18ec6963e3774e6a94b87 func WarpPerspectiveWithParams(src Mat, dst *Mat, m Mat, sz image.Point, flags InterpolationFlags, borderType BorderType, borderValue color.RGBA) error { pSize := C.struct_Size{ width: C.int(sz.X), height: C.int(sz.Y), } bv := C.struct_Scalar{ val1: C.double(borderValue.B), val2: C.double(borderValue.G), val3: C.double(borderValue.R), val4: C.double(borderValue.A), } return OpenCVResult(C.WarpPerspectiveWithParams(src.p, dst.p, m.p, pSize, C.int(flags), C.int(borderType), bv)) } // Watershed performs a marker-based image segmentation using the watershed algorithm. // // For further details, please see: // https://docs.opencv.org/master/d7/d1b/group__imgproc__misc.html#ga3267243e4d3f95165d55a618c65ac6e1 func Watershed(image Mat, markers *Mat) error { return OpenCVResult(C.Watershed(image.p, markers.p)) } // ColormapTypes are the 12 GNU Octave/MATLAB equivalent colormaps. // // For further details, please see: // https://docs.opencv.org/master/d3/d50/group__imgproc__colormap.html type ColormapTypes int // List of the available color maps // // For further details, please see: // https://docs.opencv.org/master/d3/d50/group__imgproc__colormap.html#ga9a805d8262bcbe273f16be9ea2055a65 const ( ColormapAutumn ColormapTypes = 0 ColormapBone ColormapTypes = 1 ColormapJet ColormapTypes = 2 ColormapWinter ColormapTypes = 3 ColormapRainbow ColormapTypes = 4 ColormapOcean ColormapTypes = 5 ColormapSummer ColormapTypes = 6 ColormapSpring ColormapTypes = 7 ColormapCool ColormapTypes = 8 ColormapHsv ColormapTypes = 9 ColormapPink ColormapTypes = 10 ColormapHot ColormapTypes = 11 ColormapParula ColormapTypes = 12 ColormapMagma ColormapTypes = 13 ColormapInferno ColormapTypes = 14 ColormapPlasma ColormapTypes = 15 ColormapViridis ColormapTypes = 16 ColormapCividis ColormapTypes = 17 ColormapTwilight ColormapTypes = 18 ColormapTwilightShifted ColormapTypes = 19 ColormapTurbo ColormapTypes = 20 ColormapDeepGreen ColormapTypes = 21 ) // ApplyColorMap applies a GNU Octave/MATLAB equivalent colormap on a given image. // // For further details, please see: // https://docs.opencv.org/master/d3/d50/group__imgproc__colormap.html#gadf478a5e5ff49d8aa24e726ea6f65d15 func ApplyColorMap(src Mat, dst *Mat, colormapType ColormapTypes) error { return OpenCVResult(C.ApplyColorMap(src.p, dst.p, C.int(colormapType))) } // ApplyCustomColorMap applies a custom defined colormap on a given image. // // For further details, please see: // https://docs.opencv.org/master/d3/d50/group__imgproc__colormap.html#gacb22288ddccc55f9bd9e6d492b409cae func ApplyCustomColorMap(src Mat, dst *Mat, customColormap Mat) error { return OpenCVResult(C.ApplyCustomColorMap(src.p, dst.p, customColormap.p)) } // GetPerspectiveTransform returns 3x3 perspective transformation for the // corresponding 4 point pairs as image.Point. // // For further details, please see: // https://docs.opencv.org/master/da/d54/group__imgproc__transform.html#ga8c1ae0e3589a9d77fffc962c49b22043 func GetPerspectiveTransform(src, dst PointVector) Mat { return newMat(C.GetPerspectiveTransform(src.p, dst.p)) } // GetPerspectiveTransform2f returns 3x3 perspective transformation for the // corresponding 4 point pairs as gocv.Point2f. // // For further details, please see: // https://docs.opencv.org/master/da/d54/group__imgproc__transform.html#ga8c1ae0e3589a9d77fffc962c49b22043 func GetPerspectiveTransform2f(src, dst Point2fVector) Mat { return newMat(C.GetPerspectiveTransform2f(src.p, dst.p)) } // GetAffineTransform returns a 2x3 affine transformation matrix for the // corresponding 3 point pairs as image.Point. // // For further details, please see: // https://docs.opencv.org/master/da/d54/group__imgproc__transform.html#ga8f6d378f9f8eebb5cb55cd3ae295a999 func GetAffineTransform(src, dst PointVector) Mat { return newMat(C.GetAffineTransform(src.p, dst.p)) } // GetAffineTransform2f returns a 2x3 affine transformation matrix for the // corresponding 3 point pairs as gocv.Point2f. // // For further details, please see: // https://docs.opencv.org/master/da/d54/group__imgproc__transform.html#ga8f6d378f9f8eebb5cb55cd3ae295a999 func GetAffineTransform2f(src, dst Point2fVector) Mat { return newMat(C.GetAffineTransform2f(src.p, dst.p)) } // DrawContours draws contours outlines or filled contours. // // For further details, please see: // https://docs.opencv.org/master/d6/d6e/group__imgproc__draw.html#ga746c0625f1781f1ffc9056259103edbc func DrawContours(img *Mat, contours PointsVector, contourIdx int, c color.RGBA, thickness int) error { sColor := C.struct_Scalar{ val1: C.double(c.B), val2: C.double(c.G), val3: C.double(c.R), val4: C.double(c.A), } return OpenCVResult(C.DrawContours(img.p, contours.p, C.int(contourIdx), sColor, C.int(thickness))) } // DrawContoursWithParams draws contours outlines or filled contours. // // For further details, please see: // https://docs.opencv.org/master/d6/d6e/group__imgproc__draw.html#ga746c0625f1781f1ffc9056259103edbc func DrawContoursWithParams(img *Mat, contours PointsVector, contourIdx int, c color.RGBA, thickness int, lineType LineType, hierarchy Mat, maxLevel int, offset image.Point) error { sColor := C.struct_Scalar{ val1: C.double(c.B), val2: C.double(c.G), val3: C.double(c.R), val4: C.double(c.A), } offsetP := C.struct_Point{ x: C.int(offset.X), y: C.int(offset.Y), } return OpenCVResult(C.DrawContoursWithParams(img.p, contours.p, C.int(contourIdx), sColor, C.int(thickness), C.int(lineType), hierarchy.p, C.int(maxLevel), offsetP)) } // Remap applies a generic geometrical transformation to an image. // // For further details, please see: // https://docs.opencv.org/master/da/d54/group__imgproc__transform.html#gab75ef31ce5cdfb5c44b6da5f3b908ea4 func Remap(src Mat, dst, map1, map2 *Mat, interpolation InterpolationFlags, borderMode BorderType, borderValue color.RGBA) error { bv := C.struct_Scalar{ val1: C.double(borderValue.B), val2: C.double(borderValue.G), val3: C.double(borderValue.R), val4: C.double(borderValue.A), } return OpenCVResult(C.Remap(src.p, dst.p, map1.p, map2.p, C.int(interpolation), C.int(borderMode), bv)) } // Filter2D applies an arbitrary linear filter to an image. // // For further details, please see: // https://docs.opencv.org/master/d4/d86/group__imgproc__filter.html#ga27c049795ce870216ddfb366086b5a04 func Filter2D(src Mat, dst *Mat, ddepth MatType, kernel Mat, anchor image.Point, delta float64, borderType BorderType) error { anchorP := C.struct_Point{ x: C.int(anchor.X), y: C.int(anchor.Y), } return OpenCVResult(C.Filter2D(src.p, dst.p, C.int(ddepth), kernel.p, anchorP, C.double(delta), C.int(borderType))) } // SepFilter2D applies a separable linear filter to the image. // // For further details, please see: // https://docs.opencv.org/master/d4/d86/group__imgproc__filter.html#ga910e29ff7d7b105057d1625a4bf6318d func SepFilter2D(src Mat, dst *Mat, ddepth MatType, kernelX, kernelY Mat, anchor image.Point, delta float64, borderType BorderType) error { anchorP := C.struct_Point{ x: C.int(anchor.X), y: C.int(anchor.Y), } return OpenCVResult(C.SepFilter2D(src.p, dst.p, C.int(ddepth), kernelX.p, kernelY.p, anchorP, C.double(delta), C.int(borderType))) } // LogPolar remaps an image to semilog-polar coordinates space. // // For further details, please see: // https://docs.opencv.org/master/da/d54/group__imgproc__transform.html#gaec3a0b126a85b5ca2c667b16e0ae022d func LogPolar(src Mat, dst *Mat, center image.Point, m float64, flags InterpolationFlags) error { centerP := C.struct_Point{ x: C.int(center.X), y: C.int(center.Y), } return OpenCVResult(C.LogPolar(src.p, dst.p, centerP, C.double(m), C.int(flags))) } // LinearPolar remaps an image to polar coordinates space. // // For further details, please see: // https://docs.opencv.org/master/da/d54/group__imgproc__transform.html#gaa38a6884ac8b6e0b9bed47939b5362f3 func LinearPolar(src Mat, dst *Mat, center image.Point, maxRadius float64, flags InterpolationFlags) error { centerP := C.struct_Point{ x: C.int(center.X), y: C.int(center.Y), } return OpenCVResult(C.LinearPolar(src.p, dst.p, centerP, C.double(maxRadius), C.int(flags))) } // DistanceTypes types for Distance Transform and M-estimatorss // // For further details, please see: // https://docs.opencv.org/master/d7/d1b/group__imgproc__misc.html#gaa2bfbebbc5c320526897996aafa1d8eb type DistanceTypes int const ( DistUser DistanceTypes = 0 DistL1 DistanceTypes = 1 DistL2 DistanceTypes = 2 DistC DistanceTypes = 3 DistL12 DistanceTypes = 4 DistFair DistanceTypes = 5 DistWelsch DistanceTypes = 6 DistHuber DistanceTypes = 7 ) // FitLine fits a line to a 2D or 3D point set. // // For further details, please see: // https://docs.opencv.org/master/d3/dc0/group__imgproc__shape.html#gaf849da1fdafa67ee84b1e9a23b93f91f func FitLine(pts PointVector, line *Mat, distType DistanceTypes, param, reps, aeps float64) error { return OpenCVResult(C.FitLine(pts.p, line.p, C.int(distType), C.double(param), C.double(reps), C.double(aeps))) } // Shape matching methods. // // For further details, please see: // https://docs.opencv.org/4.x/d3/dc0/group__imgproc__shape.html#gaadc90cb16e2362c9bd6e7363e6e4c317 type ShapeMatchModes int const ( ContoursMatchI1 ShapeMatchModes = 1 ContoursMatchI2 ShapeMatchModes = 2 ContoursMatchI3 ShapeMatchModes = 3 ) // Compares two shapes. // // For further details, please see: // https://docs.opencv.org/4.x/d3/dc0/group__imgproc__shape.html#gaadc90cb16e2362c9bd6e7363e6e4c317 func MatchShapes(contour1 PointVector, contour2 PointVector, method ShapeMatchModes, parameter float64) float64 { return float64(C.MatchShapes(contour1.p, contour2.p, C.int(method), C.double(parameter))) } // CLAHE is a wrapper around the cv::CLAHE algorithm. type CLAHE struct { // C.CLAHE p unsafe.Pointer } // NewCLAHE returns a new CLAHE algorithm // // For further details, please see: // https://docs.opencv.org/master/d6/db6/classcv_1_1CLAHE.html func NewCLAHE() CLAHE { return CLAHE{p: unsafe.Pointer(C.CLAHE_Create())} } // NewCLAHEWithParams returns a new CLAHE algorithm // // For further details, please see: // https://docs.opencv.org/master/d6/db6/classcv_1_1CLAHE.html func NewCLAHEWithParams(clipLimit float64, tileGridSize image.Point) CLAHE { pSize := C.struct_Size{ width: C.int(tileGridSize.X), height: C.int(tileGridSize.Y), } return CLAHE{p: unsafe.Pointer(C.CLAHE_CreateWithParams(C.double(clipLimit), pSize))} } // Close CLAHE. func (c *CLAHE) Close() error { C.CLAHE_Close((C.CLAHE)(c.p)) c.p = nil return nil } // Apply CLAHE. // // For further details, please see: // https://docs.opencv.org/master/d6/db6/classcv_1_1CLAHE.html#a4e92e0e427de21be8d1fae8dcd862c5e func (c *CLAHE) Apply(src Mat, dst *Mat) error { return OpenCVResult(C.CLAHE_Apply((C.CLAHE)(c.p), src.p, dst.p)) } func InvertAffineTransform(src Mat, dst *Mat) error { return OpenCVResult(C.InvertAffineTransform(src.p, dst.p)) } // Apply phaseCorrelate. // // For further details, please see: // https://docs.opencv.org/master/d7/df3/group__imgproc__motion.html#ga552420a2ace9ef3fb053cd630fdb4952 func PhaseCorrelate(src1, src2, window Mat) (phaseShift Point2f, response float64) { var responseDouble C.double result := C.PhaseCorrelate(src1.p, src2.p, window.p, &responseDouble) return Point2f{ X: float32(result.x), Y: float32(result.y), }, float64(responseDouble) } // CreateHanningWindow computes a Hanning window coefficients in two dimensions. // // For further details, please see: // https://docs.opencv.org/4.x/d7/df3/group__imgproc__motion.html#ga80e5c3de52f6bab3a7c1e60e89308e1b func CreateHanningWindow(img *Mat, size image.Point, typ MatType) error { sz := C.struct_Size{ width: C.int(size.X), height: C.int(size.Y), } return OpenCVResult(C.CreateHanningWindow(img.p, sz, C.int(typ))) } // ToImage converts a Mat to a image.Image. func (m *Mat) ToImage() (image.Image, error) { switch m.Type() { case MatTypeCV8UC1: img := image.NewGray(image.Rect(0, 0, m.Cols(), m.Rows())) data, err := m.DataPtrUint8() if err != nil { return nil, err } copy(img.Pix, data[0:]) return img, nil case MatTypeCV8UC3: dst := NewMat() defer dst.Close() C.CvtColor(m.p, dst.p, C.int(ColorBGRToRGBA)) img := image.NewRGBA(image.Rect(0, 0, m.Cols(), m.Rows())) data, err := dst.DataPtrUint8() if err != nil { return nil, err } copy(img.Pix, data[0:]) return img, nil case MatTypeCV8UC4: dst := NewMat() defer dst.Close() C.CvtColor(m.p, dst.p, C.int(ColorBGRAToRGBA)) img := image.NewNRGBA(image.Rect(0, 0, m.Cols(), m.Rows())) data, err := dst.DataPtrUint8() if err != nil { return nil, err } copy(img.Pix, data[0:]) return img, nil default: return nil, errors.New("ToImage supports only MatType CV8UC1, CV8UC3 and CV8UC4") } } // ToImageYUV converts a Mat to a image.YCbCr using image.YCbCrSubsampleRatio420 as default subsampling param. func (m *Mat) ToImageYUV() (*image.YCbCr, error) { img, err := m.ToImage() if err != nil { return nil, err } bounds := img.Bounds() converted := image.NewYCbCr(bounds, image.YCbCrSubsampleRatio420) for row := 0; row < bounds.Max.Y; row++ { for col := 0; col < bounds.Max.X; col++ { r, g, b, _ := img.At(col, row).RGBA() y, cb, cr := color.RGBToYCbCr(uint8(r), uint8(g), uint8(b)) converted.Y[converted.YOffset(col, row)] = y converted.Cb[converted.COffset(col, row)] = cb converted.Cr[converted.COffset(col, row)] = cr } } return converted, nil } // ToImageYUV converts a Mat to a image.YCbCr using provided YUV subsample ratio param. func (m *Mat) ToImageYUVWithParams(ratio image.YCbCrSubsampleRatio) (*image.YCbCr, error) { img, err := m.ToImage() if err != nil { return nil, err } bounds := img.Bounds() converted := image.NewYCbCr(bounds, ratio) for row := 0; row < bounds.Max.Y; row++ { for col := 0; col < bounds.Max.X; col++ { r, g, b, _ := img.At(col, row).RGBA() y, cb, cr := color.RGBToYCbCr(uint8(r), uint8(g), uint8(b)) converted.Y[converted.YOffset(col, row)] = y converted.Cb[converted.COffset(col, row)] = cb converted.Cr[converted.COffset(col, row)] = cr } } return converted, nil } // ImageToMatRGBA converts image.Image to gocv.Mat, // which represents RGBA image having 8bit for each component. // Type of Mat is gocv.MatTypeCV8UC4. func ImageToMatRGBA(img image.Image) (Mat, error) { bounds := img.Bounds() x := bounds.Dx() y := bounds.Dy() var data []uint8 switch img.ColorModel() { case color.RGBAModel: m, res := img.(*image.RGBA) if !res { return NewMat(), errors.New("Image color format error") } data = m.Pix case color.NRGBAModel: m, res := img.(*image.NRGBA) if !res { return NewMat(), errors.New("Image color format error") } data = m.Pix default: data := make([]byte, 0, x*y*3) for j := bounds.Min.Y; j < bounds.Max.Y; j++ { for i := bounds.Min.X; i < bounds.Max.X; i++ { r, g, b, _ := img.At(i, j).RGBA() data = append(data, byte(b>>8), byte(g>>8), byte(r>>8)) } } return NewMatFromBytes(y, x, MatTypeCV8UC3, data) } // speed up the conversion process of RGBA format cvt, err := NewMatFromBytes(y, x, MatTypeCV8UC4, data) if err != nil { return NewMat(), err } defer cvt.Close() dst := NewMat() C.CvtColor(cvt.p, dst.p, C.int(ColorBGRAToRGBA)) return dst, nil } // ImageToMatRGB converts image.Image to gocv.Mat, // which represents RGB image having 8bit for each component. // Type of Mat is gocv.MatTypeCV8UC3. func ImageToMatRGB(img image.Image) (Mat, error) { bounds := img.Bounds() x := bounds.Dx() y := bounds.Dy() var data []uint8 switch img.ColorModel() { case color.RGBAModel: m, res := img.(*image.RGBA) if true != res { return NewMat(), errors.New("Image color format error") } data = m.Pix // speed up the conversion process of RGBA format src, err := NewMatFromBytes(y, x, MatTypeCV8UC4, data) if err != nil { return NewMat(), err } defer src.Close() dst := NewMat() CvtColor(src, &dst, ColorRGBAToBGR) return dst, nil default: data := make([]byte, 0, x*y*3) for j := bounds.Min.Y; j < bounds.Max.Y; j++ { for i := bounds.Min.X; i < bounds.Max.X; i++ { r, g, b, _ := img.At(i, j).RGBA() data = append(data, byte(b>>8), byte(g>>8), byte(r>>8)) } } return NewMatFromBytes(y, x, MatTypeCV8UC3, data) } } // ImageGrayToMatGray converts image.Gray to gocv.Mat, // which represents grayscale image 8bit. // Type of Mat is gocv.MatTypeCV8UC1. func ImageGrayToMatGray(img *image.Gray) (Mat, error) { bounds := img.Bounds() x := bounds.Dx() y := bounds.Dy() m, err := NewMatFromBytes(y, x, MatTypeCV8UC1, img.Pix) if err != nil { return NewMat(), err } return m, nil } // Adds the square of a source image to the accumulator image. // // For further details, please see: // https://docs.opencv.org/master/d7/df3/group__imgproc__motion.html#ga1a567a79901513811ff3b9976923b199 // func Accumulate(src Mat, dst *Mat) error { return OpenCVResult(C.Mat_Accumulate(src.p, dst.p)) } // Adds an image to the accumulator image with mask. // // For further details, please see: // https://docs.opencv.org/master/d7/df3/group__imgproc__motion.html#ga1a567a79901513811ff3b9976923b199 func AccumulateWithMask(src Mat, dst *Mat, mask Mat) error { return OpenCVResult(C.Mat_AccumulateWithMask(src.p, dst.p, mask.p)) } // Adds the square of a source image to the accumulator image. // // For further details, please see: // https://docs.opencv.org/master/d7/df3/group__imgproc__motion.html#gacb75e7ffb573227088cef9ceaf80be8c func AccumulateSquare(src Mat, dst *Mat) error { return OpenCVResult(C.Mat_AccumulateSquare(src.p, dst.p)) } // Adds the square of a source image to the accumulator image with mask. // // For further details, please see: // https://docs.opencv.org/master/d7/df3/group__imgproc__motion.html#gacb75e7ffb573227088cef9ceaf80be8c func AccumulateSquareWithMask(src Mat, dst *Mat, mask Mat) error { return OpenCVResult(C.Mat_AccumulateSquareWithMask(src.p, dst.p, mask.p)) } // Adds the per-element product of two input images to the accumulator image. // // For further details, please see: // https://docs.opencv.org/master/d7/df3/group__imgproc__motion.html#ga82518a940ecfda49460f66117ac82520 func AccumulateProduct(src1 Mat, src2 Mat, dst *Mat) error { return OpenCVResult(C.Mat_AccumulateProduct(src1.p, src2.p, dst.p)) } // Adds the per-element product of two input images to the accumulator image with mask. // // For further details, please see: // https://docs.opencv.org/master/d7/df3/group__imgproc__motion.html#ga82518a940ecfda49460f66117ac82520 func AccumulateProductWithMask(src1 Mat, src2 Mat, dst *Mat, mask Mat) error { return OpenCVResult(C.Mat_AccumulateProductWithMask(src1.p, src2.p, dst.p, mask.p)) } // Updates a running average. // // For further details, please see: // https://docs.opencv.org/master/d7/df3/group__imgproc__motion.html#ga4f9552b541187f61f6818e8d2d826bc7 func AccumulatedWeighted(src Mat, dst *Mat, alpha float64) error { return OpenCVResult(C.Mat_AccumulatedWeighted(src.p, dst.p, C.double(alpha))) } // Updates a running average with mask. // // For further details, please see: // https://docs.opencv.org/master/d7/df3/group__imgproc__motion.html#ga4f9552b541187f61f6818e8d2d826bc7 func AccumulatedWeightedWithMask(src Mat, dst *Mat, alpha float64, mask Mat) error { return OpenCVResult(C.Mat_AccumulatedWeightedWithMask(src.p, dst.p, C.double(alpha), mask.p)) } ================================================ FILE: imgproc.h ================================================ #ifndef _OPENCV3_IMGPROC_H_ #define _OPENCV3_IMGPROC_H_ #include #ifdef __cplusplus #include extern "C" { #endif #ifdef __cplusplus typedef cv::Ptr* CLAHE; #else typedef void* CLAHE; #endif #include "core.h" double ArcLength(PointVector curve, bool is_closed); PointVector ApproxPolyDP(PointVector curve, double epsilon, bool closed); OpenCVResult CvtColor(Mat src, Mat dst, int code); OpenCVResult Demosaicing(Mat src, Mat dst, int code); OpenCVResult EqualizeHist(Mat src, Mat dst); OpenCVResult CalcHist(struct Mats mats, IntVector chans, Mat mask, Mat hist, IntVector sz, FloatVector rng, bool acc); OpenCVResult CalcBackProject(struct Mats mats, IntVector chans, Mat hist, Mat backProject, FloatVector rng, bool uniform); double CompareHist(Mat hist1, Mat hist2, int method); float EMD(Mat sig1, Mat sig2, int distType); OpenCVResult ConvexHull(PointVector points, Mat hull, bool clockwise, bool returnPoints); OpenCVResult ConvexityDefects(PointVector points, Mat hull, Mat result); OpenCVResult BilateralFilter(Mat src, Mat dst, int d, double sc, double ss); OpenCVResult Blur(Mat src, Mat dst, Size ps); OpenCVResult BoxFilter(Mat src, Mat dst, int ddepth, Size ps); OpenCVResult SqBoxFilter(Mat src, Mat dst, int ddepth, Size ps); OpenCVResult Dilate(Mat src, Mat dst, Mat kernel); OpenCVResult DilateWithParams(Mat src, Mat dst, Mat kernel, Point anchor, int iterations, int borderType, Scalar borderValue); OpenCVResult DistanceTransform(Mat src, Mat dst, Mat labels, int distanceType, int maskSize, int labelType); OpenCVResult Erode(Mat src, Mat dst, Mat kernel); OpenCVResult ErodeWithParams(Mat src, Mat dst, Mat kernel, Point anchor, int iterations, int borderType); OpenCVResult ErodeWithParamsAndBorderValue(Mat src, Mat dst, Mat kernel, Point anchor, int iterations, int borderType, Scalar borderValue); OpenCVResult MatchTemplate(Mat image, Mat templ, Mat result, int method, Mat mask); struct Moment Moments(Mat src, bool binaryImage); OpenCVResult PyrDown(Mat src, Mat dst, Size dstsize, int borderType); OpenCVResult PyrUp(Mat src, Mat dst, Size dstsize, int borderType); struct Rect BoundingRect(PointVector pts); OpenCVResult BoxPoints(RotatedRect rect, Mat boxPts); OpenCVResult BoxPoints2f(RotatedRect2f rect, Mat boxPts); double ContourArea(PointVector pts); struct RotatedRect MinAreaRect(PointVector pts); struct RotatedRect2f MinAreaRect2f(PointVector pts); struct RotatedRect FitEllipse(PointVector pts); OpenCVResult MinEnclosingCircle(PointVector pts, Point2f* center, float* radius); PointsVector FindContours(Mat src, Mat hierarchy, int mode, int method); double PointPolygonTest(PointVector pts, Point pt, bool measureDist); int ConnectedComponents(Mat src, Mat dst, int connectivity, int ltype, int ccltype); int ConnectedComponentsWithStats(Mat src, Mat labels, Mat stats, Mat centroids, int connectivity, int ltype, int ccltype); OpenCVResult GaussianBlur(Mat src, Mat dst, Size ps, double sX, double sY, int bt); Mat GetGaussianKernel(int ksize, double sigma, int ktype); OpenCVResult Laplacian(Mat src, Mat dst, int dDepth, int kSize, double scale, double delta, int borderType); OpenCVResult Scharr(Mat src, Mat dst, int dDepth, int dx, int dy, double scale, double delta, int borderType); Mat GetStructuringElement(int shape, Size ksize); Scalar MorphologyDefaultBorderValue(); OpenCVResult MorphologyEx(Mat src, Mat dst, int op, Mat kernel); OpenCVResult MorphologyExWithParams(Mat src, Mat dst, int op, Mat kernel, Point pt, int iterations, int borderType); OpenCVResult MedianBlur(Mat src, Mat dst, int ksize); OpenCVResult Canny(Mat src, Mat edges, double t1, double t2); OpenCVResult CornerSubPix(Mat img, Mat corners, Size winSize, Size zeroZone, TermCriteria criteria); OpenCVResult GoodFeaturesToTrack(Mat img, Mat corners, int maxCorners, double quality, double minDist); OpenCVResult GrabCut(Mat img, Mat mask, Rect rect, Mat bgdModel, Mat fgdModel, int iterCount, int mode); OpenCVResult HoughCircles(Mat src, Mat circles, int method, double dp, double minDist); OpenCVResult HoughCirclesWithParams(Mat src, Mat circles, int method, double dp, double minDist, double param1, double param2, int minRadius, int maxRadius); OpenCVResult HoughLines(Mat src, Mat lines, double rho, double theta, int threshold); OpenCVResult HoughLinesP(Mat src, Mat lines, double rho, double theta, int threshold); OpenCVResult HoughLinesPWithParams(Mat src, Mat lines, double rho, double theta, int threshold, double minLineLength, double maxLineGap); OpenCVResult HoughLinesPointSet(Mat points, Mat lines, int lines_max, int threshold, double min_rho, double max_rho, double rho_step, double min_theta, double max_theta, double theta_step); OpenCVResult Integral(Mat src, Mat sum, Mat sqsum, Mat tilted); double Threshold(Mat src, Mat dst, double thresh, double maxvalue, int typ); OpenCVResult AdaptiveThreshold(Mat src, Mat dst, double maxValue, int adaptiveTyp, int typ, int blockSize, double c); OpenCVResult ArrowedLine(Mat img, Point pt1, Point pt2, Scalar color, int thickness); OpenCVResult Circle(Mat img, Point center, int radius, Scalar color, int thickness); OpenCVResult CircleWithParams(Mat img, Point center, int radius, Scalar color, int thickness, int lineType, int shift); OpenCVResult Ellipse(Mat img, Point center, Point axes, double angle, double startAngle, double endAngle, Scalar color, int thickness); OpenCVResult EllipseWithParams(Mat img, Point center, Point axes, double angle, double startAngle, double endAngle, Scalar color, int thickness, int lineType, int shift); OpenCVResult Line(Mat img, Point pt1, Point pt2, Scalar color, int thickness); OpenCVResult Rectangle(Mat img, Rect rect, Scalar color, int thickness); OpenCVResult RectangleWithParams(Mat img, Rect rect, Scalar color, int thickness, int lineType, int shift); OpenCVResult FillPoly(Mat img, PointsVector points, Scalar color); OpenCVResult FillPolyWithParams(Mat img, PointsVector points, Scalar color, int lineType, int shift, Point offset); OpenCVResult Polylines(Mat img, PointsVector points, bool isClosed, Scalar color, int thickness); struct Size GetTextSize(const char* text, int fontFace, double fontScale, int thickness); struct Size GetTextSizeWithBaseline(const char* text, int fontFace, double fontScale, int thickness, int* baseline); OpenCVResult PutText(Mat img, const char* text, Point org, int fontFace, double fontScale, Scalar color, int thickness); OpenCVResult PutTextWithParams(Mat img, const char* text, Point org, int fontFace, double fontScale, Scalar color, int thickness, int lineType, bool bottomLeftOrigin); OpenCVResult Resize(Mat src, Mat dst, Size sz, double fx, double fy, int interp); OpenCVResult GetRectSubPix(Mat src, Size patchSize, Point center, Mat dst); Mat GetRotationMatrix2D(Point center, double angle, double scale); OpenCVResult WarpAffine(Mat src, Mat dst, Mat rot_mat, Size dsize); OpenCVResult WarpAffineWithParams(Mat src, Mat dst, Mat rot_mat, Size dsize, int flags, int borderMode, Scalar borderValue); OpenCVResult WarpPerspective(Mat src, Mat dst, Mat m, Size dsize); OpenCVResult WarpPerspectiveWithParams(Mat src, Mat dst, Mat rot_mat, Size dsize, int flags, int borderMode, Scalar borderValue); OpenCVResult Watershed(Mat image, Mat markers); OpenCVResult ApplyColorMap(Mat src, Mat dst, int colormap); OpenCVResult ApplyCustomColorMap(Mat src, Mat dst, Mat colormap); Mat GetPerspectiveTransform(PointVector src, PointVector dst); Mat GetPerspectiveTransform2f(Point2fVector src, Point2fVector dst); Mat GetAffineTransform(PointVector src, PointVector dst); Mat GetAffineTransform2f(Point2fVector src, Point2fVector dst); OpenCVResult DrawContours(Mat src, PointsVector contours, int contourIdx, Scalar color, int thickness); OpenCVResult DrawContoursWithParams(Mat src, PointsVector contours, int contourIdx, Scalar color, int thickness, int lineType, Mat hierarchy, int maxLevel, Point offset); OpenCVResult Sobel(Mat src, Mat dst, int ddepth, int dx, int dy, int ksize, double scale, double delta, int borderType); OpenCVResult SpatialGradient(Mat src, Mat dx, Mat dy, int ksize, int borderType); OpenCVResult Remap(Mat src, Mat dst, Mat map1, Mat map2, int interpolation, int borderMode, Scalar borderValue); OpenCVResult Filter2D(Mat src, Mat dst, int ddepth, Mat kernel, Point anchor, double delta, int borderType); OpenCVResult SepFilter2D(Mat src, Mat dst, int ddepth, Mat kernelX, Mat kernelY, Point anchor, double delta, int borderType); OpenCVResult LogPolar(Mat src, Mat dst, Point center, double m, int flags); OpenCVResult FitLine(PointVector pts, Mat line, int distType, double param, double reps, double aeps); OpenCVResult LinearPolar(Mat src, Mat dst, Point center, double maxRadius, int flags); double MatchShapes(PointVector contour1, PointVector contour2, int method, double parameter); bool ClipLine(Size imgSize, Point pt1, Point pt2); CLAHE CLAHE_Create(); CLAHE CLAHE_CreateWithParams(double clipLimit, Size tileGridSize); void CLAHE_Close(CLAHE c); OpenCVResult CLAHE_Apply(CLAHE c, Mat src, Mat dst); OpenCVResult InvertAffineTransform(Mat src, Mat dst); Point2f PhaseCorrelate(Mat src1, Mat src2, Mat window, double* response); OpenCVResult CreateHanningWindow(Mat dst, Size size, int typ); OpenCVResult Mat_Accumulate(Mat src, Mat dst); OpenCVResult Mat_AccumulateWithMask(Mat src, Mat dst, Mat mask); OpenCVResult Mat_AccumulateSquare(Mat src, Mat dst); OpenCVResult Mat_AccumulateSquareWithMask(Mat src, Mat dst, Mat mask); OpenCVResult Mat_AccumulateProduct(Mat src1, Mat src2, Mat dst); OpenCVResult Mat_AccumulateProductWithMask(Mat src1, Mat src2, Mat dst, Mat mask); OpenCVResult Mat_AccumulatedWeighted(Mat src, Mat dst, double alpha); OpenCVResult Mat_AccumulatedWeightedWithMask(Mat src, Mat dst, double alpha, Mat mask); #ifdef __cplusplus } #endif #endif //_OPENCV3_IMGPROC_H_ ================================================ FILE: imgproc_colorcodes.go ================================================ package gocv // ColorConversionCode is a color conversion code used on Mat. // // For further details, please see: // http://docs.opencv.org/master/d7/d1b/group__imgproc__misc.html#ga4e0972be5de079fed4e3a10e24ef5ef0 type ColorConversionCode int const ( // ColorBGRToBGRA adds alpha channel to BGR image. ColorBGRToBGRA ColorConversionCode = 0 // ColorRGBToRGBA adds alpha channel to RGB image. ColorRGBToRGBA ColorConversionCode = ColorBGRToBGRA // ColorBGRAToBGR removes alpha channel from BGR image. ColorBGRAToBGR ColorConversionCode = 1 // ColorRGBAToRGB removes alpha channel from RGB image. ColorRGBAToRGB ColorConversionCode = ColorBGRAToBGR // ColorBGRToRGBA converts from BGR to RGB with alpha channel. ColorBGRToRGBA ColorConversionCode = 2 // ColorRGBToBGRA converts from RGB to BGR with alpha channel. ColorRGBToBGRA ColorConversionCode = ColorBGRToRGBA // ColorRGBAToBGR converts from RGB with alpha to BGR color space. ColorRGBAToBGR ColorConversionCode = 3 // ColorBGRAToRGB converts from BRG with alpha to RGB color space. ColorBGRAToRGB ColorConversionCode = ColorRGBAToBGR // ColorBGRToRGB converts from BGR to RGB without alpha channel. ColorBGRToRGB ColorConversionCode = 4 // ColorRGBToBGR converts from RGB to BGR without alpha channel. ColorRGBToBGR ColorConversionCode = ColorBGRToRGB // ColorBGRAToRGBA converts from BGR with alpha channel // to RGB with alpha channel. ColorBGRAToRGBA ColorConversionCode = 5 // ColorRGBAToBGRA converts from RGB with alpha channel // to BGR with alpha channel. ColorRGBAToBGRA ColorConversionCode = ColorBGRAToRGBA // ColorBGRToGray converts from BGR to grayscale. ColorBGRToGray ColorConversionCode = 6 // ColorRGBToGray converts from RGB to grayscale. ColorRGBToGray ColorConversionCode = 7 // ColorGrayToBGR converts from grayscale to BGR. ColorGrayToBGR ColorConversionCode = 8 // ColorGrayToRGB converts from grayscale to RGB. ColorGrayToRGB ColorConversionCode = ColorGrayToBGR // ColorGrayToBGRA converts from grayscale to BGR with alpha channel. ColorGrayToBGRA ColorConversionCode = 9 // ColorGrayToRGBA converts from grayscale to RGB with alpha channel. ColorGrayToRGBA ColorConversionCode = ColorGrayToBGRA // ColorBGRAToGray converts from BGR with alpha channel to grayscale. ColorBGRAToGray ColorConversionCode = 10 // ColorRGBAToGray converts from RGB with alpha channel to grayscale. ColorRGBAToGray ColorConversionCode = 11 // ColorBGRToBGR565 converts from BGR to BGR565 (16-bit images). ColorBGRToBGR565 ColorConversionCode = 12 // ColorRGBToBGR565 converts from RGB to BGR565 (16-bit images). ColorRGBToBGR565 ColorConversionCode = 13 // ColorBGR565ToBGR converts from BGR565 (16-bit images) to BGR. ColorBGR565ToBGR ColorConversionCode = 14 // ColorBGR565ToRGB converts from BGR565 (16-bit images) to RGB. ColorBGR565ToRGB ColorConversionCode = 15 // ColorBGRAToBGR565 converts from BGRA (with alpha channel) // to BGR565 (16-bit images). ColorBGRAToBGR565 ColorConversionCode = 16 // ColorRGBAToBGR565 converts from RGBA (with alpha channel) // to BGR565 (16-bit images). ColorRGBAToBGR565 ColorConversionCode = 17 // ColorBGR565ToBGRA converts from BGR565 (16-bit images) // to BGRA (with alpha channel). ColorBGR565ToBGRA ColorConversionCode = 18 // ColorBGR565ToRGBA converts from BGR565 (16-bit images) // to RGBA (with alpha channel). ColorBGR565ToRGBA ColorConversionCode = 19 // ColorGrayToBGR565 converts from grayscale // to BGR565 (16-bit images). ColorGrayToBGR565 ColorConversionCode = 20 // ColorBGR565ToGray converts from BGR565 (16-bit images) // to grayscale. ColorBGR565ToGray ColorConversionCode = 21 // ColorBGRToBGR555 converts from BGR to BGR555 (16-bit images). ColorBGRToBGR555 ColorConversionCode = 22 // ColorRGBToBGR555 converts from RGB to BGR555 (16-bit images). ColorRGBToBGR555 ColorConversionCode = 23 // ColorBGR555ToBGR converts from BGR555 (16-bit images) to BGR. ColorBGR555ToBGR ColorConversionCode = 24 // ColorBGR555ToRGB converts from BGR555 (16-bit images) to RGB. ColorBGR555ToRGB ColorConversionCode = 25 // ColorBGRAToBGR555 converts from BGRA (with alpha channel) // to BGR555 (16-bit images). ColorBGRAToBGR555 ColorConversionCode = 26 // ColorRGBAToBGR555 converts from RGBA (with alpha channel) // to BGR555 (16-bit images). ColorRGBAToBGR555 ColorConversionCode = 27 // ColorBGR555ToBGRA converts from BGR555 (16-bit images) // to BGRA (with alpha channel). ColorBGR555ToBGRA ColorConversionCode = 28 // ColorBGR555ToRGBA converts from BGR555 (16-bit images) // to RGBA (with alpha channel). ColorBGR555ToRGBA ColorConversionCode = 29 // ColorGrayToBGR555 converts from grayscale to BGR555 (16-bit images). ColorGrayToBGR555 ColorConversionCode = 30 // ColorBGR555ToGRAY converts from BGR555 (16-bit images) to grayscale. ColorBGR555ToGRAY ColorConversionCode = 31 // ColorBGRToXYZ converts from BGR to CIE XYZ. ColorBGRToXYZ ColorConversionCode = 32 // ColorRGBToXYZ converts from RGB to CIE XYZ. ColorRGBToXYZ ColorConversionCode = 33 // ColorXYZToBGR converts from CIE XYZ to BGR. ColorXYZToBGR ColorConversionCode = 34 // ColorXYZToRGB converts from CIE XYZ to RGB. ColorXYZToRGB ColorConversionCode = 35 // ColorBGRToYCrCb converts from BGR to luma-chroma (aka YCC). ColorBGRToYCrCb ColorConversionCode = 36 // ColorRGBToYCrCb converts from RGB to luma-chroma (aka YCC). ColorRGBToYCrCb ColorConversionCode = 37 // ColorYCrCbToBGR converts from luma-chroma (aka YCC) to BGR. ColorYCrCbToBGR ColorConversionCode = 38 // ColorYCrCbToRGB converts from luma-chroma (aka YCC) to RGB. ColorYCrCbToRGB ColorConversionCode = 39 // ColorBGRToHSV converts from BGR to HSV (hue saturation value). ColorBGRToHSV ColorConversionCode = 40 // ColorRGBToHSV converts from RGB to HSV (hue saturation value). ColorRGBToHSV ColorConversionCode = 41 // ColorBGRToLab converts from BGR to CIE Lab. ColorBGRToLab ColorConversionCode = 44 // ColorRGBToLab converts from RGB to CIE Lab. ColorRGBToLab ColorConversionCode = 45 // ColorBGRToLuv converts from BGR to CIE Luv. ColorBGRToLuv ColorConversionCode = 50 // ColorRGBToLuv converts from RGB to CIE Luv. ColorRGBToLuv ColorConversionCode = 51 // ColorBGRToHLS converts from BGR to HLS (hue lightness saturation). ColorBGRToHLS ColorConversionCode = 52 // ColorRGBToHLS converts from RGB to HLS (hue lightness saturation). ColorRGBToHLS ColorConversionCode = 53 // ColorHSVToBGR converts from HSV (hue saturation value) to BGR. ColorHSVToBGR ColorConversionCode = 54 // ColorHSVToRGB converts from HSV (hue saturation value) to RGB. ColorHSVToRGB ColorConversionCode = 55 // ColorLabToBGR converts from CIE Lab to BGR. ColorLabToBGR ColorConversionCode = 56 // ColorLabToRGB converts from CIE Lab to RGB. ColorLabToRGB ColorConversionCode = 57 // ColorLuvToBGR converts from CIE Luv to BGR. ColorLuvToBGR ColorConversionCode = 58 // ColorLuvToRGB converts from CIE Luv to RGB. ColorLuvToRGB ColorConversionCode = 59 // ColorHLSToBGR converts from HLS (hue lightness saturation) to BGR. ColorHLSToBGR ColorConversionCode = 60 // ColorHLSToRGB converts from HLS (hue lightness saturation) to RGB. ColorHLSToRGB ColorConversionCode = 61 // ColorBGRToHSVFull converts from BGR to HSV (hue saturation value) full. ColorBGRToHSVFull ColorConversionCode = 66 // ColorRGBToHSVFull converts from RGB to HSV (hue saturation value) full. ColorRGBToHSVFull ColorConversionCode = 67 // ColorBGRToHLSFull converts from BGR to HLS (hue lightness saturation) full. ColorBGRToHLSFull ColorConversionCode = 68 // ColorRGBToHLSFull converts from RGB to HLS (hue lightness saturation) full. ColorRGBToHLSFull ColorConversionCode = 69 // ColorHSVToBGRFull converts from HSV (hue saturation value) to BGR full. ColorHSVToBGRFull ColorConversionCode = 70 // ColorHSVToRGBFull converts from HSV (hue saturation value) to RGB full. ColorHSVToRGBFull ColorConversionCode = 71 // ColorHLSToBGRFull converts from HLS (hue lightness saturation) to BGR full. ColorHLSToBGRFull ColorConversionCode = 72 // ColorHLSToRGBFull converts from HLS (hue lightness saturation) to RGB full. ColorHLSToRGBFull ColorConversionCode = 73 // ColorLBGRToLab converts from LBGR to CIE Lab. ColorLBGRToLab ColorConversionCode = 74 // ColorLRGBToLab converts from LRGB to CIE Lab. ColorLRGBToLab ColorConversionCode = 75 // ColorLBGRToLuv converts from LBGR to CIE Luv. ColorLBGRToLuv ColorConversionCode = 76 // ColorLRGBToLuv converts from LRGB to CIE Luv. ColorLRGBToLuv ColorConversionCode = 77 // ColorLabToLBGR converts from CIE Lab to LBGR. ColorLabToLBGR ColorConversionCode = 78 // ColorLabToLRGB converts from CIE Lab to LRGB. ColorLabToLRGB ColorConversionCode = 79 // ColorLuvToLBGR converts from CIE Luv to LBGR. ColorLuvToLBGR ColorConversionCode = 80 // ColorLuvToLRGB converts from CIE Luv to LRGB. ColorLuvToLRGB ColorConversionCode = 81 // ColorBGRToYUV converts from BGR to YUV. ColorBGRToYUV ColorConversionCode = 82 // ColorRGBToYUV converts from RGB to YUV. ColorRGBToYUV ColorConversionCode = 83 // ColorYUVToBGR converts from YUV to BGR. ColorYUVToBGR ColorConversionCode = 84 // ColorYUVToRGB converts from YUV to RGB. ColorYUVToRGB ColorConversionCode = 85 // ColorYUVToRGBNV12 converts from YUV 4:2:0 to RGB NV12. ColorYUVToRGBNV12 ColorConversionCode = 90 // ColorYUVToBGRNV12 converts from YUV 4:2:0 to BGR NV12. ColorYUVToBGRNV12 ColorConversionCode = 91 // ColorYUVToRGBNV21 converts from YUV 4:2:0 to RGB NV21. ColorYUVToRGBNV21 ColorConversionCode = 92 // ColorYUVToBGRNV21 converts from YUV 4:2:0 to BGR NV21. ColorYUVToBGRNV21 ColorConversionCode = 93 // ColorYUVToRGBANV12 converts from YUV 4:2:0 to RGBA NV12. ColorYUVToRGBANV12 ColorConversionCode = 94 // ColorYUVToBGRANV12 converts from YUV 4:2:0 to BGRA NV12. ColorYUVToBGRANV12 ColorConversionCode = 95 // ColorYUVToRGBANV21 converts from YUV 4:2:0 to RGBA NV21. ColorYUVToRGBANV21 ColorConversionCode = 96 // ColorYUVToBGRANV21 converts from YUV 4:2:0 to BGRA NV21. ColorYUVToBGRANV21 ColorConversionCode = 97 ColorYUVToRGBYV12 ColorConversionCode = 98 ColorYUVToBGRYV12 ColorConversionCode = 99 ColorYUVToRGBIYUV ColorConversionCode = 100 ColorYUVToBGRIYUV ColorConversionCode = 101 ColorYUVToRGBAYV12 ColorConversionCode = 102 ColorYUVToBGRAYV12 ColorConversionCode = 103 ColorYUVToRGBAIYUV ColorConversionCode = 104 ColorYUVToBGRAIYUV ColorConversionCode = 105 ColorYUVToGRAY420 ColorConversionCode = 106 // YUV 4:2:2 family to RGB ColorYUVToRGBUYVY ColorConversionCode = 107 ColorYUVToBGRUYVY ColorConversionCode = 108 ColorYUVToRGBAUYVY ColorConversionCode = 111 ColorYUVToBGRAUYVY ColorConversionCode = 112 ColorYUVToRGBYUY2 ColorConversionCode = 115 ColorYUVToBGRYUY2 ColorConversionCode = 116 ColorYUVToRGBYVYU ColorConversionCode = 117 ColorYUVToBGRYVYU ColorConversionCode = 118 ColorYUVToRGBAYUY2 ColorConversionCode = 119 ColorYUVToBGRAYUY2 ColorConversionCode = 120 ColorYUVToRGBAYVYU ColorConversionCode = 121 ColorYUVToBGRAYVYU ColorConversionCode = 122 ColorYUVToGRAYUYVY ColorConversionCode = 123 ColorYUVToGRAYYUY2 ColorConversionCode = 124 // alpha premultiplication ColorRGBATomRGBA ColorConversionCode = 125 ColormRGBAToRGBA ColorConversionCode = 126 // RGB to YUV 4:2:0 family ColorRGBToYUVI420 ColorConversionCode = 127 ColorBGRToYUVI420 ColorConversionCode = 128 ColorRGBAToYUVI420 ColorConversionCode = 129 ColorBGRAToYUVI420 ColorConversionCode = 130 ColorRGBToYUVYV12 ColorConversionCode = 131 ColorBGRToYUVYV12 ColorConversionCode = 132 ColorRGBAToYUVYV12 ColorConversionCode = 133 ColorBGRAToYUVYV12 ColorConversionCode = 134 // Demosaicing ColorBayerBGToBGR ColorConversionCode = 46 ColorBayerGBToBGR ColorConversionCode = 47 ColorBayerRGToBGR ColorConversionCode = 48 ColorBayerGRToBGR ColorConversionCode = 49 ColorBayerBGToRGB ColorConversionCode = ColorBayerRGToBGR ColorBayerGBToRGB ColorConversionCode = ColorBayerGRToBGR ColorBayerRGToRGB ColorConversionCode = ColorBayerBGToBGR ColorBayerGRToRGB ColorConversionCode = ColorBayerGBToBGR ColorBayerBGToGRAY ColorConversionCode = 86 ColorBayerGBToGRAY ColorConversionCode = 87 ColorBayerRGToGRAY ColorConversionCode = 88 ColorBayerGRToGRAY ColorConversionCode = 89 // Demosaicing using Variable Number of Gradients ColorBayerBGToBGRVNG ColorConversionCode = 62 ColorBayerGBToBGRVNG ColorConversionCode = 63 ColorBayerRGToBGRVNG ColorConversionCode = 64 ColorBayerGRToBGRVNG ColorConversionCode = 65 ColorBayerBGToRGBVNG ColorConversionCode = ColorBayerRGToBGRVNG ColorBayerGBToRGBVNG ColorConversionCode = ColorBayerGRToBGRVNG ColorBayerRGToRGBVNG ColorConversionCode = ColorBayerBGToBGRVNG ColorBayerGRToRGBVNG ColorConversionCode = ColorBayerGBToBGRVNG // Edge-Aware Demosaicing ColorBayerBGToBGREA ColorConversionCode = 135 ColorBayerGBToBGREA ColorConversionCode = 136 ColorBayerRGToBGREA ColorConversionCode = 137 ColorBayerGRToBGREA ColorConversionCode = 138 ColorBayerBGToRGBEA ColorConversionCode = ColorBayerRGToBGREA ColorBayerGBToRGBEA ColorConversionCode = ColorBayerGRToBGREA ColorBayerRGToRGBEA ColorConversionCode = ColorBayerBGToBGREA ColorBayerGRToRGBEA ColorConversionCode = ColorBayerGBToBGREA // Demosaicing with alpha channel ColorBayerBGToBGRA ColorConversionCode = 139 ColorBayerGBToBGRA ColorConversionCode = 140 ColorBayerRGToBGRA ColorConversionCode = 141 ColorBayerGRToBGRA ColorConversionCode = 142 ColorBayerBGToRGBA ColorConversionCode = ColorBayerRGToBGRA ColorBayerGBToRGBA ColorConversionCode = ColorBayerGRToBGRA ColorBayerRGToRGBA ColorConversionCode = ColorBayerBGToBGRA ColorBayerGRToRGBA ColorConversionCode = ColorBayerGBToBGRA ColorCOLORCVTMAX ColorConversionCode = 143 ) ================================================ FILE: imgproc_colorcodes_string.go ================================================ package gocv func (c ColorConversionCode) String() string { switch c { case ColorBGRToBGRA: return "color-bgr-to-bgra" case ColorBGRAToBGR: return "color-bgra-to-bgr" case ColorBGRToRGBA: return "color-bgr-to-rgba" case ColorRGBAToBGR: return "color-rgba-to-bgr" case ColorBGRToRGB: return "color-bgr-to-rgb" case ColorBGRAToRGBA: return "color-bgra-to-rgba" case ColorBGRToGray: return "color-bgr-to-gray" case ColorRGBToGray: return "color-rgb-to-gray" case ColorGrayToBGR: return "color-gray-to-bgr" case ColorGrayToBGRA: return "color-gray-to-bgra" case ColorBGRAToGray: return "color-bgra-to-gray" case ColorRGBAToGray: return "color-rgba-to-gray" case ColorBGRToBGR565: return "color-bgr-to-bgr565" case ColorRGBToBGR565: return "color-rgb-to-bgr565" case ColorBGR565ToBGR: return "color-bgr565-to-bgr" case ColorBGR565ToRGB: return "color-bgr565-to-rgb" case ColorBGRAToBGR565: return "color-bgra-to-bgr565" case ColorRGBAToBGR565: return "color-rgba-to-bgr565" case ColorBGR565ToBGRA: return "color-bgr565-to-bgra" case ColorBGR565ToRGBA: return "color-bgr565-to-rgba" case ColorGrayToBGR565: return "color-gray-to-bgr565" case ColorBGR565ToGray: return "color-bgr565-to-gray" case ColorBGRToBGR555: return "color-bgr-to-bgr555" case ColorRGBToBGR555: return "color-rgb-to-bgr555" case ColorBGR555ToBGR: return "color-bgr555-to-bgr" case ColorBGRAToBGR555: return "color-bgra-to-bgr555" case ColorRGBAToBGR555: return "color-rgba-to-bgr555" case ColorBGR555ToBGRA: return "color-bgr555-to-bgra" case ColorBGR555ToRGBA: return "color-bgr555-to-rgba" case ColorGrayToBGR555: return "color-gray-to-bgr555" case ColorBGR555ToGRAY: return "color-bgr555-to-gray" case ColorBGRToXYZ: return "color-bgr-to-xyz" case ColorRGBToXYZ: return "color-rgb-to-xyz" case ColorXYZToBGR: return "color-xyz-to-bgr" case ColorXYZToRGB: return "color-xyz-to-rgb" case ColorBGRToYCrCb: return "color-bgr-to-ycrcb" case ColorRGBToYCrCb: return "color-rgb-to-ycrcb" case ColorYCrCbToBGR: return "color-ycrcb-to-bgr" case ColorYCrCbToRGB: return "color-ycrcb-to-rgb" case ColorBGRToHSV: return "color-bgr-to-hsv" case ColorRGBToHSV: return "color-rgb-to-hsv" case ColorBGRToLab: return "color-bgr-to-lab" case ColorRGBToLab: return "color-rgb-to-lab" case ColorBGRToLuv: return "color-bgr-to-luv" case ColorRGBToLuv: return "color-rgb-to-luv" case ColorBGRToHLS: return "color-bgr-to-hls" case ColorRGBToHLS: return "color-rgb-to-hls" case ColorHSVToBGR: return "color-hsv-to-bgr" case ColorHSVToRGB: return "color-hsv-to-rgb" case ColorLabToBGR: return "color-lab-to-bgr" case ColorLabToRGB: return "color-lab-to-rgb" case ColorLuvToBGR: return "color-luv-to-bgr" case ColorLuvToRGB: return "color-luv-to-rgb" case ColorHLSToBGR: return "color-hls-to-bgr" case ColorHLSToRGB: return "color-hls-to-rgb" case ColorBGRToHSVFull: return "color-bgr-to-hsv-full" case ColorRGBToHSVFull: return "color-rgb-to-hsv-full" case ColorBGRToHLSFull: return "color-bgr-to-hls-full" case ColorRGBToHLSFull: return "color-rgb-to-hls-full" case ColorHSVToBGRFull: return "color-hsv-to-bgr-full" case ColorHSVToRGBFull: return "color-hsv-to-rgb-full" case ColorHLSToBGRFull: return "color-hls-to-bgr-full" case ColorHLSToRGBFull: return "color-hls-to-rgb-full" case ColorLBGRToLab: return "color-lbgr-to-lab" case ColorLRGBToLab: return "color-lrgb-to-lab" case ColorLBGRToLuv: return "color-lbgr-to-luv" case ColorLRGBToLuv: return "color-lrgb-to-luv" case ColorLabToLBGR: return "color-lab-to-lbgr" case ColorLabToLRGB: return "color-lab-to-lrgb" case ColorLuvToLBGR: return "color-luv-to-lbgr" case ColorLuvToLRGB: return "color-luv-to-lrgb" case ColorBGRToYUV: return "color-bgr-to-yuv" case ColorRGBToYUV: return "color-rgb-to-yuv" case ColorYUVToBGR: return "color-yuv-to-bgr" case ColorYUVToRGB: return "color-yuv-to-rgb" case ColorYUVToRGBNV12: return "color-yuv-to-rgbnv12" case ColorYUVToBGRNV12: return "color-yuv-to-bgrnv12" case ColorYUVToRGBNV21: return "color-yuv-to-rgbnv21" case ColorYUVToBGRNV21: return "color-yuv-to-bgrnv21" case ColorYUVToRGBANV12: return "color-yuv-to-rgbanv12" case ColorYUVToBGRANV12: return "color-yuv-to-bgranv12" case ColorYUVToRGBANV21: return "color-yuv-to-rgbanv21" case ColorYUVToBGRANV21: return "color-yuv-to-bgranv21" case ColorYUVToRGBYV12: return "color-yuv-to-rgbyv12" case ColorYUVToBGRYV12: return "color-yuv-to-bgryv12" case ColorYUVToRGBIYUV: return "color-yuv-to-rgbiyuv" case ColorYUVToBGRIYUV: return "color-yuv-to-bgriyuv" case ColorYUVToRGBAYV12: return "color-yuv-to-rgbayv12" case ColorYUVToBGRAYV12: return "color-yuv-to-bgrayv12" case ColorYUVToRGBAIYUV: return "color-yuv-to-rgbaiyuv" case ColorYUVToBGRAIYUV: return "color-yuv-to-bgraiyuv" case ColorYUVToGRAY420: return "color-yuv-to-gray420" case ColorYUVToRGBUYVY: return "color-yuv-to-rgbuyvy" case ColorYUVToBGRUYVY: return "color-yuv-to-bgruyvy" case ColorYUVToRGBAUYVY: return "color-yuv-to-rgbauyvy" case ColorYUVToBGRAUYVY: return "color-yuv-to-bgrauyvy" case ColorYUVToRGBYUY2: return "color-yuv-to-rgbyuy2" case ColorYUVToBGRYUY2: return "color-yuv-to-bgryuy2" case ColorYUVToRGBYVYU: return "color-yuv-to-rgbyvyu" case ColorYUVToBGRYVYU: return "color-yuv-to-bgryvyu" case ColorYUVToRGBAYUY2: return "color-yuv-to-rgbayuy2" case ColorYUVToBGRAYUY2: return "color-yuv-to-bgrayuy2" case ColorYUVToRGBAYVYU: return "color-yuv-to-rgbayvyu" case ColorYUVToBGRAYVYU: return "color-yuv-to-bgrayvyu" case ColorYUVToGRAYUYVY: return "color-yuv-to-grayuyvy" case ColorYUVToGRAYYUY2: return "color-yuv-to-grayyuy2" case ColorRGBATomRGBA: return "color-rgba-to-mrgba" case ColormRGBAToRGBA: return "color-mrgba-to-rgba" case ColorRGBToYUVI420: return "color-rgb-to-yuvi420" case ColorBGRToYUVI420: return "color-bgr-to-yuvi420" case ColorRGBAToYUVI420: return "color-rgba-to-yuvi420" case ColorBGRAToYUVI420: return "color-bgra-to-yuvi420" case ColorRGBToYUVYV12: return "color-rgb-to-yuvyv12" case ColorBGRToYUVYV12: return "color-bgr-to-yuvyv12" case ColorRGBAToYUVYV12: return "color-rgba-to-yuvyv12" case ColorBGRAToYUVYV12: return "color-bgra-to-yuvyv12" case ColorBayerBGToBGR: return "color-bayer-bgt-to-bgr" case ColorBayerGBToBGR: return "color-bayer-gbt-to-bgr" case ColorBayerRGToBGR: return "color-bayer-rgt-to-bgr" case ColorBayerGRToBGR: return "color-bayer-grt-to-bgr" case ColorBayerBGToGRAY: return "color-bayer-bgt-to-gray" case ColorBayerGBToGRAY: return "color-bayer-gbt-to-gray" case ColorBayerRGToGRAY: return "color-bayer-rgt-to-gray" case ColorBayerGRToGRAY: return "color-bayer-grt-to-gray" case ColorBayerBGToBGRVNG: return "color-bayer-bgt-to-bgrvng" case ColorBayerGBToBGRVNG: return "color-bayer-gbt-to-bgrvng" case ColorBayerRGToBGRVNG: return "color-bayer-rgt-to-bgrvng" case ColorBayerGRToBGRVNG: return "color-bayer-grt-to-bgrvng" case ColorBayerBGToBGREA: return "color-bayer-bgt-to-bgrea" case ColorBayerGBToBGREA: return "color-bayer-gbt-to-bgrea" case ColorBayerRGToBGREA: return "color-bayer-rgt-to-bgrea" case ColorBayerGRToBGREA: return "color-bayer-grt-to-bgrea" case ColorBayerBGToBGRA: return "color-bayer-bgt-to-bgra" case ColorBayerGBToBGRA: return "color-bayer-gbt-to-bgra" case ColorBayerRGToBGRA: return "color-bayer-rgt-to-bgra" case ColorBayerGRToBGRA: return "color-bayer-grt-to-bgra" case ColorCOLORCVTMAX: return "color-color-cvt-max" } return "" } ================================================ FILE: imgproc_string.go ================================================ package gocv func (c HistCompMethod) String() string { switch c { case HistCmpCorrel: return "hist-cmp-correl" case HistCmpChiSqr: return "hist-cmp-chi-sqr" case HistCmpIntersect: return "hist-cmp-intersect" case HistCmpBhattacharya: return "hist-cmp-bhattacharya" case HistCmpChiSqrAlt: return "hist-cmp-chi-sqr-alt" case HistCmpKlDiv: return "hist-cmp-kl-div" } return "" } func (c DistanceTransformLabelTypes) String() string { switch c { case DistanceLabelCComp: return "distance-label-ccomp" } return "" } func (c DistanceTransformMasks) String() string { switch c { case DistanceMask3: return "distance-mask3" } return "" } func (c RetrievalMode) String() string { switch c { case RetrievalExternal: return "retrieval-external" case RetrievalList: return "retrieval-list" case RetrievalCComp: return "retrieval-ccomp" case RetrievalTree: return "retrieval-tree" case RetrievalFloodfill: return "retrieval-floodfill" } return "" } func (c ContourApproximationMode) String() string { switch c { case ChainApproxNone: return "chain-approx-none" case ChainApproxSimple: return "chain-approx-simple" case ChainApproxTC89L1: return "chain-approx-tc89l1" case ChainApproxTC89KCOS: return "chain-approx-tc89kcos" } return "" } func (c ConnectedComponentsAlgorithmType) String() string { switch c { case CCL_WU: return "ccl-wu" case CCL_DEFAULT: return "ccl-default" case CCL_GRANA: return "ccl-grana" } return "" } func (c ConnectedComponentsTypes) String() string { switch c { case CC_STAT_LEFT: return "cc-stat-left" case CC_STAT_TOP: return "cc-stat-top" case CC_STAT_WIDTH: return "cc-stat-width" case CC_STAT_AREA: return "cc-stat-area" case CC_STAT_MAX: return "cc-stat-max" case CC_STAT_HEIGHT: return "cc-stat-height" } return "" } func (c TemplateMatchMode) String() string { switch c { case TmSqdiff: return "tm-sq-diff" case TmSqdiffNormed: return "tm-sq-diff-normed" case TmCcorr: return "tm-ccorr" case TmCcorrNormed: return "tm-ccorr-normed" case TmCcoeff: return "tm-ccoeff" case TmCcoeffNormed: return "tm-ccoeff-normed" } return "" } func (c MorphShape) String() string { switch c { case MorphRect: return "morph-rect" case MorphCross: return "morph-cross" case MorphEllipse: return "morph-ellispe" } return "" } func (c MorphType) String() string { switch c { case MorphErode: return "morph-erode" case MorphDilate: return "morph-dilate" case MorphOpen: return "morph-open" case MorphClose: return "morph-close" case MorphGradient: return "morph-gradient" case MorphTophat: return "morph-tophat" case MorphBlackhat: return "morph-blackhat" case MorphHitmiss: return "morph-hitmiss" } return "" } func (c BorderType) String() string { switch c { case BorderConstant: return "border-constant" case BorderReplicate: return "border-replicate" case BorderReflect: return "border-reflect" case BorderWrap: return "border-wrap" case BorderTransparent: return "border-transparent" case BorderDefault: return "border-default" case BorderIsolated: return "border-isolated" } return "" } func (c GrabCutMode) String() string { switch c { case GCInitWithRect: return "gc-init-with-rect" case GCInitWithMask: return "gc-init-with-mask" case GCEval: return "gc-eval" case GCEvalFreezeModel: return "gc-eval-freeze-model" } return "" } func (c HoughMode) String() string { switch c { case HoughStandard: return "hough-standard" case HoughProbabilistic: return "hough-probabilistic" case HoughMultiScale: return "hough-multi-scale" case HoughGradient: return "hough-gradient" } return "" } func (c ThresholdType) String() string { switch c { case ThresholdBinary: return "threshold-binary" case ThresholdBinaryInv: return "threshold-binary-inv" case ThresholdTrunc: return "threshold-trunc" case ThresholdToZero: return "threshold-to-zero" case ThresholdToZeroInv: return "threshold-to-zero-inv" case ThresholdMask: return "threshold-mask" case ThresholdOtsu: return "threshold-otsu" case ThresholdTriangle: return "threshold-triangle" } return "" } func (c AdaptiveThresholdType) String() string { switch c { case AdaptiveThresholdMean: return "adaptative-threshold-mean" case AdaptiveThresholdGaussian: return "adaptative-threshold-gaussian" } return "" } func (c HersheyFont) String() string { switch c { case FontHersheySimplex: return "font-hershey-simplex" case FontHersheyPlain: return "font-hershey-plain" case FontHersheyDuplex: return "font-hershey-duplex" case FontHersheyComplex: return "font-hershey-complex" case FontHersheyTriplex: return "font-hershey-triplex" case FontHersheyComplexSmall: return "font-hershey-complex-small" case FontHersheyScriptSimplex: return "font-hershey-script-simplex" case FontHersheyScriptComplex: return "font-hershey-scipt-complex" case FontItalic: return "font-italic" } return "" } func (c LineType) String() string { switch c { case Filled: return "filled" case Line4: return "line4" case Line8: return "line8" case LineAA: return "line-aa" } return "" } func (c InterpolationFlags) String() string { switch c { case InterpolationNearestNeighbor: return "interpolation-nearest-neighbor" case InterpolationLinear: return "interpolation-linear" case InterpolationCubic: return "interpolation-cubic" case InterpolationArea: return "interpolation-area" case InterpolationLanczos4: return "interpolation-lanczos4" case InterpolationMax: return "interpolation-max" } return "" } func (c ColormapTypes) String() string { switch c { case ColormapAutumn: return "colormap-autumn" case ColormapBone: return "colormap-bone" case ColormapJet: return "colormap-jet" case ColormapWinter: return "colormap-winter" case ColormapRainbow: return "colormap-rainbow" case ColormapOcean: return "colormap-ocean" case ColormapSummer: return "colormap-summer" case ColormapSpring: return "colormap-spring" case ColormapCool: return "colormap-cool" case ColormapHsv: return "colormap-hsv" case ColormapPink: return "colormap-pink" case ColormapParula: return "colormap-parula" case ColormapMagma: return "colormap-magma" case ColormapInferno: return "colormap-inferno" case ColormapPlasma: return "colormap-plasma" case ColormapViridis: return "colormap-viridis" case ColormapCividis: return "colormap-cividis" case ColormapTwilight: return "colormap-twilight" case ColormapTwilightShifted: return "colormap-twilight-shifted" case ColormapTurbo: return "colormap-turbo" case ColormapDeepGreen: return "colormap-deep-green" } return "" } func (c DistanceTypes) String() string { switch c { case DistUser: return "dist-user" case DistL1: return "dist-l1" case DistL2: return "dist-l2" case DistL12: return "dist-l12" case DistFair: return "dist-fair" case DistWelsch: return "dist-welsch" case DistHuber: return "dist-huber" } return "" } ================================================ FILE: imgproc_test.go ================================================ package gocv import ( "fmt" "image" "image/color" "image/draw" "log" "math" "os" "reflect" "runtime" "testing" ) func TestApproxPolyDP(t *testing.T) { img := NewMatWithSize(100, 200, MatTypeCV8UC1) defer img.Close() white := color.RGBA{255, 255, 255, 255} // Draw triangle Line(&img, image.Pt(25, 25), image.Pt(25, 75), white, 1) Line(&img, image.Pt(25, 75), image.Pt(75, 50), white, 1) Line(&img, image.Pt(75, 50), image.Pt(25, 25), white, 1) // Draw rectangle Rectangle(&img, image.Rect(125, 25, 175, 75), white, 1) contours := FindContours(img, RetrievalExternal, ChainApproxSimple) defer contours.Close() trianglePerimeter := ArcLength(contours.At(0), true) triangleContour := ApproxPolyDP(contours.At(0), 0.04*trianglePerimeter, true) defer triangleContour.Close() expectedTriangleContour := []image.Point{image.Pt(25, 25), image.Pt(25, 75), image.Pt(75, 50)} actualTriangleContour := triangleContour.ToPoints() if !reflect.DeepEqual(actualTriangleContour, expectedTriangleContour) { t.Errorf("Failed to approximate triangle.\nActual:%v\nExpect:%v", actualTriangleContour, expectedTriangleContour) } rectPerimeter := ArcLength(contours.At(1), true) rectContour := ApproxPolyDP(contours.At(1), 0.04*rectPerimeter, true) defer rectContour.Close() actualRectContour := rectContour.ToPoints() expectedRectContour := []image.Point{image.Pt(125, 24), image.Pt(124, 75), image.Pt(175, 76), image.Pt(176, 25)} if !reflect.DeepEqual(actualRectContour, expectedRectContour) { t.Errorf("Failed to approximate rectangle.\nActual:%v\nExpect:%v", actualRectContour, expectedRectContour) } } func TestConvexity(t *testing.T) { img := IMRead("images/face-detect.jpg", IMReadGrayScale) if img.Empty() { t.Error("Invalid read of Mat in FindContours test") } defer img.Close() res := FindContours(img, RetrievalExternal, ChainApproxSimple) defer res.Close() if res.Size() < 1 { t.Error("Invalid FindContours test") } area := ContourArea(res.At(0)) if area != 127280.0 { t.Errorf("Invalid ContourArea test: %f", area) } hull := NewMat() defer hull.Close() ConvexHull(res.At(0), &hull, true, false) if hull.Empty() { t.Error("Invalid ConvexHull test") } defects := NewMat() defer defects.Close() ConvexityDefects(res.At(0), hull, &defects) if defects.Empty() { t.Error("Invalid ConvexityDefects test") } } func TestMinEnclosingCircle(t *testing.T) { pts := []image.Point{ image.Pt(0, 2), image.Pt(2, 0), image.Pt(0, -2), image.Pt(-2, 0), image.Pt(1, -1), } pv := NewPointVectorFromPoints(pts) defer pv.Close() x, y, radius := MinEnclosingCircle(pv) const epsilon = 0.001 if math.Abs(float64(radius-2.0)) > epsilon || math.Abs(float64(x-0.0)) > epsilon || math.Abs(float64(y-0.0)) > epsilon { t.Error("Invalid circle returned in MinEnclosingCircle test") } } func TestCvtColor(t *testing.T) { img := IMRead("images/face-detect.jpg", IMReadColor) if img.Empty() { t.Error("Invalid read of Mat in CvtColor test") } defer img.Close() dest := NewMat() defer dest.Close() CvtColor(img, &dest, ColorBGRAToGray) if dest.Empty() || img.Rows() != dest.Rows() || img.Cols() != dest.Cols() { t.Error("Invalid convert in CvtColor test") } } func TestCvtColorException(t *testing.T) { img := NewMat() defer img.Close() dest := NewMat() defer dest.Close() err := CvtColor(img, &dest, ColorBGRAToGray) if err == nil { t.Error("Expected exception in test") } if len(err.Error()) == 0 { t.Error("Expected exception message in test") } } func NewBayerFromMat(src Mat, pattern string) (Mat, error) { dest := NewMatWithSize(src.Rows(), src.Cols(), MatTypeCV8UC1) switch pattern { case "bg": for y := 0; y < src.Rows(); y++ { for x := 0; x < src.Cols(); x++ { if (x+y)%2 != 0 { dest.SetUCharAt(y, x, src.GetVecbAt(y, x)[1]) } else if (x % 2) != 0 { dest.SetUCharAt(y, x, src.GetVecbAt(y, x)[0]) } else { dest.SetUCharAt(y, x, src.GetVecbAt(y, x)[2]) } } } case "gb": for y := 0; y < src.Rows(); y++ { for x := 0; x < src.Cols(); x++ { if (x+y)%2 == 0 { dest.SetUCharAt(y, x, src.GetVecbAt(y, x)[1]) } else if (x % 2) == 0 { dest.SetUCharAt(y, x, src.GetVecbAt(y, x)[0]) } else { dest.SetUCharAt(y, x, src.GetVecbAt(y, x)[2]) } } } case "rg": for y := 0; y < src.Rows(); y++ { for x := 0; x < src.Cols(); x++ { if (x+y)%2 != 0 { dest.SetUCharAt(y, x, src.GetVecbAt(y, x)[1]) } else if (x % 2) == 0 { dest.SetUCharAt(y, x, src.GetVecbAt(y, x)[0]) } else { dest.SetUCharAt(y, x, src.GetVecbAt(y, x)[2]) } } } case "gr": for y := 0; y < src.Rows(); y++ { for x := 0; x < src.Cols(); x++ { if (x+y)%2 == 0 { dest.SetUCharAt(y, x, src.GetVecbAt(y, x)[1]) } else if (x % 2) != 0 { dest.SetUCharAt(y, x, src.GetVecbAt(y, x)[0]) } else { dest.SetUCharAt(y, x, src.GetVecbAt(y, x)[2]) } } } default: dest.Close() return Mat{}, fmt.Errorf("invalid pattern: %s", pattern) } return dest, nil } func TestDemosaicing(t *testing.T) { img := IMRead("images/face.jpg", IMReadColor) if img.Empty() { t.Error("Invalid read of Mat in Demosaicing test") } defer img.Close() patterns := map[string]ColorConversionCode{ "bg": ColorBayerBGToBGR, "gb": ColorBayerGBToBGR, "rg": ColorBayerRGToBGR, "gr": ColorBayerGRToBGR, } for pattern, code := range patterns { bayerImg, err := NewBayerFromMat(img, pattern) if bayerImg.Empty() { t.Error("Invalid conversion from Mat to Bayer in Demosaicing test") } if err != nil { t.Error(err) } dest := NewMat() Demosaicing(bayerImg, &dest, code) if dest.Empty() || bayerImg.Rows() != dest.Rows() || bayerImg.Cols() != dest.Cols() { t.Error("Invalid convert in Demosaicing test") } bayerImg.Close() dest.Close() } } func TestBilateralFilter(t *testing.T) { img := IMRead("images/face-detect.jpg", IMReadColor) if img.Empty() { t.Error("Invalid read of Mat in BilateralFilter test") } defer img.Close() dest := NewMat() defer dest.Close() BilateralFilter(img, &dest, 1, 2.0, 3.0) if dest.Empty() || img.Rows() != dest.Rows() || img.Cols() != dest.Cols() { t.Error("Invalid BilateralFilter test") } } func TestBlur(t *testing.T) { img := IMRead("images/face-detect.jpg", IMReadColor) if img.Empty() { t.Error("Invalid read of Mat in GaussianBlur test") } defer img.Close() dest := NewMat() defer dest.Close() Blur(img, &dest, image.Pt(3, 3)) if dest.Empty() || img.Rows() != dest.Rows() || img.Cols() != dest.Cols() { t.Error("Invalid Blur test") } } func TestSobel(t *testing.T) { img := IMRead("images/face-detect.jpg", IMReadGrayScale) if img.Empty() { t.Error("Invalid read of Mat in Sobel test") } defer img.Close() dest := NewMat() defer dest.Close() Sobel(img, &dest, MatTypeCV16S, 0, 1, 3, 1, 0, BorderDefault) if dest.Empty() || img.Rows() != dest.Rows() || img.Cols() != dest.Cols() { t.Error("Invalid Sober test") } } func TestSpatialGradient(t *testing.T) { img := IMRead("images/face-detect.jpg", IMReadGrayScale) if img.Empty() { t.Error("Invalid read of Mat in SpatialGradient test") } defer img.Close() dx := NewMat() defer dx.Close() dy := NewMat() defer dy.Close() SpatialGradient(img, &dx, &dy, MatTypeCV16S, BorderDefault) if dx.Empty() || dy.Empty() || img.Rows() != dx.Rows() || img.Rows() != dy.Rows() || img.Cols() != dx.Cols() || img.Cols() != dy.Cols() { t.Error("Invalid SpatialGradient test") } } func TestBoxFilter(t *testing.T) { img := IMRead("images/face-detect.jpg", IMReadColor) if img.Empty() { t.Error("Invalid read of Mat in BoxFilter test") } defer img.Close() dest := NewMat() defer dest.Close() BoxFilter(img, &dest, -1, image.Pt(3, 3)) if dest.Empty() || img.Rows() != dest.Rows() || img.Cols() != dest.Cols() { t.Error("Invalid BoxFilter test") } } func TestSqBoxFilter(t *testing.T) { img := IMRead("images/face-detect.jpg", IMReadColor) if img.Empty() { t.Error("Invalid read of Mat in SqBoxFilter test") } defer img.Close() dest := NewMat() defer dest.Close() SqBoxFilter(img, &dest, -1, image.Pt(3, 3)) if dest.Empty() || img.Rows() != dest.Rows() || img.Cols() != dest.Cols() { t.Error("Invalid SqBoxFilter test") } } func TestDilate(t *testing.T) { img := IMRead("images/face-detect.jpg", IMReadColor) if img.Empty() { t.Error("Invalid read of Mat in Dilate test") } defer img.Close() dest := NewMat() defer dest.Close() kernel := GetStructuringElement(MorphRect, image.Pt(1, 1)) defer kernel.Close() Dilate(img, &dest, kernel) if dest.Empty() || img.Rows() != dest.Rows() || img.Cols() != dest.Cols() { t.Error("Invalid Dilate test") } } func TestDilateWithParams(t *testing.T) { img := IMRead("images/face-detect.jpg", IMReadColor) if img.Empty() { t.Error("Invalid read of Mat in DilateWithParams test") } defer img.Close() dest := NewMat() defer dest.Close() kernel := GetStructuringElement(MorphRect, image.Pt(1, 1)) defer kernel.Close() DilateWithParams(img, &dest, kernel, image.Pt(-1, -1), 3, 0, color.RGBA{0, 0, 0, 0}) if dest.Empty() || img.Rows() != dest.Rows() || img.Cols() != dest.Cols() { t.Error("Invalid DilateWithParams test") } } func TestDistanceTransform(t *testing.T) { img := IMRead("images/face-detect.jpg", IMReadColor) if img.Empty() { t.Error("Invalid read of Mat in DistanceTransform test") } defer img.Close() gray := NewMat() defer gray.Close() CvtColor(img, &gray, ColorBGRToGray) threshImg := NewMat() defer threshImg.Close() Threshold(gray, &threshImg, 25, 255, ThresholdBinary) dest := NewMat() defer dest.Close() labels := NewMat() defer labels.Close() DistanceTransform(threshImg, &dest, &labels, DistL2, DistanceMask3, DistanceLabelCComp) if dest.Empty() || dest.Rows() != img.Rows() || img.Cols() != dest.Cols() { t.Error("Invalid DistanceTransform test") } } func TestMatchTemplate(t *testing.T) { imgScene := IMRead("images/face.jpg", IMReadGrayScale) if imgScene.Empty() { t.Error("Invalid read of face.jpg in MatchTemplate test") } defer imgScene.Close() imgTemplate := IMRead("images/toy.jpg", IMReadGrayScale) if imgTemplate.Empty() { t.Error("Invalid read of toy.jpg in MatchTemplate test") } defer imgTemplate.Close() result := NewMat() defer result.Close() m := NewMat() MatchTemplate(imgScene, imgTemplate, &result, TmCcoeffNormed, m) m.Close() _, maxConfidence, _, _ := MinMaxLoc(result) if maxConfidence < 0.95 { t.Errorf("Max confidence of %f is too low. MatchTemplate could not find template in scene.", maxConfidence) } } func TestMoments(t *testing.T) { img := IMRead("images/face-detect.jpg", IMReadGrayScale) if img.Empty() { t.Error("Invalid read of Mat in Moments test") } defer img.Close() result := Moments(img, true) if len(result) < 1 { t.Errorf("Invalid Moments test: %v", result) } } func TestPyrDown(t *testing.T) { img := IMRead("images/face-detect.jpg", IMReadColor) if img.Empty() { t.Error("Invalid read of Mat in PyrDown test") } defer img.Close() dest := NewMat() defer dest.Close() PyrDown(img, &dest, image.Point{X: dest.Cols(), Y: dest.Rows()}, BorderDefault) if dest.Empty() && math.Abs(float64(img.Cols()-2*dest.Cols())) < 2.0 && math.Abs(float64(img.Rows()-2*dest.Rows())) < 2.0 { t.Error("Invalid PyrDown test") } } func TestPyrUp(t *testing.T) { img := IMRead("images/face-detect.jpg", IMReadColor) if img.Empty() { t.Error("Invalid read of Mat in PyrUp test") } defer img.Close() dest := NewMat() defer dest.Close() PyrUp(img, &dest, image.Point{X: dest.Cols(), Y: dest.Rows()}, BorderDefault) if dest.Empty() && math.Abs(float64(2*img.Cols()-dest.Cols())) < 2.0 && math.Abs(float64(2*img.Rows()-dest.Rows())) < 2.0 { t.Error("Invalid PyrUp test") } } func TestBoxPoints(t *testing.T) { img := IMRead("images/face-detect.jpg", IMReadGrayScale) if img.Empty() { t.Error("Invalid read of Mat in BoxPoints test") } defer img.Close() threshImg := NewMat() defer threshImg.Close() Threshold(img, &threshImg, 25, 255, ThresholdBinary) contours := FindContours(threshImg, RetrievalExternal, ChainApproxSimple) defer contours.Close() contour := contours.At(0) hull := NewMat() defer hull.Close() ConvexHull(contour, &hull, false, false) hullPoints := []image.Point{} for i := 0; i < hull.Cols(); i++ { for j := 0; j < hull.Rows(); j++ { p := hull.GetIntAt(j, i) hullPoints = append(hullPoints, contour.At(int(p))) } } pvhp := NewPointVectorFromPoints(hullPoints) defer pvhp.Close() rect := MinAreaRect(pvhp) pts := NewMat() defer pts.Close() BoxPoints(rect, &pts) if pts.Empty() || pts.Rows() != 4 || pts.Cols() != 2 { t.Error("Invalid BoxPoints test") } } func TestMinAreaRect(t *testing.T) { src := []image.Point{ image.Pt(10, 15), image.Pt(10, 25), } pv := NewPointVectorFromPoints(src) defer pv.Close() m := MinAreaRect(pv) if m.Center.X != 10 { t.Errorf("TestMinAreaRect(): unexpected center.X = %v, want = %v", m.Center.X, 10) } if m.Center.Y != 20 { t.Errorf("TestMinAreaRect(): unexpected center.Y = %v, want = %v", m.Center.Y, 20) } if m.Angle != -90.0 { t.Errorf("TestMinAreaRect(): unexpected angle = %v, want = %v", m.Angle, -90.0) } } func TestBoxPoints2f(t *testing.T) { img := IMRead("images/face-detect.jpg", IMReadGrayScale) if img.Empty() { t.Error("Invalid read of Mat in BoxPoints2f test") } defer img.Close() threshImg := NewMat() defer threshImg.Close() Threshold(img, &threshImg, 25, 255, ThresholdBinary) contours := FindContours(threshImg, RetrievalExternal, ChainApproxSimple) defer contours.Close() contour := contours.At(0) hull := NewMat() defer hull.Close() ConvexHull(contour, &hull, false, false) hullPoints := []image.Point{} for i := 0; i < hull.Cols(); i++ { for j := 0; j < hull.Rows(); j++ { p := hull.GetIntAt(j, i) hullPoints = append(hullPoints, contour.At(int(p))) } } pvhp := NewPointVectorFromPoints(hullPoints) defer pvhp.Close() rect := MinAreaRect2f(pvhp) pts := NewMat() defer pts.Close() BoxPoints2f(rect, &pts) if pts.Empty() || pts.Rows() != 4 || pts.Cols() != 2 { t.Error("Invalid BoxPoints2f test") } } func TestMinAreaRect2f(t *testing.T) { if runtime.GOOS == "darwin" { log.Println("Skipping TestMinAreaRect2f on macOS due to version differences between OpenCV 4.12.0 and 4.13.0") return } src := []image.Point{ image.Pt(9, 19), image.Pt(4, 7), } pv := NewPointVectorFromPoints(src) defer pv.Close() m := MinAreaRect2f(pv) if m.Center.X != 6.5 { t.Errorf("TestMinAreaRect2f(): unexpected center.X = %v, want = %v", m.Center.X, 6.5) } if m.Center.Y != 13 { t.Errorf("TestMinAreaRect2f(): unexpected center.Y = %v, want = %v", m.Center.Y, 13) } if m.Angle != -22.61986541748047 { t.Errorf("TestMinAreaRect2f(): unexpected angle = %v, want = %v", m.Angle, -22.61986541748047) } } func TestFitEllipse(t *testing.T) { src := []image.Point{ image.Pt(1, 1), image.Pt(0, 1), image.Pt(0, 2), image.Pt(1, 3), image.Pt(2, 3), image.Pt(4, 2), image.Pt(4, 1), image.Pt(0, 3), image.Pt(0, 2), } pv := NewPointVectorFromPoints(src) defer pv.Close() rect := FitEllipse(pv) if rect.Center.X != 2 { t.Errorf("TestFitEllipse(): unexpected center.X = %v, want = %v", rect.Center.X, 2) } if rect.Center.Y != 2 { t.Errorf("TestFitEllipse(): unexpected center.Y = %v, want = %v", rect.Center.Y, 2) } if rect.Angle != 78.60807800292969 { t.Errorf("TestFitEllipse(): unexpected angle = %v, want = %v", rect.Angle, 78.60807800292969) } } func TestFindContours(t *testing.T) { img := IMRead("images/face-detect.jpg", IMReadGrayScale) if img.Empty() { t.Error("Invalid read of Mat in FindContours test") } defer img.Close() res := FindContours(img, RetrievalExternal, ChainApproxSimple) defer res.Close() if res.Size() < 1 { t.Error("Invalid FindContours test") } area := ContourArea(res.At(0)) if area != 127280.0 { t.Errorf("Invalid ContourArea test: %f", area) } r := BoundingRect(res.At(0)) if !r.Eq(image.Rect(0, 0, 400, 320)) { t.Errorf("Invalid BoundingRect test: %v", r) } length := ArcLength(res.At(0), true) if int(length) != 1436 { t.Errorf("Invalid ArcLength test: %f", length) } length = ArcLength(res.At(0), false) if int(length) != 1037 { t.Errorf("Invalid ArcLength test: %f", length) } } func TestFindContoursWithParams(t *testing.T) { img := IMRead("images/contours.png", IMReadGrayScale) if img.Empty() { t.Fatal("Invalid read of Mat in FindContours test") } defer img.Close() hierarchy := NewMat() defer hierarchy.Close() res := FindContoursWithParams(img, &hierarchy, RetrievalTree, ChainApproxNone) defer res.Close() if want := 4; want != res.Size() { t.Fatalf("Expected %d contours but got %d", want, res.Size()) } if res.Size() != hierarchy.Cols() { t.Fatalf("Expected %d hierarchy of contours, got %d", res.Size(), hierarchy.Cols()) } // Assert hierarchy values, the pattern is [Next, Previous, First_Child, Parent] // More info at https://docs.opencv.org/master/d9/d8b/tutorial_py_contours_hierarchy.html for i, want := range []Veci{ {1, -1, -1, -1}, {-1, 0, 2, -1}, {-1, -1, 3, 1}, {-1, -1, -1, 2}, } { got := hierarchy.GetVeciAt(0, i) if !reflect.DeepEqual(want, got) { t.Errorf("wrong hierarchy at position %d, want %v got %v", i, want, got) } } } func TestPointPolygonTest(t *testing.T) { tests := []struct { name string // name of the testcase thickness int // thickness of the polygon point image.Point // point to be checked result float64 // expected result; either distance or -1, 0, 1 based on measure parameter measure bool // enable distance measurement, if true }{ { name: "Inside the polygon - measure=false", thickness: 1, point: image.Point{20, 30}, result: 1.0, measure: false, }, { name: "Outside the polygon - measure=false", thickness: 1, point: image.Point{5, 15}, result: -1.0, measure: false, }, { name: "On the polygon - measure=false", thickness: 1, point: image.Point{10, 10}, result: 0.0, measure: false, }, { name: "Inside the polygon - measure=true", thickness: 1, point: image.Point{20, 30}, result: 10.0, measure: true, }, { name: "Outside the polygon - measure=true", thickness: 1, point: image.Point{5, 15}, result: -5.0, measure: true, }, { name: "On the polygon - measure=true", thickness: 1, point: image.Point{10, 10}, result: 0.0, measure: true, }, } pts := []image.Point{ image.Pt(10, 10), image.Pt(10, 80), image.Pt(80, 80), image.Pt(80, 10), } ctr := NewPointVectorFromPoints(pts) defer ctr.Close() for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { if r := PointPolygonTest(ctr, tc.point, tc.measure); r != tc.result { t.Errorf("Wrong result, got = %v, want >= %v", r, tc.result) } }) } } func TestConnectedComponents(t *testing.T) { img := IMRead("images/face-detect.jpg", IMReadGrayScale) if img.Empty() { t.Error("Invalid read of Mat in FindContours test") } defer img.Close() labels := NewMat() defer labels.Close() res := ConnectedComponents(img, &labels) if res < 1 || labels.Empty() { t.Error("Invalid ConnectedComponents test") } } func TestConnectedComponentsWithParams(t *testing.T) { img := IMRead("images/face-detect.jpg", IMReadGrayScale) if img.Empty() { t.Error("Invalid read of Mat in FindContours test") } defer img.Close() labels := NewMat() defer labels.Close() res := ConnectedComponentsWithParams(img, &labels, 8, MatTypeCV32S, CCL_DEFAULT) if res < 1 || labels.Empty() { t.Error("Invalid ConnectedComponentsWithParams test") } } func TestConnectedComponentsWithStats(t *testing.T) { img := IMRead("images/face-detect.jpg", IMReadGrayScale) if img.Empty() { t.Error("Invalid read of Mat in FindContours test") } defer img.Close() labels := NewMat() defer labels.Close() stats := NewMat() defer stats.Close() centroids := NewMat() defer centroids.Close() res := ConnectedComponentsWithStats(img, &labels, &stats, ¢roids) if res < 1 || labels.Empty() || stats.Empty() || centroids.Empty() { t.Error("Invalid ConnectedComponentsWithStats test") } } func TestConnectedComponentsWithStatsWithParams(t *testing.T) { img := IMRead("images/face-detect.jpg", IMReadGrayScale) if img.Empty() { t.Error("Invalid read of Mat in FindContours test") } defer img.Close() labels := NewMat() defer labels.Close() stats := NewMat() defer stats.Close() centroids := NewMat() defer centroids.Close() res := ConnectedComponentsWithStatsWithParams(img, &labels, &stats, ¢roids, 8, MatTypeCV32S, CCL_DEFAULT) if res < 1 || labels.Empty() || stats.Empty() || centroids.Empty() { t.Error("Invalid ConnectedComponentsWithStatsWithParams test") } } func TestErode(t *testing.T) { img := IMRead("images/face-detect.jpg", IMReadColor) if img.Empty() { t.Error("Invalid read of Mat in Erode test") } defer img.Close() dest := NewMat() defer dest.Close() kernel := GetStructuringElement(MorphRect, image.Pt(1, 1)) defer kernel.Close() Erode(img, &dest, kernel) if dest.Empty() || img.Rows() != dest.Rows() || img.Cols() != dest.Cols() { t.Error("Invalid Erode test") } } func TestErodeWithParams(t *testing.T) { img := IMRead("images/face-detect.jpg", IMReadColor) if img.Empty() { t.Error("Invalid read of Mat in ErodeWithParams test") } defer img.Close() dest := NewMat() defer dest.Close() kernel := GetStructuringElement(MorphRect, image.Pt(1, 1)) defer kernel.Close() ErodeWithParams(img, &dest, kernel, image.Pt(-1, -1), 3, 0) if dest.Empty() || img.Rows() != dest.Rows() || img.Cols() != dest.Cols() { t.Error("Invalid ErodeWithParams test") } } func TestErodeWithParamsAndBorderValue(t *testing.T) { img := IMRead("images/face-detect.jpg", IMReadColor) if img.Empty() { t.Error("Invalid read of Mat in ErodeWithParamsAndBorderValue test") } defer img.Close() dest := NewMat() defer dest.Close() kernel := GetStructuringElement(MorphRect, image.Pt(1, 1)) defer kernel.Close() ErodeWithParamsAndBorderValue(img, &dest, kernel, image.Pt(-1, -1), 3, 0, NewScalar(0, 0, 0, 0)) if dest.Empty() || img.Rows() != dest.Rows() || img.Cols() != dest.Cols() { t.Error("Invalid ErodeWithParamsAndBorderValue test") } } func TestMorphologyDefaultBorderValue(t *testing.T) { zeroScalar := Scalar{} morphologyDefaultBorderValue := MorphologyDefaultBorderValue() if reflect.DeepEqual(zeroScalar, morphologyDefaultBorderValue) { t.Error("Got zero valued scalar") } } func TestMorphologyEx(t *testing.T) { img := IMRead("images/face-detect.jpg", IMReadColor) if img.Empty() { t.Error("Invalid read of Mat in MorphologyEx test") } defer img.Close() dest := NewMat() defer dest.Close() kernel := GetStructuringElement(MorphRect, image.Pt(1, 1)) defer kernel.Close() MorphologyEx(img, &dest, MorphOpen, kernel) if dest.Empty() || img.Rows() != dest.Rows() || img.Cols() != dest.Cols() { t.Error("Invalid MorphologyEx test") } } func TestMorphologyExWithParams(t *testing.T) { img := IMRead("images/face-detect.jpg", IMReadColor) if img.Empty() { t.Error("Invalid read of Mat in MorphologyEx test") } defer img.Close() dest := NewMat() defer dest.Close() kernel := GetStructuringElement(MorphRect, image.Pt(1, 1)) defer kernel.Close() MorphologyExWithParams(img, &dest, MorphOpen, kernel, 2, BorderConstant) if dest.Empty() || img.Rows() != dest.Rows() || img.Cols() != dest.Cols() { t.Error("Invalid MorphologyExWithParams test") } } func TestGaussianBlur(t *testing.T) { img := IMRead("images/face-detect.jpg", IMReadColor) if img.Empty() { t.Error("Invalid read of Mat in GaussianBlur test") } defer img.Close() dest := NewMat() defer dest.Close() GaussianBlur(img, &dest, image.Pt(23, 23), 30, 50, 4) if dest.Empty() || img.Rows() != dest.Rows() || img.Cols() != dest.Cols() { t.Error("Invalid Blur test") } } func TestGetGaussianKernel(t *testing.T) { kernel := GetGaussianKernel(1, 0.5) defer kernel.Close() if kernel.Empty() { t.Error("Invalid GetGaussianKernel test") } } func TestGetGaussianKernelWithParams(t *testing.T) { kernel := GetGaussianKernelWithParams(1, 0.5, MatTypeCV64F) defer kernel.Close() if kernel.Empty() { t.Error("Invalid GetGaussianKernel test") } } func TestLaplacian(t *testing.T) { img := IMRead("images/face-detect.jpg", IMReadColor) if img.Empty() { t.Error("Invalid read of Mat in Laplacian test") } defer img.Close() dest := NewMat() defer dest.Close() Laplacian(img, &dest, MatTypeCV16S, 1, 1, 0, BorderDefault) if dest.Empty() || img.Rows() != dest.Rows() || img.Cols() != dest.Cols() { t.Error("Invalid Laplacian test") } } func TestScharr(t *testing.T) { img := IMRead("images/face-detect.jpg", IMReadColor) if img.Empty() { t.Error("Invalid read of Mat in Scharr test") } defer img.Close() dest := NewMat() defer dest.Close() Scharr(img, &dest, MatTypeCV16S, 1, 0, 0, 0, BorderDefault) if dest.Empty() || img.Rows() != dest.Rows() || img.Cols() != dest.Cols() { t.Error("Invalid Scharr test") } } func TestMedianBlur(t *testing.T) { img := IMRead("images/face-detect.jpg", IMReadColor) if img.Empty() { t.Error("Invalid read of Mat in MedianBlur test") } defer img.Close() dest := NewMat() defer dest.Close() MedianBlur(img, &dest, 3) if dest.Empty() || img.Rows() != dest.Rows() || img.Cols() != dest.Cols() { t.Error("Invalid MedianBlur test") } } func TestCanny(t *testing.T) { img := IMRead("images/face-detect.jpg", IMReadGrayScale) if img.Empty() { t.Error("Invalid read of Mat in Canny test") } defer img.Close() dest := NewMat() defer dest.Close() Canny(img, &dest, 50, 150) if dest.Empty() { t.Error("Empty Canny test") } if img.Rows() != dest.Rows() { t.Error("Invalid Canny test rows") } if img.Cols() != dest.Cols() { t.Error("Invalid Canny test cols") } } func TestGoodFeaturesToTrackAndCornerSubPix(t *testing.T) { img := IMRead("images/face-detect.jpg", IMReadGrayScale) if img.Empty() { t.Error("Invalid read of Mat in GoodFeaturesToTrack test") } defer img.Close() corners := NewMat() defer corners.Close() GoodFeaturesToTrack(img, &corners, 500, 0.01, 10) if corners.Empty() { t.Error("Empty GoodFeaturesToTrack test") } if corners.Rows() != 205 { t.Errorf("Invalid GoodFeaturesToTrack test rows: %v", corners.Rows()) } if corners.Cols() != 1 { t.Errorf("Invalid GoodFeaturesToTrack test cols: %v", corners.Cols()) } tc := NewTermCriteria(Count|EPS, 20, 0.03) CornerSubPix(img, &corners, image.Pt(10, 10), image.Pt(-1, -1), tc) if corners.Empty() { t.Error("Empty CornerSubPix test") } if corners.Rows() != 205 { t.Errorf("Invalid CornerSubPix test rows: %v", corners.Rows()) } if corners.Cols() != 1 { t.Errorf("Invalid CornerSubPix test cols: %v", corners.Cols()) } } func TestGrabCut(t *testing.T) { img := IMRead("images/face-detect.jpg", IMReadGrayScale) if img.Empty() { t.Error("Invalid read of Mat in GrabCut test") } defer img.Close() src := NewMat() defer src.Close() CvtColor(img, &img, ColorRGBAToBGR) img.ConvertTo(&src, MatTypeCV8UC3) mask := NewMatWithSize(img.Rows(), img.Cols(), MatTypeCV8U) defer mask.Close() bgdModel := NewMat() defer bgdModel.Close() fgdModel := NewMat() defer fgdModel.Close() r := image.Rect(0, 0, 50, 50) GrabCut(src, &mask, r, &bgdModel, &fgdModel, 1, GCEval) if bgdModel.Empty() { t.Error("Empty bgdmodel") } else if fgdModel.Empty() { t.Error("Empty fgdmodel") } } func TestHoughCircles(t *testing.T) { img := IMRead("images/face-detect.jpg", IMReadGrayScale) if img.Empty() { t.Error("Invalid read of Mat in HoughCircles test") } defer img.Close() circles := NewMat() defer circles.Close() HoughCircles(img, &circles, 3, 5.0, 5.0) if circles.Empty() { t.Error("Empty HoughCircles test") } if circles.Rows() != 1 { t.Errorf("Invalid HoughCircles test rows: %v", circles.Rows()) } if circles.Cols() < 317 || circles.Cols() > 334 { t.Errorf("Invalid HoughCircles test cols: %v", circles.Cols()) } } func TestHoughCirclesWithParams(t *testing.T) { img := IMRead("images/face-detect.jpg", IMReadGrayScale) if img.Empty() { t.Error("Invalid read of Mat in HoughCircles test") } defer img.Close() circles := NewMat() defer circles.Close() HoughCirclesWithParams(img, &circles, 3, 5.0, 5.0, 100, 100, 0, 0) if circles.Empty() { t.Error("Empty HoughCirclesWithParams test") } if circles.Rows() != 1 { t.Errorf("Invalid HoughCirclesWithParams test rows: %v", circles.Rows()) } if circles.Cols() < 317 || circles.Cols() > 334 { t.Errorf("Invalid HoughCirclesWithParams test cols: %v", circles.Cols()) } } func TestHoughLines(t *testing.T) { if runtime.GOOS == "darwin" { t.Skip("skipping test on macos") } img := IMRead("images/face-detect.jpg", IMReadGrayScale) if img.Empty() { t.Error("Invalid read of Mat in HoughLines test") } defer img.Close() dest := NewMat() defer dest.Close() HoughLines(img, &dest, 1, math.Pi/180, 50) if dest.Empty() { t.Error("Empty HoughLines test") } if dest.Rows() != 6465 { t.Errorf("Invalid HoughLines test rows: %v", dest.Rows()) } if dest.Cols() != 1 { t.Errorf("Invalid HoughLines test cols: %v", dest.Cols()) } if dest.GetFloatAt(0, 0) != 226 && dest.GetFloatAt(0, 1) != 0.7853982 { t.Errorf("Invalid HoughLines first test element: %v, %v", dest.GetFloatAt(0, 0), dest.GetFloatAt(0, 1)) } if dest.GetFloatAt(1, 0) != 228 && dest.GetFloatAt(1, 1) != 0.7853982 { t.Errorf("Invalid HoughLines second test element: %v, %v", dest.GetFloatAt(1, 0), dest.GetFloatAt(1, 1)) } if dest.GetFloatAt(6463, 0) != 23 && dest.GetFloatAt(6463, 1) != 0.75049156 { t.Errorf("Invalid HoughLines penultimate test element: %v, %v", dest.GetFloatAt(6463, 0), dest.GetFloatAt(6463, 1)) } if dest.GetFloatAt(6464, 0) != 23 && dest.GetFloatAt(6464, 1) != 0.82030475 { t.Errorf("Invalid HoughLines last test element: %v, %v", dest.GetFloatAt(6464, 0), dest.GetFloatAt(6464, 1)) } } func TestHoughLinesP(t *testing.T) { if runtime.GOOS == "darwin" { t.Skip("skipping test on macos") } img := IMRead("images/face-detect.jpg", IMReadGrayScale) if img.Empty() { t.Error("Invalid read of Mat in HoughLinesP test") } defer img.Close() dest := NewMat() defer dest.Close() HoughLinesP(img, &dest, 1, math.Pi/180, 50) if dest.Empty() { t.Error("Empty HoughLinesP test") } if dest.Rows() != 4356 { t.Errorf("Invalid HoughLinesP test rows: %v", dest.Rows()) } if dest.Cols() != 1 { t.Errorf("Invalid HoughLinesP test cols: %v", dest.Cols()) } if dest.GetIntAt(0, 0) != 46 && dest.GetIntAt(0, 1) != 0 && dest.GetIntAt(0, 2) != 365 && dest.GetIntAt(0, 3) != 319 { t.Errorf("Invalid HoughLinesP first test element: %v, %v, %v, %v", dest.GetIntAt(0, 0), dest.GetIntAt(0, 1), dest.GetIntAt(0, 2), dest.GetIntAt(0, 3)) } if dest.GetIntAt(1, 0) != 62 && dest.GetIntAt(1, 1) != 319 && dest.GetIntAt(1, 2) != 197 && dest.GetIntAt(1, 3) != 197 { t.Errorf("Invalid HoughLinesP second test element: %v, %v, %v, %v", dest.GetIntAt(1, 0), dest.GetIntAt(1, 1), dest.GetIntAt(1, 2), dest.GetIntAt(1, 3)) } if dest.GetIntAt(433, 0) != 357 && dest.GetIntAt(433, 1) != 316 && dest.GetIntAt(433, 2) != 357 && dest.GetIntAt(433, 3) != 316 { t.Errorf("Invalid HoughLinesP penultimate test element: %v, %v, %v, %v", dest.GetIntAt(433, 0), dest.GetIntAt(433, 1), dest.GetIntAt(433, 2), dest.GetIntAt(433, 3)) } if dest.GetIntAt(434, 0) != 39 && dest.GetIntAt(434, 1) != 280 && dest.GetIntAt(434, 2) != 89 && dest.GetIntAt(434, 3) != 227 { t.Errorf("Invalid HoughLinesP last test element: %v, %v, %v, %v", dest.GetIntAt(434, 0), dest.GetIntAt(434, 1), dest.GetIntAt(434, 2), dest.GetIntAt(434, 3)) } } func TestHoughLinesPWithParams(t *testing.T) { img := IMRead("images/face-detect.jpg", IMReadGrayScale) if img.Empty() { t.Error("Invalid read of Mat in HoughLinesPWithParams test") } defer img.Close() dest := NewMat() defer dest.Close() HoughLinesPWithParams(img, &dest, 1, math.Pi/180, 50, 1, 1) if dest.Empty() { t.Error("Empty HoughLinesPWithParams test") } if dest.Rows() != 514 { t.Errorf("Invalid HoughLinesPWithParams test rows: %v", dest.Rows()) } if dest.Cols() != 1 { t.Errorf("Invalid HoughLinesPWithParams test cols: %v", dest.Cols()) } if dest.GetIntAt(0, 0) != 46 && dest.GetIntAt(0, 1) != 0 && dest.GetIntAt(0, 2) != 365 && dest.GetIntAt(0, 3) != 319 { t.Errorf("Invalid HoughLinesPWithParams first test element: %v, %v, %v, %v", dest.GetIntAt(0, 0), dest.GetIntAt(0, 1), dest.GetIntAt(0, 2), dest.GetIntAt(0, 3)) } if dest.GetIntAt(1, 0) != 62 && dest.GetIntAt(1, 1) != 319 && dest.GetIntAt(1, 2) != 197 && dest.GetIntAt(1, 3) != 197 { t.Errorf("Invalid HoughLinesPWithParams second test element: %v, %v, %v, %v", dest.GetIntAt(1, 0), dest.GetIntAt(1, 1), dest.GetIntAt(1, 2), dest.GetIntAt(1, 3)) } if dest.GetIntAt(433, 0) != 0 && dest.GetIntAt(433, 1) != 126 && dest.GetIntAt(433, 2) != 71 && dest.GetIntAt(433, 3) != 57 { t.Errorf("Invalid HoughLinesPWithParams penultimate test element: %v, %v, %v, %v", dest.GetIntAt(433, 0), dest.GetIntAt(433, 1), dest.GetIntAt(433, 2), dest.GetIntAt(433, 3)) } if dest.GetIntAt(434, 0) != 309 && dest.GetIntAt(434, 1) != 280 && dest.GetIntAt(434, 2) != 89 && dest.GetIntAt(434, 3) != 227 { t.Errorf("Invalid HoughLinesPWithParams last test element: %v, %v, %v, %v", dest.GetIntAt(434, 0), dest.GetIntAt(434, 1), dest.GetIntAt(434, 2), dest.GetIntAt(434, 3)) } } func TestHoughLinesPointSet(t *testing.T) { points := [][2]int{ {0, 369}, {10, 364}, {20, 358}, {30, 352}, {40, 346}, {50, 341}, {60, 335}, {70, 329}, {80, 323}, {90, 318}, {100, 312}, {110, 306}, {120, 300}, {130, 295}, {140, 289}, {150, 284}, {160, 277}, {170, 271}, {180, 266}, {190, 260}, } img := NewMatWithSize(len(points), 1, MatTypeCV32F+MatChannels2) defer img.Close() for i, p := range points { img.SetFloatAt(i, 0, float32(p[0])) img.SetFloatAt(i, 1, float32(p[1])) } dest := NewMat() defer dest.Close() rhoMin, rhoMax, rhoStep := float32(0), float32(360), float32(1) thetaMin, thetaMax, thetaStep := float32(0), float32(math.Pi/2), float32(math.Pi/180) HoughLinesPointSet(img, &dest, 20, 1, rhoMin, rhoMax, rhoStep, thetaMin, thetaMax, thetaStep) if dest.Empty() { t.Error("Empty HoughLinesPointSet test") } if dest.Rows() != 20 { t.Errorf("Invalid HoughLinesPointSet test rows: %v", dest.Rows()) } if dest.Cols() != 1 { t.Errorf("Invalid HoughLinesPointSet test cols: %v", dest.Cols()) } if dest.GetDoubleAt(0, 0) != 19 && dest.GetDoubleAt(0, 1) != 320 && dest.GetDoubleAt(0, 2) != 1.0471975803375244 { t.Errorf("Invalid HoughLinesPointSet first test element: %v, %v, %v", dest.GetDoubleAt(0, 0), dest.GetDoubleAt(0, 1), dest.GetDoubleAt(0, 2)) } if dest.GetDoubleAt(1, 0) != 7 && dest.GetDoubleAt(1, 1) != 321 && dest.GetDoubleAt(1, 2) != 1.0646508932113647 { t.Errorf("Invalid HoughLinesPointSet second test element: %v, %v, %v", dest.GetDoubleAt(1, 0), dest.GetDoubleAt(1, 1), dest.GetDoubleAt(1, 2)) } if dest.GetDoubleAt(18, 0) != 2 && dest.GetDoubleAt(18, 1) != 317 && dest.GetDoubleAt(18, 2) != 0 { t.Errorf("Invalid HoughLinesPointSet penultimate test element: %v, %v, %v", dest.GetDoubleAt(18, 0), dest.GetDoubleAt(18, 1), dest.GetDoubleAt(18, 2)) } if dest.GetDoubleAt(19, 0) != 2 && dest.GetDoubleAt(19, 1) != 330 && dest.GetDoubleAt(19, 2) != 0 { t.Errorf("Invalid HoughLinesPointSet last test element: %v, %v, %v", dest.GetDoubleAt(19, 0), dest.GetDoubleAt(19, 1), dest.GetDoubleAt(19, 1)) } } func TestIntegral(t *testing.T) { img := IMRead("images/face-detect.jpg", IMReadColor) if img.Empty() { t.Error("Invalid read of Mat in Integral test") } defer img.Close() sum := NewMat() defer sum.Close() sqSum := NewMat() defer sqSum.Close() tilted := NewMat() defer tilted.Close() Integral(img, &sum, &sqSum, &tilted) if sum.Empty() || sqSum.Empty() || tilted.Empty() { t.Error("Invalid Integral test") } } func TestThreshold(t *testing.T) { img := IMRead("images/face-detect.jpg", IMReadColor) if img.Empty() { t.Error("Invalid read of Mat in Threshold test") } defer img.Close() dest := NewMat() defer dest.Close() Threshold(img, &dest, 25, 255, ThresholdBinary) if dest.Empty() || img.Rows() != dest.Rows() || img.Cols() != dest.Cols() { t.Error("Invalid Threshold test") } } func TestAdaptiveThreshold(t *testing.T) { img := IMRead("images/face-detect.jpg", IMReadGrayScale) if img.Empty() { t.Error("Invalid read of Mat in AdaptiveThreshold test") } defer img.Close() dest := NewMat() defer dest.Close() AdaptiveThreshold(img, &dest, 255, AdaptiveThresholdMean, ThresholdBinary, 11, 2) if dest.Empty() || img.Rows() != dest.Rows() || img.Cols() != dest.Cols() { t.Error("Invalid Threshold test") } } func TestCircle(t *testing.T) { tests := []struct { name string // name of the testcase thickness int // thickness of the circle point image.Point // point to be checked result uint8 // expected value at the point to be checked }{ { name: "Without filling", thickness: 3, point: image.Point{80, 89}, result: 255, }, { name: "With filling", thickness: -1, point: image.Point{60, 60}, result: 255, }, } for _, tc := range tests { t.Run("tc.name", func(t *testing.T) { img := NewMatWithSize(100, 100, MatTypeCV8UC1) defer img.Close() white := color.RGBA{255, 255, 255, 0} Circle(&img, image.Pt(70, 70), 20, white, tc.thickness) if v := img.GetUCharAt(tc.point.X, tc.point.Y); v != tc.result { t.Errorf("Wrong pixel value, got = %v, want = %v", v, tc.result) } }) } } func TestCircleWithParams(t *testing.T) { tests := []struct { name string // name of the testcase thickness int // thickness of the circle shift int // how much to shift and reduce(in size) checks map[image.Point]uint8 // map of points to be checked and corresponding expected value }{ { name: "Without filling and shift", thickness: 3, shift: 0, checks: map[image.Point]uint8{ {80, 89}: 255, }, }, { name: "With filling, without shift", thickness: -1, shift: 0, checks: map[image.Point]uint8{ {60, 60}: 255, }, }, { name: "Without filling, with shift", thickness: 3, shift: 1, checks: map[image.Point]uint8{ {47, 38}: 255, {48, 38}: 0, }, }, } for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { img := NewMatWithSize(100, 100, MatTypeCV8UC1) defer img.Close() white := color.RGBA{255, 255, 255, 0} CircleWithParams(&img, image.Pt(70, 70), 20, white, tc.thickness, Line4, tc.shift) for c, result := range tc.checks { if v := img.GetUCharAt(c.X, c.Y); v != result { t.Errorf("Wrong pixel value, got = %v, want = %v", v, result) } } }) } } func TestRectangle(t *testing.T) { tests := []struct { name string // name of the testcase thickness int // thickness of the rectangle point image.Point // point to be checked }{ { name: "Without filling", thickness: 1, point: image.Point{10, 60}, }, { name: "With filling", thickness: -1, point: image.Point{30, 30}, }, } for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { img := NewMatWithSize(100, 100, MatTypeCV8UC1) defer img.Close() white := color.RGBA{255, 255, 255, 0} Rectangle(&img, image.Rect(10, 10, 80, 80), white, tc.thickness) if v := img.GetUCharAt(tc.point.X, tc.point.Y); v < 50 { t.Errorf("Wrong pixel value, got = %v, want >= %v", v, 50) } }) } } func TestRectangleWithParams(t *testing.T) { tests := []struct { name string // name of the testcase thickness int // thickness of the rectangle shift int // how much to shift and reduce (in size) point image.Point // point to be checked }{ { name: "Without filling and shift", thickness: 1, point: image.Point{10, 60}, }, { name: "With filling, without shift", thickness: -1, point: image.Point{30, 30}, }, { name: "Without filling, with shift", thickness: 1, shift: 1, point: image.Point{5, 5}, }, } for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { img := NewMatWithSize(100, 100, MatTypeCV8UC1) defer img.Close() white := color.RGBA{255, 255, 255, 0} RectangleWithParams(&img, image.Rect(10, 10, 80, 80), white, tc.thickness, Line4, tc.shift) if v := img.GetUCharAt(tc.point.X, tc.point.Y); v != 255 { t.Errorf("Wrong pixel value, got = %v, want = %v", v, 255) } }) } } func TestEqualizeHist(t *testing.T) { img := IMRead("images/face-detect.jpg", IMReadGrayScale) if img.Empty() { t.Error("Invalid read of Mat in EqualizeHist test") } defer img.Close() dest := NewMat() defer dest.Close() EqualizeHist(img, &dest) if dest.Empty() || img.Rows() != dest.Rows() || img.Cols() != dest.Cols() { t.Error("Invalid EqualizeHist test") } } func TestCalcHist(t *testing.T) { img := IMRead("images/face-detect.jpg", IMReadGrayScale) if img.Empty() { t.Error("Invalid read of Mat in CalcHist test") } defer img.Close() hist := NewMat() defer hist.Close() mask := NewMat() defer mask.Close() CalcHist([]Mat{img}, []int{0}, mask, &hist, []int{256}, []float64{0.0, 256.0}, false) if hist.Empty() || hist.Rows() != 256 || hist.Cols() != 1 { t.Error("Invalid CalcHist test") } } func TestCalcBackProject(t *testing.T) { img := IMRead("images/face-detect.jpg", IMReadGrayScale) if img.Empty() { t.Error("Invalid read of Mat in CalcHist test") } defer img.Close() hist := NewMat() defer hist.Close() backProject := NewMat() defer backProject.Close() mask := NewMat() defer mask.Close() CalcHist([]Mat{img}, []int{0}, mask, &hist, []int{256}, []float64{0.0, 256.0}, false) CalcBackProject([]Mat{img}, []int{0}, hist, &backProject, []float64{0.0, 256.0}, false) if backProject.Empty() { t.Error("Invalid CalcBackProject test") } } func TestCompareHist(t *testing.T) { img := IMRead("images/face-detect.jpg", IMReadGrayScale) if img.Empty() { t.Error("Invalid read of Mat in CompareHist test") } defer img.Close() hist1 := NewMat() defer hist1.Close() hist2 := NewMat() defer hist2.Close() mask := NewMat() defer mask.Close() CalcHist([]Mat{img}, []int{0}, mask, &hist1, []int{256}, []float64{0.0, 256.0}, false) CalcHist([]Mat{img}, []int{0}, mask, &hist2, []int{256}, []float64{0.0, 256.0}, false) dist := CompareHist(hist1, hist2, HistCmpCorrel) if dist != 1 { t.Error("Invalid CompareHist test") } } func TestEMD(t *testing.T) { img := IMRead("images/face-detect.jpg", IMReadUnchanged) if img.Empty() { t.Error("Invalid read of Mat in CompareHist test") } defer img.Close() hist1 := NewMat() defer hist1.Close() hist2 := NewMat() defer hist2.Close() mask := NewMat() defer mask.Close() CalcHist([]Mat{img}, []int{0, 1}, mask, &hist1, []int{30, 32}, []float64{0.0, 180.0, 0.0, 255.0}, false) CalcHist([]Mat{img}, []int{0, 1}, mask, &hist2, []int{30, 32}, []float64{0.0, 180.0, 0.0, 255.0}, false) sig1 := NewMatWithSize(30*32, 3, MatTypeCV32FC1) defer sig1.Close() sig2 := NewMatWithSize(30*32, 3, MatTypeCV32FC1) defer sig2.Close() for h := 0; h < 30; h++ { for s := 0; s < 32; s++ { val := hist1.GetFloatAt(h, s) sig1.SetFloatAt(h*32+s, 0, val) sig1.SetFloatAt(h*32+s, 1, float32(h)) sig1.SetFloatAt(h*32+s, 2, float32(s)) val = hist2.GetFloatAt(h, s) sig2.SetFloatAt(h*32+s, 0, val) sig2.SetFloatAt(h*32+s, 1, float32(h)) sig2.SetFloatAt(h*32+s, 2, float32(s)) } } sim := EMD(sig1, sig2, DistL2) if (1-sim)*100 < 99.9 { t.Error("Invalid EMD test", (1-sim)*100) } } func TestDrawing(t *testing.T) { img := NewMatWithSize(150, 150, MatTypeCV8U) if img.Empty() { t.Error("Invalid Mat in Rectangle") } defer img.Close() ArrowedLine(&img, image.Pt(50, 50), image.Pt(75, 75), color.RGBA{0, 0, 255, 0}, 3) Circle(&img, image.Pt(60, 60), 20, color.RGBA{0, 0, 255, 0}, 3) Rectangle(&img, image.Rect(50, 50, 75, 75), color.RGBA{0, 0, 255, 0}, 3) Line(&img, image.Pt(50, 50), image.Pt(75, 75), color.RGBA{0, 0, 255, 0}, 3) if img.Empty() { t.Error("Error in Rectangle test") } } func TestGetTextSize(t *testing.T) { size := GetTextSize("test", FontHersheySimplex, 1.2, 1) if size.X != 72 { t.Error("Invalid text size width") } if size.Y != 26 { t.Error("Invalid text size height") } size1, base := GetTextSizeWithBaseline("test", FontHersheySimplex, 1.2, 1) if size1.X != 72 { t.Error("Invalid text size width") } if size1.Y != 26 { t.Error("Invalid text size height") } expected := 11 if base != expected { t.Errorf("invalid base. expected %d, actual %d", expected, base) } } func TestPutText(t *testing.T) { img := NewMatWithSize(150, 150, MatTypeCV8U) if img.Empty() { t.Error("Invalid Mat in IMRead") } defer img.Close() pt := image.Pt(10, 10) PutText(&img, "Testing", pt, FontHersheyPlain, 1.2, color.RGBA{255, 255, 255, 0}, 2) if img.Empty() { t.Error("Error in PutText test") } } func TestPutTextWithParams(t *testing.T) { img := NewMatWithSize(150, 150, MatTypeCV8U) if img.Empty() { t.Error("Invalid Mat in IMRead") } defer img.Close() pt := image.Pt(10, 10) PutTextWithParams(&img, "Testing", pt, FontHersheyPlain, 1.2, color.RGBA{255, 255, 255, 0}, 2, LineAA, false) if img.Empty() { t.Error("Error in PutText test") } } func TestResize(t *testing.T) { src := IMRead("images/gocvlogo.jpg", IMReadColor) if src.Empty() { t.Error("Invalid read of Mat in Resize test") } defer src.Close() dst := NewMat() defer dst.Close() Resize(src, &dst, image.Point{}, 0.5, 0.5, InterpolationDefault) if dst.Cols() != 200 || dst.Rows() != 172 { t.Errorf("Expected dst size of 200x172 got %dx%d", dst.Cols(), dst.Rows()) } Resize(src, &dst, image.Pt(440, 377), 0, 0, InterpolationCubic) if dst.Cols() != 440 || dst.Rows() != 377 { t.Errorf("Expected dst size of 440x377 got %dx%d", dst.Cols(), dst.Rows()) } } func TestGetRectSubPix(t *testing.T) { src := IMRead("images/gocvlogo.jpg", IMReadColor) if src.Empty() { t.Error("Invalid read of Mat in Resize test") } defer src.Close() dst := NewMat() defer dst.Close() GetRectSubPix(src, image.Point{20, 30}, image.Point{200, 172}, &dst) if dst.Cols() != 20 || dst.Rows() != 30 { t.Errorf("Expected dst size of 20x30 got %dx%d", dst.Cols(), dst.Rows()) } } func TestGetRotationMatrix2D(t *testing.T) { type args struct { center image.Point angle float64 scale float64 } tests := []struct { name string args args want [][]float64 }{ { name: "90", args: args{image.Point{0, 0}, 90.0, 1.0}, want: [][]float64{ {6.123233995736766e-17, 1, 0}, {-1, 6.123233995736766e-17, 0}, }, }, { name: "45", args: args{image.Point{0, 0}, 45.0, 1.0}, want: [][]float64{ {0.7071067811865476, 0.7071067811865475, 0}, {-0.7071067811865475, 0.7071067811865476, 0}, }, }, { name: "0", args: args{image.Point{0, 0}, 0.0, 1.0}, want: [][]float64{ {1, 0, 0}, {-0, 1, 0}, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got := GetRotationMatrix2D(tt.args.center, tt.args.angle, tt.args.scale) for row := 0; row < got.Rows(); row++ { for col := 0; col < got.Cols(); col++ { if !floatEquals(got.GetDoubleAt(row, col), tt.want[row][col]) { t.Errorf("GetRotationMatrix2D() = %v, want %v at row:%v col:%v", got.GetDoubleAt(row, col), tt.want[row][col], row, col) } } } got.Close() }) } } func TestWarpAffine(t *testing.T) { src := NewMatWithSize(256, 256, MatTypeCV8UC1) defer src.Close() rot := GetRotationMatrix2D(image.Point{0, 0}, 1.0, 1.0) defer rot.Close() dst := src.Clone() defer dst.Close() WarpAffine(src, &dst, rot, image.Point{256, 256}) result := Norm(dst, NormL2) if result != 0.0 { t.Errorf("WarpAffine() = %v, want %v", result, 0.0) } } func TestWarpAffineGocvLogo(t *testing.T) { src := IMRead("images/gocvlogo.jpg", IMReadUnchanged) defer src.Close() rot := GetRotationMatrix2D(image.Point{0, 0}, 1.0, 1.0) defer rot.Close() dst := src.Clone() defer dst.Close() WarpAffine(src, &dst, rot, image.Point{343, 400}) result := Norm(dst, NormL2) if !floatEquals(round(result, 0.05), round(111111.05, 0.05)) { t.Errorf("WarpAffine() = %v, want %v", round(result, 0.05), round(111111.05, 0.05)) } } func TestWarpAffineWithParams(t *testing.T) { src := NewMatWithSize(256, 256, MatTypeCV8UC1) defer src.Close() rot := GetRotationMatrix2D(image.Point{0, 0}, 1.0, 1.0) defer rot.Close() dst := src.Clone() defer dst.Close() WarpAffineWithParams(src, &dst, rot, image.Point{256, 256}, InterpolationLinear, BorderConstant, color.RGBA{0, 0, 0, 0}) result := Norm(dst, NormL2) if !floatEquals(result, 0.0) { t.Errorf("WarpAffineWithParams() = %v, want %v", result, 0.0) } } func TestWarpAffineWithParamsGocvLogo(t *testing.T) { src := IMRead("images/gocvlogo.jpg", IMReadUnchanged) defer src.Close() rot := GetRotationMatrix2D(image.Point{0, 0}, 1.0, 1.0) defer rot.Close() dst := src.Clone() defer dst.Close() WarpAffineWithParams(src, &dst, rot, image.Point{343, 400}, InterpolationLinear, BorderConstant, color.RGBA{0, 0, 0, 0}) result := Norm(dst, NormL2) if !floatEquals(round(result, 0.05), round(111111.05, 0.05)) { t.Errorf("WarpAffine() = %v, want %v", round(result, 0.05), round(111111.05, 0.05)) } } func TestClipLine(t *testing.T) { if ok := ClipLine(image.Point{20, 20}, image.Point{5, 5}, image.Point{5, 5}); !ok { t.Error("ClipLine(): is false") } } func TestWatershed(t *testing.T) { src := IMRead("images/gocvlogo.jpg", IMReadUnchanged) if src.Empty() { t.Error("Invalid read of Mat in Watershed test") } defer src.Close() gray := NewMat() defer gray.Close() CvtColor(src, &gray, ColorBGRToGray) imgThresh := NewMat() defer imgThresh.Close() Threshold(gray, &imgThresh, 5, 50, ThresholdOtsu+ThresholdBinary) markers := NewMat() defer markers.Close() _ = ConnectedComponents(imgThresh, &markers) Watershed(src, &markers) if markers.Empty() || src.Cols() != markers.Cols() || src.Rows() != markers.Rows() { t.Error("Invalid Watershed test") } } func TestApplyColorMap(t *testing.T) { type args struct { colormapType ColormapTypes want float64 } tests := []struct { name string args args }{ {name: "COLORMAP_AUTUMN", args: args{colormapType: ColormapAutumn, want: 118090.29593069873}}, {name: "COLORMAP_BONE", args: args{colormapType: ColormapBone, want: 122067.44213343704}}, {name: "COLORMAP_JET", args: args{colormapType: ColormapJet, want: 98220.64722857409}}, {name: "COLORMAP_WINTER", args: args{colormapType: ColormapWinter, want: 94279.52859449394}}, {name: "COLORMAP_RAINBOW", args: args{colormapType: ColormapRainbow, want: 92591.40608069411}}, {name: "COLORMAP_OCEAN", args: args{colormapType: ColormapOcean, want: 106444.16919681415}}, {name: "COLORMAP_SUMMER", args: args{colormapType: ColormapSummer, want: 114434.44957703952}}, {name: "COLORMAP_SPRING", args: args{colormapType: ColormapSpring, want: 123557.60209715953}}, {name: "COLORMAP_COOL", args: args{colormapType: ColormapCool, want: 123557.60209715953}}, {name: "COLORMAP_HSV", args: args{colormapType: ColormapHsv, want: 107679.25179903508}}, {name: "COLORMAP_PINK", args: args{colormapType: ColormapPink, want: 136043.97287274434}}, {name: "COLORMAP_HOT", args: args{colormapType: ColormapHot, want: 124941.02475968412}}, {name: "COLORMAP_PARULA", args: args{colormapType: ColormapParula, want: 111483.33555738274}}, {name: "COLORMAP_MAGMA", args: args{colormapType: ColormapMagma, want: 113197.48853662788}}, {name: "COLORMAP_INFERNO", args: args{colormapType: ColormapInferno, want: 108186.83126425323}}, {name: "COLORMAP_PLASMA", args: args{colormapType: ColormapPlasma, want: 108665.39830599251}}, {name: "COLORMAP_VIRIDIS", args: args{colormapType: ColormapViridis, want: 95101.87774697196}}, {name: "COLORMAP_CIVIDIS", args: args{colormapType: ColormapCividis, want: 102175.91244515509}}, {name: "COLORMAP_TWILIGHT", args: args{colormapType: ColormapTwilight, want: 98676.48484821498}}, {name: "COLORMAP_TWILIGHT_SHIFTED", args: args{colormapType: ColormapTwilightShifted, want: 74717.33848311247}}, {name: "COLORMAP_TURBO", args: args{colormapType: ColormapTurbo, want: 96848.08501978756}}, {name: "COLORMAP_DEEPGREEN", args: args{colormapType: ColormapDeepGreen, want: 106444.16919681415}}, } src := IMRead("images/gocvlogo.jpg", IMReadGrayScale) defer src.Close() for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { dst := src.Clone() defer dst.Close() ApplyColorMap(src, &dst, tt.args.colormapType) result := Norm(dst, NormL2) if !floatEquals(result, tt.args.want) { t.Errorf("TestApplyColorMap() = %v, want %v", result, tt.args.want) } }) } } func TestApplyCustomColorMap(t *testing.T) { src := IMRead("images/gocvlogo.jpg", IMReadGrayScale) defer src.Close() customColorMap := NewMatWithSize(256, 1, MatTypeCV8UC1) defer customColorMap.Close() dst := src.Clone() defer dst.Close() ApplyCustomColorMap(src, &dst, customColorMap) result := Norm(dst, NormL2) if !floatEquals(result, 0.0) { t.Errorf("TestApplyCustomColorMap() = %v, want %v", result, 0.0) } } func TestGetPerspectiveTransform(t *testing.T) { src := []image.Point{ image.Pt(0, 0), image.Pt(10, 5), image.Pt(10, 10), image.Pt(5, 10), } pvsrc := NewPointVectorFromPoints(src) defer pvsrc.Close() dst := []image.Point{ image.Pt(0, 0), image.Pt(10, 0), image.Pt(10, 10), image.Pt(0, 10), } pvdst := NewPointVectorFromPoints(dst) defer pvdst.Close() m := GetPerspectiveTransform(pvsrc, pvdst) defer m.Close() if m.Cols() != 3 { t.Errorf("TestGetPerspectiveTransform(): unexpected cols = %v, want = %v", m.Cols(), 3) } if m.Rows() != 3 { t.Errorf("TestGetPerspectiveTransform(): unexpected rows = %v, want = %v", m.Rows(), 3) } } func TestGetPerspectiveTransform2f(t *testing.T) { src := []Point2f{ {0, 0}, {10.5, 5.5}, {10.5, 10.5}, {5.5, 10.5}, } dst := []Point2f{ {0, 0}, {590.20, 24.12}, {100.12, 150.21}, {0, 10}, } pvsrc := NewPoint2fVectorFromPoints(src) defer pvsrc.Close() pvdst := NewPoint2fVectorFromPoints(dst) defer pvdst.Close() m := GetPerspectiveTransform2f(pvsrc, pvdst) defer m.Close() if m.Cols() != 3 { t.Errorf("TestGetPerspectiveTransform2f(): unexpected cols = %v, want = %v", m.Cols(), 3) } if m.Rows() != 3 { t.Errorf("TestGetPerspectiveTransform2f(): unexpected rows = %v, want = %v", m.Rows(), 3) } } func TestGetAffineTransform(t *testing.T) { src := []image.Point{ image.Pt(0, 0), image.Pt(10, 5), image.Pt(10, 10), } pvsrc := NewPointVectorFromPoints(src) defer pvsrc.Close() dst := []image.Point{ image.Pt(0, 0), image.Pt(10, 0), image.Pt(10, 10), } pvdst := NewPointVectorFromPoints(dst) defer pvdst.Close() m := GetAffineTransform(pvsrc, pvdst) defer m.Close() if m.Cols() != 3 { t.Errorf("TestGetAffineTransform(): unexpected cols = %v, want = %v", m.Cols(), 3) } if m.Rows() != 2 { t.Errorf("TestGetAffineTransform(): unexpected rows = %v, want = %v", m.Rows(), 2) } } func TestGetAffineTransform2f(t *testing.T) { src := []Point2f{ {0, 0}, {10.5, 5.5}, {10.5, 10.5}, } dst := []Point2f{ {0, 0}, {590.20, 24.12}, {100.12, 150.21}, } pvsrc := NewPoint2fVectorFromPoints(src) defer pvsrc.Close() pvdst := NewPoint2fVectorFromPoints(dst) defer pvdst.Close() m := GetAffineTransform2f(pvsrc, pvdst) defer m.Close() if m.Cols() != 3 { t.Errorf("TestGetAffineTransform2f(): unexpected cols = %v, want = %v", m.Cols(), 3) } if m.Rows() != 2 { t.Errorf("TestGetAffineTransform2f(): unexpected rows = %v, want = %v", m.Rows(), 2) } } func TestWarpPerspective(t *testing.T) { img := IMRead("images/gocvlogo.jpg", IMReadUnchanged) defer img.Close() w := img.Cols() h := img.Rows() s := []image.Point{ image.Pt(0, 0), image.Pt(10, 5), image.Pt(10, 10), image.Pt(5, 10), } pvs := NewPointVectorFromPoints(s) defer pvs.Close() d := []image.Point{ image.Pt(0, 0), image.Pt(10, 0), image.Pt(10, 10), image.Pt(0, 10), } pvd := NewPointVectorFromPoints(d) defer pvd.Close() m := GetPerspectiveTransform(pvs, pvd) defer m.Close() dst := NewMat() defer dst.Close() WarpPerspective(img, &dst, m, image.Pt(w, h)) if dst.Cols() != w { t.Errorf("TestWarpPerspective(): unexpected cols = %v, want = %v", dst.Cols(), w) } if dst.Rows() != h { t.Errorf("TestWarpPerspective(): unexpected rows = %v, want = %v", dst.Rows(), h) } } func TestWarpPerspectiveWithParams(t *testing.T) { img := IMRead("images/gocvlogo.jpg", IMReadUnchanged) defer img.Close() w := img.Cols() h := img.Rows() s := []image.Point{ image.Pt(0, 0), image.Pt(10, 5), image.Pt(10, 10), image.Pt(5, 10), } pvs := NewPointVectorFromPoints(s) defer pvs.Close() d := []image.Point{ image.Pt(0, 0), image.Pt(10, 0), image.Pt(10, 10), image.Pt(0, 10), } pvd := NewPointVectorFromPoints(d) defer pvd.Close() m := GetPerspectiveTransform(pvs, pvd) defer m.Close() dst := NewMat() defer dst.Close() WarpPerspectiveWithParams(img, &dst, m, image.Pt(w, h), InterpolationLinear, BorderConstant, color.RGBA{}) if dst.Cols() != w { t.Errorf("TestWarpPerspectiveWithParams(): unexpected cols = %v, want = %v", dst.Cols(), w) } if dst.Rows() != h { t.Errorf("TestWarpPerspectiveWithParams(): unexpected rows = %v, want = %v", dst.Rows(), h) } } func TestDrawContours(t *testing.T) { img := NewMatWithSize(100, 200, MatTypeCV8UC1) defer img.Close() // Draw rectangle white := color.RGBA{255, 255, 255, 255} Rectangle(&img, image.Rect(125, 25, 175, 75), white, 1) contours := FindContours(img, RetrievalExternal, ChainApproxSimple) defer contours.Close() if v := img.GetUCharAt(23, 123); v != 0 { t.Errorf("TestDrawContours(): wrong pixel value = %v, want = %v", v, 0) } if v := img.GetUCharAt(25, 125); v != 206 { t.Errorf("TestDrawContours(): wrong pixel value = %v, want = %v", v, 206) } DrawContours(&img, contours, -1, white, 2) // contour should be drawn with thickness = 2 if v := img.GetUCharAt(24, 124); v != 255 { t.Errorf("TestDrawContours(): contour has not been drawn (value = %v, want = %v)", v, 255) } if v := img.GetUCharAt(25, 125); v != 255 { t.Errorf("TestDrawContours(): contour has not been drawn (value = %v, want = %v)", v, 255) } } func TestDrawContoursWithParams(t *testing.T) { img := NewMatWithSize(200, 200, MatTypeCV8UC1) defer img.Close() // Draw circle white := color.RGBA{255, 255, 255, 255} black := color.RGBA{0, 0, 0, 255} Circle(&img, image.Pt(100, 100), 80, white, -1) Circle(&img, image.Pt(100, 100), 55, black, -1) Circle(&img, image.Pt(100, 100), 30, white, -1) hierarchy := NewMat() defer hierarchy.Close() contours := FindContoursWithParams(img, &hierarchy, RetrievalTree, ChainApproxSimple) defer contours.Close() // Draw contours by different line-type and assert value cases := []struct { name string lineType LineType expectUChar uint8 }{ { name: "draw by Line4", // 4 connected line lineType: Line4, expectUChar: 255, }, { name: "draw by line8", // 8 connected line lineType: Line8, expectUChar: 0, }, { name: "draw by line-AA", // anti-aliased line lineType: LineAA, expectUChar: 68, }, } for _, c := range cases { t.Run(c.name, func(t *testing.T) { bg := NewMatWithSize(img.Rows(), img.Cols(), MatTypeCV8UC1) defer bg.Close() DrawContoursWithParams(&bg, contours, -1, white, 1, c.lineType, hierarchy, 0, image.Pt(0, 0)) if v := bg.GetUCharAt(22, 88); v != c.expectUChar { t.Errorf("TestDrawContoursWithParams(): contour value expect %v but got %v", c.expectUChar, v) } }) } } func TestEllipse(t *testing.T) { tests := []struct { name string // name of the testcase thickness int // thickness of the ellipse point image.Point // point to be checked }{ { name: "Without filling", thickness: 2, point: image.Point{24, 50}, }, { name: "With filling", thickness: -1, point: image.Point{55, 47}, }, } for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { img := NewMatWithSize(100, 100, MatTypeCV8UC1) defer img.Close() white := color.RGBA{255, 255, 255, 0} Ellipse(&img, image.Pt(50., 50.), image.Pt(25., 25.), 0., 0, 360, white, tc.thickness) if v := img.GetUCharAt(tc.point.X, tc.point.Y); v != 255 { t.Errorf("Wrong pixel value, got = %v, want = %v", v, 255) } }) } } func TestEllipseWithParams(t *testing.T) { check255 := func(v uint8) bool { return v != 255 } tests := []struct { name string // name of the testcase thickness int // thickness of the ellipse linetype LineType // type of line used for drawing shift int // how much to shift and reduce(in size) checks map[image.Point]func(uint8) bool // points to be checked and corresponding expected value checkFn func(uint8) bool // function to check if the result is as expected }{ { name: "Without filling and shift, line = Line8", thickness: 2, linetype: Line8, checks: map[image.Point]func(uint8) bool{ {24, 50}: check255, }, }, { name: "With filling, without shift, line = Line8", thickness: -1, linetype: Line8, checks: map[image.Point]func(uint8) bool{ {55, 47}: check255, }, }, { name: "Without filling, with shift 2, line = Line8", thickness: 2, linetype: Line8, shift: 2, checks: map[image.Point]func(uint8) bool{ {6, 12}: check255, {19, 13}: check255, }, }, { name: "Without filling and shift, line = LineAA", thickness: 2, linetype: LineAA, checks: map[image.Point]func(uint8) bool{ {77, 54}: func(v uint8) bool { return v < 10 || v > 220 }, }, }, } for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { img := NewMatWithSize(100, 100, MatTypeCV8UC1) defer img.Close() white := color.RGBA{255, 255, 255, 0} EllipseWithParams(&img, image.Pt(50., 50.), image.Pt(25., 25.), 0., 0, 360, white, tc.thickness, tc.linetype, tc.shift) for c, fn := range tc.checks { if v := img.GetUCharAt(c.X, c.Y); fn(v) { t.Errorf("Wrong pixel value, got = %v", v) } } }) } } func TestFillPoly(t *testing.T) { img := NewMatWithSize(100, 100, MatTypeCV8UC1) defer img.Close() white := color.RGBA{255, 255, 255, 0} pts := [][]image.Point{ { image.Pt(10, 10), image.Pt(10, 20), image.Pt(20, 20), image.Pt(20, 10), }, } pv := NewPointsVectorFromPoints(pts) defer pv.Close() FillPoly(&img, pv, white) if v := img.GetUCharAt(10, 10); v != 255 { t.Errorf("TestFillPoly(): wrong pixel value = %v, want = %v", v, 255) } } func TestFillPolyWithParams(t *testing.T) { tests := []struct { name string // name of testcase offset image.Point // offset to the FillPolyWithParams function point image.Point // point to be checked result uint8 // expected value at the point to be checked }{ { name: "No offset", point: image.Point{10, 10}, result: 255, }, { name: "Offset of 2", offset: image.Point{2, 2}, point: image.Point{12, 12}, result: 255, }, } white := color.RGBA{255, 255, 255, 0} pts := [][]image.Point{ { image.Pt(10, 10), image.Pt(10, 20), image.Pt(20, 20), image.Pt(20, 10), }, } pv := NewPointsVectorFromPoints(pts) defer pv.Close() for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { img := NewMatWithSize(100, 100, MatTypeCV8UC1) defer img.Close() FillPolyWithParams(&img, pv, white, Line4, 0, tc.offset) if v := img.GetUCharAt(tc.point.X, tc.point.Y); v != tc.result { t.Errorf("Wrong pixel value; got = %v, want = %v", v, tc.result) } }) } } func TestPolylines(t *testing.T) { img := NewMatWithSize(100, 100, MatTypeCV8UC1) defer img.Close() white := color.RGBA{255, 255, 255, 0} pts := [][]image.Point{ { image.Pt(10, 10), image.Pt(10, 20), image.Pt(20, 20), image.Pt(20, 10), }, } pv := NewPointsVectorFromPoints(pts) defer pv.Close() Polylines(&img, pv, true, white, 1) if v := img.GetUCharAt(10, 10); v != 255 { t.Errorf("TestPolylines(): wrong pixel value = %v, want = %v", v, 255) } } func TestRemap(t *testing.T) { src := IMRead("images/gocvlogo.jpg", IMReadUnchanged) defer src.Close() dst := NewMat() defer dst.Close() map1 := NewMatWithSize(256, 256, MatTypeCV16SC2) defer map1.Close() map1.SetFloatAt(50, 50, 25.4) map2 := NewMat() defer map2.Close() Remap(src, &dst, &map1, &map2, InterpolationDefault, BorderConstant, color.RGBA{0, 0, 0, 0}) if ok := dst.Empty(); ok { t.Errorf("Remap(): dst is empty") } } func TestFilter2D(t *testing.T) { src := IMRead("images/gocvlogo.jpg", IMReadUnchanged) defer src.Close() dst := src.Clone() defer dst.Close() kernel := GetStructuringElement(MorphRect, image.Pt(1, 1)) defer kernel.Close() Filter2D(src, &dst, -1, kernel, image.Pt(-1, -1), 0, BorderDefault) if ok := dst.Empty(); ok { t.Errorf("Filter2D(): dst is empty") } } func TestSepFilter2D(t *testing.T) { src := IMRead("images/gocvlogo.jpg", IMReadUnchanged) defer src.Close() dst := src.Clone() defer dst.Close() kernelX := GetStructuringElement(MorphRect, image.Pt(1, 1)) defer kernelX.Close() kernelY := GetStructuringElement(MorphRect, image.Pt(1, 1)) defer kernelY.Close() SepFilter2D(src, &dst, -1, kernelX, kernelY, image.Pt(-1, -1), 0, BorderDefault) if ok := dst.Empty(); ok { t.Errorf("Filter2D(): dst is empty") } } func TestLogPolar(t *testing.T) { src := IMRead("images/gocvlogo.jpg", IMReadUnchanged) defer src.Close() dst := src.Clone() defer dst.Close() LogPolar(src, &dst, image.Pt(22, 22), 1, InterpolationDefault) if ok := dst.Empty(); ok { t.Errorf("LogPolar(): dst is empty") } } func TestLinearPolar(t *testing.T) { src := IMRead("images/gocvlogo.jpg", IMReadUnchanged) defer src.Close() dst := src.Clone() defer dst.Close() LinearPolar(src, &dst, image.Pt(22, 22), 1, InterpolationDefault) if ok := dst.Empty(); ok { t.Errorf("LinearPolar(): dst is empty") } } func TestFitLine(t *testing.T) { points := []image.Point{image.Pt(125, 24), image.Pt(124, 75), image.Pt(175, 76), image.Pt(176, 25)} pv := NewPointVectorFromPoints(points) defer pv.Close() line := NewMat() defer line.Close() FitLine(pv, &line, DistL2, 0, 0.01, 0.01) if ok := line.Empty(); ok { t.Errorf("FitLine(): line is empty") } } func TestMatchShapes(t *testing.T) { points1 := []image.Point{image.Pt(0, 0), image.Pt(1, 0), image.Pt(2, 2), image.Pt(3, 3), image.Pt(3, 4)} points2 := []image.Point{image.Pt(0, 0), image.Pt(1, 0), image.Pt(2, 3), image.Pt(3, 3), image.Pt(3, 5)} lowerSimilarity := 2.0 upperSimilarity := 3.0 contour1 := NewPointVectorFromPoints(points1) defer contour1.Close() contour2 := NewPointVectorFromPoints(points2) defer contour2.Close() similarity := MatchShapes(contour1, contour2, ContoursMatchI2, 0) if similarity < lowerSimilarity { t.Errorf("MatchShapes(): incorrect calculation, should be more than %f, got %f", lowerSimilarity, similarity) } if similarity > upperSimilarity { t.Errorf("MatchShapes(): incorrect calculation, should be lower than %f, got %f", upperSimilarity, similarity) } } func TestInvertAffineTransform(t *testing.T) { src := NewMatWithSize(2, 3, MatTypeCV32F) defer src.Close() dst := NewMatWithSize(2, 3, MatTypeCV32F) defer dst.Close() InvertAffineTransform(src, &dst) if ok := dst.Empty(); ok { t.Errorf("InvertAffineTransform(): dst is empty") } } func TestCLAHE(t *testing.T) { img := IMRead("images/face-detect.jpg", IMReadGrayScale) if img.Empty() { t.Error("Invalid read of Mat in NewCLAHE test") } defer img.Close() src := NewMat() defer src.Close() img.ConvertTo(&src, MatTypeCV8UC1) dst := NewMat() defer dst.Close() c := NewCLAHE() defer c.Close() c.Apply(src, &dst) if dst.Empty() || img.Rows() != dst.Rows() || img.Cols() != dst.Cols() { t.Error("Invalid NewCLAHE test") } } func TestCLAHEWithParams(t *testing.T) { img := IMRead("images/face-detect.jpg", IMReadGrayScale) if img.Empty() { t.Error("Invalid read of Mat in CLAHEWithParams test") } defer img.Close() src := NewMat() defer src.Close() img.ConvertTo(&src, MatTypeCV8UC1) dst := NewMat() defer dst.Close() c := NewCLAHEWithParams(2.0, image.Pt(10, 10)) defer c.Close() c.Apply(src, &dst) if dst.Empty() || img.Rows() != dst.Rows() || img.Cols() != dst.Cols() { t.Error("Invalid NewCLAHEWithParams test") } } func TestPhaseCorrelate(t *testing.T) { template := IMRead("images/simple.jpg", IMReadGrayScale) matched := IMRead("images/simple-translated.jpg", IMReadGrayScale) notMatchedOrig := IMRead("images/space_shuttle.jpg", IMReadGrayScale) notMatched := NewMat() defer template.Close() defer matched.Close() defer notMatchedOrig.Close() defer notMatched.Close() Resize(notMatchedOrig, ¬Matched, image.Point{X: matched.Size()[0], Y: matched.Size()[1]}, 0, 0, InterpolationLinear) template32FC1 := NewMat() matched32FC1 := NewMat() notMatched32FC1 := NewMat() defer template32FC1.Close() defer matched32FC1.Close() defer notMatched32FC1.Close() template.ConvertTo(&template32FC1, MatTypeCV32FC1) matched.ConvertTo(&matched32FC1, MatTypeCV32FC1) notMatched.ConvertTo(¬Matched32FC1, MatTypeCV32FC1) window := NewMat() defer window.Close() shiftTranslated, responseTranslated := PhaseCorrelate(template32FC1, matched32FC1, window) _, responseDifferent := PhaseCorrelate(template32FC1, notMatched32FC1, window) if !(shiftTranslated.X < 15) || !(shiftTranslated.Y < 15) { t.Errorf("expected shift to be > 15 pixels, got %v", shiftTranslated) } if responseTranslated < 0.85 { t.Errorf("expected response for translated image to be > 0.85, got %f", responseTranslated) } if responseDifferent > 0.05 { t.Errorf("expected response for different image to be < 0.05, but got %f", responseDifferent) } } func TestCreateHanningWindow(t *testing.T) { dst := NewMat() defer dst.Close() CreateHanningWindow(&dst, image.Pt(100, 100), MatTypeCV32F) if dst.Empty() { t.Error("Invalid CreateHanningWindow test") } } func TestMatToImage(t *testing.T) { mat1 := NewMatWithSize(101, 102, MatTypeCV8UC3) defer mat1.Close() img, err := mat1.ToImage() if err != nil { t.Errorf("TestToImage %v.", err) } if img.Bounds().Dx() != 102 { t.Errorf("TestToImage incorrect width got %d.", img.Bounds().Dx()) } if img.Bounds().Dy() != 101 { t.Errorf("TestToImage incorrect height got %d.", img.Bounds().Dy()) } matreg := mat1.Region(image.Rect(25, 25, 75, 75)) defer matreg.Close() img, err = matreg.ToImage() if err != nil { t.Errorf("Expected error.") } mat2 := NewMatWithSize(101, 102, MatTypeCV8UC1) defer mat2.Close() img, err = mat2.ToImage() if err != nil { t.Errorf("TestToImage %v.", err) } mat3 := NewMatWithSize(101, 102, MatTypeCV8UC4) defer mat3.Close() img, err = mat3.ToImage() if err != nil { t.Errorf("TestToImage %v.", err) } matreg3 := mat3.Region(image.Rect(25, 25, 75, 75)) defer matreg3.Close() img, err = matreg3.ToImage() if err != nil { t.Errorf("Expected error.") } matWithUnsupportedType := NewMatWithSize(101, 102, MatTypeCV8S) defer matWithUnsupportedType.Close() _, err = matWithUnsupportedType.ToImage() if err == nil { t.Error("TestToImage expected error got nil.") } } func TestMatToImageYUV(t *testing.T) { mat1 := NewMatWithSize(101, 102, MatTypeCV8UC3) defer mat1.Close() img, err := mat1.ToImageYUV() if err != nil { t.Errorf("TestToImage %v.", err) } if img.Bounds().Dx() != 102 { t.Errorf("TestToImage incorrect width got %d.", img.Bounds().Dx()) } if img.Bounds().Dy() != 101 { t.Errorf("TestToImage incorrect height got %d.", img.Bounds().Dy()) } matreg := mat1.Region(image.Rect(25, 25, 75, 75)) defer matreg.Close() img, err = matreg.ToImageYUV() if err != nil { t.Errorf("Expected error.") } mat2 := NewMatWithSize(101, 102, MatTypeCV8UC1) defer mat2.Close() img, err = mat2.ToImageYUV() if err != nil { t.Errorf("TestToImageYUV %v.", err) } mat3 := NewMatWithSize(101, 102, MatTypeCV8UC4) defer mat3.Close() img, err = mat3.ToImageYUV() if err != nil { t.Errorf("TestToImageYUV %v.", err) } matreg3 := mat3.Region(image.Rect(25, 25, 75, 75)) defer matreg3.Close() img, err = matreg3.ToImageYUV() if err != nil { t.Errorf("Expected error.") } matWithUnsupportedType := NewMatWithSize(101, 102, MatTypeCV8S) defer matWithUnsupportedType.Close() _, err = matWithUnsupportedType.ToImageYUV() if err == nil { t.Error("TestToImageYUV expected error got nil.") } } func TestMatToImageYUVWithParams(t *testing.T) { mat1 := NewMatWithSize(101, 102, MatTypeCV8UC3) defer mat1.Close() img, err := mat1.ToImageYUVWithParams(image.YCbCrSubsampleRatio420) if err != nil { t.Errorf("TestToImage %v.", err) } if img.Bounds().Dx() != 102 { t.Errorf("TestToImage incorrect width got %d.", img.Bounds().Dx()) } if img.Bounds().Dy() != 101 { t.Errorf("TestToImage incorrect height got %d.", img.Bounds().Dy()) } matreg := mat1.Region(image.Rect(25, 25, 75, 75)) defer matreg.Close() img, err = matreg.ToImageYUVWithParams(image.YCbCrSubsampleRatio420) if err != nil { t.Errorf("Expected error.") } mat2 := NewMatWithSize(101, 102, MatTypeCV8UC1) defer mat2.Close() img, err = mat2.ToImageYUVWithParams(image.YCbCrSubsampleRatio420) if err != nil { t.Errorf("TestToImageYUVWithParams image.YCbCrSubsampleRatio420%v.", err) } mat3 := NewMatWithSize(101, 102, MatTypeCV8UC4) defer mat3.Close() img, err = mat3.ToImageYUVWithParams(image.YCbCrSubsampleRatio420) if err != nil { t.Errorf("TestToImageYUVWithParams image.YCbCrSubsampleRatio420%v.", err) } matreg3 := mat3.Region(image.Rect(25, 25, 75, 75)) defer matreg3.Close() img, err = matreg3.ToImageYUVWithParams(image.YCbCrSubsampleRatio420) if err != nil { t.Errorf("Expected error.") } matWithUnsupportedType := NewMatWithSize(101, 102, MatTypeCV8S) defer matWithUnsupportedType.Close() _, err = matWithUnsupportedType.ToImageYUVWithParams(image.YCbCrSubsampleRatio420) if err == nil { t.Error("TestToImageYUVWithParams image.YCbCrSubsampleRatio420expected error got nil.") } } // Tests that image is the same after converting to Mat and back to Image func TestImageToMatRGBA(t *testing.T) { file, err := os.Open("images/gocvlogo.png") if err != nil { log.Fatal(err) } defer file.Close() img0, _, err := image.Decode(file) if err != nil { log.Fatal(err) } mat, err := ImageToMatRGBA(img0) if err != nil { log.Fatal(err) } defer mat.Close() img1, err := mat.ToImage() if err != nil { log.Fatal(err) } if !compareImages(img0, img1) { t.Errorf("Image after converting to Mat and back to Image isn't the same") } img3 := image.NewRGBA(image.Rect(0, 0, 200, 200)) mat3, err := ImageToMatRGBA(img3) if err != nil { t.Error(err) } defer mat3.Close() } // Tests that image is the same after converting to Mat and back to Image func TestImageToMatRGB(t *testing.T) { file, err := os.Open("images/gocvlogo.jpg") if err != nil { log.Fatal(err) } defer file.Close() img0, _, err := image.Decode(file) if err != nil { log.Fatal(err) } mat, err := ImageToMatRGB(img0) if err != nil { log.Fatal(err) } defer mat.Close() img1, err := mat.ToImage() if err != nil { log.Fatal(err) } if !compareImages(img0, img1) { t.Errorf("Image after converting to Mat and back to Image isn't the same") } img3 := image.NewRGBA(image.Rect(0, 0, 200, 200)) mat3, err := ImageToMatRGB(img3) if err != nil { t.Error(err) } defer mat3.Close() } func TestImageGrayToMatGray(t *testing.T) { file, err := os.Open("images/gocvlogo.jpg") if err != nil { log.Fatal(err) } defer file.Close() imgSrc, _, err := image.Decode(file) if err != nil { log.Fatal(err) } img0 := image.NewGray(imgSrc.Bounds()) draw.Draw(img0, imgSrc.Bounds(), imgSrc, image.ZP, draw.Src) mat, err := ImageGrayToMatGray(img0) if err != nil { log.Fatal(err) } defer mat.Close() img1, err := mat.ToImage() if err != nil { log.Fatal(err) } if !compareImages(img0, img1) { t.Errorf("Image after converting to Mat and back to Image isn't the same") } } func TestAccumulate(t *testing.T) { src := IMRead("images/gocvlogo.jpg", IMReadUnchanged) defer src.Close() dst := NewMatWithSizes(src.Size(), MatTypeCV64FC3) defer dst.Close() Accumulate(src, &dst) if ok := dst.Empty(); ok { t.Errorf("Accumulate: dst is empty") } } func TestAccumulateWithMask(t *testing.T) { src := IMRead("images/gocvlogo.jpg", IMReadUnchanged) defer src.Close() dst := NewMatWithSizes(src.Size(), MatTypeCV64FC3) defer dst.Close() mask := NewMat() defer mask.Close() AccumulateWithMask(src, &dst, mask) if ok := dst.Empty(); ok { t.Errorf("Accumulate: dst is empty") } } func TestAccumulateSquare(t *testing.T) { src := IMRead("images/gocvlogo.jpg", IMReadUnchanged) defer src.Close() dst := NewMatWithSizes(src.Size(), MatTypeCV64FC3) defer dst.Close() AccumulateSquare(src, &dst) if ok := dst.Empty(); ok { t.Errorf("Accumulate: dst is empty") } } func TestAccumulateSquareWithMask(t *testing.T) { src := IMRead("images/gocvlogo.jpg", IMReadUnchanged) defer src.Close() dst := NewMatWithSizes(src.Size(), MatTypeCV64FC3) defer dst.Close() mask := NewMat() defer mask.Close() AccumulateSquareWithMask(src, &dst, mask) if ok := dst.Empty(); ok { t.Errorf("Accumulate: dst is empty") } } func TestAccumulateProduct(t *testing.T) { src := IMRead("images/gocvlogo.jpg", IMReadUnchanged) defer src.Close() src2 := src.Clone() defer src2.Close() dst := NewMatWithSizes(src.Size(), MatTypeCV64FC3) defer dst.Close() AccumulateProduct(src, src2, &dst) if ok := dst.Empty(); ok { t.Errorf("Accumulate: dst is empty") } } func TestAccumulateProductWithMask(t *testing.T) { src := IMRead("images/gocvlogo.jpg", IMReadUnchanged) defer src.Close() src2 := src.Clone() defer src2.Close() dst := NewMatWithSizes(src.Size(), MatTypeCV64FC3) defer dst.Close() mask := NewMat() defer mask.Close() AccumulateProductWithMask(src, src2, &dst, mask) if ok := dst.Empty(); ok { t.Errorf("Accumulate: dst is empty") } } func TestAccumulatedWeighted(t *testing.T) { src := IMRead("images/gocvlogo.jpg", IMReadUnchanged) defer src.Close() dst := NewMatWithSizes(src.Size(), MatTypeCV64FC3) defer dst.Close() AccumulatedWeighted(src, &dst, 0.1) if ok := dst.Empty(); ok { t.Errorf("AccumulatedWeighted: dst is empty") } } func TestAccumulatedWeightedWithMask(t *testing.T) { src := IMRead("images/gocvlogo.jpg", IMReadUnchanged) defer src.Close() dst := NewMatWithSizes(src.Size(), MatTypeCV64FC3) defer dst.Close() mask := NewMat() defer mask.Close() AccumulatedWeightedWithMask(src, &dst, 0.1, mask) if ok := dst.Empty(); ok { t.Errorf("AccumulatedWeighted: dst is empty") } } ================================================ FILE: mat_noprofile.go ================================================ //go:build !matprofile // +build !matprofile package gocv /* #include #include "core.h" */ import "C" // addMatToProfile does nothing if matprofile tag is not set. func addMatToProfile(p C.Mat) { return } // newMat returns a new Mat from a C Mat func newMat(p C.Mat) Mat { return Mat{p: p} } // Close the Mat object. func (m *Mat) Close() error { C.Mat_Close(m.p) m.p = nil m.d = nil return nil } ================================================ FILE: mat_profile.go ================================================ //go:build matprofile // +build matprofile package gocv /* #include #include "core.h" */ import ( "C" ) import ( "runtime/pprof" ) // MatProfile a pprof.Profile that contains stack traces that led to (currently) // unclosed Mat's creations. Every time a Mat is created, the stack trace is // added to this profile and every time the Mat is closed the trace is removed. // In a program that is not leaking, this profile's count should not // continuously increase and ideally when a program is terminated the count // should be zero. You can get the count at any time with: // // gocv.MatProfile.Count() // // and you can display the current entries with: // // var b bytes.Buffer // gocv.MatProfile.WriteTo(&b, 1) // fmt.Print(b.String()) // // This will display stack traces of where the unclosed Mats were instantiated. // For example, the results could look something like this: // // 1 @ 0x4146a0c 0x4146a57 0x4119666 0x40bb18f 0x405a841 // # 0x4146a0b gocv.io/x/gocv.newMat+0x4b /go/src/gocv.io/x/gocv/core.go:120 // # 0x4146a56 gocv.io/x/gocv.NewMat+0x26 /go/src/gocv.io/x/gocv/core.go:126 // # 0x4119665 gocv.io/x/gocv.TestMat+0x25 /go/src/gocv.io/x/gocv/core_test.go:29 // # 0x40bb18e testing.tRunner+0xbe /usr/local/Cellar/go/1.11/libexec/src/testing/testing.go:827 // // Furthermore, if the program is a long running process or if gocv is being used on a // web server, it may be helpful to install the HTTP interface using: // // import _ "net/http/pprof" // // In order to include the MatProfile custom profiler, you MUST build or run your application // or tests using the following build tag: // -tags matprofile // // For more information, see the runtime/pprof package documentation. var MatProfile *pprof.Profile func init() { profName := "gocv.io/x/gocv.Mat" MatProfile = pprof.Lookup(profName) if MatProfile == nil { MatProfile = pprof.NewProfile(profName) } } // addMatToProfile records Mat to the MatProfile. func addMatToProfile(p C.Mat) { MatProfile.Add(p, 1) return } // newMat returns a new Mat from a C Mat and records it to the MatProfile. func newMat(p C.Mat) Mat { m := Mat{p: p} MatProfile.Add(p, 1) return m } // Close the Mat object. func (m *Mat) Close() error { // NOTE: The pointer must be removed from the profile before it is deleted to // avoid a data race. MatProfile.Remove(m.p) C.Mat_Close(m.p) m.p = nil m.d = nil return nil } ================================================ FILE: matprofile_test.go ================================================ //go:build matprofile // +build matprofile package gocv import ( "bytes" "fmt" "os" "testing" ) func TestMain(m *testing.M) { ret := m.Run() if MatProfile.Count() != 0 { var b bytes.Buffer MatProfile.WriteTo(&b, 1) fmt.Printf("Not all Mat's in tests were closed: %v", b.String()) os.Exit(1) } os.Exit(ret) } func TestMatProfile(t *testing.T) { if MatProfile.Count() != 0 { var b bytes.Buffer MatProfile.WriteTo(&b, 1) t.Errorf("Mat profile should start with 0 entries. A test failure here likely means that some other test is not closing all Mats. Here are the current profile entries:\n%v", b.String()) } mat := NewMat() if MatProfile.Count() != 1 { t.Errorf("Mat profile should == 1 after NewMat but instead was %v", MatProfile.Count()) } mat2 := NewMat() if MatProfile.Count() != 2 { t.Errorf("Mat profile should == 2 after NewMat but instead was %v", MatProfile.Count()) } mat.Close() mat2.Close() if MatProfile.Count() != 0 { t.Errorf("Mat profile should == 0 after Close but instead was %v", MatProfile.Count()) } } func TestAddMatToProfile(t *testing.T) { if MatProfile.Count() != 0 { var b bytes.Buffer MatProfile.WriteTo(&b, 1) t.Errorf("Mat profile should start with 0 entries. A test failure here likely means that some other test is not closing all Mats. Here are the current profile entries:\n%v", b.String()) } mat := NewMatWithSize(5, 5, MatTypeCV8UC3) if MatProfile.Count() != 1 { t.Errorf("Mat profile should == 1 after creating 3 channel mat but instead was %v", MatProfile.Count()) } channels := Split(mat) if MatProfile.Count() != 4 { t.Errorf("Mat profile should == 4 after split channel but instead was %v", MatProfile.Count()) } for _, channel := range channels { channel.Close() } if MatProfile.Count() != 1 { t.Errorf("Mat profile should == 1 after closing channels but instead was %v", MatProfile.Count()) } mat.Close() if MatProfile.Count() != 0 { t.Errorf("Mat profile should == 0 after closing all mats but instead was %v", MatProfile.Count()) } } ================================================ FILE: objdetect.cpp ================================================ //go:build !gocv_specific_modules || (gocv_specific_modules && gocv_objdetect) #include "objdetect.h" // CascadeClassifier CascadeClassifier CascadeClassifier_New() { try { return new cv::CascadeClassifier(); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } void CascadeClassifier_Close(CascadeClassifier cs) { delete cs; } int CascadeClassifier_Load(CascadeClassifier cs, const char* name) { try { return cs->load(name); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return 0; } } struct Rects CascadeClassifier_DetectMultiScale(CascadeClassifier cs, Mat img) { try { std::vector detected; cs->detectMultiScale(*img, detected); // uses all default parameters Rect* rects = new Rect[detected.size()]; for (size_t i = 0; i < detected.size(); ++i) { Rect r = {detected[i].x, detected[i].y, detected[i].width, detected[i].height}; rects[i] = r; } Rects ret = {rects, (int)detected.size()}; return ret; } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); Rects ret = {NULL, 0}; return ret; } } struct Rects CascadeClassifier_DetectMultiScaleWithParams(CascadeClassifier cs, Mat img, double scale, int minNeighbors, int flags, Size minSize, Size maxSize) { try { cv::Size minSz(minSize.width, minSize.height); cv::Size maxSz(maxSize.width, maxSize.height); std::vector detected; cs->detectMultiScale(*img, detected, scale, minNeighbors, flags, minSz, maxSz); Rect* rects = new Rect[detected.size()]; for (size_t i = 0; i < detected.size(); ++i) { Rect r = {detected[i].x, detected[i].y, detected[i].width, detected[i].height}; rects[i] = r; } Rects ret = {rects, (int)detected.size()}; return ret; } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); Rects ret = {NULL, 0}; return ret; } } // HOGDescriptor HOGDescriptor HOGDescriptor_New() { try { return new cv::HOGDescriptor(); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } void HOGDescriptor_Close(HOGDescriptor hog) { delete hog; } int HOGDescriptor_Load(HOGDescriptor hog, const char* name) { try { return hog->load(name); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return 0; } } struct Rects HOGDescriptor_DetectMultiScale(HOGDescriptor hog, Mat img) { try { std::vector detected; hog->detectMultiScale(*img, detected); Rect* rects = new Rect[detected.size()]; for (size_t i = 0; i < detected.size(); ++i) { Rect r = {detected[i].x, detected[i].y, detected[i].width, detected[i].height}; rects[i] = r; } Rects ret = {rects, (int)detected.size()}; return ret; } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); Rects ret = {NULL, 0}; return ret; } } struct Rects HOGDescriptor_DetectMultiScaleWithParams(HOGDescriptor hog, Mat img, double hitThresh, Size winStride, Size padding, double scale, double finalThresh, bool useMeanshiftGrouping) { try { cv::Size wSz(winStride.width, winStride.height); cv::Size pSz(padding.width, padding.height); std::vector detected; hog->detectMultiScale(*img, detected, hitThresh, wSz, pSz, scale, finalThresh, useMeanshiftGrouping); Rect* rects = new Rect[detected.size()]; for (size_t i = 0; i < detected.size(); ++i) { Rect r = {detected[i].x, detected[i].y, detected[i].width, detected[i].height}; rects[i] = r; } Rects ret = {rects, (int)detected.size()}; return ret; } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); Rects ret = {NULL, 0}; return ret; } } Mat HOG_GetDefaultPeopleDetector() { try { return new cv::Mat(cv::HOGDescriptor::getDefaultPeopleDetector()); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return new cv::Mat(); } } void HOGDescriptor_SetSVMDetector(HOGDescriptor hog, Mat det) { try { hog->setSVMDetector(*det); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); } } struct Rects GroupRectangles(struct Rects rects, int groupThreshold, double eps) { try { std::vector vRect; for (int i = 0; i < rects.length; ++i) { cv::Rect r = cv::Rect(rects.rects[i].x, rects.rects[i].y, rects.rects[i].width, rects.rects[i].height); vRect.push_back(r); } cv::groupRectangles(vRect, groupThreshold, eps); Rect* results = new Rect[vRect.size()]; for (size_t i = 0; i < vRect.size(); ++i) { Rect r = {vRect[i].x, vRect[i].y, vRect[i].width, vRect[i].height}; results[i] = r; } Rects ret = {results, (int)vRect.size()}; return ret; } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); Rects ret = {NULL, 0}; return ret; } } // QRCodeDetector QRCodeDetector QRCodeDetector_New() { try { return new cv::QRCodeDetector(); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } void QRCodeDetector_Close(QRCodeDetector qr) { delete qr; } const char* QRCodeDetector_DetectAndDecode(QRCodeDetector qr, Mat input,Mat points,Mat straight_qrcode) { try { cv::String *str = new cv::String(qr->detectAndDecode(*input,*points,*straight_qrcode)); return str->c_str(); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return ""; } } bool QRCodeDetector_Detect(QRCodeDetector qr, Mat input,Mat points) { try { return qr->detect(*input,*points); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return false; } } const char* QRCodeDetector_Decode(QRCodeDetector qr, Mat input,Mat inputPoints,Mat straight_qrcode) { try { cv::String *str = new cv::String(qr->detectAndDecode(*input,*inputPoints,*straight_qrcode)); return str->c_str(); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return ""; } } bool QRCodeDetector_DetectMulti(QRCodeDetector qr, Mat input, Mat points) { try { return qr->detectMulti(*input,*points); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return false; } } bool QRCodeDetector_DetectAndDecodeMulti(QRCodeDetector qr, Mat input, CStrings* decoded, Mat points, struct Mats* qrCodes) { try { std::vector decodedCodes; std::vector straightQrCodes; bool res = qr->detectAndDecodeMulti(*input, decodedCodes, *points, straightQrCodes); if (!res) { return res; } qrCodes->mats = new Mat[straightQrCodes.size()]; qrCodes->length = straightQrCodes.size(); for (size_t i = 0; i < straightQrCodes.size(); i++) { qrCodes->mats[i] = new cv::Mat(straightQrCodes[i]); } const char **strs = new const char*[decodedCodes.size()]; for (size_t i = 0; i < decodedCodes.size(); ++i) { strs[i] = decodedCodes[i].c_str(); } decoded->length = decodedCodes.size(); decoded->strs = strs; return res; } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return false; } } FaceDetectorYN FaceDetectorYN_Create(const char* model, const char* config, Size size) { try { cv::String smodel = cv::String(model); cv::String sconfig = cv::String(config); cv::Size ssize = cv::Size(size.width, size.height); return new cv::Ptr(cv::FaceDetectorYN::create(smodel, sconfig, ssize)); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } FaceDetectorYN FaceDetectorYN_Create_WithParams(const char* model, const char* config, Size size, float score_threshold, float nms_threshold, int top_k, int backend_id, int target_id) { try { cv::String smodel = cv::String(model); cv::String sconfig = cv::String(config); cv::Size ssize = cv::Size(size.width, size.height); return new cv::Ptr(cv::FaceDetectorYN::create(smodel, sconfig, ssize, score_threshold, nms_threshold, top_k, backend_id, target_id)); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } FaceDetectorYN FaceDetectorYN_Create_FromBytes(const char* framework, void* bufferModel, int model_size, void* bufferConfig, int config_size, Size size) { try { cv::String sframework = cv::String(framework); cv::Size ssize = cv::Size(size.width, size.height); std::vector bufferModelV; std::vector bufferConfigV; uchar* bmv = (uchar*)bufferModel; uchar* bcv = (uchar*)bufferConfig; for(int i = 0; i < model_size; i ++) { bufferModelV.push_back(bmv[i]); } for(int i = 0; i < config_size; i ++) { bufferConfigV.push_back(bcv[i]); } return new cv::Ptr(cv::FaceDetectorYN::create(sframework, bufferModelV, bufferConfigV, ssize)); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } FaceDetectorYN FaceDetectorYN_Create_FromBytes_WithParams(const char* framework, void* bufferModel, int model_size, void* bufferConfig, int config_size, Size size, float score_threshold, float nms_threshold, int top_k, int backend_id, int target_id) { try { cv::String sframework = cv::String(framework); cv::Size ssize = cv::Size(size.width, size.height); std::vector bufferModelV; std::vector bufferConfigV; uchar* bmv = (uchar*)bufferModel; uchar* bcv = (uchar*)bufferConfig; for(int i = 0; i < model_size; i ++) { bufferModelV.push_back(bmv[i]); } for(int i = 0; i < config_size; i ++) { bufferConfigV.push_back(bcv[i]); } return new cv::Ptr(cv::FaceDetectorYN::create(sframework, bufferModelV, bufferConfigV, ssize, score_threshold, nms_threshold, top_k, backend_id, target_id)); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } void FaceDetectorYN_Close(FaceDetectorYN fd) { delete fd; } int FaceDetectorYN_Detect(FaceDetectorYN fd, Mat image, Mat faces) { try { return (*fd)->detect(*image, *faces); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return 0; } } Size FaceDetectorYN_GetInputSize(FaceDetectorYN fd) { try { Size sz; cv::Size cvsz = (*fd)->getInputSize(); sz.width = cvsz.width; sz.height = cvsz.height; return sz; } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); Size sz = {0, 0}; return sz; } } float FaceDetectorYN_GetNMSThreshold(FaceDetectorYN fd) { try { return (*fd)->getNMSThreshold(); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return 0.0; } } float FaceDetectorYN_GetScoreThreshold(FaceDetectorYN fd) { try { return (*fd)->getScoreThreshold(); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return 0.0; } } int FaceDetectorYN_GetTopK(FaceDetectorYN fd) { try { return (*fd)->getTopK(); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return 0; } } void FaceDetectorYN_SetInputSize(FaceDetectorYN fd, Size input_size){ try { cv::Size isz(input_size.width, input_size.height); (*fd)->setInputSize(isz); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); } } void FaceDetectorYN_SetNMSThreshold(FaceDetectorYN fd, float nms_threshold){ try { (*fd)->setNMSThreshold(nms_threshold); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); } } void FaceDetectorYN_SetScoreThreshold(FaceDetectorYN fd, float score_threshold){ try { (*fd)->setScoreThreshold(score_threshold); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); } } void FaceDetectorYN_SetTopK(FaceDetectorYN fd, int top_k){ try { (*fd)->setTopK(top_k); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); } } FaceRecognizerSF FaceRecognizerSF_Create(const char* model, const char* config) { try { return FaceRecognizerSF_Create_WithParams(model, config, 0, 0); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } FaceRecognizerSF FaceRecognizerSF_Create_WithParams(const char* model, const char* config, int backend_id, int target_id) { try { return new cv::Ptr(cv::FaceRecognizerSF::create(model, config, backend_id, target_id)); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } void FaceRecognizerSF_Close(FaceRecognizerSF fr) { delete fr; } void FaceRecognizerSF_AlignCrop(FaceRecognizerSF fr, Mat src_img, Mat face_box, Mat aligned_img) { try { (*fr)->alignCrop(*src_img, *face_box, *aligned_img); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); } } void FaceRecognizerSF_Feature(FaceRecognizerSF fr, Mat aligned_img, Mat face_feature) { try { (*fr)->feature(*aligned_img, *face_feature); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); } } float FaceRecognizerSF_Match(FaceRecognizerSF fr, Mat face_feature1, Mat face_feature2) { try { return FaceRecognizerSF_Match_WithParams(fr, face_feature1, face_feature2, 0); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return 0.0; } } float FaceRecognizerSF_Match_WithParams(FaceRecognizerSF fr, Mat face_feature1, Mat face_feature2, int dis_type) { try { double rv = (*fr)->match(*face_feature1, *face_feature2, dis_type); return (float)rv; } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return 0.0; } } ================================================ FILE: objdetect.go ================================================ //go:build !gocv_specific_modules || (gocv_specific_modules && gocv_objdetect) package gocv /* #include #include "objdetect.h" */ import "C" import ( "image" "unsafe" ) // CascadeClassifier is a cascade classifier class for object detection. // // For further details, please see: // http://docs.opencv.org/master/d1/de5/classcv_1_1CascadeClassifier.html type CascadeClassifier struct { p C.CascadeClassifier } // NewCascadeClassifier returns a new CascadeClassifier. func NewCascadeClassifier() CascadeClassifier { return CascadeClassifier{p: C.CascadeClassifier_New()} } // Close deletes the CascadeClassifier's pointer. func (c *CascadeClassifier) Close() error { C.CascadeClassifier_Close(c.p) c.p = nil return nil } // Load cascade classifier from a file. // // For further details, please see: // http://docs.opencv.org/master/d1/de5/classcv_1_1CascadeClassifier.html#a1a5884c8cc749422f9eb77c2471958bc func (c *CascadeClassifier) Load(name string) bool { cName := C.CString(name) defer C.free(unsafe.Pointer(cName)) return C.CascadeClassifier_Load(c.p, cName) != 0 } // DetectMultiScale detects objects of different sizes in the input Mat image. // The detected objects are returned as a slice of image.Rectangle structs. // // For further details, please see: // http://docs.opencv.org/master/d1/de5/classcv_1_1CascadeClassifier.html#aaf8181cb63968136476ec4204ffca498 func (c *CascadeClassifier) DetectMultiScale(img Mat) []image.Rectangle { ret := C.CascadeClassifier_DetectMultiScale(c.p, img.p) defer C.Rects_Close(ret) return toRectangles(ret) } // DetectMultiScaleWithParams calls DetectMultiScale but allows setting parameters // to values other than just the defaults. // // For further details, please see: // http://docs.opencv.org/master/d1/de5/classcv_1_1CascadeClassifier.html#aaf8181cb63968136476ec4204ffca498 func (c *CascadeClassifier) DetectMultiScaleWithParams(img Mat, scale float64, minNeighbors, flags int, minSize, maxSize image.Point) []image.Rectangle { minSz := C.struct_Size{ width: C.int(minSize.X), height: C.int(minSize.Y), } maxSz := C.struct_Size{ width: C.int(maxSize.X), height: C.int(maxSize.Y), } ret := C.CascadeClassifier_DetectMultiScaleWithParams(c.p, img.p, C.double(scale), C.int(minNeighbors), C.int(flags), minSz, maxSz) defer C.Rects_Close(ret) return toRectangles(ret) } // HOGDescriptor is a Histogram Of Gradiants (HOG) for object detection. // // For further details, please see: // https://docs.opencv.org/master/d5/d33/structcv_1_1HOGDescriptor.html#a723b95b709cfd3f95cf9e616de988fc8 type HOGDescriptor struct { p C.HOGDescriptor } // NewHOGDescriptor returns a new HOGDescriptor. func NewHOGDescriptor() HOGDescriptor { return HOGDescriptor{p: C.HOGDescriptor_New()} } // Close deletes the HOGDescriptor's pointer. func (h *HOGDescriptor) Close() error { C.HOGDescriptor_Close(h.p) h.p = nil return nil } // DetectMultiScale detects objects in the input Mat image. // The detected objects are returned as a slice of image.Rectangle structs. // // For further details, please see: // https://docs.opencv.org/master/d5/d33/structcv_1_1HOGDescriptor.html#a660e5cd036fd5ddf0f5767b352acd948 func (h *HOGDescriptor) DetectMultiScale(img Mat) []image.Rectangle { ret := C.HOGDescriptor_DetectMultiScale(h.p, img.p) defer C.Rects_Close(ret) return toRectangles(ret) } // DetectMultiScaleWithParams calls DetectMultiScale but allows setting parameters // to values other than just the defaults. // // For further details, please see: // https://docs.opencv.org/master/d5/d33/structcv_1_1HOGDescriptor.html#a660e5cd036fd5ddf0f5767b352acd948 func (h *HOGDescriptor) DetectMultiScaleWithParams(img Mat, hitThresh float64, winStride, padding image.Point, scale, finalThreshold float64, useMeanshiftGrouping bool) []image.Rectangle { wSz := C.struct_Size{ width: C.int(winStride.X), height: C.int(winStride.Y), } pSz := C.struct_Size{ width: C.int(padding.X), height: C.int(padding.Y), } ret := C.HOGDescriptor_DetectMultiScaleWithParams(h.p, img.p, C.double(hitThresh), wSz, pSz, C.double(scale), C.double(finalThreshold), C.bool(useMeanshiftGrouping)) defer C.Rects_Close(ret) return toRectangles(ret) } // HOGDefaultPeopleDetector returns a new Mat with the HOG DefaultPeopleDetector. // // For further details, please see: // https://docs.opencv.org/master/d5/d33/structcv_1_1HOGDescriptor.html#a660e5cd036fd5ddf0f5767b352acd948 func HOGDefaultPeopleDetector() Mat { return newMat(C.HOG_GetDefaultPeopleDetector()) } // SetSVMDetector sets the data for the HOGDescriptor. // // For further details, please see: // https://docs.opencv.org/master/d5/d33/structcv_1_1HOGDescriptor.html#a09e354ad701f56f9c550dc0385dc36f1 func (h *HOGDescriptor) SetSVMDetector(det Mat) error { C.HOGDescriptor_SetSVMDetector(h.p, det.p) return nil } // GroupRectangles groups the object candidate rectangles. // // For further details, please see: // https://docs.opencv.org/master/d5/d54/group__objdetect.html#ga3dba897ade8aa8227edda66508e16ab9 func GroupRectangles(rects []image.Rectangle, groupThreshold int, eps float64) []image.Rectangle { cRectArray := make([]C.struct_Rect, len(rects)) for i, r := range rects { cRect := C.struct_Rect{ x: C.int(r.Min.X), y: C.int(r.Min.Y), width: C.int(r.Size().X), height: C.int(r.Size().Y), } cRectArray[i] = cRect } cRects := C.struct_Rects{ rects: (*C.Rect)(&cRectArray[0]), length: C.int(len(rects)), } ret := C.GroupRectangles(cRects, C.int(groupThreshold), C.double(eps)) return toRectangles(ret) } // QRCodeDetector groups the object candidate rectangles. // // For further details, please see: // https://docs.opencv.org/master/de/dc3/classcv_1_1QRCodeDetector.html type QRCodeDetector struct { p C.QRCodeDetector } // newQRCodeDetector returns a new QRCodeDetector from a C QRCodeDetector func newQRCodeDetector(p C.QRCodeDetector) QRCodeDetector { return QRCodeDetector{p: p} } func NewQRCodeDetector() QRCodeDetector { return newQRCodeDetector(C.QRCodeDetector_New()) } func (a *QRCodeDetector) Close() error { C.QRCodeDetector_Close(a.p) a.p = nil return nil } // DetectAndDecode Both detects and decodes QR code. // // Returns true as long as some QR code was detected even in case where the decoding failed // For further details, please see: // https://docs.opencv.org/master/de/dc3/classcv_1_1QRCodeDetector.html#a7290bd6a5d59b14a37979c3a14fbf394 func (a *QRCodeDetector) DetectAndDecode(input Mat, points *Mat, straight_qrcode *Mat) string { goResult := C.GoString(C.QRCodeDetector_DetectAndDecode(a.p, input.p, points.p, straight_qrcode.p)) return string(goResult) } // Detect detects QR code in image and returns the quadrangle containing the code. // // For further details, please see: // https://docs.opencv.org/master/de/dc3/classcv_1_1QRCodeDetector.html#a64373f7d877d27473f64fe04bb57d22b func (a *QRCodeDetector) Detect(input Mat, points *Mat) bool { result := C.QRCodeDetector_Detect(a.p, input.p, points.p) return bool(result) } // Decode decodes QR code in image once it's found by the detect() method. Returns UTF8-encoded output string or empty string if the code cannot be decoded. // // For further details, please see: // https://docs.opencv.org/master/de/dc3/classcv_1_1QRCodeDetector.html#a4172c2eb4825c844fb1b0ae67202d329 func (a *QRCodeDetector) Decode(input Mat, points Mat, straight_qrcode *Mat) string { goResult := C.GoString(C.QRCodeDetector_DetectAndDecode(a.p, input.p, points.p, straight_qrcode.p)) return string(goResult) } // Detects QR codes in image and finds of the quadrangles containing the codes. // // Each quadrangle would be returned as a row in the `points` Mat and each point is a Vecf. // Returns true if QR code was detected // For usage please see TestQRCodeDetector // For further details, please see: // https://docs.opencv.org/master/de/dc3/classcv_1_1QRCodeDetector.html#aaf2b6b2115b8e8fbc9acf3a8f68872b6 func (a *QRCodeDetector) DetectMulti(input Mat, points *Mat) bool { result := C.QRCodeDetector_DetectMulti(a.p, input.p, points.p) return bool(result) } // Detects QR codes in image, finds the quadrangles containing the codes, and decodes the QRCodes to strings. // // Each quadrangle would be returned as a row in the `points` Mat and each point is a Vecf. // Returns true as long as some QR code was detected even in case where the decoding failed // For usage please see TestQRCodeDetector // For further details, please see: // https://docs.opencv.org/master/de/dc3/classcv_1_1QRCodeDetector.html#a188b63ffa17922b2c65d8a0ab7b70775 func (a *QRCodeDetector) DetectAndDecodeMulti(input Mat, decoded []string, points *Mat, qrCodes []Mat) bool { cDecoded := C.CStrings{} defer C.CStrings_Close(cDecoded) cQrCodes := C.struct_Mats{} defer C.Mats_Close(cQrCodes) success := C.QRCodeDetector_DetectAndDecodeMulti(a.p, input.p, &cDecoded, points.p, &cQrCodes) if !success { return bool(success) } tmpCodes := make([]Mat, cQrCodes.length) for i := C.int(0); i < cQrCodes.length; i++ { tmpCodes[i].p = C.Mats_get(cQrCodes, i) } for _, qr := range tmpCodes { qrCodes = append(qrCodes, qr) } for _, s := range toGoStrings(cDecoded) { decoded = append(decoded, s) } return bool(success) } type FaceDetectorYN struct { p C.FaceDetectorYN } // NewFaceDetectorYN Creates an instance of face detector with given parameters. // // modelPath: the path to the requested model // // configPath: the path to the config file for compability, which is not requested for ONNX models // // size: the size of the input image // // For further details, please see: // https://docs.opencv.org/4.x/df/d20/classcv_1_1FaceDetectorYN.html#a5f7fb43c60c95ca5ebab78483de02516 func NewFaceDetectorYN(modelPath string, configPath string, size image.Point) FaceDetectorYN { c_model_path := C.CString(modelPath) defer C.free(unsafe.Pointer(c_model_path)) c_config_path := C.CString(configPath) defer C.free(unsafe.Pointer(c_config_path)) c_size := C.Size{ width: C.int(size.X), height: C.int(size.Y), } return FaceDetectorYN{p: C.FaceDetectorYN_Create(c_model_path, c_config_path, c_size)} } // NewFaceDetectorYNWithParams Creates an instance of face detector with given parameters. // // For further details, please see: // https://docs.opencv.org/4.x/df/d20/classcv_1_1FaceDetectorYN.html#a5f7fb43c60c95ca5ebab78483de02516 func NewFaceDetectorYNWithParams(modelPath string, configPath string, size image.Point, scoreThreshold float32, nmsThreshold float32, topK int, backendId int, targetId int) FaceDetectorYN { c_model_path := C.CString(modelPath) defer C.free(unsafe.Pointer(c_model_path)) c_config_path := C.CString(configPath) defer C.free(unsafe.Pointer(c_config_path)) c_size := C.Size{ width: C.int(size.X), height: C.int(size.Y), } return FaceDetectorYN{p: C.FaceDetectorYN_Create_WithParams(c_model_path, c_config_path, c_size, C.float(scoreThreshold), C.float(nmsThreshold), C.int(topK), C.int(backendId), C.int(targetId))} } // NewFaceDetectorYNFromBytes Creates an instance of face detector with given parameters. // // For further details, please see: // https://docs.opencv.org/4.x/df/d20/classcv_1_1FaceDetectorYN.html#aa0796a4bfe2d4709bef81abbae9a927a func NewFaceDetectorYNFromBytes(framework string, bufferModel []byte, bufferConfig []byte, size image.Point) FaceDetectorYN { c_framework := C.CString(framework) defer C.free(unsafe.Pointer(c_framework)) c_size := C.Size{ width: C.int(size.X), height: C.int(size.Y), } return FaceDetectorYN{p: C.FaceDetectorYN_Create_FromBytes(c_framework, unsafe.Pointer(unsafe.SliceData(bufferModel)), C.int(len(bufferModel)), unsafe.Pointer(unsafe.SliceData(bufferConfig)), C.int(len(bufferConfig)), c_size)} } // NewFaceDetectorYNFromBuffers Creates an instance of face detector with given parameters. // // For further details, please see: // https://docs.opencv.org/4.x/df/d20/classcv_1_1FaceDetectorYN.html#aa0796a4bfe2d4709bef81abbae9a927a func NewFaceDetectorYNFromBytesWithParams(framework string, bufferModel []byte, bufferConfig []byte, size image.Point, scoreThreshold float32, nmsThreshold float32, topK int, backendId int, targetId int) FaceDetectorYN { c_framework := C.CString(framework) defer C.free(unsafe.Pointer(c_framework)) c_size := C.Size{ width: C.int(size.X), height: C.int(size.Y), } return FaceDetectorYN{p: C.FaceDetectorYN_Create_FromBytes_WithParams(c_framework, unsafe.Pointer(unsafe.SliceData(bufferModel)), C.int(len(bufferModel)), unsafe.Pointer(unsafe.SliceData(bufferConfig)), C.int(len(bufferConfig)), c_size, C.float(scoreThreshold), C.float(nmsThreshold), C.int(topK), C.int(backendId), C.int(targetId))} } func (fd *FaceDetectorYN) Close() { C.FaceDetectorYN_Close(fd.p) } // Detect Detects faces in the input image. // // image: an image to detect // // faces: detection results stored in a 2D cv::Mat of shape [num_faces, 15] // // 0-1: x, y of bbox top left corner // // 2-3: width, height of bbox // // 4-5: x, y of right eye (blue point in the example image) // // 6-7: x, y of left eye (red point in the example image) // // 8-9: x, y of nose tip (green point in the example image) // // 10-11: x, y of right corner of mouth (pink point in the example image) // // 12-13: x, y of left corner of mouth (yellow point in the example image) // // 14: face score // // For further details, please see: // https://docs.opencv.org/4.x/df/d20/classcv_1_1FaceDetectorYN.html#ac05bd075ca3e6edc0e328927aae6f45b func (fd *FaceDetectorYN) Detect(image Mat, faces *Mat) int { c_rv := C.FaceDetectorYN_Detect(fd.p, image.p, faces.p) return int(c_rv) } func (fd *FaceDetectorYN) GetInputSize() image.Point { sz := C.FaceDetectorYN_GetInputSize(fd.p) return image.Pt(int(sz.width), int(sz.height)) } func (fd *FaceDetectorYN) GetNMSThreshold() float32 { t := C.FaceDetectorYN_GetNMSThreshold(fd.p) return float32(t) } func (fd *FaceDetectorYN) GetScoreThreshold() float32 { t := C.FaceDetectorYN_GetScoreThreshold(fd.p) return float32(t) } func (fd *FaceDetectorYN) GetTopK() int { i := C.FaceDetectorYN_GetTopK(fd.p) return int(i) } // SetInputSize Set the size for the network input, which overwrites the input size of creating model. // Call this method when the size of input image does not match the input size when creating model. // // For further details, please see: // https://docs.opencv.org/4.x/df/d20/classcv_1_1FaceDetectorYN.html#a072418e5ce7beeb69c41edda75c41d2e func (fd *FaceDetectorYN) SetInputSize(sz image.Point) { c_sz := C.Size{ width: C.int(sz.X), height: C.int(sz.Y), } C.FaceDetectorYN_SetInputSize(fd.p, c_sz) } // SetNMSThreshold Set the Non-maximum-suppression threshold to suppress // bounding boxes that have IoU greater than the given value. // // For further details, please see: // https://docs.opencv.org/4.x/df/d20/classcv_1_1FaceDetectorYN.html#ab6011efee7e12dca3857d82de5269ac5 func (fd *FaceDetectorYN) SetNMSThreshold(nmsThreshold float32) { C.FaceDetectorYN_SetNMSThreshold(fd.p, C.float(nmsThreshold)) } // SetScoreThreshold Set the score threshold to filter out bounding boxes of score less than the given value. // // For further details, please see: // https://docs.opencv.org/4.x/df/d20/classcv_1_1FaceDetectorYN.html#a37f3c23b82158fac7fdad967d315f85a func (fd *FaceDetectorYN) SetScoreThreshold(scoreThreshold float32) { C.FaceDetectorYN_SetScoreThreshold(fd.p, C.float(scoreThreshold)) } // SetTopK Set the number of bounding boxes preserved before NMS. // // For further details, please see: // https://docs.opencv.org/4.x/df/d20/classcv_1_1FaceDetectorYN.html#aa88d20e1e2df75ea36b851534089856a func (fd *FaceDetectorYN) SetTopK(topK int) { C.FaceDetectorYN_SetTopK(fd.p, C.int(topK)) } type FaceRecognizerSFDisType int const ( FaceRecognizerSFDisTypeCosine FaceRecognizerSFDisType = 0 FaceRecognizerSFDisTypeNormL2 FaceRecognizerSFDisType = 1 ) type FaceRecognizerSF struct { p C.FaceRecognizerSF } // NewFaceRecognizerSF Creates an instance with given parameters. // // model: the path of the onnx model used for face recognition // // config: the path to the config file for compability, which is not requested for ONNX models // // For further details, please see: // https://docs.opencv.org/4.x/da/d09/classcv_1_1FaceRecognizerSF.html#a04df90b0cd7d26d350acd92621a35743 func NewFaceRecognizerSF(modelPath string, configPath string) FaceRecognizerSF { c_model := C.CString(modelPath) defer C.free(unsafe.Pointer(c_model)) c_config := C.CString(configPath) defer C.free(unsafe.Pointer(c_config)) return FaceRecognizerSF{p: C.FaceRecognizerSF_Create(c_model, c_config)} } // NewFaceRecognizerSFWithParams Creates an instance with given parameters. // // model: the path of the onnx model used for face recognition // // config: the path to the config file for compability, which is not requested for ONNX models // // backend_id: the id of backend // // target_id: the id of target device // // For further details, please see: // https://docs.opencv.org/4.x/da/d09/classcv_1_1FaceRecognizerSF.html#a04df90b0cd7d26d350acd92621a35743 func NewFaceRecognizerSFWithParams(modelPath string, configPath string, backendId int, targetId int) FaceRecognizerSF { c_model := C.CString(modelPath) defer C.free(unsafe.Pointer(c_model)) c_config := C.CString(configPath) defer C.free(unsafe.Pointer(c_config)) return FaceRecognizerSF{p: C.FaceRecognizerSF_Create_WithParams(c_model, c_config, C.int(backendId), C.int(targetId))} } // Close Releases FaceRecognizerSF resources. func (fr *FaceRecognizerSF) Close() { C.FaceRecognizerSF_Close(fr.p) } // AlignCrop Aligns detected face with the source input image and crops it. // // srcImg: input image // // faceBox: the detected face result from the input image // // alignedImg: output aligned image // // For further details, please see: // https://docs.opencv.org/4.x/da/d09/classcv_1_1FaceRecognizerSF.html#a84492908abecbc9362b4ddc8d46b8345 func (fr *FaceRecognizerSF) AlignCrop(srcImg Mat, faceBox Mat, alignedImg *Mat) { C.FaceRecognizerSF_AlignCrop(fr.p, srcImg.p, faceBox.p, alignedImg.p) } // Feature Extracts face feature from aligned image. // // alignedImg: input aligned image // // faceFeature: output face feature // // For further details, please see: // https://docs.opencv.org/4.x/da/d09/classcv_1_1FaceRecognizerSF.html#ab1b4a3c12213e89091a490c573dc5aba func (fr *FaceRecognizerSF) Feature(alignedImg Mat, faceFeature *Mat) { C.FaceRecognizerSF_Feature(fr.p, alignedImg.p, faceFeature.p) } // Match Calculates the distance between two face features. // // faceFeature1: the first input feature // // faceFeature2: the second input feature of the same size and the same type as face_feature1 // // For further details, please see: // https://docs.opencv.org/4.x/da/d09/classcv_1_1FaceRecognizerSF.html#a2f0362ca1e64320a1f3ba7e1386d0219 func (fr *FaceRecognizerSF) Match(faceFeature1 Mat, faceFeature2 Mat) float32 { rv := C.FaceRecognizerSF_Match(fr.p, faceFeature1.p, faceFeature2.p) return float32(rv) } // MatchWithParams Calculates the distance between two face features. // // faceFeature1: the first input feature // // faceFeature2: the second input feature of the same size and the same type as face_feature1 // // disType: defines how to calculate the distance between two face features // // For further details, please see: // https://docs.opencv.org/4.x/da/d09/classcv_1_1FaceRecognizerSF.html#a2f0362ca1e64320a1f3ba7e1386d0219 func (fr *FaceRecognizerSF) MatchWithParams(faceFeature1 Mat, faceFeature2 Mat, disType FaceRecognizerSFDisType) float32 { rv := C.FaceRecognizerSF_Match_WithParams(fr.p, faceFeature1.p, faceFeature2.p, C.int(disType)) return float32(rv) } ================================================ FILE: objdetect.h ================================================ #ifndef _OPENCV3_OBJDETECT_H_ #define _OPENCV3_OBJDETECT_H_ #include #ifdef __cplusplus #include extern "C" { #endif #include "core.h" #ifdef __cplusplus typedef cv::CascadeClassifier* CascadeClassifier; typedef cv::HOGDescriptor* HOGDescriptor; typedef cv::QRCodeDetector* QRCodeDetector; typedef cv::Ptr* FaceDetectorYN; typedef cv::Ptr* FaceRecognizerSF; #else typedef void* CascadeClassifier; typedef void* HOGDescriptor; typedef void* QRCodeDetector; typedef void* FaceDetectorYN; typedef void* FaceRecognizerSF; #endif // CascadeClassifier CascadeClassifier CascadeClassifier_New(); void CascadeClassifier_Close(CascadeClassifier cs); int CascadeClassifier_Load(CascadeClassifier cs, const char* name); struct Rects CascadeClassifier_DetectMultiScale(CascadeClassifier cs, Mat img); struct Rects CascadeClassifier_DetectMultiScaleWithParams(CascadeClassifier cs, Mat img, double scale, int minNeighbors, int flags, Size minSize, Size maxSize); HOGDescriptor HOGDescriptor_New(); void HOGDescriptor_Close(HOGDescriptor hog); int HOGDescriptor_Load(HOGDescriptor hog, const char* name); struct Rects HOGDescriptor_DetectMultiScale(HOGDescriptor hog, Mat img); struct Rects HOGDescriptor_DetectMultiScaleWithParams(HOGDescriptor hog, Mat img, double hitThresh, Size winStride, Size padding, double scale, double finalThreshold, bool useMeanshiftGrouping); Mat HOG_GetDefaultPeopleDetector(); void HOGDescriptor_SetSVMDetector(HOGDescriptor hog, Mat det); struct Rects GroupRectangles(struct Rects rects, int groupThreshold, double eps); QRCodeDetector QRCodeDetector_New(); const char* QRCodeDetector_DetectAndDecode(QRCodeDetector qr, Mat input,Mat points,Mat straight_qrcode); bool QRCodeDetector_Detect(QRCodeDetector qr, Mat input,Mat points); const char* QRCodeDetector_Decode(QRCodeDetector qr, Mat input,Mat inputPoints,Mat straight_qrcode); void QRCodeDetector_Close(QRCodeDetector qr); bool QRCodeDetector_DetectMulti(QRCodeDetector qr, Mat input, Mat points); bool QRCodeDetector_DetectAndDecodeMulti(QRCodeDetector qr, Mat input, CStrings* decoded ,Mat points, struct Mats* mats); // FaceDetectorYN FaceDetectorYN FaceDetectorYN_Create(const char* model, const char* config, Size size); FaceDetectorYN FaceDetectorYN_Create_WithParams(const char* model, const char* config, Size size, float score_threshold, float mms_threshold, int top_k, int backend_id, int target_id); FaceDetectorYN FaceDetectorYN_Create_FromBytes(const char* framework, void* bufferModel, int model_size, void* bufferConfig, int config_size, Size size); FaceDetectorYN FaceDetectorYN_Create_FromBytes_WithParams(const char* framework, void* bufferModel, int model_size, void* bufferConfig, int config_size, Size size, float score_threshold, float mms_threshold, int top_k, int backend_id, int target_id); void FaceDetectorYN_Close(FaceDetectorYN fd); int FaceDetectorYN_Detect(FaceDetectorYN fd, Mat image, Mat faces); Size FaceDetectorYN_GetInputSize(FaceDetectorYN fd); float FaceDetectorYN_GetNMSThreshold(FaceDetectorYN fd); float FaceDetectorYN_GetScoreThreshold(FaceDetectorYN fd); int FaceDetectorYN_GetTopK(FaceDetectorYN fd); void FaceDetectorYN_SetInputSize(FaceDetectorYN fd, Size input_size); void FaceDetectorYN_SetNMSThreshold(FaceDetectorYN fd, float nms_threshold); void FaceDetectorYN_SetScoreThreshold(FaceDetectorYN fd, float score_threshold); void FaceDetectorYN_SetTopK(FaceDetectorYN fd, int top_k); // FaceRecognizerSF FaceRecognizerSF FaceRecognizerSF_Create(const char* model, const char* config); FaceRecognizerSF FaceRecognizerSF_Create_WithParams(const char* model, const char* config, int backend_id, int target_id); void FaceRecognizerSF_Close(FaceRecognizerSF fr); void FaceRecognizerSF_AlignCrop(FaceRecognizerSF fr, Mat src_img, Mat face_box, Mat aligned_img); void FaceRecognizerSF_Feature(FaceRecognizerSF fr, Mat aligned_img, Mat face_feature); float FaceRecognizerSF_Match(FaceRecognizerSF fr, Mat face_feature1, Mat face_feature2); float FaceRecognizerSF_Match_WithParams(FaceRecognizerSF fr, Mat face_feature1, Mat face_feature2, int dis_type); #ifdef __cplusplus } #endif #endif //_OPENCV3_OBJDETECT_H_ ================================================ FILE: objdetect_test.go ================================================ //go:build !gocv_specific_modules || (gocv_specific_modules && gocv_objdetect) package gocv import ( "image" "image/color" "os" "testing" ) func TestCascadeClassifier(t *testing.T) { img := IMRead("images/face.jpg", IMReadColor) if img.Empty() { t.Error("Invalid Mat in CascadeClassifier test") } defer img.Close() // load classifier to recognize faces classifier := NewCascadeClassifier() defer classifier.Close() classifier.Load("data/haarcascade_frontalface_default.xml") rects := classifier.DetectMultiScale(img) if len(rects) != 1 { t.Error("Error in TestCascadeClassifier test") } } func TestCascadeClassifierWithParams(t *testing.T) { img := IMRead("images/face.jpg", IMReadColor) if img.Empty() { t.Error("Invalid Mat in CascadeClassifierWithParams test") } defer img.Close() // load classifier to recognize faces classifier := NewCascadeClassifier() defer classifier.Close() classifier.Load("data/haarcascade_frontalface_default.xml") rects := classifier.DetectMultiScaleWithParams(img, 1.1, 3, 0, image.Pt(0, 0), image.Pt(0, 0)) if len(rects) != 1 { t.Errorf("Error in CascadeClassifierWithParams test: %v", len(rects)) } } func TestHOGDescriptor(t *testing.T) { img := IMRead("images/face.jpg", IMReadColor) if img.Empty() { t.Error("Invalid Mat in HOGDescriptor test") } defer img.Close() // load HOGDescriptor to recognize people hog := NewHOGDescriptor() defer hog.Close() d := HOGDefaultPeopleDetector() defer d.Close() hog.SetSVMDetector(d) rects := hog.DetectMultiScale(img) if len(rects) != 1 { t.Errorf("Error in TestHOGDescriptor test: %d", len(rects)) } } func TestHOGDescriptorWithParams(t *testing.T) { img := IMRead("images/face.jpg", IMReadColor) if img.Empty() { t.Error("Invalid Mat in HOGDescriptorWithParams test") } defer img.Close() // load HOGDescriptor to recognize people hog := NewHOGDescriptor() defer hog.Close() d := HOGDefaultPeopleDetector() defer d.Close() hog.SetSVMDetector(d) rects := hog.DetectMultiScaleWithParams(img, 0, image.Pt(0, 0), image.Pt(0, 0), 1.05, 2.0, false) if len(rects) != 1 { t.Errorf("Error in TestHOGDescriptorWithParams test: %d", len(rects)) } } func TestGroupRectangles(t *testing.T) { rects := []image.Rectangle{ image.Rect(10, 10, 30, 30), image.Rect(10, 10, 30, 30), image.Rect(10, 10, 30, 30), image.Rect(10, 10, 30, 30), image.Rect(10, 10, 30, 30), image.Rect(10, 10, 30, 30), image.Rect(10, 10, 30, 30), image.Rect(10, 10, 30, 30), image.Rect(10, 10, 30, 30), image.Rect(10, 10, 30, 30), image.Rect(10, 10, 35, 35), image.Rect(10, 10, 35, 35), image.Rect(10, 10, 35, 35), image.Rect(10, 10, 35, 35), image.Rect(10, 10, 35, 35), image.Rect(10, 10, 35, 35), image.Rect(10, 10, 35, 35), image.Rect(10, 10, 35, 35), image.Rect(10, 10, 35, 35), image.Rect(10, 10, 35, 35), } results := GroupRectangles(rects, 1, 0.2) if len(results) != 2 { t.Errorf("Error in TestGroupRectangles test: %d", len(results)) } } func TestQRCodeDetector(t *testing.T) { img := IMRead("images/qrcode.png", IMReadColor) if img.Empty() { t.Error("Invalid Mat in QRCodeDetector test") } defer img.Close() // load QRCodeDetector to QR codes detector := NewQRCodeDetector() defer detector.Close() bbox := NewMat() qr := NewMat() defer bbox.Close() defer qr.Close() res := detector.Detect(img, &bbox) if !res { t.Errorf("Error in TestQRCodeDetector test: res == false") } res2 := detector.Decode(img, bbox, &qr) res3 := detector.DetectAndDecode(img, &bbox, &qr) if res2 != res3 { t.Errorf("Error in TestQRCodeDetector res2: %s != res3: %s", res2, res3) } // multi img2 := IMRead("images/multi_qrcodes.png", IMReadColor) defer img2.Close() if img2.Empty() { t.Error("Invalid Mat in QRCodeDetector test") } multiBox := NewMat() defer multiBox.Close() res4 := detector.DetectMulti(img2, &multiBox) if !res4 { t.Errorf("Error in TestQRCodeDetector Multi test: res == false") } if multiBox.Rows() != 2 { t.Errorf("Error in TestQRCodeDetector Multi test: number of Rows = %d", multiBox.Rows()) } multiBox2 := NewMat() defer multiBox2.Close() decoded := []string{} qrCodes := make([]Mat, 0) defer func() { for _, q := range qrCodes { q.Close() } }() success := detector.DetectAndDecodeMulti(img2, decoded, &multiBox2, qrCodes) if !success { t.Errorf("Error in TestQRCodeDetector Multi test: returned false") } tmpPoints := NewMat() defer tmpPoints.Close() tmpQr := NewMat() defer tmpQr.Close() var tmpDecoded string for i, s := range decoded { tmpInput := padQr(&(qrCodes[i])) defer tmpInput.Close() tmpDecoded = detector.Decode(tmpInput, tmpPoints, &tmpQr) if tmpDecoded != s { t.Errorf("Error in TestQRCodeDetector Multi test: decoded straight QR code=%s, decoded[%d] = %s", tmpDecoded, i, s) } } emptyMat := NewMatWithSize(100, 200, MatTypeCV8UC3) success = detector.DetectAndDecodeMulti(emptyMat, decoded, &multiBox2, qrCodes) if success { t.Errorf("Error in TestQRCodeDetector Multi test: empty Mat returned success=true") } emptyMat.Close() } func padQr(qr *Mat) Mat { l := 101 d := 10 L := l + 2*d out := NewMatWithSizeFromScalar(NewScalar(255, 255, 255, 255), L, L, MatTypeCV8UC3) qrCodes0 := NewMat() defer qrCodes0.Close() qr.ConvertTo(&qrCodes0, MatTypeCV8UC3) Resize(qrCodes0, &qrCodes0, image.Point{L, L}, 0, 0, InterpolationArea) CopyMakeBorder(qrCodes0, &out, d, d, d, d, BorderConstant, color.RGBA{255, 255, 255, 255}) return out } func TestFaceDetectorYN(t *testing.T) { img := IMRead("images/face.jpg", IMReadAnyColor) defer img.Close() s := image.Pt(img.Size()[1], img.Size()[0]) faces := NewMat() defer faces.Close() fd := NewFaceDetectorYN("testdata/face_detection_yunet_2023mar.onnx", "", s) defer fd.Close() sz := fd.GetInputSize() if sz.X != 640 && sz.Y != 480 { t.Error("error on FaceDetectorYN.GetInputSize()") } fd.SetInputSize(sz) t1 := fd.GetNMSThreshold() fd.SetNMSThreshold(t1) t2 := fd.GetScoreThreshold() fd.SetScoreThreshold(t2) topK := fd.GetTopK() fd.SetTopK(topK) fd.Detect(img, &faces) facesCount := faces.Rows() if facesCount < 1 { t.Error("no face detected") } } func TestFaceDetectorYNWithParams(t *testing.T) { img := IMRead("images/face.jpg", IMReadAnyColor) defer img.Close() s := image.Pt(img.Size()[1], img.Size()[0]) faces := NewMat() defer faces.Close() fd := NewFaceDetectorYNWithParams("testdata/face_detection_yunet_2023mar.onnx", "", s, 0.9, 0.3, 5000, 0, 0) defer fd.Close() sz := fd.GetInputSize() if sz.X != 640 && sz.Y != 480 { t.Error("error on FaceDetectorYN.GetInputSize()") } fd.SetInputSize(sz) t1 := fd.GetNMSThreshold() fd.SetNMSThreshold(t1) t2 := fd.GetScoreThreshold() fd.SetScoreThreshold(t2) topK := fd.GetTopK() fd.SetTopK(topK) fd.Detect(img, &faces) facesCount := faces.Rows() if facesCount < 1 { t.Error("no face detected") } } func TestFaceDetectorYNFromBytes(t *testing.T) { modelBuffer, err := os.ReadFile("testdata/face_detection_yunet_2023mar.onnx") if err != nil { t.Errorf("%s reading testdata/face_detection_yunet_2023mar.onnx", err.Error()) } img := IMRead("images/face.jpg", IMReadAnyColor) defer img.Close() s := image.Pt(img.Size()[1], img.Size()[0]) faces := NewMat() defer faces.Close() fd := NewFaceDetectorYNFromBytes("onnx", modelBuffer, []byte(""), s) defer fd.Close() sz := fd.GetInputSize() if sz.X != 640 && sz.Y != 480 { t.Error("error on FaceDetectorYN.GetInputSize()") } fd.SetInputSize(sz) t1 := fd.GetNMSThreshold() fd.SetNMSThreshold(t1) t2 := fd.GetScoreThreshold() fd.SetScoreThreshold(t2) topK := fd.GetTopK() fd.SetTopK(topK) fd.Detect(img, &faces) facesCount := faces.Rows() if facesCount < 1 { t.Error("no face detected") } } func TestFaceDetectorYNFromBytesWithParams(t *testing.T) { modelBuffer, err := os.ReadFile("testdata/face_detection_yunet_2023mar.onnx") if err != nil { t.Errorf("%s reading testdata/face_detection_yunet_2023mar.onnx", err.Error()) } img := IMRead("images/face.jpg", IMReadAnyColor) defer img.Close() s := image.Pt(img.Size()[1], img.Size()[0]) faces := NewMat() defer faces.Close() fd := NewFaceDetectorYNFromBytesWithParams("onnx", modelBuffer, []byte(""), s, 0.9, 0.3, 5000, 0, 0) defer fd.Close() sz := fd.GetInputSize() if sz.X != 640 && sz.Y != 480 { t.Error("error on FaceDetectorYN.GetInputSize()") } fd.SetInputSize(sz) t1 := fd.GetNMSThreshold() fd.SetNMSThreshold(t1) t2 := fd.GetScoreThreshold() fd.SetScoreThreshold(t2) topK := fd.GetTopK() fd.SetTopK(topK) fd.Detect(img, &faces) facesCount := faces.Rows() if facesCount < 1 { t.Error("no face detected") } } func TestFaceRecognizerSF(t *testing.T) { rons := IMRead("images/face.jpg", IMReadUnchanged) defer rons.Close() ronsImgSz := rons.Size() s := image.Pt(ronsImgSz[1], ronsImgSz[0]) fd := NewFaceDetectorYN("testdata/face_detection_yunet_2023mar.onnx", "", s) defer fd.Close() ronsFaces := NewMat() defer ronsFaces.Close() detectRv := fd.Detect(rons, &ronsFaces) t.Log("detect rv is", detectRv) facesCount := ronsFaces.Rows() if facesCount < 1 { t.Error("no face detected") } ronsFaceX0 := ronsFaces.GetFloatAt(0, 0) ronsFaceY0 := ronsFaces.GetFloatAt(0, 1) ronsFaceX1 := ronsFaces.GetFloatAt(0, 0) + ronsFaces.GetFloatAt(0, 2) ronsFaceY1 := ronsFaces.GetFloatAt(0, 1) + ronsFaces.GetFloatAt(0, 3) ronsFace := rons.Region(image.Rect(int(ronsFaceX0), int(ronsFaceY0), int(ronsFaceX1), int(ronsFaceY1))) defer ronsFace.Close() fr := NewFaceRecognizerSF("testdata/face_recognition_sface_2021dec.onnx", "") defer fr.Close() ronsAligned := NewMat() defer ronsAligned.Close() fr.AlignCrop(rons, ronsFace, &ronsAligned) if ronsAligned.Empty() { t.Error("aligned is empty") } ronsFaceFeature := NewMat() defer ronsFaceFeature.Close() fr.Feature(ronsAligned, &ronsFaceFeature) match := fr.Match(ronsFaceFeature, ronsFaceFeature) t.Log("face feature match: ", match) } func TestFaceRecognizerSFWithParams(t *testing.T) { rons := IMRead("images/face.jpg", IMReadUnchanged) defer rons.Close() ronsImgSz := rons.Size() s := image.Pt(ronsImgSz[1], ronsImgSz[0]) fd := NewFaceDetectorYN("testdata/face_detection_yunet_2023mar.onnx", "", s) defer fd.Close() ronsFaces := NewMat() defer ronsFaces.Close() detectRv := fd.Detect(rons, &ronsFaces) t.Log("detect rv is", detectRv) facesCount := ronsFaces.Rows() if facesCount < 1 { t.Error("no face detected") } ronsFaceX0 := ronsFaces.GetFloatAt(0, 0) ronsFaceY0 := ronsFaces.GetFloatAt(0, 1) ronsFaceX1 := ronsFaces.GetFloatAt(0, 0) + ronsFaces.GetFloatAt(0, 2) ronsFaceY1 := ronsFaces.GetFloatAt(0, 1) + ronsFaces.GetFloatAt(0, 3) ronsFace := rons.Region(image.Rect(int(ronsFaceX0), int(ronsFaceY0), int(ronsFaceX1), int(ronsFaceY1))) defer ronsFace.Close() fr := NewFaceRecognizerSFWithParams("testdata/face_recognition_sface_2021dec.onnx", "", 0, 0) defer fr.Close() ronsAligned := NewMat() defer ronsAligned.Close() fr.AlignCrop(rons, ronsFace, &ronsAligned) if ronsAligned.Empty() { t.Error("aligned is empty") } ronsFaceFeature := NewMat() defer ronsFaceFeature.Close() fr.Feature(ronsAligned, &ronsFaceFeature) match := fr.MatchWithParams(ronsFaceFeature, ronsFaceFeature, FaceRecognizerSFDisTypeCosine) t.Log("face feature match: ", match) } ================================================ FILE: openvino/README.md ================================================ # Using the Intel® Distribution of OpenVINO™ toolkit The [Intel® Distribution of OpenVINO™ toolkit](https://software.intel.com/en-us/openvino-toolkit) is a set of tools and libraries for computer vision applications, that uses computer vision and imaging algorithms developed at Intel. It also includes a complete build of OpenCV 4.5.5. Users must build opencv from source with openvino support to use a newer opencv version (eg. 4.6.0). GoCV supports using the Intel GPU or Intel OpenVINO Inference Engine as a backend for the OpenCV deep neural network (DNN) module. For details, please see: https://github.com/hybridgroup/gocv/blob/release/openvino/ie/README.md ## Installing Intel OpenVINO toolkit The most recent version of the Intel OpenVINO toolkit is currently 2022.1 LTS. You can obtain it from here: https://software.intel.com/en-us/openvino-toolkit One you have downloaded the compressed file, unzip the contents, and then run the `install.sh` program within the extracted directory. ## How to build/run code Setup the environment for the Intel OpenVINO toolkit, by running the `setupvars.sh` program included with OpenVINO: ``` source /opt/intel/openvino_2022/setupvars.sh ``` Then set the needed other exports for building/running GoCV code by running the `env.sh` that is in the GoCV `openvino` directory: ``` source openvino/env.sh ``` You only need to do these two steps one time per session. Once you have run them, you do not need to run them again until you close your terminal window. Now you can run the version command example to make sure you are compiling/linking against Intel OpenVINO: ``` $ go run -tags customenv ./cmd/version/main.go gocv version: 0.31.0 opencv lib version: 4.5.5-openvino ``` Note the use of `-tags customenv` is needed when using `go run`, `go build`, and `go test` with OpenVINO, so the CGo compiler can pickup the correct settings for the environment, and ignore the usual defaults. Examples that use the Intel OpenVINO toolkit can be found in the `cmd/openvino` directory of this repository. ================================================ FILE: openvino/env.sh ================================================ export CGO_CXXFLAGS="--std=c++11" export CGO_CPPFLAGS="-I${INTEL_OPENVINO_DIR}/extras/opencv/include -I${INTEL_OPENVINO_DIR}/runtime/include -I${INTEL_OPENVINO_DIR}/runtime/include/ie" export CGO_LDFLAGS="-L${INTEL_OPENVINO_DIR}/extras/opencv/lib -L${INTEL_OPENVINO_DIR}/runtime/lib/intel64 -lpthread -ldl -lopenvino -lopencv_core -lopencv_videoio -lopencv_imgproc -lopencv_highgui -lopencv_imgcodecs -lopencv_objdetect -lopencv_features2d -lopencv_video -lopencv_dnn -lopencv_calib3d -lopencv_photo" export PKG_CONFIG_PATH=/usr/lib64/pkgconfig ================================================ FILE: openvino/ie/README.md ================================================ # Using the Intel OpenVINO Inference Engine The Intel OpenVINO Inference Engine is a set of libraries for executing convolutional neural networks. GoCV support for the Intel OpenVINO Inference Engine will be able to be found here in the "gocv.io/x/gocv/openvino/ie" package. ## How It Works Support in GoCV for the Intel OpenVINO Inference Engine requires version 2019 R3+ in order to work. ## How to use This code loads a Caffe model, and then uses OpenVINO inference engine to prepare it for execution on the GPU: ```go net := gocv.ReadNet("/path/to/your/model.caffemodel", "/path/to/your/config.proto") if net.Empty() { fmt.Println("Error reading network model") return } // GPU usage net.SetPreferableBackend(gocv.NetBackendType(gocv.NetBackendOpenVINO)) net.SetPreferableTarget(gocv.NetTargetType(gocv.NetTargetFP16)) // Intel Neural Compute Stick 2 usage net.SetPreferableBackend(gocv.NetBackendType(gocv.NetBackendOpenVINO)) net.SetPreferableTarget(gocv.NetTargetType(gocv.NetTargetVPU)) ``` ================================================ FILE: openvino/ie/ie.go ================================================ // Package ie is the GoCV wrapper around the Intel OpenVINO toolkit's // Inference Engine. // // For further details, please see: // https://software.intel.com/en-us/openvino-toolkit package ie // import "gocv.io/x/gocv/openvino/ie" ================================================ FILE: openvino/ie/inference_engine.cpp ================================================ #include "inference_engine.h" const char* OpenVinoVersion() { std::ostringstream buf; buf << std::to_string(InferenceEngine::GetInferenceEngineVersion()->apiVersion.major) << "." << std::to_string(InferenceEngine::GetInferenceEngineVersion()->apiVersion.minor) << "." << InferenceEngine::GetInferenceEngineVersion()->buildNumber; auto version = buf.str(); size_t resLen = version.size() + 1; auto res = (char*)malloc(resLen); memset(res ,0, resLen); memcpy(res, version.c_str(), resLen); return res; } ================================================ FILE: openvino/ie/inference_engine.go ================================================ package ie /* #include #include "inference_engine.h" */ import ( "C" ) import "unsafe" // Version returns the current Inference Engine library version func Version() string { v := C.OpenVinoVersion() defer C.free(unsafe.Pointer(v)) return C.GoString(v) } ================================================ FILE: openvino/ie/inference_engine.h ================================================ #ifndef _GOCVOPENVINO_IE_H_ #define _GOCVOPENVINO_IE_H_ #ifdef __cplusplus #include extern "C" { #endif #ifdef __cplusplus #else #endif const char* OpenVinoVersion(); #ifdef __cplusplus } #endif #endif //_GOCVOPENVINO_IE_H_ ================================================ FILE: openvino/ie/inference_engine_test.go ================================================ package ie import ( "strings" "testing" ) func TestInferenceEngineVersion(t *testing.T) { v := Version() expected := "2022.1" if v == "" || len(v) < len(expected) { t.Error("Invalid IE Version") return } // Different platforms can have different strings, only warn if expected // version string does not match. // eg. archlinux: 2.1.custom_makepkg_cdb9bec7210f8c24fde3e416c7ada820faaaa23e if !strings.Contains(v, expected) { t.Log("Unexpected IE Version: ", v) } } ================================================ FILE: openvino/openvino.go ================================================ // Package openvino is the GoCV wrapper around the Intel OpenVINO toolkit. // // For further details, please see: // https://software.intel.com/en-us/openvino-toolkit package openvino // import "gocv.io/x/gocv/openvino" ================================================ FILE: patches/gstreamer-full.patch ================================================ From a784b9d05fddd0078b41a18377f4ced380fd53f0 Mon Sep 17 00:00:00 2001 From: deadprogram Date: Mon, 21 Oct 2024 10:08:11 +0200 Subject: [PATCH] gstreamer: modify cmake file to handle staticly linked gstreamer lib Signed-off-by: deadprogram --- modules/videoio/cmake/detect_gstreamer.cmake | 233 ++++++++++++++++++- 1 file changed, 232 insertions(+), 1 deletion(-) diff --git a/modules/videoio/cmake/detect_gstreamer.cmake b/modules/videoio/cmake/detect_gstreamer.cmake index b2ab06060d..ae148a3a1d 100644 --- a/modules/videoio/cmake/detect_gstreamer.cmake +++ b/modules/videoio/cmake/detect_gstreamer.cmake @@ -100,7 +100,238 @@ if(NOT HAVE_GSTREAMER AND PKG_CONFIG_FOUND) ocv_check_modules(GSTREAMER_pbutils gstreamer-pbutils-1.0) ocv_check_modules(GSTREAMER_video gstreamer-video-1.0) ocv_check_modules(GSTREAMER_audio gstreamer-audio-1.0) - if(GSTREAMER_base_FOUND AND GSTREAMER_app_FOUND AND GSTREAMER_riff_FOUND AND GSTREAMER_pbutils_FOUND AND GSTREAMER_video_FOUND AND GSTREAMER_audio_FOUND) + + set(gst_paths "${GSTREAMER_STATIC_LIB}" ENV GSTREAMER_STATIC_LIB) + find_library(GSTREAMER_full_LIBRARY + NAMES gstreamer-full-1.0 + PATHS ${gst_paths}/..) + if(GSTREAMER_base_FOUND AND GSTREAMER_full_LIBRARY) + find_library(GSTREAMER_gstcoreelements_LIBRARY + NAMES gstcoreelements + PATHS ${gst_paths}) + find_library(GSTREAMER_gstapp1_LIBRARY + NAMES gstapp + PATHS ${gst_paths}) + find_library(GSTREAMER_gstplayback_LIBRARY + NAMES gstplayback + PATHS ${gst_paths}) + find_library(GSTREAMER_gstrawparse_LIBRARY + NAMES gstrawparse + PATHS ${gst_paths}) + find_library(GSTREAMER_gsttcp_LIBRARY + NAMES gsttcp + PATHS ${gst_paths}) + find_library(GSTREAMER_gstvideoconvertscale_LIBRARY + NAMES gstvideoconvertscale + PATHS ${gst_paths}) + find_library(GSTREAMER_gstvideotestsrc_LIBRARY + NAMES gstvideotestsrc + PATHS ${gst_paths}) + find_library(GSTREAMER_gstaudioparsers_LIBRARY + NAMES gstaudioparsers + PATHS ${gst_paths}) + find_library(GSTREAMER_gstisomp4_LIBRARY + NAMES gstisomp4 + PATHS ${gst_paths}) + find_library(GSTREAMER_gstrtp_LIBRARY + NAMES gstrtp + PATHS ${gst_paths}) + find_library(GSTREAMER_gstrtpmanager_LIBRARY + NAMES gstrtpmanager + PATHS ${gst_paths}) + find_library(GSTREAMER_gstrtsp_LIBRARY + NAMES gstrtsp + PATHS ${gst_paths}) + find_library(GSTREAMER_gstudp_LIBRARY + NAMES gstudp + PATHS ${gst_paths}) + find_library(GSTREAMER_gstcodectimestamper_LIBRARY + NAMES gstcodectimestamper + PATHS ${gst_paths}) + find_library(GSTREAMER_gstvideoparsersbad_LIBRARY + NAMES gstvideoparsersbad + PATHS ${gst_paths}) + find_library(GSTREAMER_gstopenh264_LIBRARY + NAMES gstopenh264 + PATHS ${gst_paths}) + find_library(GSTREAMER_gstadaptivedemux_LIBRARY + NAMES gstadaptivedemux-1.0 + PATHS ${gst_paths}/..) + find_library(GSTREAMER_gstallocators_LIBRARY + NAMES gstallocators-1.0 + PATHS ${gst_paths}/..) + find_library(GSTREAMER_gstanalytics_LIBRARY + NAMES gstanalytics-1.0 + PATHS ${gst_paths}/..) + find_library(GSTREAMER_gstapp_LIBRARY + NAMES gstapp-1.0 + PATHS ${gst_paths}/..) + find_library(GSTREAMER_gstaudio_LIBRARY + NAMES gstaudio-1.0 + PATHS ${gst_paths}/..) + find_library(GSTREAMER_gstbadaudio_LIBRARY + NAMES gstbadaudio-1.0 + PATHS ${gst_paths}/..) + find_library(GSTREAMER_gstbase_LIBRARY + NAMES gstbase-1.0 + PATHS ${gst_paths}/..) + find_library(GSTREAMER_gstbasecamerabinsrc_LIBRARY + NAMES gstbasecamerabinsrc-1.0 + PATHS ${gst_paths}/..) + find_library(GSTREAMER_gstcodecparsers_LIBRARY + NAMES gstcodecparsers-1.0 + PATHS ${gst_paths}/..) + find_library(GSTREAMER_gstcodecs_LIBRARY + NAMES gstcodecs-1.0 + PATHS ${gst_paths}/..) + find_library(GSTREAMER_gstcontroller_LIBRARY + NAMES gstcontroller-1.0 + PATHS ${gst_paths}/..) + find_library(GSTREAMER_gstcuda_LIBRARY + NAMES gstcuda-1.0 + PATHS ${gst_paths}/..) + find_library(GSTREAMER_gstfft_LIBRARY + NAMES gstfft-1.0 + PATHS ${gst_paths}/..) + find_library(GSTREAMER_gstinsertbin_LIBRARY + NAMES gstinsertbin-1.0 + PATHS ${gst_paths}/..) + find_library(GSTREAMER_gstisoff_LIBRARY + NAMES gstisoff-1.0 + PATHS ${gst_paths}/..) + find_library(GSTREAMER_gstmpegts_LIBRARY + NAMES gstmpegts-1.0 + PATHS ${gst_paths}/..) + find_library(GSTREAMER_gstmse_LIBRARY + NAMES gstmse-1.0 + PATHS ${gst_paths}/..) + find_library(GSTREAMER_gstnet_LIBRARY + NAMES gstnet-1.0 + PATHS ${gst_paths}/..) + find_library(GSTREAMER_gstpbutils_LIBRARY + NAMES gstpbutils-1.0 + PATHS ${gst_paths}/..) + find_library(GSTREAMER_gstphotography_LIBRARY + NAMES gstphotography-1.0 + PATHS ${gst_paths}/..) + find_library(GSTREAMER_gstplay_LIBRARY + NAMES gstplay-1.0 + PATHS ${gst_paths}/..) + find_library(GSTREAMER_gstplayer_LIBRARY + NAMES gstplayer-1.0 + PATHS ${gst_paths}/..) + find_library(GSTREAMER_gstreamer_LIBRARY + NAMES gstreamer-1.0 + PATHS ${gst_paths}/..) + find_library(GSTREAMER_gstriff_LIBRARY + NAMES gstriff-1.0 + PATHS ${gst_paths}/..) + find_library(GSTREAMER_gstrtp1_LIBRARY + NAMES gstrtp-1.0 + PATHS ${gst_paths}/..) + find_library(GSTREAMER_gstrtsp1_LIBRARY + NAMES gstrtsp-1.0 + PATHS ${gst_paths}/..) + find_library(GSTREAMER_gstsctp_LIBRARY + NAMES gstsctp-1.0 + PATHS ${gst_paths}/..) + find_library(GSTREAMER_gstsdp_LIBRARY + NAMES gstsdp-1.0 + PATHS ${gst_paths}/..) + find_library(GSTREAMER_gsttag_LIBRARY + NAMES gsttag-1.0 + PATHS ${gst_paths}/..) + find_library(GSTREAMER_gsttranscoder_LIBRARY + NAMES gsttranscoder-1.0 + PATHS ${gst_paths}/..) + find_library(GSTREAMER_gsturidownloader_LIBRARY + NAMES gsturidownloader-1.0 + PATHS ${gst_paths}/..) + find_library(GSTREAMER_gstvideo_LIBRARY + NAMES gstvideo-1.0 + PATHS ${gst_paths}/..) + find_library(GSTREAMER_gstwebrtc_LIBRARY + NAMES gstwebrtc-1.0 + PATHS ${gst_paths}/..) + find_library(GSTREAMER_openh264_LIBRARY + NAMES openh264 + PATHS ${gst_paths}/..) + find_library(GSTREAMER_gio_LIBRARY + NAMES gio-2.0) + find_library(GSTREAMER_gobject_LIBRARY + NAMES gobject-2.0) + find_library(GSTREAMER_intl_LIBRARY + NAMES intl) + + set(HAVE_GSTREAMER TRUE) + set(GSTREAMER_LIBRARIES ${GSTREAMER_full_LIBRARY} + ${GSTREAMER_gstcoreelements_LIBRARY} + ${GSTREAMER_gstapp1_LIBRARY} + ${GSTREAMER_gstplayback_LIBRARY} + ${GSTREAMER_gstrawparse_LIBRARY} + ${GSTREAMER_gsttcp_LIBRARY} + ${GSTREAMER_gstvideoconvertscale_LIBRARY} + ${GSTREAMER_gstvideotestsrc_LIBRARY} + ${GSTREAMER_gstaudioparsers_LIBRARY} + ${GSTREAMER_gstisomp4_LIBRARY} + ${GSTREAMER_gstrtp_LIBRARY} + ${GSTREAMER_gstrtpmanager_LIBRARY} + ${GSTREAMER_gstrtsp_LIBRARY} + ${GSTREAMER_gstudp_LIBRARY} + ${GSTREAMER_gstcodectimestamper_LIBRARY} + ${GSTREAMER_gstvideoparsersbad_LIBRARY} + ${GSTREAMER_gstopenh264_LIBRARY} + ${GSTREAMER_gstadaptivedemux_LIBRARY} + ${GSTREAMER_gstallocators_LIBRARY} + ${GSTREAMER_gstanalytics_LIBRARY} + ${GSTREAMER_gstapp_LIBRARY} + ${GSTREAMER_gstaudio_LIBRARY} + ${GSTREAMER_gstbadaudio_LIBRARY} + ${GSTREAMER_gstbase_LIBRARY} + ${GSTREAMER_gstbasecamerabinsrc_LIBRARY} + ${GSTREAMER_gstcodecparsers_LIBRARY} + ${GSTREAMER_gstcodecs_LIBRARY} + ${GSTREAMER_gstcontroller_LIBRARY} + ${GSTREAMER_gstcuda_LIBRARY} + ${GSTREAMER_gstfft_LIBRARY} + ${GSTREAMER_gstinsertbin_LIBRARY} + ${GSTREAMER_gstisoff_LIBRARY} + ${GSTREAMER_gstmpegts_LIBRARY} + ${GSTREAMER_gstmse_LIBRARY} + ${GSTREAMER_gstnet_LIBRARY} + ${GSTREAMER_gstpbutils_LIBRARY} + ${GSTREAMER_gstphotography_LIBRARY} + ${GSTREAMER_gstplay_LIBRARY} + ${GSTREAMER_gstplayer_LIBRARY} + ${GSTREAMER_gstreamer_LIBRARY} + ${GSTREAMER_gstriff_LIBRARY} + ${GSTREAMER_gstrtp1_LIBRARY} + ${GSTREAMER_gstrtsp1_LIBRARY} + ${GSTREAMER_gstsctp_LIBRARY} + ${GSTREAMER_gstsdp_LIBRARY} + ${GSTREAMER_gsttag_LIBRARY} + ${GSTREAMER_gsttranscoder_LIBRARY} + ${GSTREAMER_gsturidownloader_LIBRARY} + ${GSTREAMER_gstvideo_LIBRARY} + ${GSTREAMER_gstwebrtc_LIBRARY} + ${GSTREAMER_openh264_LIBRARY} + ${GSTREAMER_gio_LIBRARY} + ${GSTREAMER_gobject_LIBRARY} + ${GSTREAMER_intl_LIBRARY} + ${GSTREAMER_base_LIBRARIES} + ${GSTREAMER_app_LIBRARIES} + ${GSTREAMER_riff_LIBRARIES} + ${GSTREAMER_pbutils_LIBRARIES} + ${GSTREAMER_video_LIBRARIES} + ${GSTREAMER_audio_LIBRARIES}) + set(GSTREAMER_INCLUDE_DIRS + ${GSTREAMER_base_INCLUDE_DIRS} + ${GSTREAMER_app_INCLUDE_DIRS} + ${GSTREAMER_riff_INCLUDE_DIRS} + ${GSTREAMER_pbutils_INCLUDE_DIRS} + ${GSTREAMER_video_INCLUDE_DIRS} + ${GSTREAMER_audio_INCLUDE_DIRS}) + else(GSTREAMER_base_FOUND AND GSTREAMER_app_FOUND AND GSTREAMER_riff_FOUND AND GSTREAMER_pbutils_FOUND AND GSTREAMER_video_FOUND AND GSTREAMER_audio_FOUND) set(HAVE_GSTREAMER TRUE) set(GSTREAMER_VERSION ${GSTREAMER_base_VERSION}) # informational set(GSTREAMER_LIBRARIES ${GSTREAMER_base_LIBRARIES} ${GSTREAMER_app_LIBRARIES} ${GSTREAMER_riff_LIBRARIES} ${GSTREAMER_pbutils_LIBRARIES} ${GSTREAMER_video_LIBRARIES} ${GSTREAMER_audio_LIBRARIES}) -- 2.34.1 ================================================ FILE: persistence.h ================================================ #ifndef _OPENCV3_PERSISTENCE_H_ #define _OPENCV3_PERSISTENCE_H_ #include #ifdef __cplusplus #include extern "C" { #endif #include "core.h" #ifdef __cplusplus typedef cv::FileStorage* FileStorage; typedef cv::FileNode* FileNode; #else typedef void* FileStorage; typedef void* FileNode; #endif // FileStorage FileStorage FileStorage_Create(void); FileStorage FileStorage_CreateWithParams(const char* filename, int flags, const char* encoding); void FileStorage_Close(FileStorage fs); const char *FileStorage_ElName(FileStorage fs); int FileStorage_State(FileStorage fs); void FileStorage_EndWriteStruct(FileStorage fs); int FileStorage_GetFormat(FileStorage fs); bool FileStorage_IsOpened(FileStorage fs); bool FileStorage_Open(FileStorage fs, const char* filename, int flags, const char* encoding); void FileStorage_Release(FileStorage fs); const char* FileStorage_ReleaseAndGetString(FileStorage fs); void FileStorage_StartWriteStruct(FileStorage fs, const char* name, int flags, const char* typeName); void FileStorage_WriteMat(FileStorage fs, const char* name, Mat val); void FileStorage_WriteString(FileStorage fs, const char* name, const char* val); void FileStorage_WriteStringArray(FileStorage fs, const char* name, const char** val, size_t len); void FileStorage_WriteDouble(FileStorage fs, const char* name, double val); void FileStorage_WriteInt(FileStorage fs, const char* name, int val); void FileStorage_WriteComment(FileStorage fs, const char* comment, bool append); void FileStorage_WriteRaw(FileStorage fs, const char* fmt, const void* vec, size_t len); FileNode FileStorage_GetFirstTopLevelNode(FileStorage fs); FileNode FileStorage_GetNode(FileStorage fs, const char* nodename); FileNode FileStorage_Root(FileStorage fs, int streamidx); bool FileNode_Empty(FileNode fn); bool FileNode_IsInt(FileNode fn); bool FileNode_IsMap(FileNode fn); bool FileNode_IsNamed(FileNode fn); bool FileNode_IsNone(FileNode fn); bool FileNode_IsReal(FileNode fn); bool FileNode_IsSeq(FileNode fn); bool FileNode_IsString(FileNode fn); char** FileNode_Keys(FileNode fn); size_t FileNode_KeysCount(FileNode fn); void FileNode_KeysFree(char** keys, size_t len); Mat FileNode_Mat(FileNode fn); const char* FileNode_Name(FileNode fn); float FileNode_Float(FileNode fn); const char* FileNode_String(FileNode fn); FileNode FileNode_Get(FileNode fn, int i); //FileNode operator[] (int i) const FileNode FileNode_GetByName(FileNode fn, const char* nodename); //FileNode operator[] (const char *nodename) const size_t FileNode_RawSize(FileNode fn); void FileNode_ReadRaw(FileNode fn, const char* fmt, void *vec, size_t len); void FileNode_SetValue(FileNode fn, int type, const void *value, int len); size_t FileNode_Size(FileNode fn); int FileNode_Type(FileNode fn); void FileNode_Close(FileNode fn); #ifdef __cplusplus } #endif #endif //_OPENCV3_PERSISTENCE_H_ ================================================ FILE: persistence_filenode.cpp ================================================ #include #include "persistence.h" bool FileNode_Empty(FileNode fn) { return fn->empty(); } bool FileNode_IsInt(FileNode fn){ return fn->isInt(); } bool FileNode_IsMap(FileNode fn){ return fn->isMap(); } bool FileNode_IsNamed(FileNode fn) { return fn->isNamed(); } bool FileNode_IsNone(FileNode fn){ return fn->isNone(); } bool FileNode_IsReal(FileNode fn){ return fn->isReal(); } bool FileNode_IsSeq(FileNode fn) { return fn->isSeq(); } bool FileNode_IsString(FileNode fn) { return fn->isString(); } char** FileNode_Keys(FileNode fn) { std::vector keys = fn->keys(); char** c_keys = new char*[keys.size()]; for (int i = 0; i < keys.size(); i++) { char *c_key = new char[keys[i].length()+1]; strcpy(c_key, keys[i].c_str()); c_keys[i] = c_key; } return c_keys; } size_t FileNode_KeysCount(FileNode fn) { return fn->keys().size(); } void FileNode_KeysFree(char** keys, size_t len) { for(int i = 0; i < len; i++) { delete keys[i]; } delete keys; } Mat FileNode_Mat(FileNode fn) { return new cv::Mat(fn->mat()); } const char* FileNode_Name(FileNode fn) { char* str = new char[fn->name().length()+1]; strcpy(str, fn->name().c_str()); return str; } float FileNode_Float(FileNode fn) { return (float)fn->real(); } const char* FileNode_String(FileNode fn) { char* str = new char[fn->string().length()+1]; strcpy(str, fn->string().c_str()); return str; } FileNode FileNode_Get(FileNode fn, int i) { return new cv::FileNode((*fn)[i]); } FileNode FileNode_GetByName(FileNode fn, const char* nodename) { return new cv::FileNode((*fn)[nodename]); } size_t FileNode_RawSize(FileNode fn) { return fn->rawSize(); } void FileNode_ReadRaw(FileNode fn, const char* fmt, void *vec, size_t len) { fn->readRaw(fmt, vec, len); } void FileNode_SetValue(FileNode fn, int type, const void *value, int len) { fn->setValue(type, value, len); } size_t FileNode_Size(FileNode fn) { return fn->size(); } int FileNode_Type(FileNode fn) { return fn->type(); } void FileNode_Close(FileNode fn){ delete fn; } ================================================ FILE: persistence_filenode.go ================================================ package gocv /* #include #include "persistence.h" */ import "C" import "unsafe" type FileNodeType int const ( FileNodeTypeNone FileNodeType = 0 FileNodeTypeInt FileNodeType = 1 FileNodeTypeReal FileNodeType = 2 FileNodeTypeFloat FileNodeType = FileNodeTypeReal FileNodeTypeStr FileNodeType = 3 FileNodeTypeString FileNodeType = FileNodeTypeStr FileNodeTypeSeq FileNodeType = 4 FileNodeTypeMap FileNodeType = 5 FileNodeTypeTypeMask FileNodeType = 7 FileNodeTypeFlow FileNodeType = 8 FileNodeTypeUniform FileNodeType = 8 FileNodeTypeEmpty FileNodeType = 16 FileNodeTypeNamed FileNodeType = 32 ) // FileNode is a wrapper for the OpenCV FileNode class // // Ref: https://docs.opencv.org/4.x/de/dd9/classcv_1_1FileNode.html type FileNode struct { p C.FileNode } func (fn *FileNode) Ptr() C.FileNode { return fn.p } func (fn *FileNode) Empty() bool { return bool(C.FileNode_Empty(fn.p)) } func (fn *FileNode) IsInt() bool { return bool(C.FileNode_IsInt(fn.p)) } func (fn *FileNode) IsMap() bool { return bool(C.FileNode_IsMap(fn.p)) } func (fn *FileNode) IsNamed() bool { return bool(C.FileNode_IsNamed(fn.p)) } func (fn *FileNode) IsNone() bool { return bool(C.FileNode_IsNone(fn.p)) } func (fn *FileNode) IsReal() bool { return bool(C.FileNode_IsReal(fn.p)) } func (fn *FileNode) IsSeq() bool { return bool(C.FileNode_IsSeq(fn.p)) } func (fn *FileNode) IsString() bool { return bool(C.FileNode_IsString(fn.p)) } func (fn *FileNode) Keys() []string { c_keys_count := C.FileNode_KeysCount(fn.p) c_keys := C.FileNode_Keys(fn.p) defer C.FileNode_KeysFree(c_keys, c_keys_count) keys := make([]string, int(c_keys_count)) c_keys_slice := unsafe.Slice(c_keys, c_keys_count) for i := 0; i < int(c_keys_count); i++ { keys[i] = C.GoString(c_keys_slice[i]) } return keys } func (fn *FileNode) Close() { C.FileNode_Close(fn.p) } ================================================ FILE: persistence_filestorage.cpp ================================================ #include #include "persistence.h" FileStorage FileStorage_Create(void) { return new cv::FileStorage(); } FileStorage FileStorage_CreateWithParams(const char* filename, int flags, const char* encoding) { return new cv::FileStorage(filename, flags, encoding); } const char *FileStorage_ElName(FileStorage fs) { char* str = new char[fs->elname.length()+1]; strcpy(str, fs->elname.c_str()); return str; } int FileStorage_State(FileStorage fs) { return fs->state; } void FileStorage_Close(FileStorage fs) { fs->release(); delete fs; } void FileStorage_EndWriteStruct(FileStorage fs) { fs->endWriteStruct(); } int FileStorage_GetFormat(FileStorage fs){ return fs->getFormat(); } bool FileStorage_IsOpened(FileStorage fs) { return fs->isOpened(); } bool FileStorage_Open(FileStorage fs, const char* filename, int flags, const char* encoding) { return fs->open(filename, flags, encoding); } void FileStorage_Release(FileStorage fs) { fs->release(); delete fs; } const char* FileStorage_ReleaseAndGetString(FileStorage fs) { cv::String s = fs->releaseAndGetString(); char* str = new char[s.length()+1]; strcpy(str, s.c_str()); return str; } void FileStorage_StartWriteStruct(FileStorage fs, const char* name, int flags, const char* typeName){ fs->startWriteStruct(name, flags, typeName); } void FileStorage_WriteMat(FileStorage fs, const char* name, Mat val){ fs->write(name, *val); } void FileStorage_WriteString(FileStorage fs, const char* name, const char* val) { fs->write(name, val); } void FileStorage_WriteStringArray(FileStorage fs, const char* name, const char** val, size_t len) { std::vector vals; for(int i = 0; i < len; i++) { vals.push_back(val[i]); } fs->write(name, vals); } void FileStorage_WriteDouble(FileStorage fs, const char* name, double val){ fs->write(name, val); } void FileStorage_WriteInt(FileStorage fs, const char* name, int val){ fs->write(name, val); } void FileStorage_WriteComment(FileStorage fs, const char* comment, bool append){ fs->writeComment(comment, append); } void FileStorage_WriteRaw(FileStorage fs, const char* fmt, const void* vec, size_t len){ fs->writeRaw(fmt, vec, len); } FileNode FileStorage_GetFirstTopLevelNode(FileStorage fs) { cv::FileNode node = fs->getFirstTopLevelNode(); FileNode fn = new cv::FileNode(node); return fn; } FileNode FileStorage_GetNode(FileStorage fs, const char* nodename) { cv::FileNode node = (*fs)[nodename]; FileNode fn = new cv::FileNode(node); return fn; } FileNode FileStorage_Root(FileStorage fs, int streamidx) { cv::FileNode node = fs->root(streamidx); FileNode fn = new cv::FileNode(node); return fn; } ================================================ FILE: persistence_filestorage.go ================================================ package gocv /* #include #include #include "persistence.h" */ import "C" import "unsafe" type FileStorageMode int const ( FileStorageModeRead FileStorageMode = 0 FileStorageModeWrite FileStorageMode = 1 FileStorageModeAppend FileStorageMode = 2 FileStorageModeMemory FileStorageMode = 4 FileStorageModeFormatMask FileStorageMode = (7 << 3) FileStorageModeFormatAuto FileStorageMode = 0 FileStorageModeFormatXml FileStorageMode = (1 << 3) FileStorageModeFormatYaml FileStorageMode = (2 << 3) FileStorageModeFormatJson FileStorageMode = (3 << 3) FileStorageModeBase64 FileStorageMode = 64 FileStorageModeWriteBase64 FileStorageMode = FileStorageModeBase64 | FileStorageModeWrite ) type FileStorageState int const ( FileStorageStateUndefined FileStorageState = 0 FileStorageStateValueExpected FileStorageState = 1 FileStorageStateNameExpected FileStorageState = 2 FileStorageStateInsideMap FileStorageState = 4 ) // FileStorage is a wrapper for the OpenCV FileStorage class // // Ref: https://docs.opencv.org/4.x/da/d56/classcv_1_1FileStorage.html type FileStorage struct { p C.FileStorage } func NewFileStorage() *FileStorage { return &FileStorage{p: C.FileStorage_Create()} } func NewFileStorageWithParams(filename string, flags FileStorageMode, encoding string) *FileStorage { c_filename := C.CString(filename) c_encoding := C.CString(encoding) defer C.free(unsafe.Pointer(c_filename)) defer C.free(unsafe.Pointer(c_encoding)) return &FileStorage{p: C.FileStorage_CreateWithParams(c_filename, C.int(flags), c_encoding)} } func (fs *FileStorage) Close() { fs.Release() } func (fs *FileStorage) Release() { C.FileStorage_Release(fs.p) } func (fs *FileStorage) ElName() string { c_str := C.FileStorage_ElName(fs.p) defer C.free(unsafe.Pointer(c_str)) str := C.GoString(c_str) return str } func (fs *FileStorage) State() FileStorageState { state := C.FileStorage_State(fs.p) return FileStorageState(int(state)) } func (fs *FileStorage) EndWriteStruct() { C.FileStorage_EndWriteStruct(fs.p) } func (fs *FileStorage) GetFormat() FileStorageMode { fmt := C.FileStorage_GetFormat(fs.p) return FileStorageMode(int(fmt)) } func (fs *FileStorage) IsOpened() bool { b := C.FileStorage_IsOpened(fs.p) return bool(b) } func (fs *FileStorage) Open(filename string, flags FileStorageMode, encoding string) bool { c_filename := C.CString(filename) c_encoding := C.CString(encoding) defer C.free(unsafe.Pointer(c_filename)) defer C.free(unsafe.Pointer(c_encoding)) b := C.FileStorage_Open(fs.p, c_filename, C.int(flags), c_encoding) return bool(b) } func (fs *FileStorage) ReleaseAndGetString() string { c_str := C.FileStorage_ReleaseAndGetString(fs.p) defer C.free(unsafe.Pointer(c_str)) str := C.GoString(c_str) return str } func (fs *FileStorage) StartWriteStruct(name string, flags FileNodeType, typeName string) { c_name := C.CString(name) c_typeName := C.CString(typeName) defer C.free(unsafe.Pointer(c_name)) defer C.free(unsafe.Pointer(c_typeName)) C.FileStorage_StartWriteStruct(fs.p, c_name, C.int(flags), c_typeName) } func (fs *FileStorage) WriteMat(name string, mat Mat) { c_name := C.CString(name) defer C.free(unsafe.Pointer(c_name)) C.FileStorage_WriteMat(fs.p, c_name, mat.p) } func (fs *FileStorage) WriteString(name string, val string) { c_name := C.CString(name) c_val := C.CString(val) defer C.free(unsafe.Pointer(c_name)) defer C.free(unsafe.Pointer(c_val)) C.FileStorage_WriteString(fs.p, c_name, c_val) } func (fs *FileStorage) WriteStringArray(name string, val []string) { c_name := C.CString(name) defer C.free(unsafe.Pointer(c_name)) c_val := make([]*C.char, 0, len(val)) for _, v := range val { c_val = append(c_val, C.CString(v)) } defer func() { for _, p := range c_val { C.free(unsafe.Pointer(p)) } }() C.FileStorage_WriteStringArray(fs.p, c_name, &c_val[0], C.size_t(len(val))) } func (fs *FileStorage) WriteDouble(name string, val float32) { c_name := C.CString(name) defer C.free(unsafe.Pointer(c_name)) C.FileStorage_WriteDouble(fs.p, c_name, C.double(val)) } func (fs *FileStorage) WriteInt(name string, val int) { c_name := C.CString(name) defer C.free(unsafe.Pointer(c_name)) C.FileStorage_WriteInt(fs.p, c_name, C.int(val)) } func (fs *FileStorage) WriteComment(comment string, append bool) { c_comment := C.CString(comment) defer C.free(unsafe.Pointer(c_comment)) C.FileStorage_WriteComment(fs.p, c_comment, C.bool(append)) } func (fs *FileStorage) WriteRaw(fmt string, vec []byte) { c_fmt := C.CString(fmt) defer C.free(unsafe.Pointer(c_fmt)) c_vec := C.CBytes(vec) defer C.free(c_vec) C.FileStorage_WriteRaw(fs.p, c_fmt, c_vec, C.size_t(len(vec))) } func (fs *FileStorage) GetFirstTopLevelNode() *FileNode { node_p := C.FileStorage_GetFirstTopLevelNode(fs.p) return &FileNode{p: node_p} } func (fs *FileStorage) GetNode(name string) *FileNode { c_name := C.CString(name) defer C.free(unsafe.Pointer(c_name)) node_p := C.FileStorage_GetNode(fs.p, c_name) return &FileNode{p: node_p} } func (fs *FileStorage) Root(streamIdx int) *FileNode { node_p := C.FileStorage_Root(fs.p, C.int(streamIdx)) return &FileNode{p: node_p} } func (fs *FileStorage) Ptr() C.FileStorage { return fs.p } ================================================ FILE: persistence_test.go ================================================ package gocv import ( "os" "path/filepath" "testing" ) func TestFileStorage(t *testing.T) { fileStorageTestFilename := filepath.Join(os.TempDir(), "filestorage.json") fs := NewFileStorageWithParams(fileStorageTestFilename, FileStorageModeWrite|FileStorageModeFormatJson, "utf-8") fs.StartWriteStruct("gocv", FileNodeTypeMap, "person") fs.ElName() fs.State() fs.GetFormat() fs.IsOpened() m := NewMat() defer m.Close() fs.WriteMat("mat", m) fs.WriteString("string", "string value") fs.WriteStringArray("stringArray", []string{"string", "array"}) fs.WriteDouble("double", 3.1415927) fs.WriteInt("int", 42) fs.WriteComment("no comments", true) fs.EndWriteStruct() fs.StartWriteStruct("gocv2", FileNodeTypeSeq, "int") fs.WriteRaw("u", []byte{0, 0}) fs.EndWriteStruct() fs.GetNode("gocv") fs.Root(0) fs.ReleaseAndGetString() fs = NewFileStorage() fs.Open(fileStorageTestFilename, FileStorageModeRead|FileStorageModeFormatJson, "utf-8") fn := fs.GetFirstTopLevelNode() defer fn.Close() fn.Empty() fn.IsInt() fn.IsMap() fn.IsNamed() fn.IsNone() fn.IsReal() fn.IsSeq() fn.IsString() fn.Keys() fs.Release() } ================================================ FILE: photo.cpp ================================================ //go:build !gocv_specific_modules || (gocv_specific_modules && gocv_photo) #include "photo.h" OpenCVResult ColorChange(Mat src, Mat mask, Mat dst, float red_mul, float green_mul, float blue_mul) { try { cv::colorChange(*src, *mask, *dst, red_mul, green_mul, blue_mul); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult IlluminationChange(Mat src, Mat mask, Mat dst, float alpha, float beta) { try { cv::illuminationChange(*src, *mask, *dst, alpha, beta); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult SeamlessClone(Mat src, Mat dst, Mat mask, Point p, Mat blend, int flags) { try { cv::Point pt(p.x, p.y); cv::seamlessClone(*src, *dst, *mask, pt, *blend, flags); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult TextureFlattening(Mat src, Mat mask, Mat dst, float low_threshold, float high_threshold, int kernel_size) { try { cv::textureFlattening(*src, *mask, *dst, low_threshold, high_threshold, kernel_size); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult FastNlMeansDenoisingColoredMulti( struct Mats src, Mat dst, int imgToDenoiseIndex, int temporalWindowSize){ try { std::vector images; for (int i = 0; i < src.length; ++i) { images.push_back(*src.mats[i]); } cv::fastNlMeansDenoisingColoredMulti( images, *dst, imgToDenoiseIndex, temporalWindowSize ); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult FastNlMeansDenoisingColoredMultiWithParams( struct Mats src, Mat dst, int imgToDenoiseIndex, int temporalWindowSize, float h, float hColor, int templateWindowSize, int searchWindowSize ){ try { std::vector images; for (int i = 0; i < src.length; ++i) { images.push_back(*src.mats[i]); } cv::fastNlMeansDenoisingColoredMulti( images, *dst, imgToDenoiseIndex, temporalWindowSize, h, hColor, templateWindowSize, searchWindowSize ); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } MergeMertens MergeMertens_Create() { try { return new cv::Ptr(cv::createMergeMertens()); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } MergeMertens MergeMertens_CreateWithParams(float contrast_weight, float saturation_weight, float exposure_weight) { try { return new cv::Ptr(cv::createMergeMertens(contrast_weight, saturation_weight, exposure_weight)); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } void MergeMertens_Close(MergeMertens b) { delete b; } OpenCVResult MergeMertens_Process(MergeMertens b, struct Mats src, Mat dst) { try { std::vector images; for (int i = 0; i < src.length; ++i) { images.push_back(*src.mats[i]); } (*b)->process(images, *dst); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } AlignMTB AlignMTB_Create() { try { return new cv::Ptr(cv::createAlignMTB(6,4,false)); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } AlignMTB AlignMTB_CreateWithParams(int max_bits, int exclude_range, bool cut) { try { return new cv::Ptr(cv::createAlignMTB(max_bits, exclude_range, cut)); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } void AlignMTB_Close(AlignMTB b) { delete b; } OpenCVResult AlignMTB_Process(AlignMTB b, struct Mats src, struct Mats *dst) { try { std::vector srcMats; for (int i = 0; i < src.length; ++i) { srcMats.push_back(*src.mats[i]); } std::vector dstMats; (*b)->process(srcMats, dstMats); dst->mats = new Mat[dstMats.size()]; for (size_t i = 0; i < dstMats.size() ; ++i) { dst->mats[i] = new cv::Mat( dstMats[i] ); } dst->length = (int)dstMats.size(); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult FastNlMeansDenoising(Mat src, Mat dst) { try { cv::fastNlMeansDenoising(*src, *dst); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult FastNlMeansDenoisingWithParams(Mat src, Mat dst, float h, int templateWindowSize, int searchWindowSize) { try { cv::fastNlMeansDenoising(*src, *dst, h, templateWindowSize, searchWindowSize); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult FastNlMeansDenoisingColored(Mat src, Mat dst) { try { cv::fastNlMeansDenoisingColored(*src, *dst); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult FastNlMeansDenoisingColoredWithParams(Mat src, Mat dst, float h, float hColor, int templateWindowSize, int searchWindowSize) { try { cv::fastNlMeansDenoisingColored(*src, *dst, h, hColor, templateWindowSize, searchWindowSize); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult EdgePreservingFilter(Mat src, Mat dst, int filter, float sigma_s, float sigma_r) { try { cv::edgePreservingFilter(*src, *dst, filter, sigma_s, sigma_r); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult DetailEnhance(Mat src, Mat dst, float sigma_s, float sigma_r) { try { cv::detailEnhance(*src, *dst, sigma_s, sigma_r); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult PencilSketch(Mat src, Mat dst1, Mat dst2, float sigma_s, float sigma_r, float shade_factor) { try { cv::pencilSketch(*src, *dst1, *dst2, sigma_s, sigma_r, shade_factor); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Stylization(Mat src, Mat dst, float sigma_s, float sigma_r) { try { cv::stylization(*src, *dst, sigma_s, sigma_r); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult PhotoInpaint(Mat src, Mat mask, Mat dst, float inpaint_radius, int algorithm_type) { try { cv::inpaint(*src, *mask, *dst, inpaint_radius, algorithm_type); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } OpenCVResult Decolor(Mat src, Mat grey, Mat boost) { try { cv::decolor(*src, *grey, *boost); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } ================================================ FILE: photo.go ================================================ //go:build !gocv_specific_modules || (gocv_specific_modules && gocv_photo) package gocv /* #include #include "photo.h" */ import "C" import ( "image" "unsafe" ) // SeamlessCloneFlags seamlessClone algorithm flags type SeamlessCloneFlags int // MergeMertens is a wrapper around the cv::MergeMertens. type MergeMertens struct { p unsafe.Pointer // This unsafe pointer will in fact be a C.MergeMertens } // AlignMTB is a wrapper around the cv::AlignMTB. type AlignMTB struct { p unsafe.Pointer // This unsafe pointer will in fact be a C.AlignMTB } const ( // NormalClone The power of the method is fully expressed when inserting objects with complex outlines into a new background. NormalClone SeamlessCloneFlags = iota // MixedClone The classic method, color-based selection and alpha masking might be time consuming and often leaves an undesirable halo. Seamless cloning, even averaged with the original image, is not effective. Mixed seamless cloning based on a loose selection proves effective. MixedClone // MonochromeTransfer Monochrome transfer allows the user to easily replace certain features of one object by alternative features. MonochromeTransfer ) // ColorChange mix two differently colored versions of an image seamlessly. // // For further details, please see: // https://docs.opencv.org/master/df/da0/group__photo__clone.html#ga6684f35dc669ff6196a7c340dc73b98e func ColorChange(src, mask Mat, dst *Mat, red_mul, green_mul, blue_mul float32) error { return OpenCVResult(C.ColorChange(src.p, mask.p, dst.p, C.float(red_mul), C.float(green_mul), C.float(blue_mul))) } // SeamlessClone blend two image by Poisson Blending. // // For further details, please see: // https://docs.opencv.org/master/df/da0/group__photo__clone.html#ga2bf426e4c93a6b1f21705513dfeca49d func SeamlessClone(src, dst, mask Mat, p image.Point, blend *Mat, flags SeamlessCloneFlags) error { cp := C.struct_Point{ x: C.int(p.X), y: C.int(p.Y), } return OpenCVResult(C.SeamlessClone(src.p, dst.p, mask.p, cp, blend.p, C.int(flags))) } // IlluminationChange modifies locally the apparent illumination of an image. // // For further details, please see: // https://docs.opencv.org/master/df/da0/group__photo__clone.html#gac5025767cf2febd8029d474278e886c7 func IlluminationChange(src, mask Mat, dst *Mat, alpha, beta float32) error { return OpenCVResult(C.IlluminationChange(src.p, mask.p, dst.p, C.float(alpha), C.float(beta))) } // TextureFlattening washes out the texture of the selected region, giving its contents a flat aspect. // // For further details, please see: // https://docs.opencv.org/master/df/da0/group__photo__clone.html#gad55df6aa53797365fa7cc23959a54004 func TextureFlattening(src, mask Mat, dst *Mat, lowThreshold, highThreshold float32, kernelSize int) error { return OpenCVResult(C.TextureFlattening(src.p, mask.p, dst.p, C.float(lowThreshold), C.float(highThreshold), C.int(kernelSize))) } // FastNlMeansDenoisingColoredMulti denoises the selected images. // // For further details, please see: // https://docs.opencv.org/master/d1/d79/group__photo__denoise.html#gaa501e71f52fb2dc17ff8ca5e7d2d3619 func FastNlMeansDenoisingColoredMulti(src []Mat, dst *Mat, imgToDenoiseIndex int, temporalWindowSize int) error { cMatArray := make([]C.Mat, len(src)) for i, r := range src { cMatArray[i] = (C.Mat)(r.p) } matsVector := C.struct_Mats{ mats: (*C.Mat)(&cMatArray[0]), length: C.int(len(src)), } return OpenCVResult(C.FastNlMeansDenoisingColoredMulti(matsVector, dst.p, C.int(imgToDenoiseIndex), C.int(temporalWindowSize))) } // FastNlMeansDenoisingColoredMulti denoises the selected images. // // For further details, please see: // https://docs.opencv.org/master/d1/d79/group__photo__denoise.html#gaa501e71f52fb2dc17ff8ca5e7d2d3619 func FastNlMeansDenoisingColoredMultiWithParams(src []Mat, dst *Mat, imgToDenoiseIndex int, temporalWindowSize int, h float32, hColor float32, templateWindowSize int, searchWindowSize int) error { cMatArray := make([]C.Mat, len(src)) for i, r := range src { cMatArray[i] = (C.Mat)(r.p) } matsVector := C.struct_Mats{ mats: (*C.Mat)(&cMatArray[0]), length: C.int(len(src)), } return OpenCVResult(C.FastNlMeansDenoisingColoredMultiWithParams(matsVector, dst.p, C.int(imgToDenoiseIndex), C.int(temporalWindowSize), C.float(h), C.float(hColor), C.int(templateWindowSize), C.int(searchWindowSize))) } // NewMergeMertens returns returns a new MergeMertens white LDR merge algorithm. // of type MergeMertens with default parameters. // MergeMertens algorithm merge the ldr image should result in a HDR image. // // For further details, please see: // https://docs.opencv.org/master/d6/df5/group__photo__hdr.html // https://docs.opencv.org/master/d7/dd6/classcv_1_1MergeMertens.html // https://docs.opencv.org/master/d6/df5/group__photo__hdr.html#ga79d59aa3cb3a7c664e59a4b5acc1ccb6 func NewMergeMertens() MergeMertens { return MergeMertens{p: unsafe.Pointer(C.MergeMertens_Create())} } // NewMergeMertensWithParams returns a new MergeMertens white LDR merge algorithm // of type MergeMertens with customized parameters. // MergeMertens algorithm merge the ldr image should result in a HDR image. // // For further details, please see: // https://docs.opencv.org/master/d6/df5/group__photo__hdr.html // https://docs.opencv.org/master/d7/dd6/classcv_1_1MergeMertens.html // https://docs.opencv.org/master/d6/df5/group__photo__hdr.html#ga79d59aa3cb3a7c664e59a4b5acc1ccb6 func NewMergeMertensWithParams(contrast_weight float32, saturation_weight float32, exposure_weight float32) MergeMertens { return MergeMertens{p: unsafe.Pointer(C.MergeMertens_CreateWithParams(C.float(contrast_weight), C.float(saturation_weight), C.float(exposure_weight)))} } // Close MergeMertens. func (b *MergeMertens) Close() error { C.MergeMertens_Close((C.MergeMertens)(b.p)) // Here the unsafe pointer is cast into the right type b.p = nil return nil } // BalanceWhite computes merge LDR images using the current MergeMertens. // Return a image MAT : 8bits 3 channel image ( RGB 8 bits ) // For further details, please see: // https://docs.opencv.org/master/d7/dd6/classcv_1_1MergeMertens.html#a2d2254b2aab722c16954de13a663644d func (b *MergeMertens) Process(src []Mat, dst *Mat) error { cMatArray := make([]C.Mat, len(src)) for i, r := range src { cMatArray[i] = (C.Mat)(r.p) } // Conversion function from a Golang slice into an array of matrices that are understood by OpenCV matsVector := C.struct_Mats{ mats: (*C.Mat)(&cMatArray[0]), length: C.int(len(src)), } res := C.MergeMertens_Process((C.MergeMertens)(b.p), matsVector, dst.p) // Convert a series of double [0.0,1.0] to [0,255] with Golang dst.ConvertToWithParams(dst, MatTypeCV8UC3, 255.0, 0.0) return OpenCVResult(res) } // NewAlignMTB returns an AlignMTB for converts images to median threshold bitmaps. // of type AlignMTB converts images to median threshold bitmaps (1 for pixels // brighter than median luminance and 0 otherwise) and than aligns the resulting // bitmaps using bit operations. // For further details, please see: // https://docs.opencv.org/master/d6/df5/group__photo__hdr.html // https://docs.opencv.org/master/d7/db6/classcv_1_1AlignMTB.html // https://docs.opencv.org/master/d6/df5/group__photo__hdr.html#ga2f1fafc885a5d79dbfb3542e08db0244 func NewAlignMTB() AlignMTB { return AlignMTB{p: unsafe.Pointer(C.AlignMTB_Create())} } // NewAlignMTBWithParams returns an AlignMTB for converts images to median threshold bitmaps. // of type AlignMTB converts images to median threshold bitmaps (1 for pixels // brighter than median luminance and 0 otherwise) and than aligns the resulting // bitmaps using bit operations. // For further details, please see: // https://docs.opencv.org/master/d6/df5/group__photo__hdr.html // https://docs.opencv.org/master/d7/db6/classcv_1_1AlignMTB.html // https://docs.opencv.org/master/d6/df5/group__photo__hdr.html#ga2f1fafc885a5d79dbfb3542e08db0244 func NewAlignMTBWithParams(max_bits int, exclude_range int, cut bool) AlignMTB { return AlignMTB{p: unsafe.Pointer(C.AlignMTB_CreateWithParams(C.int(max_bits), C.int(exclude_range), C.bool(cut)))} } // Close AlignMTB. func (b *AlignMTB) Close() error { C.AlignMTB_Close((C.AlignMTB)(b.p)) b.p = nil return nil } // Process computes an alignment using the current AlignMTB. // // For further details, please see: // https://docs.opencv.org/master/d7/db6/classcv_1_1AlignMTB.html#a37b3417d844f362d781f34155cbcb201 func (b *AlignMTB) Process(src []Mat, dst *[]Mat) error { cSrcArray := make([]C.Mat, len(src)) for i, r := range src { cSrcArray[i] = r.p } cSrcMats := C.struct_Mats{ mats: (*C.Mat)(&cSrcArray[0]), length: C.int(len(src)), } cDstMats := C.struct_Mats{} res := C.AlignMTB_Process((C.AlignMTB)(b.p), cSrcMats, &cDstMats) // Pass the matrices by reference from an OpenCV/C++ to a GoCV::Mat object for i := C.int(0); i < cDstMats.length; i++ { var tempdst Mat tempdst.p = C.Mats_get(cDstMats, i) *dst = append(*dst, tempdst) } return OpenCVResult(res) } // FastNlMeansDenoising performs image denoising using Non-local Means Denoising algorithm // http://www.ipol.im/pub/algo/bcm_non_local_means_denoising/ // // For further details, please see: // https://docs.opencv.org/4.x/d1/d79/group__photo__denoise.html#ga4c6b0031f56ea3f98f768881279ffe93 func FastNlMeansDenoising(src Mat, dst *Mat) error { return OpenCVResult(C.FastNlMeansDenoising(src.p, dst.p)) } // FastNlMeansDenoisingWithParams performs image denoising using Non-local Means Denoising algorithm // http://www.ipol.im/pub/algo/bcm_non_local_means_denoising/ // // For further details, please see: // https://docs.opencv.org/4.x/d1/d79/group__photo__denoise.html#ga4c6b0031f56ea3f98f768881279ffe93 func FastNlMeansDenoisingWithParams(src Mat, dst *Mat, h float32, templateWindowSize int, searchWindowSize int) error { return OpenCVResult(C.FastNlMeansDenoisingWithParams(src.p, dst.p, C.float(h), C.int(templateWindowSize), C.int(searchWindowSize))) } // FastNlMeansDenoisingColored is a modification of fastNlMeansDenoising function for colored images. // // For further details, please see: // https://docs.opencv.org/4.x/d1/d79/group__photo__denoise.html#ga21abc1c8b0e15f78cd3eff672cb6c476 func FastNlMeansDenoisingColored(src Mat, dst *Mat) error { return OpenCVResult(C.FastNlMeansDenoisingColored(src.p, dst.p)) } // FastNlMeansDenoisingColoredWithParams is a modification of fastNlMeansDenoising function for colored images. // // For further details, please see: // https://docs.opencv.org/4.x/d1/d79/group__photo__denoise.html#ga21abc1c8b0e15f78cd3eff672cb6c476 func FastNlMeansDenoisingColoredWithParams(src Mat, dst *Mat, h float32, hColor float32, templateWindowSize int, searchWindowSize int) error { return OpenCVResult(C.FastNlMeansDenoisingColoredWithParams(src.p, dst.p, C.float(h), C.float(hColor), C.int(templateWindowSize), C.int(searchWindowSize))) } // DetailEnhance filter enhances the details of a particular image // // For further details, please see: // https://docs.opencv.org/4.x/df/dac/group__photo__render.html#gae5930dd822c713b36f8529b21ddebd0c func DetailEnhance(src Mat, dst *Mat, sigma_s, sigma_r float32) error { return OpenCVResult(C.DetailEnhance(src.p, dst.p, C.float(sigma_s), C.float(sigma_r))) } type EdgeFilter int const ( // RecursFilter Recursive Filtering. RecursFilter EdgeFilter = 1 // NormconvFilter Normalized Convolution Filtering. NormconvFilter = 2 ) // EdgePreservingFilter filtering is the fundamental operation in image and video processing. // Edge-preserving smoothing filters are used in many different applications. // // For further details, please see: // https://docs.opencv.org/4.x/df/dac/group__photo__render.html#gafaee2977597029bc8e35da6e67bd31f7 func EdgePreservingFilter(src Mat, dst *Mat, filter EdgeFilter, sigma_s, sigma_r float32) error { return OpenCVResult(C.EdgePreservingFilter(src.p, dst.p, C.int(filter), C.float(sigma_s), C.float(sigma_r))) } // PencilSketch pencil-like non-photorealistic line drawing. // // For further details, please see: // https://docs.opencv.org/4.x/df/dac/group__photo__render.html#gae5930dd822c713b36f8529b21ddebd0c func PencilSketch(src Mat, dst1, dst2 *Mat, sigma_s, sigma_r, shade_factor float32) error { return OpenCVResult(C.PencilSketch(src.p, dst1.p, dst2.p, C.float(sigma_s), C.float(sigma_r), C.float(shade_factor))) } // Stylization aims to produce digital imagery with a wide variety of effects // not focused on photorealism. Edge-aware filters are ideal for stylization, // as they can abstract regions of low contrast while preserving, or enhancing, // high-contrast features. // // For further details, please see: // https://docs.opencv.org/4.x/df/dac/group__photo__render.html#gacb0f7324017df153d7b5d095aed53206 func Stylization(src Mat, dst *Mat, sigma_s, sigma_r float32) error { return OpenCVResult(C.Stylization(src.p, dst.p, C.float(sigma_s), C.float(sigma_r))) } // InpaintMethods is the methods for inpainting process. type InpaintMethods int const ( // NS inpaints using Navier-Stokes based method, created by Bertalmio, Marcelo, // Andrea L. Bertozzi, and Guillermo Sapiro in 2001 NS InpaintMethods = 0 // Telea inpaints using Fast Marching Method proposed by Alexandru Telea in 2004. Telea InpaintMethods = 1 ) // Inpaint reconstructs the selected image area from the pixel near the area boundary. // The function may be used to remove dust and scratches from a scanned photo, or to // remove undesirable objects from still images or video. // // For further details, please see: // https://docs.opencv.org/4.x/d7/d8b/group__photo__inpaint.html#gaedd30dfa0214fec4c88138b51d678085 func Inpaint(src Mat, mask Mat, dst *Mat, inpaintRadius float32, algorithmType InpaintMethods) error { return OpenCVResult(C.PhotoInpaint(C.Mat(src.Ptr()), C.Mat(mask.Ptr()), C.Mat(dst.Ptr()), C.float(inpaintRadius), C.int(algorithmType))) } // Decolor Transforms a color image to a grayscale image. // It is a basic tool in digital printing, stylized black-and-white photograph rendering, // and in many single channel image processing applications // // For further details, please see: // https://docs.opencv.org/4.x/d4/d32/group__photo__decolor.html#ga4864d4c007bda5dacdc5e9d4ed7e222c func Decolor(src Mat, grey *Mat, boost *Mat) error { return OpenCVResult(C.Decolor(src.p, grey.p, boost.p)) } ================================================ FILE: photo.h ================================================ #ifndef _OPENCV3_PHOTO_H_ #define _OPENCV3_PHOTO_H_ #ifdef __cplusplus #include #include extern "C" { #endif #include "core.h" #ifdef __cplusplus // see : https://docs.opencv.org/3.4/d7/dd6/classcv_1_1MergeMertens.html typedef cv::Ptr *MergeMertens; // see : https://docs.opencv.org/master/d7/db6/classcv_1_1AlignMTB.html typedef cv::Ptr *AlignMTB; #else typedef void *MergeMertens; typedef void *AlignMTB; #endif OpenCVResult ColorChange(Mat src, Mat mask, Mat dst, float red_mul, float green_mul, float blue_mul); OpenCVResult SeamlessClone(Mat src, Mat dst, Mat mask, Point p, Mat blend, int flags); OpenCVResult IlluminationChange(Mat src, Mat mask, Mat dst, float alpha, float beta); OpenCVResult TextureFlattening(Mat src, Mat mask, Mat dst, float low_threshold, float high_threshold, int kernel_size); OpenCVResult FastNlMeansDenoisingColoredMulti(struct Mats src, Mat dst, int imgToDenoiseIndex, int temporalWindowSize); OpenCVResult FastNlMeansDenoisingColoredMultiWithParams(struct Mats src, Mat dst, int imgToDenoiseIndex, int temporalWindowSize, float h, float hColor, int templateWindowSize, int searchWindowSize ); OpenCVResult FastNlMeansDenoising(Mat src, Mat dst); OpenCVResult FastNlMeansDenoisingWithParams(Mat src, Mat dst, float h, int templateWindowSize, int searchWindowSize); OpenCVResult FastNlMeansDenoisingColored(Mat src, Mat dst); OpenCVResult FastNlMeansDenoisingColoredWithParams(Mat src, Mat dst, float h, float hColor, int templateWindowSize, int searchWindowSize); MergeMertens MergeMertens_Create(); MergeMertens MergeMertens_CreateWithParams(float contrast_weight, float saturation_weight, float exposure_weight); OpenCVResult MergeMertens_Process(MergeMertens b, struct Mats src, Mat dst); void MergeMertens_Close(MergeMertens b); AlignMTB AlignMTB_Create(); AlignMTB AlignMTB_CreateWithParams(int max_bits, int exclude_range, bool cut); OpenCVResult AlignMTB_Process(AlignMTB b, struct Mats src, struct Mats *dst); void AlignMTB_Close(AlignMTB b); OpenCVResult DetailEnhance(Mat src, Mat dst, float sigma_s, float sigma_r); OpenCVResult EdgePreservingFilter(Mat src, Mat dst, int filter, float sigma_s, float sigma_r); OpenCVResult PencilSketch(Mat src, Mat dst1, Mat dst2, float sigma_s, float sigma_r, float shade_factor); OpenCVResult Stylization(Mat src, Mat dst, float sigma_s, float sigma_r); OpenCVResult PhotoInpaint(Mat src, Mat mask, Mat dst, float inpaint_radius, int algorithm_type); OpenCVResult Decolor(Mat src, Mat grey, Mat boost); #ifdef __cplusplus } #endif #endif //_OPENCV3_PHOTO_H ================================================ FILE: photo_string.go ================================================ //go:build !gocv_specific_modules || (gocv_specific_modules && gocv_photo) package gocv func (c SeamlessCloneFlags) String() string { switch c { case NormalClone: return "normal-clone" case MixedClone: return "mixed-clone" case MonochromeTransfer: return "monochrome-transfer" } return "" } ================================================ FILE: photo_test.go ================================================ //go:build !gocv_specific_modules || (gocv_specific_modules && gocv_photo) package gocv import ( "image" "testing" ) func TestColorChange(t *testing.T) { src := NewMatWithSize(20, 20, MatTypeCV8UC3) defer src.Close() dst := NewMat() defer dst.Close() mask := src.Clone() defer mask.Close() ColorChange(src, mask, &dst, 1.5, .5, .5) if dst.Empty() || dst.Rows() != src.Rows() || dst.Cols() != src.Cols() { t.Error("Invlalid ColorChange test") } } func TestSeamlessClone(t *testing.T) { src := NewMatWithSize(20, 20, MatTypeCV8UC3) defer src.Close() dst := NewMatWithSize(30, 30, MatTypeCV8UC3) defer dst.Close() blend := NewMatWithSize(dst.Rows(), dst.Cols(), dst.Type()) defer blend.Close() mask := src.Clone() defer mask.Close() center := image.Point{dst.Cols() / 2, dst.Rows() / 2} SeamlessClone(src, dst, mask, center, &blend, NormalClone) if blend.Empty() || dst.Rows() != blend.Rows() || dst.Cols() != blend.Cols() { t.Error("Invlalid SeamlessClone test") } } func TestIlluminationChange(t *testing.T) { src := NewMatWithSize(20, 20, MatTypeCV8UC3) defer src.Close() dst := NewMat() defer dst.Close() mask := src.Clone() defer mask.Close() IlluminationChange(src, mask, &dst, 0.2, 0.4) if dst.Empty() || dst.Rows() != src.Rows() || dst.Cols() != src.Cols() { t.Error("Invlalid IlluminationChange test") } } func TestTextureFlattening(t *testing.T) { src := NewMatWithSize(20, 20, MatTypeCV8UC3) defer src.Close() dst := NewMat() defer dst.Close() mask := src.Clone() defer mask.Close() TextureFlattening(src, mask, &dst, 30, 45, 3) if dst.Empty() || dst.Rows() != src.Rows() || dst.Cols() != src.Cols() { t.Error("Invlalid TextureFlattening test") } } func TestFastNlMeansDenoisingColoredMultiWithParams(t *testing.T) { var src [3]Mat for i := 0; i < 3; i++ { src[i] = NewMatWithSize(20, 20, MatTypeCV8UC3) defer src[i].Close() } dst := NewMat() defer dst.Close() FastNlMeansDenoisingColoredMultiWithParams([]Mat{src[0], src[1], src[2]}, &dst, 1, 1, 3, 3, 7, 21) if dst.Empty() || dst.Rows() != src[0].Rows() || dst.Cols() != src[0].Cols() { t.Error("Invalid FastNlMeansDenoisingColoredMultiWithParams test") } } func TestMergeMertens(t *testing.T) { var src [3]Mat for i := 0; i < 3; i++ { src[i] = NewMatWithSize(20, 20, MatTypeCV8UC3) defer src[i].Close() } dst := NewMat() defer dst.Close() mertens := NewMergeMertens() defer mertens.Close() mertens.Process([]Mat{src[0], src[1], src[2]}, &dst) if dst.Empty() || dst.Rows() != src[0].Rows() || dst.Cols() != src[0].Cols() { t.Error("Invalid TestMergeMertens test") } } func TestNewAlignMTB(t *testing.T) { var src [3]Mat for i := 0; i < 3; i++ { src[i] = NewMatWithSize(20, 20, MatTypeCV8UC3) defer src[i].Close() } alignwtb := NewAlignMTB() defer alignwtb.Close() var dst []Mat alignwtb.Process([]Mat{src[0], src[1], src[2]}, &dst) sizedst := len(dst) t.Logf(" Size Dst slice : %d ", sizedst) if sizedst > 0 { if dst[0].Empty() || dst[0].Rows() != src[0].Rows() || dst[0].Cols() != src[0].Cols() { t.Error("Invalid TestNewAlignMTB test") } } if sizedst <= 0 { t.Error("Invalid TestNewAlignMTB test : empty result") } } func TestFastNlMeansDenoising(t *testing.T) { img := IMRead("images/face-detect.jpg", IMReadGrayScale) if img.Empty() { t.Error("Invalid read of Mat in TestFastNlMeansDenoising test") } defer img.Close() dest := NewMat() defer dest.Close() FastNlMeansDenoising(img, &dest) if dest.Empty() || img.Rows() != dest.Rows() || img.Cols() != dest.Cols() { t.Error("Error in TestFastNlMeansDenoising test") } } func TestFastNlMeansDenoisingWithParams(t *testing.T) { img := IMRead("images/face-detect.jpg", IMReadGrayScale) if img.Empty() { t.Error("Invalid read of Mat in TestFastNlMeansDenoising test") } defer img.Close() dest := NewMat() defer dest.Close() FastNlMeansDenoisingWithParams(img, &dest, 3, 7, 21) if dest.Empty() || img.Rows() != dest.Rows() || img.Cols() != dest.Cols() { t.Error("Error in TestFastNlMeansDenoising test") } } func TestFastNlMeansDenoisingColored(t *testing.T) { img := IMRead("images/face-detect.jpg", IMReadColor) if img.Empty() { t.Error("Invalid read of Mat in FastNlMeansDenoisingColored test") } defer img.Close() dest := NewMat() defer dest.Close() FastNlMeansDenoisingColored(img, &dest) if dest.Empty() || img.Rows() != dest.Rows() || img.Cols() != dest.Cols() { t.Error("Error in FastNlMeansDenoisingColored test") } } func TestFastNlMeansDenoisingColoredWithParams(t *testing.T) { img := IMRead("images/face-detect.jpg", IMReadColor) if img.Empty() { t.Error("Invalid read of Mat in FastNlMeansDenoisingColored test") } defer img.Close() dest := NewMat() defer dest.Close() FastNlMeansDenoisingColoredWithParams(img, &dest, 3, 3, 7, 21) if dest.Empty() || img.Rows() != dest.Rows() || img.Cols() != dest.Cols() { t.Error("Error in FastNlMeansDenoisingColored test") } } func TestDetailEnhance(t *testing.T) { src := NewMatWithSize(20, 20, MatTypeCV8UC3) defer src.Close() dst := NewMat() defer dst.Close() DetailEnhance(src, &dst, 100.0, .5) if dst.Empty() || dst.Rows() != src.Rows() || dst.Cols() != src.Cols() { t.Error("Invlalid DetailEnhance test") } } func TestEdgePreservingFilter(t *testing.T) { src := NewMatWithSize(20, 20, MatTypeCV8UC3) defer src.Close() dst := NewMat() defer dst.Close() EdgePreservingFilter(src, &dst, RecursFilter, 100.0, .5) if dst.Empty() || dst.Rows() != src.Rows() || dst.Cols() != src.Cols() { t.Error("Invalid EdgePreservingFilter test") } } func TestStylization(t *testing.T) { src := NewMatWithSize(20, 20, MatTypeCV8UC3) defer src.Close() dst := NewMat() defer dst.Close() Stylization(src, &dst, 100.0, .5) if dst.Empty() || dst.Rows() != src.Rows() || dst.Cols() != src.Cols() { t.Error("Invlalid Stylization test") } } func TestPencilSketch(t *testing.T) { src := NewMatWithSize(20, 20, MatTypeCV8UC3) defer src.Close() dst1 := NewMat() defer dst1.Close() dst2 := NewMat() defer dst2.Close() PencilSketch(src, &dst1, &dst2, 100.0, .5, 0.05) if dst1.Empty() || dst1.Rows() != src.Rows() || dst1.Cols() != src.Cols() { t.Error("Invlalid PencilSketch test") } if dst2.Empty() || dst2.Rows() != src.Rows() || dst2.Cols() != src.Cols() { t.Error("Invlalid PencilSketch test") } } func TestInpaint(t *testing.T) { src := IMRead("images/inpaint-src.jpg", IMReadColor) defer src.Close() mask := IMRead("images/inpaint-mask.jpg", IMReadGrayScale) defer mask.Close() dst := NewMatWithSize(src.Rows(), src.Cols(), MatTypeCV8U) defer dst.Close() Inpaint(src, mask, &dst, 10, Telea) if dst.Channels() == 1 { t.Error("Invalid inpaint test") } if sum := dst.Sum(); sum.Val1 == 0 || sum.Val2 == 0 || sum.Val3 == 0 { t.Error("Invalid inpaint test") } } func TestDecolor(t *testing.T) { img := IMRead("images/face-detect.jpg", IMReadColor) if img.Empty() { t.Error("Invalid read of Mat in Decolor test") } defer img.Close() grey := NewMat() defer grey.Close() boost := NewMat() defer boost.Close() if err := Decolor(img, &grey, &boost); err != nil { t.Error("Error in Decolor test", err) } if grey.Empty() || img.Rows() != grey.Rows() || img.Cols() != grey.Cols() { t.Error("Error in Decolor test") } if boost.Empty() || img.Rows() != boost.Rows() || img.Cols() != boost.Cols() { t.Error("Error in Decolor test") } } ================================================ FILE: svd.cpp ================================================ //go:build !gocv_specific_modules || (gocv_specific_modules && gocv_svd) #include "svd.h" OpenCVResult SVD_Compute(Mat src, Mat w, Mat u, Mat vt) { try { cv::SVD::compute(*src, *w, *u, *vt, 0); return successResult(); } catch(const cv::Exception& e) { return errorResult(e.code, e.what()); } } ================================================ FILE: svd.go ================================================ //go:build !gocv_specific_modules || (gocv_specific_modules && gocv_svd) package gocv /* #include #include "svd.h" */ import "C" // SVDCompute decomposes matrix and stores the results to user-provided matrices // // https://docs.opencv.org/4.1.2/df/df7/classcv_1_1SVD.html#a76f0b2044df458160292045a3d3714c6 func SVDCompute(src Mat, w, u, vt *Mat) error { return OpenCVResult(C.SVD_Compute(src.Ptr(), w.Ptr(), u.Ptr(), vt.Ptr())) } ================================================ FILE: svd.h ================================================ #ifndef _OPENCV3_SVD_H_ #define _OPENCV3_SVD_H_ #ifdef __cplusplus #include extern "C" { #endif #include "core.h" OpenCVResult SVD_Compute(Mat src, Mat w, Mat u, Mat vt); #ifdef __cplusplus } #endif #endif //_OPENCV3_SVD_H ================================================ FILE: svd_test.go ================================================ //go:build !gocv_specific_modules || (gocv_specific_modules && gocv_svd) package gocv import ( "runtime" "testing" ) func TestSVDCompute(t *testing.T) { if runtime.GOOS == "darwin" { t.Skip("skipping test on macos") } var resultW = []float32{6.167493, 3.8214223} var resultU = []float32{-0.1346676, -0.99089086, 0.9908908, -0.1346676} var resultVt = []float32{0.01964448, 0.999807, -0.999807, 0.01964448} checkFunc := func(a []float32, b []float32) bool { if len(a) != len(b) { return false } for i := range a { if a[i] != b[i] { return false } } return true } src := NewMatWithSize(2, 2, MatTypeCV32F) src.SetFloatAt(0, 0, 3.76956568) src.SetFloatAt(0, 1, -0.90478725) src.SetFloatAt(1, 0, 0.634576) src.SetFloatAt(1, 1, 6.10002347) defer src.Close() w := NewMat() defer w.Close() u := NewMat() defer u.Close() vt := NewMat() defer vt.Close() SVDCompute(src, &w, &u, &vt) dataW, err := w.DataPtrFloat32() if err != nil { t.Error(err) } if !checkFunc(resultW, dataW) { t.Error("w value is incorrect") } dataU, err := u.DataPtrFloat32() if err != nil { t.Error(err) } if !checkFunc(resultU, dataU) { t.Error("u value is incorrect") } dataVt, err := vt.DataPtrFloat32() if err != nil { t.Error(err) } if !checkFunc(resultVt, dataVt) { t.Error("vt value is incorrect") } } ================================================ FILE: version.cpp ================================================ #include "version.h" const char* openCVVersion() { return CV_VERSION; } ================================================ FILE: version.go ================================================ package gocv /* #include #include "version.h" */ import "C" // GoCVVersion of this package, for display purposes. const GoCVVersion = "0.43.0" // Version returns the current golang package version func Version() string { return GoCVVersion } // OpenCVVersion returns the current OpenCV lib version func OpenCVVersion() string { return C.GoString(C.openCVVersion()) } ================================================ FILE: version.h ================================================ #ifndef _OPENCV3_VERSION_H_ #define _OPENCV3_VERSION_H_ #ifdef __cplusplus #include extern "C" { #endif #include "core.h" const char* openCVVersion(); #ifdef __cplusplus } #endif #endif //_OPENCV3_VERSION_H_ ================================================ FILE: version_test.go ================================================ package gocv import ( "strings" "testing" ) func TestVersions(t *testing.T) { ocvv := OpenCVVersion() if !(strings.Contains(ocvv, "4.11") || strings.Contains(ocvv, "4.12") || strings.Contains(ocvv, "4.13")) { t.Error("Wrong version of OpenCV:", ocvv) } v := Version() if v != GoCVVersion { t.Error("Wrong version of GoCV") } } ================================================ FILE: video.cpp ================================================ //go:build !gocv_specific_modules || (gocv_specific_modules && gocv_video) #include "video.h" BackgroundSubtractorMOG2 BackgroundSubtractorMOG2_Create() { try { return new cv::Ptr(cv::createBackgroundSubtractorMOG2()); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } BackgroundSubtractorMOG2 BackgroundSubtractorMOG2_CreateWithParams(int history, double varThreshold, bool detectShadows) { try { return new cv::Ptr(cv::createBackgroundSubtractorMOG2(history,varThreshold,detectShadows)); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } BackgroundSubtractorKNN BackgroundSubtractorKNN_Create() { try { return new cv::Ptr(cv::createBackgroundSubtractorKNN()); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } BackgroundSubtractorKNN BackgroundSubtractorKNN_CreateWithParams(int history, double dist2Threshold, bool detectShadows) { try { return new cv::Ptr(cv::createBackgroundSubtractorKNN(history,dist2Threshold,detectShadows)); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } void BackgroundSubtractorMOG2_Close(BackgroundSubtractorMOG2 b) { delete b; } OpenCVResult BackgroundSubtractorMOG2_Apply(BackgroundSubtractorMOG2 b, Mat src, Mat dst) { try { (*b)->apply(*src, *dst); OpenCVResult result = {0, NULL}; return result; } catch(const cv::Exception& e) { OpenCVResult result = {e.code, e.what()}; return result; } } OpenCVResult BackgroundSubtractorMOG2_ApplyWithParams(BackgroundSubtractorMOG2 b, Mat src, Mat dst, double learningRate) { try { (*b)->apply(*src, *dst, learningRate); OpenCVResult result = {0, NULL}; return result; } catch(const cv::Exception& e) { OpenCVResult result = {e.code, e.what()}; return result; } } void BackgroundSubtractorKNN_Close(BackgroundSubtractorKNN k) { delete k; } OpenCVResult BackgroundSubtractorKNN_Apply(BackgroundSubtractorKNN k, Mat src, Mat dst) { try { (*k)->apply(*src, *dst); OpenCVResult result = {0, NULL}; return result; } catch(const cv::Exception& e) { OpenCVResult result = {e.code, e.what()}; return result; } } OpenCVResult CalcOpticalFlowFarneback(Mat prevImg, Mat nextImg, Mat flow, double scale, int levels, int winsize, int iterations, int polyN, double polySigma, int flags) { try { cv::calcOpticalFlowFarneback(*prevImg, *nextImg, *flow, scale, levels, winsize, iterations, polyN, polySigma, flags); OpenCVResult result = {0, NULL}; return result; } catch(const cv::Exception& e) { OpenCVResult result = {e.code, e.what()}; return result; } } OpenCVResult CalcOpticalFlowPyrLK(Mat prevImg, Mat nextImg, Mat prevPts, Mat nextPts, Mat status, Mat err) { try { cv::calcOpticalFlowPyrLK(*prevImg, *nextImg, *prevPts, *nextPts, *status, *err); OpenCVResult result = {0, NULL}; return result; } catch(const cv::Exception& e) { OpenCVResult result = {e.code, e.what()}; return result; } } OpenCVResult CalcOpticalFlowPyrLKWithParams(Mat prevImg, Mat nextImg, Mat prevPts, Mat nextPts, Mat status, Mat err, Size winSize, int maxLevel, TermCriteria criteria, int flags, double minEigThreshold){ try { cv::Size sz(winSize.width, winSize.height); cv::calcOpticalFlowPyrLK(*prevImg, *nextImg, *prevPts, *nextPts, *status, *err, sz, maxLevel, *criteria, flags, minEigThreshold); OpenCVResult result = {0, NULL}; return result; } catch(const cv::Exception& e) { OpenCVResult result = {e.code, e.what()}; return result; } } double FindTransformECC(Mat templateImage, Mat inputImage, Mat warpMatrix, int motionType, TermCriteria criteria, Mat inputMask, int gaussFiltSize){ try { return cv::findTransformECC(*templateImage, *inputImage, *warpMatrix, motionType, *criteria, *inputMask, gaussFiltSize); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return 0.0; } } bool Tracker_Init(Tracker self, Mat image, Rect boundingBox) { try { cv::Rect bb(boundingBox.x, boundingBox.y, boundingBox.width, boundingBox.height); (*self)->init(*image, bb); return true; } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return false; } } bool Tracker_Update(Tracker self, Mat image, Rect* boundingBox) { try { cv::Rect bb; bool ret = (*self)->update(*image, bb); boundingBox->x = int(bb.x); boundingBox->y = int(bb.y); boundingBox->width = int(bb.width); boundingBox->height = int(bb.height); return ret; } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return false; } } TrackerMIL TrackerMIL_Create() { try { return new cv::Ptr(cv::TrackerMIL::create()); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } void TrackerMIL_Close(TrackerMIL self) { delete self; } TrackerGOTURN TrackerGOTURN_Create(void){ try { return new cv::Ptr(cv::TrackerGOTURN::create()); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } TrackerGOTURN TrackerGOTURN_CreateWithParams(const char* modelBin, const char* modelTxt){ try { cv::TrackerGOTURN::Params params; params.modelBin = modelBin; params.modelTxt = modelTxt; return new cv::Ptr(cv::TrackerGOTURN::create(params)); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } void TrackerGOTURN_Close(TrackerGOTURN tr) { delete tr; } TrackerVit TrackerVit_Create() { try { return new cv::Ptr(cv::TrackerVit::create()); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } TrackerVit TrackerVit_CreateWithParams(const char* model){ try { cv::TrackerVit::Params params; params.net = model; return new cv::Ptr(cv::TrackerVit::create(params)); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } void TrackerVit_Close(TrackerVit self) { delete self; } KalmanFilter KalmanFilter_New(int dynamParams, int measureParams) { try { return new cv::KalmanFilter(dynamParams, measureParams, 0, CV_32F); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } KalmanFilter KalmanFilter_NewWithParams(int dynamParams, int measureParams, int controlParams, int type) { try { return new cv::KalmanFilter(dynamParams, measureParams, controlParams, type); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } OpenCVResult KalmanFilter_Init(KalmanFilter kf, int dynamParams, int measureParams) { try { kf->init(dynamParams, measureParams, 0, CV_32F); OpenCVResult result = {0, NULL}; return result; } catch(const cv::Exception& e) { OpenCVResult result = {e.code, e.what()}; return result; } } OpenCVResult KalmanFilter_InitWithParams(KalmanFilter kf, int dynamParams, int measureParams, int controlParams, int type) { try { kf->init(dynamParams, measureParams, controlParams, type); OpenCVResult result = {0, NULL}; return result; } catch(const cv::Exception& e) { OpenCVResult result = {e.code, e.what()}; return result; } } void KalmanFilter_Close(KalmanFilter kf) { delete kf; } Mat KalmanFilter_Predict(KalmanFilter kf) { try { return new cv::Mat(kf->predict()); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return new cv::Mat(); } } Mat KalmanFilter_PredictWithParams(KalmanFilter kf, Mat control) { try { return new cv::Mat(kf->predict(*control)); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return new cv::Mat(); } } Mat KalmanFilter_Correct(KalmanFilter kf, Mat measurement) { try { return new cv::Mat(kf->correct(*measurement)); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return new cv::Mat(); } } Mat KalmanFilter_GetStatePre(KalmanFilter kf) { try { return new cv::Mat(kf->statePre); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return new cv::Mat(); } } Mat KalmanFilter_GetStatePost(KalmanFilter kf) { try { return new cv::Mat(kf->statePost); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return new cv::Mat(); } } Mat KalmanFilter_GetTransitionMatrix(KalmanFilter kf) { try { return new cv::Mat(kf->transitionMatrix); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return new cv::Mat(); } } Mat KalmanFilter_GetControlMatrix(KalmanFilter kf) { try { return new cv::Mat(kf->controlMatrix); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return new cv::Mat(); } } Mat KalmanFilter_GetMeasurementMatrix(KalmanFilter kf) { try { return new cv::Mat(kf->measurementMatrix); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return new cv::Mat(); } } Mat KalmanFilter_GetProcessNoiseCov(KalmanFilter kf) { try { return new cv::Mat(kf->processNoiseCov); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return new cv::Mat(); } } Mat KalmanFilter_GetMeasurementNoiseCov(KalmanFilter kf) { try { return new cv::Mat(kf->measurementNoiseCov); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return new cv::Mat(); } } Mat KalmanFilter_GetErrorCovPre(KalmanFilter kf) { try { return new cv::Mat(kf->errorCovPre); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return new cv::Mat(); } } Mat KalmanFilter_GetGain(KalmanFilter kf) { try { return new cv::Mat(kf->gain); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return new cv::Mat(); } } Mat KalmanFilter_GetErrorCovPost(KalmanFilter kf) { try { return new cv::Mat(kf->errorCovPost); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return new cv::Mat(); } } Mat KalmanFilter_GetTemp1(KalmanFilter kf) { try { return new cv::Mat(kf->temp1); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return new cv::Mat(); } } Mat KalmanFilter_GetTemp2(KalmanFilter kf) { try { return new cv::Mat(kf->temp2); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return new cv::Mat(); } } Mat KalmanFilter_GetTemp3(KalmanFilter kf) { try { return new cv::Mat(kf->temp3); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return new cv::Mat(); } } Mat KalmanFilter_GetTemp4(KalmanFilter kf) { try { return new cv::Mat(kf->temp4); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return new cv::Mat(); } } Mat KalmanFilter_GetTemp5(KalmanFilter kf) { try { return new cv::Mat(kf->temp5); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return new cv::Mat(); } } void KalmanFilter_SetStatePre(KalmanFilter kf, Mat statePre) { kf->statePre = *statePre; } void KalmanFilter_SetStatePost(KalmanFilter kf, Mat statePost) { kf->statePost = *statePost; } void KalmanFilter_SetTransitionMatrix(KalmanFilter kf, Mat transitionMatrix) { kf->transitionMatrix = *transitionMatrix; } void KalmanFilter_SetControlMatrix(KalmanFilter kf, Mat controlMatrix) { kf->controlMatrix = *controlMatrix; } void KalmanFilter_SetMeasurementMatrix(KalmanFilter kf, Mat measurementMatrix) { kf->measurementMatrix = *measurementMatrix; } void KalmanFilter_SetProcessNoiseCov(KalmanFilter kf, Mat processNoiseCov) { kf->processNoiseCov = *processNoiseCov; } void KalmanFilter_SetMeasurementNoiseCov(KalmanFilter kf, Mat measurementNoiseCov) { kf->measurementNoiseCov = *measurementNoiseCov; } void KalmanFilter_SetErrorCovPre(KalmanFilter kf, Mat errorCovPre) { kf->errorCovPre = *errorCovPre; } void KalmanFilter_SetGain(KalmanFilter kf, Mat gain) { kf->gain = *gain; } void KalmanFilter_SetErrorCovPost(KalmanFilter kf, Mat errorCovPost) { kf->errorCovPost = *errorCovPost; } ================================================ FILE: video.go ================================================ //go:build !gocv_specific_modules || (gocv_specific_modules && gocv_video) package gocv /* #include #include "video.h" */ import "C" import ( "image" "unsafe" ) /* * cv::OPTFLOW_USE_INITIAL_FLOW = 4, cv::OPTFLOW_LK_GET_MIN_EIGENVALS = 8, cv::OPTFLOW_FARNEBACK_GAUSSIAN = 256 For further details, please see: https://docs.opencv.org/master/dc/d6b/group__video__track.html#gga2c6cc144c9eee043575d5b311ac8af08a9d4430ac75199af0cf6fcdefba30eafe */ const ( OptflowUseInitialFlow = 4 OptflowLkGetMinEigenvals = 8 OptflowFarnebackGaussian = 256 ) /* * cv::MOTION_TRANSLATION = 0, cv::MOTION_EUCLIDEAN = 1, cv::MOTION_AFFINE = 2, cv::MOTION_HOMOGRAPHY = 3 For further details, please see: https://docs.opencv.org/4.x/dc/d6b/group__video__track.html#ggaaedb1f94e6b143cef163622c531afd88a01106d6d20122b782ff25eaeffe9a5be */ const ( MotionTranslation = 0 MotionEuclidean = 1 MotionAffine = 2 MotionHomography = 3 ) // BackgroundSubtractorMOG2 is a wrapper around the cv::BackgroundSubtractorMOG2. type BackgroundSubtractorMOG2 struct { // C.BackgroundSubtractorMOG2 p unsafe.Pointer } // NewBackgroundSubtractorMOG2 returns a new BackgroundSubtractor algorithm // of type MOG2. MOG2 is a Gaussian Mixture-based Background/Foreground // Segmentation Algorithm. // // For further details, please see: // https://docs.opencv.org/master/de/de1/group__video__motion.html#ga2beb2dee7a073809ccec60f145b6b29c // https://docs.opencv.org/master/d7/d7b/classcv_1_1BackgroundSubtractorMOG2.html func NewBackgroundSubtractorMOG2() BackgroundSubtractorMOG2 { return BackgroundSubtractorMOG2{p: unsafe.Pointer(C.BackgroundSubtractorMOG2_Create())} } // NewBackgroundSubtractorMOG2WithParams returns a new BackgroundSubtractor algorithm // of type MOG2 with customized parameters. MOG2 is a Gaussian Mixture-based Background/Foreground // Segmentation Algorithm. // // For further details, please see: // https://docs.opencv.org/master/de/de1/group__video__motion.html#ga2beb2dee7a073809ccec60f145b6b29c // https://docs.opencv.org/master/d7/d7b/classcv_1_1BackgroundSubtractorMOG2.html func NewBackgroundSubtractorMOG2WithParams(history int, varThreshold float64, detectShadows bool) BackgroundSubtractorMOG2 { return BackgroundSubtractorMOG2{p: unsafe.Pointer(C.BackgroundSubtractorMOG2_CreateWithParams(C.int(history), C.double(varThreshold), C.bool(detectShadows)))} } // Close BackgroundSubtractorMOG2. func (b *BackgroundSubtractorMOG2) Close() error { C.BackgroundSubtractorMOG2_Close((C.BackgroundSubtractorMOG2)(b.p)) b.p = nil return nil } // Apply computes a foreground mask using the current BackgroundSubtractorMOG2. // // For further details, please see: // https://docs.opencv.org/master/d7/df6/classcv_1_1BackgroundSubtractor.html#aa735e76f7069b3fa9c3f32395f9ccd21 func (b *BackgroundSubtractorMOG2) Apply(src Mat, dst *Mat) error { return OpenCVResult(C.BackgroundSubtractorMOG2_Apply((C.BackgroundSubtractorMOG2)(b.p), src.p, dst.p)) } func (b *BackgroundSubtractorMOG2) ApplyWithLearningRate(src Mat, dst *Mat, learningRate float64) error { return OpenCVResult(C.BackgroundSubtractorMOG2_ApplyWithParams((C.BackgroundSubtractorMOG2)(b.p), src.p, dst.p, C.double(learningRate))) } // BackgroundSubtractorKNN is a wrapper around the cv::BackgroundSubtractorKNN. type BackgroundSubtractorKNN struct { // C.BackgroundSubtractorKNN p unsafe.Pointer } // NewBackgroundSubtractorKNN returns a new BackgroundSubtractor algorithm // of type KNN. K-Nearest Neighbors (KNN) uses a Background/Foreground // Segmentation Algorithm // // For further details, please see: // https://docs.opencv.org/master/de/de1/group__video__motion.html#gac9be925771f805b6fdb614ec2292006d // https://docs.opencv.org/master/db/d88/classcv_1_1BackgroundSubtractorKNN.html func NewBackgroundSubtractorKNN() BackgroundSubtractorKNN { return BackgroundSubtractorKNN{p: unsafe.Pointer(C.BackgroundSubtractorKNN_Create())} } // NewBackgroundSubtractorKNNWithParams returns a new BackgroundSubtractor algorithm // of type KNN with customized parameters. K-Nearest Neighbors (KNN) uses a Background/Foreground // Segmentation Algorithm // // For further details, please see: // https://docs.opencv.org/master/de/de1/group__video__motion.html#gac9be925771f805b6fdb614ec2292006d // https://docs.opencv.org/master/db/d88/classcv_1_1BackgroundSubtractorKNN.html func NewBackgroundSubtractorKNNWithParams(history int, dist2Threshold float64, detectShadows bool) BackgroundSubtractorKNN { return BackgroundSubtractorKNN{p: unsafe.Pointer(C.BackgroundSubtractorKNN_CreateWithParams(C.int(history), C.double(dist2Threshold), C.bool(detectShadows)))} } // Close BackgroundSubtractorKNN. func (k *BackgroundSubtractorKNN) Close() error { C.BackgroundSubtractorKNN_Close((C.BackgroundSubtractorKNN)(k.p)) k.p = nil return nil } // Apply computes a foreground mask using the current BackgroundSubtractorKNN. // // For further details, please see: // https://docs.opencv.org/master/d7/df6/classcv_1_1BackgroundSubtractor.html#aa735e76f7069b3fa9c3f32395f9ccd21 func (k *BackgroundSubtractorKNN) Apply(src Mat, dst *Mat) error { return OpenCVResult(C.BackgroundSubtractorKNN_Apply((C.BackgroundSubtractorKNN)(k.p), src.p, dst.p)) } // CalcOpticalFlowFarneback computes a dense optical flow using // Gunnar Farneback's algorithm. // // For further details, please see: // https://docs.opencv.org/master/dc/d6b/group__video__track.html#ga5d10ebbd59fe09c5f650289ec0ece5af func CalcOpticalFlowFarneback(prevImg Mat, nextImg Mat, flow *Mat, pyrScale float64, levels int, winsize int, iterations int, polyN int, polySigma float64, flags int) error { return OpenCVResult(C.CalcOpticalFlowFarneback(prevImg.p, nextImg.p, flow.p, C.double(pyrScale), C.int(levels), C.int(winsize), C.int(iterations), C.int(polyN), C.double(polySigma), C.int(flags))) } // CalcOpticalFlowPyrLK calculates an optical flow for a sparse feature set using // the iterative Lucas-Kanade method with pyramids. // // For further details, please see: // https://docs.opencv.org/master/dc/d6b/group__video__track.html#ga473e4b886d0bcc6b65831eb88ed93323 func CalcOpticalFlowPyrLK(prevImg Mat, nextImg Mat, prevPts Mat, nextPts Mat, status *Mat, err *Mat) error { return OpenCVResult(C.CalcOpticalFlowPyrLK(prevImg.p, nextImg.p, prevPts.p, nextPts.p, status.p, err.p)) } // CalcOpticalFlowPyrLKWithParams calculates an optical flow for a sparse feature set using // the iterative Lucas-Kanade method with pyramids. // // For further details, please see: // https://docs.opencv.org/master/dc/d6b/group__video__track.html#ga473e4b886d0bcc6b65831eb88ed93323 func CalcOpticalFlowPyrLKWithParams(prevImg Mat, nextImg Mat, prevPts Mat, nextPts Mat, status *Mat, err *Mat, winSize image.Point, maxLevel int, criteria TermCriteria, flags int, minEigThreshold float64) error { winSz := C.struct_Size{ width: C.int(winSize.X), height: C.int(winSize.Y), } return OpenCVResult(C.CalcOpticalFlowPyrLKWithParams(prevImg.p, nextImg.p, prevPts.p, nextPts.p, status.p, err.p, winSz, C.int(maxLevel), criteria.p, C.int(flags), C.double(minEigThreshold))) } // FindTransformECC finds the geometric transform (warp) between two images in terms of the ECC criterion. // // For futther details, please see: // https://docs.opencv.org/4.x/dc/d6b/group__video__track.html#ga1aa357007eaec11e9ed03500ecbcbe47 func FindTransformECC(templateImage Mat, inputImage Mat, warpMatrix *Mat, motionType int, criteria TermCriteria, inputMask Mat, gaussFiltSize int) float64 { return float64(C.FindTransformECC(templateImage.p, inputImage.p, warpMatrix.p, C.int(motionType), criteria.p, inputMask.p, C.int(gaussFiltSize))) } // Tracker is the base interface for object tracking. // // see: https://docs.opencv.org/master/d0/d0a/classcv_1_1Tracker.html type Tracker interface { // Close closes, as Trackers need to be Closed manually. // Close() error // Init initializes the tracker with a known bounding box that surrounded the target. // Note: this can only be called once. If you lose the object, you have to Close() the instance, // create a new one, and call Init() on it again. // // see: https://docs.opencv.org/master/d0/d0a/classcv_1_1Tracker.html#a4d285747589b1bdd16d2e4f00c3255dc // Init(image Mat, boundingBox image.Rectangle) bool // Update updates the tracker, returns a new bounding box and a boolean determining whether the tracker lost the target. // // see: https://docs.opencv.org/master/d0/d0a/classcv_1_1Tracker.html#a549159bd0553e6a8de356f3866df1f18 // Update(image Mat) (image.Rectangle, bool) } func trackerInit(trk C.Tracker, img Mat, boundingBox image.Rectangle) bool { cBox := C.struct_Rect{ x: C.int(boundingBox.Min.X), y: C.int(boundingBox.Min.Y), width: C.int(boundingBox.Size().X), height: C.int(boundingBox.Size().Y), } ret := C.Tracker_Init(trk, C.Mat(img.Ptr()), cBox) return bool(ret) } func trackerUpdate(trk C.Tracker, img Mat) (image.Rectangle, bool) { cBox := C.struct_Rect{} ret := C.Tracker_Update(trk, C.Mat(img.Ptr()), &cBox) rect := image.Rect(int(cBox.x), int(cBox.y), int(cBox.x+cBox.width), int(cBox.y+cBox.height)) return rect, bool(ret) } // TrackerMIL is a Tracker that uses the MIL algorithm. MIL trains a classifier in an online manner // to separate the object from the background. // Multiple Instance Learning avoids the drift problem for a robust tracking. // // For further details, please see: // https://docs.opencv.org/master/d0/d26/classcv_1_1TrackerMIL.html type TrackerMIL struct { p C.TrackerMIL } // NewTrackerMIL returns a new TrackerMIL. func NewTrackerMIL() Tracker { return TrackerMIL{p: C.TrackerMIL_Create()} } // Close closes the TrackerMIL. func (trk TrackerMIL) Close() error { C.TrackerMIL_Close(trk.p) trk.p = nil return nil } // Init initializes the TrackerMIL. func (trk TrackerMIL) Init(img Mat, boundingBox image.Rectangle) bool { return trackerInit(C.Tracker(trk.p), img, boundingBox) } // Update updates the TrackerMIL. func (trk TrackerMIL) Update(img Mat) (image.Rectangle, bool) { return trackerUpdate(C.Tracker(trk.p), img) } type TrackerGOTURN struct { p C.TrackerGOTURN } // NewTrackerGOTURN the GOTURN (Generic Object Tracking Using Regression Networks) tracker // GOTURN ([122]) is kind of trackers based on Convolutional Neural Networks (CNN). // // For further details, please see: // https://docs.opencv.org/4.x/d7/d4c/classcv_1_1TrackerGOTURN.html#details func NewTrackerGOTURN() TrackerGOTURN { return TrackerGOTURN{p: C.TrackerGOTURN_Create()} } // NewTrackerGOTURNWithParams the GOTURN (Generic Object Tracking Using Regression Networks) tracker // GOTURN ([122]) is kind of trackers based on Convolutional Neural Networks (CNN). // // For further details, please see: // https://docs.opencv.org/4.x/d7/d4c/classcv_1_1TrackerGOTURN.html#details func NewTrackerGOTURNWithParams(modelBin string, modelTxt string) TrackerGOTURN { c_modelBin := C.CString(modelBin) c_modelTxt := C.CString(modelTxt) defer C.free(unsafe.Pointer(c_modelBin)) defer C.free(unsafe.Pointer(c_modelTxt)) return TrackerGOTURN{p: C.TrackerGOTURN_CreateWithParams(c_modelBin, c_modelTxt)} } // Init initializes the tracker with a known bounding box that surrounded the target. // Note: this can only be called once. If you lose the object, you have to Close() the instance, // create a new one, and call Init() on it again. // // see: https://docs.opencv.org/master/d0/d0a/classcv_1_1Tracker.html#a4d285747589b1bdd16d2e4f00c3255dc func (t TrackerGOTURN) Init(mat Mat, boundingBox image.Rectangle) bool { return trackerInit(C.Tracker(t.p), mat, boundingBox) } // Update updates the tracker, returns a new bounding box and a boolean determining whether the tracker lost the target. // // see: https://docs.opencv.org/master/d0/d0a/classcv_1_1Tracker.html#a549159bd0553e6a8de356f3866df1f18 func (t TrackerGOTURN) Update(mat Mat) (image.Rectangle, bool) { return trackerUpdate(C.Tracker(t.p), mat) } func (t TrackerGOTURN) Close() error { C.TrackerGOTURN_Close(t.p) t.p = nil return nil } // TrackerVit is a Tracker using the Vit tracker, a super lightweight dnn-based general object tracking. // // For further details, please see: // https://docs.opencv.org/4.x/d9/d26/classcv_1_1TrackerVit.html type TrackerVit struct { p C.TrackerVit } // NewTrackerVit returns a new TrackerVit. func NewTrackerVit() Tracker { return TrackerVit{p: C.TrackerVit_Create()} } func NewTrackerVitWithParams(model string) TrackerVit { c_model := C.CString(model) defer C.free(unsafe.Pointer(c_model)) return TrackerVit{p: C.TrackerVit_CreateWithParams(c_model)} } // Close closes the TrackerMIL. func (trk TrackerVit) Close() error { C.TrackerVit_Close(trk.p) trk.p = nil return nil } // Init initializes the TrackerVIT. func (trk TrackerVit) Init(img Mat, boundingBox image.Rectangle) bool { return trackerInit(C.Tracker(trk.p), img, boundingBox) } // Update updates the TrackerVIT. func (trk TrackerVit) Update(img Mat) (image.Rectangle, bool) { return trackerUpdate(C.Tracker(trk.p), img) } // KalmanFilter implements a standard Kalman filter http://en.wikipedia.org/wiki/Kalman_filter. // However, you can modify transitionMatrix, controlMatrix, and measurementMatrix // to get an extended Kalman filter functionality. // // For further details, please see: // https://docs.opencv.org/4.6.0/dd/d6a/classcv_1_1KalmanFilter.html type KalmanFilter struct { p C.KalmanFilter } // NewKalmanFilter returns a new KalmanFilter. // // For further details, please see: // https://docs.opencv.org/4.6.0/dd/d6a/classcv_1_1KalmanFilter.html#ac0799f0611baee9e7e558f016e4a7b40 func NewKalmanFilter(dynamParams int, measureParams int) KalmanFilter { return KalmanFilter{p: C.KalmanFilter_New(C.int(dynamParams), C.int(measureParams))} } // NewKalmanFilterWithParams returns a new KalmanFilter. // // For further details, please see: // https://docs.opencv.org/4.6.0/dd/d6a/classcv_1_1KalmanFilter.html#abac82ecfa530611a163255bc7d91c088 func NewKalmanFilterWithParams(dynamParams int, measureParams int, controlParams int, matType MatType) KalmanFilter { return KalmanFilter{p: C.KalmanFilter_NewWithParams(C.int(dynamParams), C.int(measureParams), C.int(controlParams), C.int(matType))} } // Init re-initializes the Kalman filter. The previous content is destroyed. // // For further details, please see: // https://docs.opencv.org/4.6.0/dd/d6a/classcv_1_1KalmanFilter.html#a4f136c39c016d3530c7c5801dd1ddb3b func (kf *KalmanFilter) Init(dynamParams int, measureParams int) error { return OpenCVResult(C.KalmanFilter_Init(kf.p, C.int(dynamParams), C.int(measureParams))) } // Predict computes a predicted state. // // For further details, please see: // https://docs.opencv.org/4.6.0/dd/d6a/classcv_1_1KalmanFilter.html#aa710d2255566bec8d6ce608d103d4fa7 func (kf *KalmanFilter) Predict() Mat { return newMat(C.KalmanFilter_Predict(kf.p)) } // PredictWithParams computes a predicted state. // // For further details, please see: // https://docs.opencv.org/4.6.0/dd/d6a/classcv_1_1KalmanFilter.html#aa710d2255566bec8d6ce608d103d4fa7 func (kf *KalmanFilter) PredictWithParams(control Mat) Mat { return newMat(C.KalmanFilter_PredictWithParams(kf.p, control.p)) } // Correct the predicted state from the measurement. // // For further details, please see: // https://docs.opencv.org/4.6.0/dd/d6a/classcv_1_1KalmanFilter.html#a60eb7feb569222ad0657ef1875884b5e func (kf *KalmanFilter) Correct(measurement Mat) Mat { return newMat(C.KalmanFilter_Correct(kf.p, measurement.p)) } // Close closes the kalman filter. func (kf *KalmanFilter) Close() { C.KalmanFilter_Close(kf.p) kf.p = nil } // GetStatePre returns the Kalman filter's statePre Mat. // // predicted state (x'(k)): x(k)=A*x(k-1)+B*u(k) // // For further details, please see: // https://docs.opencv.org/4.6.0/dd/d6a/classcv_1_1KalmanFilter.html#a60eb7feb569222ad0657ef1875884b5e func (kf *KalmanFilter) GetStatePre() Mat { return newMat(C.KalmanFilter_GetStatePre(kf.p)) } // GetStatePost returns the Kalman filter's statePost Mat. // // corrected state (x(k)): x(k)=x'(k)+K(k)*(z(k)-H*x'(k)) // // For further details, please see: // https://docs.opencv.org/4.6.0/dd/d6a/classcv_1_1KalmanFilter.html#add8fb5ac9c04b4600b679698dcb0447d func (kf *KalmanFilter) GetStatePost() Mat { return newMat(C.KalmanFilter_GetStatePost(kf.p)) } // GetTransitionMatrix returns the Kalman filter's transitionMatrix Mat. // // state transition matrix (A) // // For further details, please see: // https://docs.opencv.org/4.6.0/dd/d6a/classcv_1_1KalmanFilter.html#a0657173e411acbf40d2d3c6b46e03b19 func (kf *KalmanFilter) GetTransitionMatrix() Mat { return newMat(C.KalmanFilter_GetTransitionMatrix(kf.p)) } // GetControlMatrix returns the Kalman filter's controlMatrix Mat. // // control matrix (B) (not used if there is no control) // // For further details, please see: // https://docs.opencv.org/4.6.0/dd/d6a/classcv_1_1KalmanFilter.html#a6486e7287114810636fb33953280ed52 func (kf *KalmanFilter) GetControlMatrix() Mat { return newMat(C.KalmanFilter_GetControlMatrix(kf.p)) } // GetMeasurementMatrix returns the Kalman filter's measurementMatrix Mat. // // measurement matrix (H) // // For further details, please see: // https://docs.opencv.org/4.6.0/dd/d6a/classcv_1_1KalmanFilter.html#a0f60b78726d8eccf74a1f2479c2d1f97 func (kf *KalmanFilter) GetMeasurementMatrix() Mat { return newMat(C.KalmanFilter_GetMeasurementMatrix(kf.p)) } // GetProcessNoiseCov returns the Kalman filter's processNoiseCov Mat. // // process noise covariance matrix (Q) // // For further details, please see: // https://docs.opencv.org/4.6.0/dd/d6a/classcv_1_1KalmanFilter.html#af19be9c0630d0f658bdbaea409a35cda func (kf *KalmanFilter) GetProcessNoiseCov() Mat { return newMat(C.KalmanFilter_GetProcessNoiseCov(kf.p)) } // GetMeasurementNoiseCov returns the Kalman filter's measurementNoiseCov Mat. // // measurement noise covariance matrix (R) // // For further details, please see: // https://docs.opencv.org/4.6.0/dd/d6a/classcv_1_1KalmanFilter.html#a828d051035ba807966ad65edf288a08e func (kf *KalmanFilter) GetMeasurementNoiseCov() Mat { return newMat(C.KalmanFilter_GetMeasurementNoiseCov(kf.p)) } // GetErrorCovPre returns the Kalman filter's errorCovPre Mat. // // priori error estimate covariance matrix (P'(k)): P'(k)=A*P(k-1)*At + Q)*/ // // For further details, please see: // https://docs.opencv.org/4.6.0/dd/d6a/classcv_1_1KalmanFilter.html#ae1bd3a86f10753d723e7174d570d9ac1 func (kf *KalmanFilter) GetErrorCovPre() Mat { return newMat(C.KalmanFilter_GetErrorCovPre(kf.p)) } // GetGain returns the Kalman filter's gain Mat. // // Kalman gain matrix (K(k)): K(k)=P'(k)*Ht*inv(H*P'(k)*Ht+R) // // For further details, please see: // https://docs.opencv.org/4.6.0/dd/d6a/classcv_1_1KalmanFilter.html#a077d73eb075b00779dc009a9057c27c3 func (kf *KalmanFilter) GetGain() Mat { return newMat(C.KalmanFilter_GetGain(kf.p)) } // GetErrorCovPost returns the Kalman filter's errorCovPost Mat. // // posteriori error estimate covariance matrix (P(k)): P(k)=(I-K(k)*H)*P'(k) // // For further details, please see: // https://docs.opencv.org/4.6.0/dd/d6a/classcv_1_1KalmanFilter.html#a446d8e9a0105b0aa35cd66119c529803 func (kf *KalmanFilter) GetErrorCovPost() Mat { return newMat(C.KalmanFilter_GetErrorCovPost(kf.p)) } // GetTemp1 returns the Kalman filter's temp1 Mat. // // For further details, please see: // https://docs.opencv.org/4.6.0/dd/d6a/classcv_1_1KalmanFilter.html#aa3d064a9194c2815dbe19c056b6dc763 func (kf *KalmanFilter) GetTemp1() Mat { return newMat(C.KalmanFilter_GetTemp1(kf.p)) } // GetTemp2 returns the Kalman filter's temp2 Mat. // // For further details, please see: // https://docs.opencv.org/4.6.0/dd/d6a/classcv_1_1KalmanFilter.html#a14866bd506668eb0ed57b3974b3a1ee7 func (kf *KalmanFilter) GetTemp2() Mat { return newMat(C.KalmanFilter_GetTemp2(kf.p)) } // GetTemp3 returns the Kalman filter's temp3 Mat. // // For further details, please see: // https://docs.opencv.org/4.6.0/dd/d6a/classcv_1_1KalmanFilter.html#afdbe36066a7d7f560aa02abe6be114d8 func (kf *KalmanFilter) GetTemp3() Mat { return newMat(C.KalmanFilter_GetTemp3(kf.p)) } // GetTemp4 returns the Kalman filter's temp4 Mat. // // For further details, please see: // https://docs.opencv.org/4.6.0/dd/d6a/classcv_1_1KalmanFilter.html#a84342f2d9dec1e6389025ad229401809 func (kf *KalmanFilter) GetTemp4() Mat { return newMat(C.KalmanFilter_GetTemp4(kf.p)) } // GetTemp5 returns the Kalman filter's temp5 Mat. // // For further details, please see: // https://docs.opencv.org/4.6.0/dd/d6a/classcv_1_1KalmanFilter.html#a846c2a6222c6e5d8b1385dfbccc83ae0 func (kf *KalmanFilter) GetTemp5() Mat { return newMat(C.KalmanFilter_GetTemp5(kf.p)) } // SetStatePre sets the Kalman filter's statePre Mat. func (kf *KalmanFilter) SetStatePre(statePre Mat) { C.KalmanFilter_SetStatePre(kf.p, statePre.p) } // SetStatePost sets the Kalman filter's statePost Mat. func (kf *KalmanFilter) SetStatePost(statePost Mat) { C.KalmanFilter_SetStatePost(kf.p, statePost.p) } // SetTransitionMatrix sets the Kalman filter's transitionMatrix Mat. func (kf *KalmanFilter) SetTransitionMatrix(transitionMatrix Mat) { C.KalmanFilter_SetTransitionMatrix(kf.p, transitionMatrix.p) } // SetControlMatrix sets the Kalman filter's controlMatrix Mat. func (kf *KalmanFilter) SetControlMatrix(controlMatrix Mat) { C.KalmanFilter_SetControlMatrix(kf.p, controlMatrix.p) } // SetMeasurementMatrix sets the Kalman filter's measurementMatrix Mat. func (kf *KalmanFilter) SetMeasurementMatrix(measurementMatrix Mat) { C.KalmanFilter_SetMeasurementMatrix(kf.p, measurementMatrix.p) } // SetProcessNoiseCov sets the Kalman filter's processNoiseCov Mat. func (kf *KalmanFilter) SetProcessNoiseCov(processNoiseCov Mat) { C.KalmanFilter_SetProcessNoiseCov(kf.p, processNoiseCov.p) } // SetMeasurementNoiseCov sets the Kalman filter's measurementNoiseCov Mat. func (kf *KalmanFilter) SetMeasurementNoiseCov(measurementNoiseCov Mat) { C.KalmanFilter_SetMeasurementNoiseCov(kf.p, measurementNoiseCov.p) } // SetErrorCovPre sets the Kalman filter's errorCovPre Mat. func (kf *KalmanFilter) SetErrorCovPre(errorCovPre Mat) { C.KalmanFilter_SetErrorCovPre(kf.p, errorCovPre.p) } // SetGain sets the Kalman filter's gain Mat. func (kf *KalmanFilter) SetGain(gain Mat) { C.KalmanFilter_SetGain(kf.p, gain.p) } // SetErrorCovPost sets the Kalman filter's errorCovPost Mat. func (kf *KalmanFilter) SetErrorCovPost(errorCovPost Mat) { C.KalmanFilter_SetErrorCovPost(kf.p, errorCovPost.p) } ================================================ FILE: video.h ================================================ #ifndef _OPENCV3_VIDEO_H_ #define _OPENCV3_VIDEO_H_ #ifdef __cplusplus #include #include extern "C" { #endif #include "core.h" #ifdef __cplusplus typedef cv::Ptr* BackgroundSubtractorMOG2; typedef cv::Ptr* BackgroundSubtractorKNN; typedef cv::Ptr* Tracker; typedef cv::Ptr* TrackerMIL; typedef cv::Ptr* TrackerGOTURN; typedef cv::Ptr* TrackerVit; typedef cv::KalmanFilter* KalmanFilter; #else typedef void* BackgroundSubtractorMOG2; typedef void* BackgroundSubtractorKNN; typedef void* Tracker; typedef void* TrackerMIL; typedef void* TrackerGOTURN; typedef void* TrackerVit; typedef void* KalmanFilter; #endif BackgroundSubtractorMOG2 BackgroundSubtractorMOG2_Create(); BackgroundSubtractorMOG2 BackgroundSubtractorMOG2_CreateWithParams(int history, double varThreshold, bool detectShadows); void BackgroundSubtractorMOG2_Close(BackgroundSubtractorMOG2 b); OpenCVResult BackgroundSubtractorMOG2_Apply(BackgroundSubtractorMOG2 b, Mat src, Mat dst); OpenCVResult BackgroundSubtractorMOG2_ApplyWithParams(BackgroundSubtractorMOG2 b, Mat src, Mat dst, double learningRate); BackgroundSubtractorKNN BackgroundSubtractorKNN_Create(); BackgroundSubtractorKNN BackgroundSubtractorKNN_CreateWithParams(int history, double dist2Threshold, bool detectShadows); void BackgroundSubtractorKNN_Close(BackgroundSubtractorKNN b); OpenCVResult BackgroundSubtractorKNN_Apply(BackgroundSubtractorKNN b, Mat src, Mat dst); OpenCVResult CalcOpticalFlowPyrLK(Mat prevImg, Mat nextImg, Mat prevPts, Mat nextPts, Mat status, Mat err); OpenCVResult CalcOpticalFlowPyrLKWithParams(Mat prevImg, Mat nextImg, Mat prevPts, Mat nextPts, Mat status, Mat err, Size winSize, int maxLevel, TermCriteria criteria, int flags, double minEigThreshold); OpenCVResult CalcOpticalFlowFarneback(Mat prevImg, Mat nextImg, Mat flow, double pyrScale, int levels, int winsize, int iterations, int polyN, double polySigma, int flags); double FindTransformECC(Mat templateImage, Mat inputImage, Mat warpMatrix, int motionType, TermCriteria criteria, Mat inputMask, int gaussFiltSize); bool Tracker_Init(Tracker self, Mat image, Rect boundingBox); bool Tracker_Update(Tracker self, Mat image, Rect* boundingBox); TrackerMIL TrackerMIL_Create(); void TrackerMIL_Close(TrackerMIL self); TrackerGOTURN TrackerGOTURN_Create(void); TrackerGOTURN TrackerGOTURN_CreateWithParams(const char* modelBin, const char* modelTxt); void TrackerGOTURN_Close(TrackerGOTURN tr); TrackerVit TrackerVit_Create(); TrackerVit TrackerVit_CreateWithParams(const char* model); void TrackerVit_Close(TrackerVit self); KalmanFilter KalmanFilter_New(int dynamParams, int measureParams); KalmanFilter KalmanFilter_NewWithParams(int dynamParams, int measureParams, int controlParams, int type); void KalmanFilter_Close(KalmanFilter kf); OpenCVResult KalmanFilter_Init(KalmanFilter kf, int dynamParams, int measureParams); OpenCVResult KalmanFilter_InitWithParams(KalmanFilter kf, int dynamParams, int measureParams, int controlParams, int type); Mat KalmanFilter_Predict(KalmanFilter kf); Mat KalmanFilter_PredictWithParams(KalmanFilter kf, Mat control); Mat KalmanFilter_Correct(KalmanFilter kf, Mat measurement); Mat KalmanFilter_GetStatePre(KalmanFilter kf); Mat KalmanFilter_GetStatePost(KalmanFilter kf); Mat KalmanFilter_GetTransitionMatrix(KalmanFilter kf); Mat KalmanFilter_GetControlMatrix(KalmanFilter kf); Mat KalmanFilter_GetMeasurementMatrix(KalmanFilter kf); Mat KalmanFilter_GetProcessNoiseCov(KalmanFilter kf); Mat KalmanFilter_GetMeasurementNoiseCov(KalmanFilter kf); Mat KalmanFilter_GetErrorCovPre(KalmanFilter kf); Mat KalmanFilter_GetGain(KalmanFilter kf); Mat KalmanFilter_GetErrorCovPost(KalmanFilter kf); Mat KalmanFilter_GetTemp1(KalmanFilter kf); Mat KalmanFilter_GetTemp2(KalmanFilter kf); Mat KalmanFilter_GetTemp3(KalmanFilter kf); Mat KalmanFilter_GetTemp4(KalmanFilter kf); Mat KalmanFilter_GetTemp5(KalmanFilter kf); void KalmanFilter_SetStatePre(KalmanFilter kf, Mat statePre); void KalmanFilter_SetStatePost(KalmanFilter kf, Mat statePost); void KalmanFilter_SetTransitionMatrix(KalmanFilter kf, Mat transitionMatrix); void KalmanFilter_SetControlMatrix(KalmanFilter kf, Mat controlMatrix); void KalmanFilter_SetMeasurementMatrix(KalmanFilter kf, Mat measurementMatrix); void KalmanFilter_SetProcessNoiseCov(KalmanFilter kf, Mat processNoiseCov); void KalmanFilter_SetMeasurementNoiseCov(KalmanFilter kf, Mat measurementNoiseCov); void KalmanFilter_SetErrorCovPre(KalmanFilter kf, Mat errorCovPre); void KalmanFilter_SetGain(KalmanFilter kf, Mat gain); void KalmanFilter_SetErrorCovPost(KalmanFilter kf, Mat errorCovPost); #ifdef __cplusplus } #endif #endif //_OPENCV3_VIDEO_H_ ================================================ FILE: video_test.go ================================================ //go:build !gocv_specific_modules || (gocv_specific_modules && gocv_video) package gocv import ( "image" "image/color" "math" "os" "testing" ) func TestMOG2(t *testing.T) { img := IMRead("images/face.jpg", IMReadColor) if img.Empty() { t.Error("Invalid Mat in MOG2 test") } defer img.Close() dst := NewMat() defer dst.Close() mog2 := NewBackgroundSubtractorMOG2() defer mog2.Close() mog2.Apply(img, &dst) if dst.Empty() { t.Error("Error in TestMOG2 test") } } func TestMOG2ApplyWithParams(t *testing.T) { img := IMRead("images/face.jpg", IMReadColor) if img.Empty() { t.Error("Invalid Mat in MOG2 test") } defer img.Close() dst := NewMat() defer dst.Close() mog2 := NewBackgroundSubtractorMOG2() defer mog2.Close() mog2.ApplyWithLearningRate(img, &dst, 0.01) if dst.Empty() { t.Error("Error in TestMOG2 test") } } func TestMOG2WithParams(t *testing.T) { img := IMRead("images/face.jpg", IMReadColor) if img.Empty() { t.Error("Invalid Mat in MOG2 test") } defer img.Close() dst := NewMat() defer dst.Close() mog2 := NewBackgroundSubtractorMOG2WithParams(250, 8, false) defer mog2.Close() mog2.Apply(img, &dst) if dst.Empty() { t.Error("Error in TestMOG2WithParams test") } } func TestMOG2WithParamsWithLR(t *testing.T) { img := IMRead("images/face.jpg", IMReadColor) if img.Empty() { t.Error("Invalid Mat in MOG2 test") } defer img.Close() dst := NewMat() defer dst.Close() mog2 := NewBackgroundSubtractorMOG2WithParams(250, 8, false) defer mog2.Close() mog2.ApplyWithLearningRate(img, &dst, 0.0) if dst.Empty() { t.Error("Error in TestMOG2WithParams test") } } func TestKNN(t *testing.T) { img := IMRead("images/face.jpg", IMReadColor) if img.Empty() { t.Error("Invalid Mat in KNN test") } defer img.Close() dst := NewMat() defer dst.Close() knn := NewBackgroundSubtractorKNN() defer knn.Close() knn.Apply(img, &dst) if dst.Empty() { t.Error("Error in TestKNN test") } } func TestKNNWithParams(t *testing.T) { img := IMRead("images/face.jpg", IMReadColor) if img.Empty() { t.Error("Invalid Mat in KNN test") } defer img.Close() dst := NewMat() defer dst.Close() knn := NewBackgroundSubtractorKNNWithParams(250, 200, false) defer knn.Close() knn.Apply(img, &dst) if dst.Empty() { t.Error("Error in TestKNNWithParams test") } } func TestCalcOpticalFlowFarneback(t *testing.T) { img1 := IMRead("images/face.jpg", IMReadColor) if img1.Empty() { t.Error("Invalid Mat in CalcOpticalFlowFarneback test") } defer img1.Close() dest := NewMat() defer dest.Close() CvtColor(img1, &dest, ColorBGRAToGray) img2 := dest.Clone() defer img2.Close() flow := NewMat() defer flow.Close() CalcOpticalFlowFarneback(dest, img2, &flow, 0.4, 1, 12, 2, 8, 1.2, 0) if flow.Empty() { t.Error("Error in CalcOpticalFlowFarneback test") } if flow.Rows() != 480 { t.Errorf("Invalid CalcOpticalFlowFarneback test rows: %v", flow.Rows()) } if flow.Cols() != 640 { t.Errorf("Invalid CalcOpticalFlowFarneback test cols: %v", flow.Cols()) } } func TestCalcOpticalFlowPyrLK(t *testing.T) { img1 := IMRead("images/face.jpg", IMReadColor) if img1.Empty() { t.Error("Invalid Mat in CalcOpticalFlowPyrLK test") } defer img1.Close() dest := NewMat() defer dest.Close() CvtColor(img1, &dest, ColorBGRAToGray) img2 := dest.Clone() defer img2.Close() prevPts := NewMat() defer prevPts.Close() nextPts := NewMat() defer nextPts.Close() status := NewMat() defer status.Close() err := NewMat() defer err.Close() corners := NewMat() defer corners.Close() GoodFeaturesToTrack(dest, &corners, 500, 0.01, 10) tc := NewTermCriteria(Count|EPS, 20, 0.03) CornerSubPix(dest, &corners, image.Pt(10, 10), image.Pt(-1, -1), tc) CalcOpticalFlowPyrLK(dest, img2, corners, nextPts, &status, &err) if status.Empty() { t.Error("Error in CalcOpticalFlowPyrLK test") } if status.Rows() != 323 { t.Errorf("Invalid CalcOpticalFlowPyrLK test rows: %v", status.Rows()) } if status.Cols() != 1 { t.Errorf("Invalid CalcOpticalFlowPyrLK test cols: %v", status.Cols()) } } func TestCalcOpticalFlowPyrLKWithParams(t *testing.T) { img1 := IMRead("images/face.jpg", IMReadColor) if img1.Empty() { t.Error("Invalid Mat in CalcOpticalFlowPyrLK test") } defer img1.Close() dest := NewMat() defer dest.Close() CvtColor(img1, &dest, ColorBGRAToGray) img2 := dest.Clone() defer img2.Close() prevPts := NewMat() defer prevPts.Close() nextPts := NewMat() defer nextPts.Close() status := NewMat() defer status.Close() err := NewMat() defer err.Close() corners := NewMat() defer corners.Close() GoodFeaturesToTrack(dest, &corners, 500, 0.01, 10) tc := NewTermCriteria(Count|EPS, 30, 0.03) CornerSubPix(dest, &corners, image.Pt(10, 10), image.Pt(-1, -1), tc) CalcOpticalFlowPyrLKWithParams(dest, img2, corners, nextPts, &status, &err, image.Pt(21, 21), 3, tc, 0, 0.0001) if status.Empty() { t.Error("Error in CalcOpticalFlowPyrLK test") } if status.Rows() != 323 { t.Errorf("Invalid CalcOpticalFlowPyrLK test rows: %v", status.Rows()) } if status.Cols() != 1 { t.Errorf("Invalid CalcOpticalFlowPyrLK test cols: %v", status.Cols()) } } func computeRMS(mat1 Mat, mat2 Mat) float64 { var rms float64 for y := 0; y < mat1.Rows(); y++ { for x := 0; x < mat1.Cols(); x++ { diff := float64(mat1.GetFloatAt(y, x) - mat2.GetFloatAt(y, x)) rms += diff * diff } } rms /= float64(mat1.Rows() * mat1.Cols()) return math.Sqrt(rms) } func TestFindTransformECC(t *testing.T) { img := IMRead("images/face.jpg", IMReadGrayScale) if img.Empty() { t.Error("Invalid Mat in FindTransformECC test") } defer img.Close() testImg := NewMat() defer testImg.Close() Resize(img, &testImg, image.Point{216, 216}, 0, 0, InterpolationLinear) translationGround := Eye(2, 3, MatTypeCV32F) defer translationGround.Close() translationGround.SetFloatAt(0, 2, 11.4159) translationGround.SetFloatAt(1, 2, 17.1828) warpedImage := NewMat() defer warpedImage.Close() WarpAffineWithParams(testImg, &warpedImage, translationGround, image.Point{200, 200}, InterpolationLinear+WarpInverseMap, BorderConstant, color.RGBA{}) mapTranslation := Eye(2, 3, MatTypeCV32F) defer mapTranslation.Close() eecIterations := 50 // Negative value means that ECC_Iterations will be executed. var eecEpsilon float64 = -1 criteria := NewTermCriteria(Count+EPS, eecIterations, eecEpsilon) inputMask := NewMat() defer inputMask.Close() gaussFiltSize := 5 FindTransformECC(warpedImage, testImg, &mapTranslation, MotionTranslation, criteria, inputMask, gaussFiltSize) maxRMSECC := 0.1 rms := computeRMS(mapTranslation, translationGround) if rms > maxRMSECC { t.Errorf("FindTransformECC RMS = %f", rms) } } func BaseTestTracker(t *testing.T, tracker Tracker, name string) { if tracker == nil { t.Error("TestTracker " + name + " should not be nil") } img := IMRead("./images/face.jpg", 1) if img.Empty() { t.Error("TestTracker " + name + " input img failed to load") } defer img.Close() rect := image.Rect(250, 150, 250+200, 150+250) init := tracker.Init(img, rect) if !init { t.Error("TestTracker " + name + " failed in Init") } _, ok := tracker.Update(img) if !ok { t.Error("TestTracker " + name + " lost object in Update") } } func TestSingleTrackers(t *testing.T) { goturnPath := os.Getenv("GOCV_TRACKER_GOTURN_TEST_FILES") if goturnPath == "" { goturnPath = "./testdata" } vitPath := os.Getenv("GOCV_ONNX_TEST_FILES") if vitPath == "" { vitPath = "./testdata" } tab := []struct { name string tracker Tracker }{ {"MIL", NewTrackerMIL()}, {"GOTURN", NewTrackerGOTURNWithParams(goturnPath+"/goturn.caffemodel", goturnPath+"/goturn.prototxt")}, {"Vit", NewTrackerVitWithParams(vitPath + "/object_tracking_vittrack_2023sep.onnx")}, } for _, test := range tab { func() { defer test.tracker.Close() BaseTestTracker(t, test.tracker, test.name) }() } } func TestKalmanFilter(t *testing.T) { // Basic test with default constructor. kf := NewKalmanFilter(2, 1) kf.Init(2, 1) measurement := Zeros(1, 1, MatTypeCV32F) prediction := kf.Predict() statePost := kf.Correct(measurement) statePost.Close() prediction.Close() measurement.Close() kf.Close() // Basic test with param constructor. kf = NewKalmanFilterWithParams(2, 1, 1, MatTypeCV32F) control := Ones(1, 1, MatTypeCV32F) measurement = Ones(1, 1, MatTypeCV32F) prediction = kf.PredictWithParams(control) statePost = kf.Correct(measurement) statePost.Close() prediction.Close() measurement.Close() control.Close() kf.Close() } func TestKalmanFilter_Getters(t *testing.T) { kf := NewKalmanFilterWithParams(2, 1, 1, MatTypeCV32F) getterTests := []struct { desc string f func() Mat }{ {desc: "GetStatePre()", f: kf.GetStatePre}, {desc: "GetStatePost()", f: kf.GetStatePost}, {desc: "GetTransitionMatrix()", f: kf.GetTransitionMatrix}, {desc: "GetControlMatrix()", f: kf.GetControlMatrix}, {desc: "GetMeasurementMatrix()", f: kf.GetMeasurementMatrix}, {desc: "GetProcessNoiseCov()", f: kf.GetProcessNoiseCov}, {desc: "GetMeasurementNoiseCov()", f: kf.GetMeasurementNoiseCov}, {desc: "GetErrorCovPre()", f: kf.GetErrorCovPre}, {desc: "GetGain()", f: kf.GetGain}, {desc: "GetErrorCovPost()", f: kf.GetErrorCovPost}, {desc: "GetTemp1()", f: kf.GetTemp1}, {desc: "GetTemp2()", f: kf.GetTemp2}, {desc: "GetTemp3()", f: kf.GetTemp3}, {desc: "GetTemp4()", f: kf.GetTemp4}, {desc: "GetTemp5()", f: kf.GetTemp5}, } for _, test := range getterTests { t.Run(test.desc, func(t *testing.T) { if got := test.f(); got.Empty() { t.Errorf("%v: returned empty, want non-Empty", test.desc) } else { got.Close() } }) } kf.Close() } func TestKalmanFilter_Setters(t *testing.T) { kf := NewKalmanFilter(2, 1) tests := []struct { desc string f func(Mat) }{ {desc: "SetStatePre()", f: kf.SetStatePre}, {desc: "SetStatePost()", f: kf.SetStatePost}, {desc: "SetTransitionMatrix()", f: kf.SetTransitionMatrix}, {desc: "SetControlMatrix()", f: kf.SetControlMatrix}, {desc: "SetMeasurementMatrix()", f: kf.SetMeasurementMatrix}, {desc: "SetProcessNoiseCov()", f: kf.SetProcessNoiseCov}, {desc: "SetMeasurementNoiseCov()", f: kf.SetMeasurementNoiseCov}, {desc: "SetErrorCovPre()", f: kf.SetErrorCovPre}, {desc: "SetGain()", f: kf.SetGain}, {desc: "SetErrorCovPost()", f: kf.SetErrorCovPost}, } for _, test := range tests { t.Run(test.desc, func(t *testing.T) { testMat := Ones(2, 1, MatTypeCV32F) // Just run this to make sure the execution doesn't fail. test.f(testMat) testMat.Close() }) } kf.Close() } ================================================ FILE: videoio.cpp ================================================ //go:build !gocv_specific_modules || (gocv_specific_modules && gocv_videoio) #include #include "videoio.h" // VideoWriter VideoCapture VideoCapture_New() { try { return new cv::VideoCapture(); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } void VideoCapture_Close(VideoCapture v) { delete v; } bool VideoCapture_Open(VideoCapture v, const char* uri) { try { return v->open(uri); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return false; } } bool VideoCapture_OpenWithAPI(VideoCapture v, const char* uri, int apiPreference) { try { return v->open(uri, apiPreference); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return false; } } bool VideoCapture_OpenWithAPIParams(VideoCapture v, const char* uri, int apiPreference, int *paramsv, int paramsc) { try { std::vector< int > params; for( int i = 0; i< paramsc; i++) { params.push_back(paramsv[i]); } return v->open(cv::String(uri), apiPreference, params); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return false; } } bool VideoCapture_OpenDevice(VideoCapture v, int device) { try { return v->open(device); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return false; } } bool VideoCapture_OpenDeviceWithAPI(VideoCapture v, int device, int apiPreference) { try { return v->open(device, apiPreference); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return false; } } bool VideoCapture_OpenDeviceWithAPIParams(VideoCapture v, int device, int apiPreference, int *paramsv, int paramsc) { try { std::vector< int > params; for( int i = 0; i< paramsc; i++) { params.push_back(paramsv[i]); } return v->open(device, apiPreference, params); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return false; } } OpenCVResult VideoCapture_Set(VideoCapture v, int prop, double param) { try { v->set(prop, param); OpenCVResult result = {0, NULL}; return result; } catch(const cv::Exception& e) { OpenCVResult result = {e.code, e.what()}; return result; } } double VideoCapture_Get(VideoCapture v, int prop) { try { return v->get(prop); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return 0.0; } } int VideoCapture_IsOpened(VideoCapture v) { try { return v->isOpened(); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return 0; } } int VideoCapture_Read(VideoCapture v, Mat buf) { try { return v->read(*buf); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return 0; } } OpenCVResult VideoCapture_Grab(VideoCapture v, int skip) { try { for (int i = 0; i < skip; i++) { v->grab(); } OpenCVResult result = {0, NULL}; return result; } catch(const cv::Exception& e) { OpenCVResult result = {e.code, e.what()}; return result; } } int VideoCapture_Retrieve(VideoCapture v, Mat buf) { try { return v->retrieve(*buf); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return 0; } } int VideoCapture_RetrieveChannel(VideoCapture v, Mat buf, int channel) { try { return v->retrieve(*buf, channel); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return 0; } } // VideoWriter VideoWriter VideoWriter_New() { try { return new cv::VideoWriter(); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return NULL; } } void VideoWriter_Close(VideoWriter vw) { delete vw; } OpenCVResult VideoWriter_Open(VideoWriter vw, const char* name, const char* codec, double fps, int width, int height, bool isColor) { try { int codecCode = cv::VideoWriter::fourcc(codec[0], codec[1], codec[2], codec[3]); vw->open(name, codecCode, fps, cv::Size(width, height), isColor); OpenCVResult result = {0, NULL}; return result; } catch(const cv::Exception& e) { OpenCVResult result = {e.code, e.what()}; return result; } } OpenCVResult VideoWriter_OpenWithAPI(VideoWriter vw, const char* name, int apiPreference, const char* codec, double fps, int width, int height, bool isColor) { try { int codecCode = cv::VideoWriter::fourcc(codec[0], codec[1], codec[2], codec[3]); vw->open(name, apiPreference, codecCode, fps, cv::Size(width, height), isColor); OpenCVResult result = {0, NULL}; return result; } catch(const cv::Exception& e) { OpenCVResult result = {e.code, e.what()}; return result; } } OpenCVResult VideoWriter_OpenWithAPIParams(VideoWriter vw, const char* name, int apiPreference, const char* codec, double fps, int width, int height, IntVector params) { try { std::vector cpp_params; for(int i = 0; i < params.length; i++) { cpp_params.push_back(params.val[i]); } int codecCode = cv::VideoWriter::fourcc(codec[0], codec[1], codec[2], codec[3]); vw->open(name, apiPreference, codecCode, fps, cv::Size(width, height), cpp_params); OpenCVResult result = {0, NULL}; return result; } catch(const cv::Exception& e) { OpenCVResult result = {e.code, e.what()}; return result; } } int VideoWriter_IsOpened(VideoWriter vw) { try { return vw->isOpened(); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return 0; } } OpenCVResult VideoWriter_Write(VideoWriter vw, Mat img) { try { *vw << *img; OpenCVResult result = {0, NULL}; return result; } catch(const cv::Exception& e) { OpenCVResult result = {e.code, e.what()}; return result; } } const char* Videoio_Registry_GetBackendName(int api) { try { cv::String name; name = cv::videoio_registry::getBackendName((cv::VideoCaptureAPIs)(api)); return strdup(name.c_str()); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return ""; } } IntVector Videio_Registry_GetBackends() { try { IntVector c_backs; std::vector backs = cv::videoio_registry::getBackends(); c_backs.val = new int[backs.size()]; c_backs.length = backs.size(); for(int i = 0; i < c_backs.length; i++) { c_backs.val[i] = backs[i]; } return c_backs; } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); IntVector empty; return empty; } } const char* Videoio_Registry_GetCameraBackendPluginVersion(int api, int* version_ABI, int* version_API) { try { std::string desc = cv::videoio_registry::getCameraBackendPluginVersion((cv::VideoCaptureAPIs)(api), *version_ABI, *version_API); return strdup(desc.c_str()); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return ""; } } IntVector Videoio_Registry_GetCameraBackends() { try { IntVector c_backs; std::vector backs = cv::videoio_registry::getCameraBackends(); c_backs.val = new int[backs.size()]; c_backs.length = backs.size(); for(int i = 0; i < c_backs.length; i++) { c_backs.val[i] = backs[i]; } return c_backs; } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); IntVector empty; return empty; } } const char* Videoio_Registry_GetStreamBackendPluginVersion(int api, int* version_ABI, int* version_API){ try { std::string desc = cv::videoio_registry::getStreamBackendPluginVersion((cv::VideoCaptureAPIs)(api), *version_ABI, *version_API); return strdup(desc.c_str()); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return ""; } } IntVector Videoio_Registry_GetStreamBackends() { try { IntVector c_backs; std::vector backs = cv::videoio_registry::getStreamBackends(); c_backs.val = new int[backs.size()]; c_backs.length = backs.size(); for(int i = 0; i < c_backs.length; i++) { c_backs.val[i] = backs[i]; } return c_backs; } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); IntVector empty; return empty; } } const char* Videoio_Registry_GetWriterBackendPluginVersion(int api, int* version_ABI, int* version_API){ try { std::string desc = cv::videoio_registry::getWriterBackendPluginVersion((cv::VideoCaptureAPIs)(api), *version_ABI, *version_API); return strdup(desc.c_str()); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return ""; } } IntVector Videoio_Registry_GetWriterBackends() { try { IntVector c_backs; std::vector backs = cv::videoio_registry::getWriterBackends(); c_backs.val = new int[backs.size()]; c_backs.length = backs.size(); for(int i = 0; i < c_backs.length; i++) { c_backs.val[i] = backs[i]; } return c_backs; } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); IntVector empty; return empty; } } bool Videoio_Registry_HasBackend(int api) { try { return cv::videoio_registry::hasBackend((cv::VideoCaptureAPIs)(api)); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return false; } } bool Videoio_Registry_IsBackendBuiltIn(int api) { try { return cv::videoio_registry::isBackendBuiltIn((cv::VideoCaptureAPIs)(api)); } catch(const cv::Exception& e){ setExceptionInfo(e.code, e.what()); return false; } } ================================================ FILE: videoio.go ================================================ //go:build !gocv_specific_modules || (gocv_specific_modules && gocv_videoio) package gocv /* #include #include "videoio.h" */ import "C" import ( "errors" "fmt" "strconv" "sync" "unsafe" ) // Select preferred API for a capture object. // Note: Backends are available only if they have been built with your OpenCV binaries type VideoCaptureAPI int const ( // Auto detect == 0 VideoCaptureAny VideoCaptureAPI = 0 // Video For Windows (obsolete, removed) VideoCaptureVFW VideoCaptureAPI = 200 // V4L/V4L2 capturing support VideoCaptureV4L VideoCaptureAPI = 200 // Same as VideoCaptureV4L VideoCaptureV4L2 VideoCaptureAPI = 200 // IEEE 1394 drivers VideoCaptureFirewire VideoCaptureAPI = 300 // Same value as VideoCaptureFirewire VideoCaptureFireware VideoCaptureAPI = 300 // Same value as VideoCaptureFirewire VideoCaptureIEEE1394 VideoCaptureAPI = 300 // Same value as VideoCaptureFirewire VideoCaptureDC1394 VideoCaptureAPI = 300 // Same value as VideoCaptureFirewire VideoCaptureCMU1394 VideoCaptureAPI = 300 // QuickTime (obsolete, removed) VideoCaptureQT VideoCaptureAPI = 500 // Unicap drivers (obsolete, removed) VideoCaptureUnicap VideoCaptureAPI = 600 // DirectShow (via videoInput) VideoCaptureDshow VideoCaptureAPI = 700 // PvAPI, Prosilica GigE SDK VideoCapturePvAPI VideoCaptureAPI = 800 // OpenNI (for Kinect) VideoCaptureOpenNI VideoCaptureAPI = 900 // OpenNI (for Asus Xtion) VideoCaptureOpenNIAsus VideoCaptureAPI = 910 // Android - not used VideoCaptureAndroid VideoCaptureAPI = 1000 // XIMEA Camera API VideoCaptureXiAPI VideoCaptureAPI = 1100 // AVFoundation framework for iOS (OS X Lion will have the same API) VideoCaptureAVFoundation VideoCaptureAPI = 1200 // Smartek Giganetix GigEVisionSDK VideoCaptureGiganetix VideoCaptureAPI = 1300 // Microsoft Media Foundation (via videoInput) VideoCaptureMSMF VideoCaptureAPI = 1400 // Microsoft Windows Runtime using Media Foundation VideoCaptureWinRT VideoCaptureAPI = 1410 // RealSense (former Intel Perceptual Computing SDK) VideoCaptureIntelPerc VideoCaptureAPI = 1500 // Synonym for VideoCaptureIntelPerc VideoCaptureRealsense VideoCaptureAPI = 1500 // OpenNI2 (for Kinect) VideoCaptureOpenNI2 VideoCaptureAPI = 1600 // OpenNI2 (for Asus Xtion and Occipital Structure sensors) VideoCaptureOpenNI2Asus VideoCaptureAPI = 1610 // gPhoto2 connection VideoCaptureGPhoto2 VideoCaptureAPI = 1700 // GStreamer VideoCaptureGstreamer VideoCaptureAPI = 1800 // Open and record video file or stream using the FFMPEG library VideoCaptureFFmpeg VideoCaptureAPI = 1900 // OpenCV Image Sequence (e.g. img_%02d.jpg) VideoCaptureImages VideoCaptureAPI = 2000 // Aravis SDK VideoCaptureAravis VideoCaptureAPI = 2100 // Built-in OpenCV MotionJPEG codec VideoCaptureOpencvMjpeg VideoCaptureAPI = 2200 // Intel MediaSDK VideoCaptureIntelMFX VideoCaptureAPI = 2300 // XINE engine (Linux) VideoCaptureXINE VideoCaptureAPI = 2400 ) // VideoCaptureProperties are the properties used for VideoCapture operations. type VideoCaptureProperties int32 const ( // VideoCapturePosMsec contains current position of the // video file in milliseconds. VideoCapturePosMsec VideoCaptureProperties = 0 // VideoCapturePosFrames 0-based index of the frame to be // decoded/captured next. VideoCapturePosFrames VideoCaptureProperties = 1 // VideoCapturePosAVIRatio relative position of the video file: // 0=start of the film, 1=end of the film. VideoCapturePosAVIRatio VideoCaptureProperties = 2 // VideoCaptureFrameWidth is width of the frames in the video stream. VideoCaptureFrameWidth VideoCaptureProperties = 3 // VideoCaptureFrameHeight controls height of frames in the video stream. VideoCaptureFrameHeight VideoCaptureProperties = 4 // VideoCaptureFPS controls capture frame rate. VideoCaptureFPS VideoCaptureProperties = 5 // VideoCaptureFOURCC contains the 4-character code of codec. // see VideoWriter::fourcc for details. VideoCaptureFOURCC VideoCaptureProperties = 6 // VideoCaptureFrameCount contains number of frames in the video file. VideoCaptureFrameCount VideoCaptureProperties = 7 // VideoCaptureFormat format of the Mat objects returned by // VideoCapture::retrieve(). VideoCaptureFormat VideoCaptureProperties = 8 // VideoCaptureMode contains backend-specific value indicating // the current capture mode. VideoCaptureMode VideoCaptureProperties = 9 // VideoCaptureBrightness is brightness of the image // (only for those cameras that support). VideoCaptureBrightness VideoCaptureProperties = 10 // VideoCaptureContrast is contrast of the image // (only for cameras that support it). VideoCaptureContrast VideoCaptureProperties = 11 // VideoCaptureSaturation saturation of the image // (only for cameras that support). VideoCaptureSaturation VideoCaptureProperties = 12 // VideoCaptureHue hue of the image (only for cameras that support). VideoCaptureHue VideoCaptureProperties = 13 // VideoCaptureGain is the gain of the capture image. // (only for those cameras that support). VideoCaptureGain VideoCaptureProperties = 14 // VideoCaptureExposure is the exposure of the capture image. // (only for those cameras that support). VideoCaptureExposure VideoCaptureProperties = 15 // VideoCaptureConvertRGB is a boolean flags indicating whether // images should be converted to RGB. VideoCaptureConvertRGB VideoCaptureProperties = 16 // VideoCaptureWhiteBalanceBlueU is currently unsupported. VideoCaptureWhiteBalanceBlueU VideoCaptureProperties = 17 // VideoCaptureRectification is the rectification flag for stereo cameras. // Note: only supported by DC1394 v 2.x backend currently. VideoCaptureRectification VideoCaptureProperties = 18 // VideoCaptureMonochrome indicates whether images should be // converted to monochrome. VideoCaptureMonochrome VideoCaptureProperties = 19 // VideoCaptureSharpness controls image capture sharpness. VideoCaptureSharpness VideoCaptureProperties = 20 // VideoCaptureAutoExposure controls the DC1394 exposure control // done by camera, user can adjust reference level using this feature. VideoCaptureAutoExposure VideoCaptureProperties = 21 // VideoCaptureGamma controls video capture gamma. VideoCaptureGamma VideoCaptureProperties = 22 // VideoCaptureTemperature controls video capture temperature. VideoCaptureTemperature VideoCaptureProperties = 23 // VideoCaptureTrigger controls video capture trigger. VideoCaptureTrigger VideoCaptureProperties = 24 // VideoCaptureTriggerDelay controls video capture trigger delay. VideoCaptureTriggerDelay VideoCaptureProperties = 25 // VideoCaptureWhiteBalanceRedV controls video capture setting for // white balance. VideoCaptureWhiteBalanceRedV VideoCaptureProperties = 26 // VideoCaptureZoom controls video capture zoom. VideoCaptureZoom VideoCaptureProperties = 27 // VideoCaptureFocus controls video capture focus. VideoCaptureFocus VideoCaptureProperties = 28 // VideoCaptureGUID controls video capture GUID. VideoCaptureGUID VideoCaptureProperties = 29 // VideoCaptureISOSpeed controls video capture ISO speed. VideoCaptureISOSpeed VideoCaptureProperties = 30 // VideoCaptureBacklight controls video capture backlight. VideoCaptureBacklight VideoCaptureProperties = 32 // VideoCapturePan controls video capture pan. VideoCapturePan VideoCaptureProperties = 33 // VideoCaptureTilt controls video capture tilt. VideoCaptureTilt VideoCaptureProperties = 34 // VideoCaptureRoll controls video capture roll. VideoCaptureRoll VideoCaptureProperties = 35 // VideoCaptureIris controls video capture iris. VideoCaptureIris VideoCaptureProperties = 36 // VideoCaptureSettings is the pop up video/camera filter dialog. Note: // only supported by DSHOW backend currently. The property value is ignored. VideoCaptureSettings VideoCaptureProperties = 37 // VideoCaptureBufferSize controls video capture buffer size. VideoCaptureBufferSize VideoCaptureProperties = 38 // VideoCaptureAutoFocus controls video capture auto focus.. VideoCaptureAutoFocus VideoCaptureProperties = 39 // VideoCaptureSarNumerator controls the sample aspect ratio: num/den (num) VideoCaptureSarNumerator VideoCaptureProperties = 40 // VideoCaptureSarDenominator controls the sample aspect ratio: num/den (den) VideoCaptureSarDenominator VideoCaptureProperties = 41 // VideoCaptureBackend is the current api backend (VideoCaptureAPI). Read-only property. VideoCaptureBackend VideoCaptureProperties = 42 // VideoCaptureChannel controls the video input or channel number (only for those cameras that support). VideoCaptureChannel VideoCaptureProperties = 43 // VideoCaptureAutoWB controls the auto white-balance. VideoCaptureAutoWB VideoCaptureProperties = 44 // VideoCaptureWBTemperature controls the white-balance color temperature VideoCaptureWBTemperature VideoCaptureProperties = 45 // VideoCaptureCodecPixelFormat shows the the codec's pixel format (4-character code). Read-only property. // Subset of AV_PIX_FMT_* or -1 if unknown. VideoCaptureCodecPixelFormat VideoCaptureProperties = 46 // VideoCaptureBitrate displays the video bitrate in kbits/s. Read-only property. VideoCaptureBitrate VideoCaptureProperties = 47 // VideoCaptureHWAcceleration Hardware acceleration type. VideoCaptureHWAcceleration VideoCaptureProperties = 50 // VideoCaptureHWDevice Hardware device index (select GPU if multiple available). VideoCaptureHWDevice VideoCaptureProperties = 51 ) // VideoWriterProperty // // For further details, please see: // https://docs.opencv.org/4.x/d4/d15/group__videoio__flags__base.html#ga41c5cfa7859ae542b71b1d33bbd4d2b4 type VideoWriterProperty int const ( // VideoWriterQuality Current quality (0..100%) of the encoded videostream. // Can be adjusted dynamically in some codecs. VideoWriterQuality VideoWriterProperty = 1 // VideoWriterFramebytes (Read-only): Size of just encoded video frame. // Note that the encoding order may be different from representation order. VideoWriterFramebytes VideoWriterProperty = 2 // VideoWriterNstripes Number of stripes for parallel encoding. -1 for auto detection. VideoWriterNstripes VideoWriterProperty = 3 // VideoWriterIsColor If it is not zero, the encoder will expect and encode color frames, // otherwise it will work with grayscale frames. VideoWriterIsColor VideoWriterProperty = 4 // VideoWriterDepth Defaults to CV8U. VideoWriterDepth VideoWriterProperty = 5 // VideoWriterHwAcceleration (open-only) Hardware acceleration type // (see https://docs.opencv.org/4.x/dc/dfc/group__videoio__flags__others.html#gaf61f8388a47aad88cd82cbda6d52c391). // Setting supported only via params parameter in VideoWriterFileWithAPIParams. // Default value is backend-specific. VideoWriterHwAcceleration VideoWriterProperty = 6 // VideoWriterHwDevice (open-only) Hardware device index (select GPU if multiple available). // Device enumeration is acceleration type specific. VideoWriterHwDevice VideoWriterProperty = 7 // VideoWriterHwAccelerationUseOpencl open-only) If non-zero, create new OpenCL context and bind it to current thread. VideoWriterHwAccelerationUseOpencl VideoWriterProperty = 8 // VideoWriterRawVideo (open-only) Set to non-zero to enable encapsulation of an encoded raw video stream. VideoWriterRawVideo VideoWriterProperty = 9 // VideoWriterKeyInterval (open-only) Set the key frame interval using raw video encapsulation // (VideoWriterRawVideo != 0). Defaults to 1 when not set. FFmpeg back-end only. VideoWriterKeyInterval VideoWriterProperty = 10 // VideoWriterKeyFlag Set to non-zero to signal that the following frames are key frames or zero if not, // when encapsulating raw video (VideoWriterRawVideo != 0). FFmpeg back-end only. VideoWriterKeyFlag VideoWriterProperty = 11 // VideoWriterPts Specifies the frame presentation timestamp for each frame using the FPS time base. VideoWriterPts VideoWriterProperty = 12 // VideoWriterDtsDelay Specifies the maximum difference between presentation (pts) // and decompression timestamps (dts) using the FPS time base. VideoWriterDtsDelay VideoWriterProperty = 13 ) // VideoCapture is a wrapper around the OpenCV VideoCapture class. // // For further details, please see: // http://docs.opencv.org/master/d8/dfe/classcv_1_1VideoCapture.html type VideoCapture struct { p C.VideoCapture } // VideoCaptureFile opens a VideoCapture from a file and prepares // to start capturing. It returns error if it fails to open the file stored in uri path. func VideoCaptureFile(uri string) (vc *VideoCapture, err error) { vc = &VideoCapture{p: C.VideoCapture_New()} cURI := C.CString(uri) defer C.free(unsafe.Pointer(cURI)) if !C.VideoCapture_Open(vc.p, cURI) { err = fmt.Errorf("Error opening file: %s", uri) } return } // VideoCaptureFile opens a VideoCapture from a file and prepares // to start capturing. It returns error if it fails to open the file stored in uri path. func VideoCaptureFileWithAPI(uri string, apiPreference VideoCaptureAPI) (vc *VideoCapture, err error) { vc = &VideoCapture{p: C.VideoCapture_New()} cURI := C.CString(uri) defer C.free(unsafe.Pointer(cURI)) if !C.VideoCapture_OpenWithAPI(vc.p, cURI, C.int(apiPreference)) { err = fmt.Errorf("Error opening file: %s with api backend: %d", uri, apiPreference) } return } // VideoCaptureFileWithAPIParams opens a VideoCapture from a file and prepares // to start capturing. It returns error if it fails to open the file stored in uri path. func VideoCaptureFileWithAPIParams(uri string, apiPreference VideoCaptureAPI, params []VideoCaptureProperties) (vc *VideoCapture, err error) { vc = &VideoCapture{p: C.VideoCapture_New()} cURI := C.CString(uri) defer C.free(unsafe.Pointer(cURI)) if !C.VideoCapture_OpenWithAPIParams(vc.p, cURI, C.int(apiPreference), (*C.int)(unsafe.Pointer(¶ms[0])), C.int(len(params))) { err = fmt.Errorf("Error opening file: %s with api backend: %d", uri, apiPreference) } return } // VideoCaptureDevice opens a VideoCapture from a device and prepares // to start capturing. It returns error if it fails to open the video device. func VideoCaptureDevice(device int) (vc *VideoCapture, err error) { vc = &VideoCapture{p: C.VideoCapture_New()} if !C.VideoCapture_OpenDevice(vc.p, C.int(device)) { err = fmt.Errorf("Error opening device: %d", device) } return } // VideoCaptureDeviceWithAPI opens a VideoCapture from a device with the api preference. // It returns error if it fails to open the video device. func VideoCaptureDeviceWithAPI(device int, apiPreference VideoCaptureAPI) (vc *VideoCapture, err error) { vc = &VideoCapture{p: C.VideoCapture_New()} if !C.VideoCapture_OpenDeviceWithAPI(vc.p, C.int(device), C.int(apiPreference)) { err = fmt.Errorf("Error opening device: %d with api backend: %d", device, apiPreference) } return } // VideoCaptureDeviceWithAPIParams opens a VideoCapture from a device with the api preference. // It returns error if it fails to open the video device. func VideoCaptureDeviceWithAPIParams(device int, apiPreference VideoCaptureAPI, params []VideoCaptureProperties) (vc *VideoCapture, err error) { vc = &VideoCapture{p: C.VideoCapture_New()} if !C.VideoCapture_OpenDeviceWithAPIParams(vc.p, C.int(device), C.int(apiPreference), (*C.int)(unsafe.Pointer(¶ms[0])), C.int(len(params))) { err = fmt.Errorf("Error opening device: %d with api backend: %d", device, apiPreference) } return } // Close VideoCapture object. func (v *VideoCapture) Close() error { C.VideoCapture_Close(v.p) v.p = nil return nil } // Set parameter with property (=key). func (v *VideoCapture) Set(prop VideoCaptureProperties, param float64) { C.VideoCapture_Set(v.p, C.int(prop), C.double(param)) } // Get parameter with property (=key). func (v VideoCapture) Get(prop VideoCaptureProperties) float64 { return float64(C.VideoCapture_Get(v.p, C.int(prop))) } // IsOpened returns if the VideoCapture has been opened to read from // a file or capture device. func (v *VideoCapture) IsOpened() bool { isOpened := C.VideoCapture_IsOpened(v.p) return isOpened != 0 } // Read reads the next frame from the VideoCapture to the Mat passed in // as the param. It returns false if the VideoCapture cannot read frame. func (v *VideoCapture) Read(m *Mat) bool { return C.VideoCapture_Read(v.p, m.p) != 0 } // Grab skips a specific number of frames. func (v *VideoCapture) Grab(skip int) error { return OpenCVResult(C.VideoCapture_Grab(v.p, C.int(skip))) } // Retrieve decodes and returns the grabbed video frame. Should be used after Grab // // For further details, please see: // https://docs.opencv.org/4.x/d8/dfe/classcv_1_1VideoCapture.html#a9ac7f4b1cdfe624663478568486e6712 func (v *VideoCapture) Retrieve(m *Mat) bool { return C.VideoCapture_Retrieve(v.p, m.p) != 0 } // Retrieve decodes and returns the grabbed frame for a specific channel. Should be used after Grab // // For further details, please see: // https://docs.opencv.org/4.x/d8/dfe/classcv_1_1VideoCapture.html#a9ac7f4b1cdfe624663478568486e6712 func (v *VideoCapture) RetrieveChannel(m *Mat, channel int) bool { return C.VideoCapture_RetrieveChannel(v.p, m.p, C.int(channel)) != 0 } // CodecString returns a string representation of FourCC bytes, i.e. the name of a codec func (v *VideoCapture) CodecString() string { res := "" hexes := []int64{0xff, 0xff00, 0xff0000, 0xff000000} for i, h := range hexes { res += string(rune(int64(v.Get(VideoCaptureFOURCC)) & h >> (uint(i * 8)))) } return res } // ToCodec returns an float64 representation of FourCC bytes func (v *VideoCapture) ToCodec(codec string) float64 { if len(codec) != 4 { return -1.0 } c1 := []rune(string(codec[0]))[0] c2 := []rune(string(codec[1]))[0] c3 := []rune(string(codec[2]))[0] c4 := []rune(string(codec[3]))[0] return float64((c1 & 255) + ((c2 & 255) << 8) + ((c3 & 255) << 16) + ((c4 & 255) << 24)) } // VideoWriter is a wrapper around the OpenCV VideoWriter`class. // // For further details, please see: // http://docs.opencv.org/master/dd/d9e/classcv_1_1VideoWriter.html type VideoWriter struct { mu *sync.RWMutex p C.VideoWriter } // VideoWriterFile opens a VideoWriter with a specific output file. // The "codec" param should be the four-letter code for the desired output // codec, for example "MJPG". // // For further details, please see: // http://docs.opencv.org/master/dd/d9e/classcv_1_1VideoWriter.html#a0901c353cd5ea05bba455317dab81130 func VideoWriterFile(name string, codec string, fps float64, width int, height int, isColor bool) (vw *VideoWriter, err error) { if fps == 0 || width == 0 || height == 0 { return nil, fmt.Errorf("one of the numerical parameters "+ "is equal to zero: FPS: %f, width: %d, height: %d", fps, width, height) } vw = &VideoWriter{ p: C.VideoWriter_New(), mu: &sync.RWMutex{}, } cName := C.CString(name) defer C.free(unsafe.Pointer(cName)) cCodec := C.CString(codec) defer C.free(unsafe.Pointer(cCodec)) err = OpenCVResult(C.VideoWriter_Open(vw.p, cName, cCodec, C.double(fps), C.int(width), C.int(height), C.bool(isColor))) return } // VideoWriterFileWithAPI opens a VideoWriter with a specific output file. // The "codec" param should be the four-letter code for the desired output // codec, for example "MJPG". // // For further details, please see: // http://docs.opencv.org/master/dd/d9e/classcv_1_1VideoWriter.html#a0901c353cd5ea05bba455317dab81130 func VideoWriterFileWithAPI(name string, apiPreference VideoCaptureAPI, codec string, fps float64, width int, height int, isColor bool) (vw *VideoWriter, err error) { if fps == 0 || width == 0 || height == 0 { return nil, fmt.Errorf("one of the numerical parameters "+ "is equal to zero: FPS: %f, width: %d, height: %d", fps, width, height) } vw = &VideoWriter{ p: C.VideoWriter_New(), mu: &sync.RWMutex{}, } cName := C.CString(name) defer C.free(unsafe.Pointer(cName)) cCodec := C.CString(codec) defer C.free(unsafe.Pointer(cCodec)) err = OpenCVResult(C.VideoWriter_OpenWithAPI(vw.p, cName, C.int(apiPreference), cCodec, C.double(fps), C.int(width), C.int(height), C.bool(isColor))) return } // VideoWriterFileWithAPIParams opens a VideoWriter with a specific output file. // The "codec" param should be the four-letter code for the desired output // codec, for example "MJPG". // // For further details, please see: // http://docs.opencv.org/master/dd/d9e/classcv_1_1VideoWriter.html#a0901c353cd5ea05bba455317dab81130 func VideoWriterFileWithAPIParams(name string, apiPreference VideoCaptureAPI, codec string, fps float64, width int, height int, params []VideoWriterProperty) (vw *VideoWriter, err error) { if fps == 0 || width == 0 || height == 0 { return nil, fmt.Errorf("one of the numerical parameters "+ "is equal to zero: FPS: %f, width: %d, height: %d", fps, width, height) } vw = &VideoWriter{ p: C.VideoWriter_New(), mu: &sync.RWMutex{}, } c_name := C.CString(name) defer C.free(unsafe.Pointer(c_name)) c_codec := C.CString(codec) defer C.free(unsafe.Pointer(c_codec)) c_ints := make([]C.int, len(params)) for i := range params { c_ints[i] = C.int(params[i]) } c_params := C.IntVector{ val: unsafe.SliceData(c_ints), length: C.int(len(params)), } err = OpenCVResult(C.VideoWriter_OpenWithAPIParams(vw.p, c_name, C.int(apiPreference), c_codec, C.double(fps), C.int(width), C.int(height), c_params)) return } // Close VideoWriter object. func (vw *VideoWriter) Close() error { C.VideoWriter_Close(vw.p) vw.p = nil return nil } // IsOpened checks if the VideoWriter is open and ready to be written to. // // For further details, please see: // http://docs.opencv.org/master/dd/d9e/classcv_1_1VideoWriter.html#a9a40803e5f671968ac9efa877c984d75 func (vw *VideoWriter) IsOpened() bool { isOpend := C.VideoWriter_IsOpened(vw.p) return isOpend != 0 } // Write the next video frame from the Mat image to the open VideoWriter. // // For further details, please see: // http://docs.opencv.org/master/dd/d9e/classcv_1_1VideoWriter.html#a3115b679d612a6a0b5864a0c88ed4b39 func (vw *VideoWriter) Write(img Mat) error { vw.mu.Lock() defer vw.mu.Unlock() return OpenCVResult(C.VideoWriter_Write(vw.p, img.p)) } // OpenVideoCapture return VideoCapture specified by device ID if v is a // number. Return VideoCapture created from video file, URL, or GStreamer // pipeline if v is a string. func OpenVideoCapture(v interface{}) (*VideoCapture, error) { switch vv := v.(type) { case int: return VideoCaptureDevice(vv) case string: id, err := strconv.Atoi(vv) if err == nil { return VideoCaptureDevice(id) } return VideoCaptureFile(vv) default: return nil, errors.New("argument must be int or string") } } // OpenVideoCaptureWithAPI return VideoCapture specified by device ID if v is a // number. Return VideoCapture created from video file, URL, or GStreamer // pipeline if v is a string. func OpenVideoCaptureWithAPI(v interface{}, apiPreference VideoCaptureAPI) (*VideoCapture, error) { switch vv := v.(type) { case int: return VideoCaptureDeviceWithAPI(vv, apiPreference) case string: id, err := strconv.Atoi(vv) if err == nil { return VideoCaptureDeviceWithAPI(id, apiPreference) } return VideoCaptureFileWithAPI(vv, apiPreference) default: return nil, errors.New("argument must be int or string") } } // OpenVideoCaptureWithAPIParams return VideoCapture specified by device ID if v is a // number. Return VideoCapture created from video file, URL, or GStreamer // pipeline if v is a string. func OpenVideoCaptureWithAPIParams(v interface{}, apiPreference VideoCaptureAPI, params []VideoCaptureProperties) (*VideoCapture, error) { switch vv := v.(type) { case int: return VideoCaptureDeviceWithAPIParams(vv, apiPreference, params) case string: id, err := strconv.Atoi(vv) if err == nil { return VideoCaptureDeviceWithAPIParams(id, apiPreference, params) } //TODO: params with files return VideoCaptureFileWithAPIParams(vv, apiPreference, params) default: return nil, errors.New("argument must be int or string") } } type VideoRegistryType struct{} // VideoRegistry // // For further details, please see: // https://docs.opencv.org/4.x/de/db1/group__videoio__registry.html var VideoRegistry VideoRegistryType // GetBackendName Returns backend API name or "UnknownVideoAPI(xxx)". // // For further details, please see: // https://docs.opencv.org/4.x/de/db1/group__videoio__registry.html#ga6723e68832186e20bd44cd3c2b0d8c60 func (VideoRegistryType) GetBackendName(api VideoCaptureAPI) string { c_name := C.Videoio_Registry_GetBackendName(C.int(api)) defer C.free(unsafe.Pointer(c_name)) name := C.GoString(c_name) return name } // GetBackends Returns list of all available backends. // // For further details, please see: // https://docs.opencv.org/4.x/de/db1/group__videoio__registry.html#ga973abd27c3ea165472f789fa511d9f7b func (VideoRegistryType) GetBackends() []VideoCaptureAPI { intVec := C.Videio_Registry_GetBackends() defer C.IntVector_Close(intVec) c_ints := unsafe.Slice(intVec.val, int(intVec.length)) ints := make([]VideoCaptureAPI, len(c_ints)) for i, val := range c_ints { ints[i] = VideoCaptureAPI(int(val)) } return ints } // GetCameraBackendPluginVersion Returns description and ABI/API version of videoio plugin's camera interface. // // For further details, please see: // https://docs.opencv.org/4.x/de/db1/group__videoio__registry.html#gab36e3e19ab2396410b74046de141323c func (VideoRegistryType) GetCameraBackendPluginVersion(api VideoCaptureAPI) (string, int, int) { var ( version_abi C.int version_api C.int ) c_desc := C.Videoio_Registry_GetCameraBackendPluginVersion(C.int(api), &version_abi, &version_api) defer C.free(unsafe.Pointer(c_desc)) desc := C.GoString(c_desc) return desc, int(version_abi), int(version_api) } // GetCameraBackends Returns list of available backends which works via gocv.VideoCapture(int index) // // For further details, please see: // https://docs.opencv.org/4.x/de/db1/group__videoio__registry.html#ga043347faf6f5590b867a8b621906f7a9 func (VideoRegistryType) GetCameraBackends() []VideoCaptureAPI { intVec := C.Videoio_Registry_GetCameraBackends() defer C.IntVector_Close(intVec) c_ints := unsafe.Slice(intVec.val, int(intVec.length)) ints := make([]VideoCaptureAPI, len(c_ints)) for i, val := range c_ints { ints[i] = VideoCaptureAPI(int(val)) } return ints } // GetStreamBackendPluginVersion Returns description and ABI/API version of videoio plugin's stream capture interface // // For further details, please see: // https://docs.opencv.org/4.x/de/db1/group__videoio__registry.html#gadf3c0c355f0917ccf754ac1af79d605a func (VideoRegistryType) GetStreamBackendPluginVersion(api VideoCaptureAPI) (string, int, int) { var ( version_abi C.int version_api C.int ) c_desc := C.Videoio_Registry_GetStreamBackendPluginVersion(C.int(api), &version_abi, &version_api) defer C.free(unsafe.Pointer(c_desc)) desc := C.GoString(c_desc) return desc, int(version_abi), int(version_api) } // GetStreamBackends Returns list of available backends which works via gocv.VideoCapture(filename string) // // For further details, please see: // https://docs.opencv.org/4.x/de/db1/group__videoio__registry.html#ga29296d4c06ed9a9ff8bddae9fe581de1 func (VideoRegistryType) GetStreamBackends() []VideoCaptureAPI { intVec := C.Videoio_Registry_GetStreamBackends() defer C.IntVector_Close(intVec) c_ints := unsafe.Slice(intVec.val, int(intVec.length)) ints := make([]VideoCaptureAPI, len(c_ints)) for i, val := range c_ints { ints[i] = VideoCaptureAPI(int(val)) } return ints } // GetWriterBackendPluginVersion Returns description and ABI/API version of videoio plugin's writer interface. // // For further details, please see: // https://docs.opencv.org/4.x/de/db1/group__videoio__registry.html#gac41a544552a08bf3dc8142d687fbe4e5 func (VideoRegistryType) GetWriterBackendPluginVersion(api VideoCaptureAPI) (string, int, int) { var ( version_abi C.int version_api C.int ) c_desc := C.Videoio_Registry_GetWriterBackendPluginVersion(C.int(api), &version_abi, &version_api) defer C.free(unsafe.Pointer(c_desc)) desc := C.GoString(c_desc) return desc, int(version_abi), int(version_api) } // GetWriterBackends Returns list of available backends which works via gocv.VideoWriter() // // For further details, please see: // https://docs.opencv.org/4.x/de/db1/group__videoio__registry.html#gaed03e49e6a45ca5b20afe1b9f78955e0 func (VideoRegistryType) GetWriterBackends() []VideoCaptureAPI { intVec := C.Videoio_Registry_GetWriterBackends() defer C.IntVector_Close(intVec) c_ints := unsafe.Slice(intVec.val, int(intVec.length)) ints := make([]VideoCaptureAPI, len(c_ints)) for i, val := range c_ints { ints[i] = VideoCaptureAPI(int(val)) } return ints } // HasBackend Returns true if backend is available. // // For further details, please see: // https://docs.opencv.org/4.x/de/db1/group__videoio__registry.html#ga9068310d50ef430c2f5f6b185a99a24b func (VideoRegistryType) HasBackend(api VideoCaptureAPI) bool { b := C.Videoio_Registry_HasBackend(C.int(api)) return bool(b) } // IsBackendBuiltIn Returns true if backend is built in (false if backend is used as plugin) // // For further details, please see: // https://docs.opencv.org/4.x/de/db1/group__videoio__registry.html#gadf24ec0854bb893a75591306ad9f3878 func (VideoRegistryType) IsBackendBuiltIn(api VideoCaptureAPI) bool { b := C.Videoio_Registry_IsBackendBuiltIn(C.int(api)) return bool(b) } ================================================ FILE: videoio.h ================================================ #ifndef _OPENCV3_VIDEOIO_H_ #define _OPENCV3_VIDEOIO_H_ #ifdef __cplusplus #include #include extern "C" { #endif #include "core.h" #ifdef __cplusplus typedef cv::VideoCapture* VideoCapture; typedef cv::VideoWriter* VideoWriter; #else typedef void* VideoCapture; typedef void* VideoWriter; #endif // VideoCapture VideoCapture VideoCapture_New(); void VideoCapture_Close(VideoCapture v); bool VideoCapture_Open(VideoCapture v, const char* uri); bool VideoCapture_OpenWithAPI(VideoCapture v, const char* uri, int apiPreference); bool VideoCapture_OpenWithAPIParams(VideoCapture v, const char* uri, int apiPreference, int *paramsv, int paramsc); bool VideoCapture_OpenDevice(VideoCapture v, int device); bool VideoCapture_OpenDeviceWithAPI(VideoCapture v, int device, int apiPreference); bool VideoCapture_OpenDeviceWithAPIParams(VideoCapture v, int device, int apiPreference, int *paramsv, int paramsc); OpenCVResult VideoCapture_Set(VideoCapture v, int prop, double param); double VideoCapture_Get(VideoCapture v, int prop); int VideoCapture_IsOpened(VideoCapture v); int VideoCapture_Read(VideoCapture v, Mat buf); OpenCVResult VideoCapture_Grab(VideoCapture v, int skip); int VideoCapture_Retrieve(VideoCapture v, Mat buf); int VideoCapture_RetrieveChannel(VideoCapture v, Mat buf, int channel); // VideoWriter VideoWriter VideoWriter_New(); void VideoWriter_Close(VideoWriter vw); OpenCVResult VideoWriter_Open(VideoWriter vw, const char* name, const char* codec, double fps, int width, int height, bool isColor); OpenCVResult VideoWriter_OpenWithAPI(VideoWriter vw, const char* name, int apiPreference, const char* codec, double fps, int width, int height, bool isColor); OpenCVResult VideoWriter_OpenWithAPIParams(VideoWriter vw, const char* name, int apiPreference, const char* codec, double fps, int width, int height, IntVector params); int VideoWriter_IsOpened(VideoWriter vw); OpenCVResult VideoWriter_Write(VideoWriter vw, Mat img); //Videoio Query I/O API backends registry const char* Videoio_Registry_GetBackendName(int api); IntVector Videio_Registry_GetBackends(); const char* Videoio_Registry_GetCameraBackendPluginVersion(int api, int* version_ABI, int* version_API); IntVector Videoio_Registry_GetCameraBackends(); const char* Videoio_Registry_GetStreamBackendPluginVersion(int api, int* version_ABI, int* version_API); IntVector Videoio_Registry_GetStreamBackends(); const char* Videoio_Registry_GetWriterBackendPluginVersion(int api, int* version_ABI, int* version_API); IntVector Videoio_Registry_GetWriterBackends(); bool Videoio_Registry_HasBackend(int api); bool Videoio_Registry_IsBackendBuiltIn(int api); #ifdef __cplusplus } #endif #endif //_OPENCV3_VIDEOIO_H_ ================================================ FILE: videoio_string.go ================================================ //go:build !gocv_specific_modules || (gocv_specific_modules && gocv_videoio) package gocv func (c VideoCaptureAPI) String() string { switch c { case VideoCaptureAny: return "video-capture-any" case VideoCaptureV4L2: return "video-capture-v4l2" case VideoCaptureFirewire: return "video-capture-firewire" case VideoCaptureQT: return "video-capture-qt" case VideoCaptureUnicap: return "video-capture-unicap" case VideoCaptureDshow: return "video-capture-dshow" case VideoCapturePvAPI: return "video-capture-pvapi" case VideoCaptureOpenNI: return "video-capture-openni" case VideoCaptureOpenNIAsus: return "video-capture-openni-asus" case VideoCaptureAndroid: return "video-capture-android" case VideoCaptureXiAPI: return "video-capture-xiapi" case VideoCaptureAVFoundation: return "video-capture-av-foundation" case VideoCaptureGiganetix: return "video-capture-giganetix" case VideoCaptureMSMF: return "video-capture-msmf" case VideoCaptureWinRT: return "video-capture-winrt" case VideoCaptureIntelPerc: return "video-capture-intel-perc" case VideoCaptureOpenNI2: return "video-capture-openni2" case VideoCaptureOpenNI2Asus: return "video-capture-openni2-asus" case VideoCaptureGPhoto2: return "video-capture-gphoto2" case VideoCaptureGstreamer: return "video-capture-gstreamer" case VideoCaptureFFmpeg: return "video-capture-ffmpeg" case VideoCaptureImages: return "video-capture-images" case VideoCaptureAravis: return "video-capture-aravis" case VideoCaptureOpencvMjpeg: return "video-capture-opencv-mjpeg" case VideoCaptureIntelMFX: return "video-capture-intel-mfx" case VideoCaptureXINE: return "video-capture-xine" } return "" } func (c VideoCaptureProperties) String() string { switch c { case VideoCapturePosMsec: return "video-capture-pos-msec" case VideoCapturePosFrames: return "video-capture-pos-frames" case VideoCapturePosAVIRatio: return "video-capture-pos-avi-ratio" case VideoCaptureFrameWidth: return "video-capture-frame-width" case VideoCaptureFrameHeight: return "video-capture-frame-height" case VideoCaptureFPS: return "video-capture-fps" case VideoCaptureFOURCC: return "video-capture-fourcc" case VideoCaptureFrameCount: return "video-capture-frame-count" case VideoCaptureFormat: return "video-capture-format" case VideoCaptureMode: return "video-capture-mode" case VideoCaptureBrightness: return "video-capture-brightness" case VideoCaptureContrast: return "video-capture-contrast" case VideoCaptureSaturation: return "video-capture-saturation" case VideoCaptureHue: return "video-capture-hue" case VideoCaptureGain: return "video-capture-gain" case VideoCaptureExposure: return "video-capture-exposure" case VideoCaptureConvertRGB: return "video-capture-convert-rgb" case VideoCaptureWhiteBalanceBlueU: return "video-capture-white-balanced-blue-u" case VideoCaptureWhiteBalanceRedV: return "video-capture-white-balanced-red-v" case VideoCaptureRectification: return "video-capture-rectification" case VideoCaptureMonochrome: return "video-capture-monochrome" case VideoCaptureSharpness: return "video-capture-sharpness" case VideoCaptureAutoExposure: return "video-capture-auto-exposure" case VideoCaptureGamma: return "video-capture-gamma" case VideoCaptureTemperature: return "video-capture-temperature" case VideoCaptureTrigger: return "video-capture-trigger" case VideoCaptureTriggerDelay: return "video-capture-trigger-delay" case VideoCaptureZoom: return "video-capture-zoom" case VideoCaptureFocus: return "video-capture-focus" case VideoCaptureGUID: return "video-capture-guid" case VideoCaptureISOSpeed: return "video-capture-iso-speed" case VideoCaptureBacklight: return "video-capture-backlight" case VideoCapturePan: return "video-capture-pan" case VideoCaptureTilt: return "video-capture-tilt" case VideoCaptureRoll: return "video-capture-roll" case VideoCaptureIris: return "video-capture-iris" case VideoCaptureSettings: return "video-capture-settings" case VideoCaptureBufferSize: return "video-capture-buffer-size" case VideoCaptureAutoFocus: return "video-capture-auto-focus" case VideoCaptureSarNumerator: return "video-capture-sar-numerator" case VideoCaptureSarDenominator: return "video-capture-sar-denominator" case VideoCaptureBackend: return "video-capture-backend" case VideoCaptureChannel: return "video-capture-channel" case VideoCaptureAutoWB: return "video-capture-auto-wb" case VideoCaptureWBTemperature: return "video-capture-wb-temperature" case VideoCaptureCodecPixelFormat: return "video-capture-pixel-format" case VideoCaptureBitrate: return "video-capture-bitrate" } return "" } ================================================ FILE: videoio_test.go ================================================ //go:build !gocv_specific_modules || (gocv_specific_modules && gocv_videoio) package gocv import ( "io/ioutil" "math" "os" "path/filepath" "strconv" "strings" "testing" ) func TestVideoCaptureEmptyNumericalParameters(t *testing.T) { _, err := VideoWriterFile( "images/small.mp4", "MJPEG", 0, 0, 0, true) if err == nil { t.Error("Must fail due to an empty numerical parameters.") } if !strings.Contains(err.Error(), "one of the numerical parameters is equal to zero") { t.Errorf("Must fail due to an empty numerical "+ "parameters, but have different error: %v", err) } } func TestVideoCaptureCodecString(t *testing.T) { vc, err := OpenVideoCapture("images/small.mp4") if err != nil { t.Errorf("TestVideoCaptureCodecString: error loading a file: %v", err) } if vc.CodecString() == "" { t.Fatal("TestVideoCaptureCodecString: empty codec string") } } func TestVideoCaptureCodecConversion(t *testing.T) { vc, err := OpenVideoCapture("images/small.mp4") if err != nil { t.Errorf("TestVideoCaptureCodecConversion: error loading a file: %v", err) } if vc.CodecString() == "" { t.Fatal("TestVideoCaptureCodecConversion: empty codec string") } if int64(vc.ToCodec(vc.CodecString())) != int64(vc.Get(VideoCaptureFOURCC)) { t.Fatal("TestVideoCaptureCodecConversion: codec conversion failed") } } func TestVideoCaptureCodecConversionBadInput(t *testing.T) { vc, err := OpenVideoCapture("images/small.mp4") if err != nil { t.Errorf("TestVideoCaptureCodecString: error loading a file: %v", err) } codec := vc.ToCodec("BAD CODEC") if int64(codec) != -1 { t.Fatal("TestVideoCaptureCodecConversionBadInput: input validation failed") } } func TestVideoCaptureInvalid(t *testing.T) { _, err := OpenVideoCapture(1.1) if err == nil { t.Errorf("Should return error with invalid param") } } func TestVideoCaptureWithAPI(t *testing.T) { t.Run("video capture file with api", func(t *testing.T) { vc, err := OpenVideoCaptureWithAPI("images/small.mp4", VideoCaptureAny) if err != nil { t.Errorf("error loading a file: %v", err) } backend := vc.Get(VideoCaptureBackend) if backend == float64(VideoCaptureAny) { t.Errorf("video capture backend api did not select a backend") } }) t.Run("video capture unknown device with api", func(t *testing.T) { _, err := OpenVideoCaptureWithAPI(math.MaxInt32, VideoCaptureAny) if err == nil { t.Errorf("should return error opening device") } }) t.Run("video capture invalid with api", func(t *testing.T) { _, err := OpenVideoCaptureWithAPI(1.1, VideoCaptureAny) if err == nil { t.Errorf("should return error with invalid param") } }) t.Run("video capture valid int string with api no available device", func(t *testing.T) { vc5, err := OpenVideoCaptureWithAPI("99", VideoCaptureAny) defer vc5.Close() if err == nil { t.Errorf("should return error opening device") } }) } func TestVideoCaptureWithAPIParams(t *testing.T) { vc, _ := OpenVideoCaptureWithAPIParams(0, VideoCaptureAny, []VideoCaptureProperties{VideoCaptureHWAcceleration, 1, VideoCaptureHWDevice, 0}) defer vc.Close() } func TestVideoCaptureFileWithAPIParams(t *testing.T) { vc, _ := OpenVideoCaptureWithAPIParams("images/small.mp4", VideoCaptureAny, []VideoCaptureProperties{VideoCaptureHWAcceleration, 1, VideoCaptureHWDevice, 0}) defer vc.Close() } func TestVideoCaptureFile(t *testing.T) { vc, err := VideoCaptureFile("images/small.mp4") defer vc.Close() if err != nil { t.Errorf("%s", err) } if !vc.IsOpened() { t.Error("Unable to open VideoCaptureFile") } if fw := vc.Get(VideoCaptureFrameWidth); int(fw) != 560 { t.Errorf("Expected frame width property of 560.0 got %f", fw) } if fh := vc.Get(VideoCaptureFrameHeight); int(fh) != 320 { t.Errorf("Expected frame height property of 320.0 got %f", fh) } vc.Set(VideoCaptureBrightness, 100.0) vc.Grab(10) img := NewMat() defer img.Close() vc.Read(&img) if img.Empty() { t.Error("Unable to read VideoCaptureFile") } // video capture file with non-existent video vc2, err := VideoCaptureFile("nonexistent.mp4") defer vc2.Close() if err == nil { t.Errorf("Expected error when opening invalid file") } t.Run(" video capture file with api", func(t *testing.T) { vc3, err := VideoCaptureFileWithAPI("images/small.mp4", VideoCaptureAny) defer vc3.Close() if err != nil { t.Error(err) } }) t.Run("video capture non-existent video with api", func(t *testing.T) { vc4, err := VideoCaptureFileWithAPI("nonexistent.mp4", VideoCaptureAny) defer vc4.Close() if err == nil { t.Errorf("Expected error when opening invalid file") } }) t.Run("video capture invalid int", func(t *testing.T) { vc5, err := OpenVideoCapture(math.MaxInt32) defer vc5.Close() if err == nil { t.Errorf("should return error opening device") } }) t.Run("video capture invalid string", func(t *testing.T) { vc5, err := OpenVideoCapture("test-device") defer vc5.Close() if err == nil { t.Errorf("should return error opening device") } }) t.Run("video capture valid string", func(t *testing.T) { vc5, err := OpenVideoCapture(strconv.Itoa(math.MaxInt32)) defer vc5.Close() if err == nil { t.Errorf("should return error opening device") } }) } func TestVideoWriterFile(t *testing.T) { dir, _ := ioutil.TempDir("", "gocvtests") tmpfn := filepath.Join(dir, "test.avi") img := IMRead("images/face-detect.jpg", IMReadColor) if img.Empty() { t.Error("Invalid read of Mat in VideoWriterFile test") } defer img.Close() vw, _ := VideoWriterFile(tmpfn, "MJPG", 25, img.Cols(), img.Rows(), true) defer vw.Close() if !vw.IsOpened() { t.Error("Unable to open VideoWriterFile") } err := vw.Write(img) if err != nil { t.Error("Invalid Write() in VideoWriter") } } func TestVideoWriterFileWithAPI(t *testing.T) { dir := os.TempDir() tmpfn := filepath.Join(dir, "test.avi") img := IMRead("images/face-detect.jpg", IMReadColor) if img.Empty() { t.Error("Invalid read of Mat in VideoWriterFile test") } defer img.Close() vw, _ := VideoWriterFileWithAPI(tmpfn, VideoCaptureFFmpeg, "MJPG", 25, img.Cols(), img.Rows(), true) defer vw.Close() if !vw.IsOpened() { t.Error("Unable to open VideoWriterFile") } err := vw.Write(img) if err != nil { t.Error("Invalid Write() in VideoWriter") } } func TestVideoWriterFileWithAPIParams(t *testing.T) { dir := os.TempDir() tmpfn := filepath.Join(dir, "test.avi") img := IMRead("images/face-detect.jpg", IMReadColor) if img.Empty() { t.Error("Invalid read of Mat in VideoWriterFile test") } defer img.Close() vw, _ := VideoWriterFileWithAPIParams(tmpfn, VideoCaptureFFmpeg, "MJPG", 25, img.Cols(), img.Rows(), []VideoWriterProperty{VideoWriterHwAcceleration, 0, VideoWriterIsColor, 1}) defer vw.Close() if !vw.IsOpened() { t.Error("Unable to open VideoWriterFile") } err := vw.Write(img) if err != nil { t.Error("Invalid Write() in VideoWriter") } } func TestVideoCaptureFile_GrabRetrieve(t *testing.T) { vc, err := VideoCaptureFile("images/small.mp4") defer vc.Close() if err != nil { t.Errorf("%s", err) } if !vc.IsOpened() { t.Error("Unable to open VideoCaptureFile") } if fw := vc.Get(VideoCaptureFrameWidth); int(fw) != 560 { t.Errorf("Expected frame width property of 560.0 got %f", fw) } if fh := vc.Get(VideoCaptureFrameHeight); int(fh) != 320 { t.Errorf("Expected frame height property of 320.0 got %f", fh) } vc.Set(VideoCaptureBrightness, 100.0) vc.Grab(10) img := NewMat() defer img.Close() if ok := vc.Retrieve(&img); !ok { t.Error("Unable to read VideoCaptureFile") } if img.Empty() { t.Error("Unable to read VideoCaptureFile") } } func TestVideoCaptureFile_GrabRetrieveChannel(t *testing.T) { vc, err := VideoCaptureFile("images/small.mp4") defer vc.Close() if err != nil { t.Errorf("%s", err) } if !vc.IsOpened() { t.Error("Unable to open VideoCaptureFile") } if fw := vc.Get(VideoCaptureFrameWidth); int(fw) != 560 { t.Errorf("Expected frame width property of 560.0 got %f", fw) } if fh := vc.Get(VideoCaptureFrameHeight); int(fh) != 320 { t.Errorf("Expected frame height property of 320.0 got %f", fh) } vc.Set(VideoCaptureBrightness, 100.0) vc.Grab(10) img := NewMat() defer img.Close() if ok := vc.RetrieveChannel(&img, 0); !ok { t.Error("Unable to read VideoCaptureFile") } if img.Empty() { t.Error("Unable to read VideoCaptureFile") } } func TestVideoRegistry(t *testing.T) { name := VideoRegistry.GetBackendName(VideoCaptureFFmpeg) t.Log("VideoRegistry.GetBackendName()", name) backs := VideoRegistry.GetBackends() for _, b := range backs { t.Log("VideoRegistry.GetBackends()", b.String()) } cameraBacks := VideoRegistry.GetCameraBackends() for _, b := range cameraBacks { t.Log("VideoRegistry.GetCameraBackends()", b.String()) if !VideoRegistry.IsBackendBuiltIn(b) && VideoRegistry.HasBackend(b) { description, abiVersion, apiVersion := VideoRegistry.GetCameraBackendPluginVersion(b) t.Log("VideoRegistry.GetCameraBackendPluginVersion()", description, abiVersion, apiVersion) } } streamBacks := VideoRegistry.GetStreamBackends() for _, b := range streamBacks { t.Log("VideoRegistry.GetStreamBackends()", b.String()) if !VideoRegistry.IsBackendBuiltIn(b) && VideoRegistry.HasBackend(b) { description, abiVersion, apiVersion := VideoRegistry.GetStreamBackendPluginVersion(b) t.Log("VideoRegistry.GetStreamBackendPluginVersion()", description, abiVersion, apiVersion) } } writerBacks := VideoRegistry.GetWriterBackends() for _, b := range writerBacks { t.Log("VideoRegistry.GetWriterBackends()", b.String()) if !VideoRegistry.IsBackendBuiltIn(b) && VideoRegistry.HasBackend(b) { description, abiVersion, apiVersion := VideoRegistry.GetWriterBackendPluginVersion(b) t.Log("VideoRegistry.GetWriterBackendPluginVersion()", description, abiVersion, apiVersion) } } } ================================================ FILE: win_build_opencv.cmd ================================================ @echo off REM Save the starting directory set "START_DIR=%CD%" REM Set install directory, default to C:\opencv if not provided set "INSTALL_DIR=%~1" if "%INSTALL_DIR%"=="" set "INSTALL_DIR=C:\opencv" REM Always quote paths to handle spaces if not exist "%INSTALL_DIR%\build" mkdir "%INSTALL_DIR%\build" REM Change to build directory cd /D "%INSTALL_DIR%\build" REM Set enable_shared default set "enable_shared=ON" if /I "%2"=="static" ( echo Build static opencv set "enable_shared=OFF" ) REM Use variables for version set "OPENCV_VERSION=4.13.0" REM Run CMake with quoted paths cmake "%INSTALL_DIR%\opencv-%OPENCV_VERSION%" -G "MinGW Makefiles" -B"%INSTALL_DIR%\build" -DENABLE_CXX11=ON -DOPENCV_EXTRA_MODULES_PATH="%INSTALL_DIR%\opencv_contrib-%OPENCV_VERSION%\modules" -DBUILD_SHARED_LIBS=%enable_shared% -DWITH_IPP=OFF -DWITH_MSMF=OFF -DBUILD_EXAMPLES=OFF -DBUILD_TESTS=OFF -DBUILD_PERF_TESTS=ON -DBUILD_opencv_java=OFF -DBUILD_opencv_python=OFF -DBUILD_opencv_python2=OFF -DBUILD_opencv_python3=OFF -DBUILD_DOCS=OFF -DENABLE_PRECOMPILED_HEADERS=OFF -DBUILD_opencv_saliency=OFF -DBUILD_opencv_wechat_qrcode=ON -DCPU_DISPATCH= -DOPENCV_GENERATE_PKGCONFIG=ON -DWITH_OPENCL_D3D11_NV=OFF -DOPENCV_ALLOCATOR_STATS_COUNTER_TYPE=int64_t -DOPENCV_ENABLE_NONFREE=ON -Wno-dev if errorlevel 1 ( echo CMake configuration failed! cd /D "%START_DIR%" exit /b 1 ) cmake --build . --target install if errorlevel 1 ( echo Build failed! cd /D "%START_DIR%" exit /b 1 ) REM Return to the original directory cd /D "%START_DIR%" ================================================ FILE: win_download_opencv.cmd ================================================ @echo off REM Save the starting directory set "START_DIR=%CD%" REM Set install directory, default to C:\opencv if not provided set "INSTALL_DIR=%~1" if "%INSTALL_DIR%"=="" set "INSTALL_DIR=C:\opencv" if not exist "%INSTALL_DIR%" mkdir "%INSTALL_DIR%" echo Downloading OpenCV sources echo. echo For monitoring the download progress please check the %INSTALL_DIR% directory. echo. REM This is why there is no progress bar: REM https://github.com/PowerShell/PowerShell/issues/2138 REM Downloading: opencv-4.13.0.zip [91MB] powershell -command "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $ProgressPreference = 'SilentlyContinue'; Invoke-WebRequest -Uri 'https://github.com/opencv/opencv/archive/4.13.0.zip' -OutFile \"%INSTALL_DIR%\opencv-4.13.0.zip\"" echo Extracting... powershell -command "$ProgressPreference = 'SilentlyContinue'; Expand-Archive -Path \"%INSTALL_DIR%\opencv-4.13.0.zip\" -DestinationPath \"%INSTALL_DIR%\"" del "%INSTALL_DIR%\opencv-4.13.0.zip" /q echo. echo Downloading: opencv_contrib-4.13.0.zip [58MB] powershell -command "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $ProgressPreference = 'SilentlyContinue'; Invoke-WebRequest -Uri 'https://github.com/opencv/opencv_contrib/archive/4.13.0.zip' -OutFile \"%INSTALL_DIR%\opencv_contrib-4.13.0.zip\"" echo Extracting... powershell -command "$ProgressPreference = 'SilentlyContinue'; Expand-Archive -Path \"%INSTALL_DIR%\opencv_contrib-4.13.0.zip\" -DestinationPath \"%INSTALL_DIR%\"" del "%INSTALL_DIR%\opencv_contrib-4.13.0.zip" /q echo. echo Done with downloading and extracting sources. echo. @echo on REM Return to the original directory chdir /D "%START_DIR%"