From 5e454018588a74793263572d7e60b267ad21635b Mon Sep 17 00:00:00 2001 From: Cyrille Nofficial Date: Thu, 19 Dec 2019 00:08:07 +0100 Subject: [PATCH] First implementation --- .gitignore | 285 +++ .sonarcloud.properties | 1 + Dockerfile | 33 + LICENSE | 201 ++ README.md | 11 + camera/camera.go | 81 + camera/camera_test.go | 57 + camera/testdata/img.jpg | Bin 0 -> 2105 bytes cmd/rc-camera/rc-camera.go | 59 + go.mod | 9 + go.sum | 125 ++ .../github.com/cyrilix/robocar-base/LICENSE | 201 ++ .../cyrilix/robocar-base/cli/cli.go | 95 + .../cyrilix/robocar-base/mode/mode.go | 37 + .../robocar-base/mqttdevice/mqttdevice.go | 151 ++ .../robocar-base/testtools/testtools.go | 73 + .../eclipse/paho.mqtt.golang/.gitignore | 36 + .../eclipse/paho.mqtt.golang/CONTRIBUTING.md | 56 + .../eclipse/paho.mqtt.golang/DISTRIBUTION | 15 + .../eclipse/paho.mqtt.golang/LICENSE | 87 + .../eclipse/paho.mqtt.golang/README.md | 67 + .../eclipse/paho.mqtt.golang/about.html | 41 + .../eclipse/paho.mqtt.golang/client.go | 759 +++++++ .../eclipse/paho.mqtt.golang/components.go | 31 + .../eclipse/paho.mqtt.golang/edl-v10 | 15 + .../eclipse/paho.mqtt.golang/epl-v10 | 70 + .../eclipse/paho.mqtt.golang/filestore.go | 255 +++ .../eclipse/paho.mqtt.golang/memstore.go | 138 ++ .../eclipse/paho.mqtt.golang/message.go | 127 ++ .../eclipse/paho.mqtt.golang/messageids.go | 117 ++ .../eclipse/paho.mqtt.golang/net.go | 355 ++++ .../eclipse/paho.mqtt.golang/notice.html | 108 + .../eclipse/paho.mqtt.golang/oops.go | 21 + .../eclipse/paho.mqtt.golang/options.go | 340 +++ .../paho.mqtt.golang/options_reader.go | 149 ++ .../paho.mqtt.golang/packets/connack.go | 55 + .../paho.mqtt.golang/packets/connect.go | 154 ++ .../paho.mqtt.golang/packets/disconnect.go | 36 + .../paho.mqtt.golang/packets/packets.go | 346 +++ .../paho.mqtt.golang/packets/pingreq.go | 36 + .../paho.mqtt.golang/packets/pingresp.go | 36 + .../paho.mqtt.golang/packets/puback.go | 45 + .../paho.mqtt.golang/packets/pubcomp.go | 45 + .../paho.mqtt.golang/packets/publish.go | 88 + .../paho.mqtt.golang/packets/pubrec.go | 45 + .../paho.mqtt.golang/packets/pubrel.go | 45 + .../paho.mqtt.golang/packets/suback.go | 60 + .../paho.mqtt.golang/packets/subscribe.go | 72 + .../paho.mqtt.golang/packets/unsuback.go | 45 + .../paho.mqtt.golang/packets/unsubscribe.go | 59 + .../eclipse/paho.mqtt.golang/ping.go | 69 + .../eclipse/paho.mqtt.golang/router.go | 187 ++ .../eclipse/paho.mqtt.golang/store.go | 136 ++ .../eclipse/paho.mqtt.golang/token.go | 184 ++ .../eclipse/paho.mqtt.golang/topic.go | 82 + .../eclipse/paho.mqtt.golang/trace.go | 40 + vendor/gocv.io/x/gocv/.astylerc | 28 + vendor/gocv.io/x/gocv/.dockerignore | 1 + vendor/gocv.io/x/gocv/.gitignore | 10 + vendor/gocv.io/x/gocv/.travis.yml | 60 + vendor/gocv.io/x/gocv/CHANGELOG.md | 675 ++++++ vendor/gocv.io/x/gocv/CONTRIBUTING.md | 136 ++ vendor/gocv.io/x/gocv/Dockerfile | 60 + vendor/gocv.io/x/gocv/LICENSE.txt | 202 ++ vendor/gocv.io/x/gocv/Makefile | 138 ++ vendor/gocv.io/x/gocv/README.md | 565 +++++ vendor/gocv.io/x/gocv/ROADMAP.md | 209 ++ vendor/gocv.io/x/gocv/appveyor.yml | 35 + .../gocv.io/x/gocv/appveyor_build_opencv.cmd | 23 + vendor/gocv.io/x/gocv/calib3d.cpp | 29 + vendor/gocv.io/x/gocv/calib3d.go | 99 + vendor/gocv.io/x/gocv/calib3d.h | 25 + vendor/gocv.io/x/gocv/cgo.go | 13 + vendor/gocv.io/x/gocv/core.cpp | 742 +++++++ vendor/gocv.io/x/gocv/core.go | 1869 +++++++++++++++++ vendor/gocv.io/x/gocv/core.h | 378 ++++ vendor/gocv.io/x/gocv/dnn.cpp | 169 ++ vendor/gocv.io/x/gocv/dnn.go | 450 ++++ vendor/gocv.io/x/gocv/dnn.h | 57 + vendor/gocv.io/x/gocv/dnn_ext.go | 67 + vendor/gocv.io/x/gocv/env.cmd | 2 + vendor/gocv.io/x/gocv/env.sh | 2 + vendor/gocv.io/x/gocv/features2d.cpp | 430 ++++ vendor/gocv.io/x/gocv/features2d.go | 750 +++++++ vendor/gocv.io/x/gocv/features2d.h | 89 + vendor/gocv.io/x/gocv/go.mod | 3 + vendor/gocv.io/x/gocv/gocv.go | 11 + vendor/gocv.io/x/gocv/highgui.cpp | 79 + vendor/gocv.io/x/gocv/highgui.go | 323 +++ vendor/gocv.io/x/gocv/highgui_gocv.h | 35 + vendor/gocv.io/x/gocv/imgcodecs.cpp | 51 + vendor/gocv.io/x/gocv/imgcodecs.go | 248 +++ vendor/gocv.io/x/gocv/imgcodecs.h | 24 + vendor/gocv.io/x/gocv/imgproc.cpp | 575 +++++ vendor/gocv.io/x/gocv/imgproc.go | 1667 +++++++++++++++ vendor/gocv.io/x/gocv/imgproc.h | 113 + vendor/gocv.io/x/gocv/imgproc_colorcodes.go | 351 ++++ vendor/gocv.io/x/gocv/mat_noprofile.go | 21 + vendor/gocv.io/x/gocv/mat_profile.go | 74 + vendor/gocv.io/x/gocv/objdetect.cpp | 127 ++ vendor/gocv.io/x/gocv/objdetect.go | 186 ++ vendor/gocv.io/x/gocv/objdetect.h | 45 + vendor/gocv.io/x/gocv/travis_build_opencv.sh | 79 + vendor/gocv.io/x/gocv/version.cpp | 5 + vendor/gocv.io/x/gocv/version.go | 20 + vendor/gocv.io/x/gocv/version.h | 17 + vendor/gocv.io/x/gocv/video.cpp | 49 + vendor/gocv.io/x/gocv/video.go | 157 ++ vendor/gocv.io/x/gocv/video.h | 38 + vendor/gocv.io/x/gocv/videoio.cpp | 63 + vendor/gocv.io/x/gocv/videoio.go | 332 +++ vendor/gocv.io/x/gocv/videoio.h | 42 + vendor/gocv.io/x/gocv/win_build_opencv.cmd | 40 + vendor/golang.org/x/net/AUTHORS | 3 + vendor/golang.org/x/net/CONTRIBUTORS | 3 + vendor/golang.org/x/net/LICENSE | 27 + vendor/golang.org/x/net/PATENTS | 22 + .../golang.org/x/net/internal/socks/client.go | 168 ++ .../golang.org/x/net/internal/socks/socks.go | 317 +++ vendor/golang.org/x/net/proxy/dial.go | 54 + vendor/golang.org/x/net/proxy/direct.go | 31 + vendor/golang.org/x/net/proxy/per_host.go | 155 ++ vendor/golang.org/x/net/proxy/proxy.go | 149 ++ vendor/golang.org/x/net/proxy/socks5.go | 42 + vendor/golang.org/x/net/websocket/client.go | 106 + vendor/golang.org/x/net/websocket/dial.go | 24 + vendor/golang.org/x/net/websocket/hybi.go | 583 +++++ vendor/golang.org/x/net/websocket/server.go | 113 + .../golang.org/x/net/websocket/websocket.go | 451 ++++ vendor/modules.txt | 14 + 130 files changed, 20421 insertions(+) create mode 100644 .gitignore create mode 100644 .sonarcloud.properties create mode 100644 Dockerfile create mode 100644 LICENSE create mode 100644 README.md create mode 100644 camera/camera.go create mode 100644 camera/camera_test.go create mode 100644 camera/testdata/img.jpg create mode 100644 cmd/rc-camera/rc-camera.go create mode 100644 go.mod create mode 100644 go.sum create mode 100644 vendor/github.com/cyrilix/robocar-base/LICENSE create mode 100644 vendor/github.com/cyrilix/robocar-base/cli/cli.go create mode 100644 vendor/github.com/cyrilix/robocar-base/mode/mode.go create mode 100644 vendor/github.com/cyrilix/robocar-base/mqttdevice/mqttdevice.go create mode 100644 vendor/github.com/cyrilix/robocar-base/testtools/testtools.go create mode 100644 vendor/github.com/eclipse/paho.mqtt.golang/.gitignore create mode 100644 vendor/github.com/eclipse/paho.mqtt.golang/CONTRIBUTING.md create mode 100644 vendor/github.com/eclipse/paho.mqtt.golang/DISTRIBUTION create mode 100644 vendor/github.com/eclipse/paho.mqtt.golang/LICENSE create mode 100644 vendor/github.com/eclipse/paho.mqtt.golang/README.md create mode 100644 vendor/github.com/eclipse/paho.mqtt.golang/about.html create mode 100644 vendor/github.com/eclipse/paho.mqtt.golang/client.go create mode 100644 vendor/github.com/eclipse/paho.mqtt.golang/components.go create mode 100644 vendor/github.com/eclipse/paho.mqtt.golang/edl-v10 create mode 100644 vendor/github.com/eclipse/paho.mqtt.golang/epl-v10 create mode 100644 vendor/github.com/eclipse/paho.mqtt.golang/filestore.go create mode 100644 vendor/github.com/eclipse/paho.mqtt.golang/memstore.go create mode 100644 vendor/github.com/eclipse/paho.mqtt.golang/message.go create mode 100644 vendor/github.com/eclipse/paho.mqtt.golang/messageids.go create mode 100644 vendor/github.com/eclipse/paho.mqtt.golang/net.go create mode 100644 vendor/github.com/eclipse/paho.mqtt.golang/notice.html create mode 100644 vendor/github.com/eclipse/paho.mqtt.golang/oops.go create mode 100644 vendor/github.com/eclipse/paho.mqtt.golang/options.go create mode 100644 vendor/github.com/eclipse/paho.mqtt.golang/options_reader.go create mode 100644 vendor/github.com/eclipse/paho.mqtt.golang/packets/connack.go create mode 100644 vendor/github.com/eclipse/paho.mqtt.golang/packets/connect.go create mode 100644 vendor/github.com/eclipse/paho.mqtt.golang/packets/disconnect.go create mode 100644 vendor/github.com/eclipse/paho.mqtt.golang/packets/packets.go create mode 100644 vendor/github.com/eclipse/paho.mqtt.golang/packets/pingreq.go create mode 100644 vendor/github.com/eclipse/paho.mqtt.golang/packets/pingresp.go create mode 100644 vendor/github.com/eclipse/paho.mqtt.golang/packets/puback.go create mode 100644 vendor/github.com/eclipse/paho.mqtt.golang/packets/pubcomp.go create mode 100644 vendor/github.com/eclipse/paho.mqtt.golang/packets/publish.go create mode 100644 vendor/github.com/eclipse/paho.mqtt.golang/packets/pubrec.go create mode 100644 vendor/github.com/eclipse/paho.mqtt.golang/packets/pubrel.go create mode 100644 vendor/github.com/eclipse/paho.mqtt.golang/packets/suback.go create mode 100644 vendor/github.com/eclipse/paho.mqtt.golang/packets/subscribe.go create mode 100644 vendor/github.com/eclipse/paho.mqtt.golang/packets/unsuback.go create mode 100644 vendor/github.com/eclipse/paho.mqtt.golang/packets/unsubscribe.go create mode 100644 vendor/github.com/eclipse/paho.mqtt.golang/ping.go create mode 100644 vendor/github.com/eclipse/paho.mqtt.golang/router.go create mode 100644 vendor/github.com/eclipse/paho.mqtt.golang/store.go create mode 100644 vendor/github.com/eclipse/paho.mqtt.golang/token.go create mode 100644 vendor/github.com/eclipse/paho.mqtt.golang/topic.go create mode 100644 vendor/github.com/eclipse/paho.mqtt.golang/trace.go create mode 100644 vendor/gocv.io/x/gocv/.astylerc create mode 100644 vendor/gocv.io/x/gocv/.dockerignore create mode 100644 vendor/gocv.io/x/gocv/.gitignore create mode 100644 vendor/gocv.io/x/gocv/.travis.yml create mode 100644 vendor/gocv.io/x/gocv/CHANGELOG.md create mode 100644 vendor/gocv.io/x/gocv/CONTRIBUTING.md create mode 100644 vendor/gocv.io/x/gocv/Dockerfile create mode 100644 vendor/gocv.io/x/gocv/LICENSE.txt create mode 100644 vendor/gocv.io/x/gocv/Makefile create mode 100644 vendor/gocv.io/x/gocv/README.md create mode 100644 vendor/gocv.io/x/gocv/ROADMAP.md create mode 100644 vendor/gocv.io/x/gocv/appveyor.yml create mode 100644 vendor/gocv.io/x/gocv/appveyor_build_opencv.cmd create mode 100644 vendor/gocv.io/x/gocv/calib3d.cpp create mode 100644 vendor/gocv.io/x/gocv/calib3d.go create mode 100644 vendor/gocv.io/x/gocv/calib3d.h create mode 100644 vendor/gocv.io/x/gocv/cgo.go create mode 100644 vendor/gocv.io/x/gocv/core.cpp create mode 100644 vendor/gocv.io/x/gocv/core.go create mode 100644 vendor/gocv.io/x/gocv/core.h create mode 100644 vendor/gocv.io/x/gocv/dnn.cpp create mode 100644 vendor/gocv.io/x/gocv/dnn.go create mode 100644 vendor/gocv.io/x/gocv/dnn.h create mode 100644 vendor/gocv.io/x/gocv/dnn_ext.go create mode 100644 vendor/gocv.io/x/gocv/env.cmd create mode 100644 vendor/gocv.io/x/gocv/env.sh create mode 100644 vendor/gocv.io/x/gocv/features2d.cpp create mode 100644 vendor/gocv.io/x/gocv/features2d.go create mode 100644 vendor/gocv.io/x/gocv/features2d.h create mode 100644 vendor/gocv.io/x/gocv/go.mod create mode 100644 vendor/gocv.io/x/gocv/gocv.go create mode 100644 vendor/gocv.io/x/gocv/highgui.cpp create mode 100644 vendor/gocv.io/x/gocv/highgui.go create mode 100644 vendor/gocv.io/x/gocv/highgui_gocv.h create mode 100644 vendor/gocv.io/x/gocv/imgcodecs.cpp create mode 100644 vendor/gocv.io/x/gocv/imgcodecs.go create mode 100644 vendor/gocv.io/x/gocv/imgcodecs.h create mode 100644 vendor/gocv.io/x/gocv/imgproc.cpp create mode 100644 vendor/gocv.io/x/gocv/imgproc.go create mode 100644 vendor/gocv.io/x/gocv/imgproc.h create mode 100644 vendor/gocv.io/x/gocv/imgproc_colorcodes.go create mode 100644 vendor/gocv.io/x/gocv/mat_noprofile.go create mode 100644 vendor/gocv.io/x/gocv/mat_profile.go create mode 100644 vendor/gocv.io/x/gocv/objdetect.cpp create mode 100644 vendor/gocv.io/x/gocv/objdetect.go create mode 100644 vendor/gocv.io/x/gocv/objdetect.h create mode 100644 vendor/gocv.io/x/gocv/travis_build_opencv.sh create mode 100644 vendor/gocv.io/x/gocv/version.cpp create mode 100644 vendor/gocv.io/x/gocv/version.go create mode 100644 vendor/gocv.io/x/gocv/version.h create mode 100644 vendor/gocv.io/x/gocv/video.cpp create mode 100644 vendor/gocv.io/x/gocv/video.go create mode 100644 vendor/gocv.io/x/gocv/video.h create mode 100644 vendor/gocv.io/x/gocv/videoio.cpp create mode 100644 vendor/gocv.io/x/gocv/videoio.go create mode 100644 vendor/gocv.io/x/gocv/videoio.h create mode 100644 vendor/gocv.io/x/gocv/win_build_opencv.cmd create mode 100644 vendor/golang.org/x/net/AUTHORS create mode 100644 vendor/golang.org/x/net/CONTRIBUTORS create mode 100644 vendor/golang.org/x/net/LICENSE create mode 100644 vendor/golang.org/x/net/PATENTS create mode 100644 vendor/golang.org/x/net/internal/socks/client.go create mode 100644 vendor/golang.org/x/net/internal/socks/socks.go create mode 100644 vendor/golang.org/x/net/proxy/dial.go create mode 100644 vendor/golang.org/x/net/proxy/direct.go create mode 100644 vendor/golang.org/x/net/proxy/per_host.go create mode 100644 vendor/golang.org/x/net/proxy/proxy.go create mode 100644 vendor/golang.org/x/net/proxy/socks5.go create mode 100644 vendor/golang.org/x/net/websocket/client.go create mode 100644 vendor/golang.org/x/net/websocket/dial.go create mode 100644 vendor/golang.org/x/net/websocket/hybi.go create mode 100644 vendor/golang.org/x/net/websocket/server.go create mode 100644 vendor/golang.org/x/net/websocket/websocket.go create mode 100644 vendor/modules.txt diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a3bb0b8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,285 @@ +# Created by .ignore support plugin (hsz.mobi) +### Emacs template +# -*- mode: gitignore; -*- +*~ +\#*\# +/.emacs.desktop +/.emacs.desktop.lock +*.elc +auto-save-list +tramp +.\#* + +# Org-mode +.org-id-locations +*_archive + +# flymake-mode +*_flymake.* + +# eshell files +/eshell/history +/eshell/lastdir + +# elpa packages +/elpa/ + +# reftex files +*.rel + +# AUCTeX auto folder +/auto/ + +# cask packages +.cask/ +dist/ + +# Flycheck +flycheck_*.el + +# server auth directory +/server/ + +# projectiles files +.projectile + +# directory configuration +.dir-locals.el + +# network security +/network-security.data + + +### JetBrains template +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/artifacts +# .idea/compiler.xml +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser + +### Vim template +# Swap +[._]*.s[a-v][a-z] +!*.svg # comment out if you don't need vector files +[._]*.sw[a-p] +[._]s[a-rt-v][a-z] +[._]ss[a-gi-z] +[._]sw[a-p] + +# Session +Session.vim +Sessionx.vim + +# Temporary +.netrwhist +*~ +# Auto-generated tag files +tags +# Persistent undo +[._]*.un~ + +### macOS template +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +### Xcode template +# Xcode +# +# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore + +## User settings +xcuserdata/ + +## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9) +*.xcscmblueprint +*.xccheckout + +## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4) +build/ +DerivedData/ +*.moved-aside +*.pbxuser +!default.pbxuser +*.mode1v3 +!default.mode1v3 +*.mode2v3 +!default.mode2v3 +*.perspectivev3 +!default.perspectivev3 + +## Gcc Patch +/*.gcno + +### Go template +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, built with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Dependency directories (remove the comment below to include it) +# vendor/ + +### Eclipse template +.metadata +bin/ +tmp/ +*.tmp +*.bak +*.swp +*~.nib +local.properties +.settings/ +.loadpath +.recommenders + +# External tool builders +.externalToolBuilders/ + +# Locally stored "Eclipse launch configurations" +*.launch + +# PyDev specific (Python IDE for Eclipse) +*.pydevproject + +# CDT-specific (C/C++ Development Tooling) +.cproject + +# CDT- autotools +.autotools + +# Java annotation processor (APT) +.factorypath + +# PDT-specific (PHP Development Tools) +.buildpath + +# sbteclipse plugin +.target + +# Tern plugin +.tern-project + +# TeXlipse plugin +.texlipse + +# STS (Spring Tool Suite) +.springBeans + +# Code Recommenders +.recommenders/ + +# Annotation Processing +.apt_generated/ +.apt_generated_test/ + +# Scala IDE specific (Scala & Java development for Eclipse) +.cache-main +.scala_dependencies +.worksheet + +### VisualStudioCode template +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +*.code-workspace + +./rc-* diff --git a/.sonarcloud.properties b/.sonarcloud.properties new file mode 100644 index 0000000..7bff57b --- /dev/null +++ b/.sonarcloud.properties @@ -0,0 +1 @@ +sonar.exclusions=./vendor/** diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..910722b --- /dev/null +++ b/Dockerfile @@ -0,0 +1,33 @@ +FROM golang:alpine as gobuilder + + +FROM cyrilix/opencv-buildstage:4.1.2 as builder + +LABEL maintainer="Cyrille Nofficial" + +COPY --from=gobuilder /usr/local/go /usr/local/go +ENV GOPATH /go +ENV PATH /usr/local/go/bin:$GOPATH/bin:/usr/local/go/bin:$PATH + +RUN mkdir -p "/src $GOPATH/src" "$GOPATH/bin" && chmod -R 777 "$GOPATH" + +ENV PKG_CONFIG_PATH /usr/local/lib/pkgconfig:/usr/local/lib64/pkgconfig +ENV CGO_CPPFLAGS -I/usr/local/include +ENV CGO_CXXFLAGS "--std=c++1z" + +WORKDIR /src +ADD . . + +RUN CGO_LDFLAGS="$(pkg-config --libs opencv4)" \ + CGO_ENABLED=1 CGO_CPPFLAGS=${CGO_CPPFLAGS} CGO_CXXFLAGS=${CGO_CXXFLAGS} CGO_LDFLAGS=${CGO_LDFLAGS} GOOS=${GOOS} GOARCH=${GOARCH} GOARM=${GOARM} go build -mod vendor -a ./cmd/rc-camera/ + + + + +FROM cyrilix/opencv-runtime:4.1.2 + +ENV LD_LIBRARY_PATH /usr/local/lib:/usr/local/lib64 + +USER 1234 +COPY --from=builder /src/rc-camera /go/bin/rc-camera +ENTRYPOINT ["/go/bin/rc-camera"] diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/README.md b/README.md new file mode 100644 index 0000000..5bf9c0c --- /dev/null +++ b/README.md @@ -0,0 +1,11 @@ +# robocar-camera + +Microservice part to manage camera + + +## Docker build + +```bash +export DOCKER_CLI_EXPERIMENTAL=enabled +docker buildx build . --platform linux/amd64,linux/arm/7,linux/arm64 -t cyrilix/robocar-led +``` diff --git a/camera/camera.go b/camera/camera.go new file mode 100644 index 0000000..70750c5 --- /dev/null +++ b/camera/camera.go @@ -0,0 +1,81 @@ +package camera + +import ( + "github.com/cyrilix/robocar-base/mqttdevice" + "gocv.io/x/gocv" + "io" + "log" + "sync" + "time" +) + +type VideoSource interface { + Read(m *gocv.Mat) bool + io.Closer +} + +type OpencvCameraPart struct { + vc VideoSource + pub mqttdevice.Publisher + topic string + publishFrequency int + muImgBuffered sync.Mutex + imgBuffered *gocv.Mat +} + +func New(topic string, publisher mqttdevice.Publisher, publishFrequency int, videoProperties map[gocv.VideoCaptureProperties]float64) *OpencvCameraPart { + log.Printf("Run camera part") + + vc, err := gocv.OpenVideoCapture(0) + if err != nil { + log.Fatalf("unable to open video device: %v", err) + } + for k, v := range videoProperties { + vc.Set(k, v) + } + + img := gocv.NewMat() + o := OpencvCameraPart{ + vc: vc, + pub: publisher, + topic: topic, + publishFrequency: publishFrequency, + imgBuffered: &img, + } + return &o +} + +func (o *OpencvCameraPart) Start() error { + log.Printf("start camera") + ticker := time.NewTicker(1 * time.Second / time.Duration(o.publishFrequency)) + defer ticker.Stop() + + for { + go o.publishFrame() + <-ticker.C + } +} + +func (o *OpencvCameraPart) Stop() { + log.Print("close video device") + if err := o.vc.Close(); err != nil { + log.Printf("unexpected error while VideoCapture is closed: %v", err) + } + if err := o.imgBuffered.Close(); err != nil { + log.Printf("unexpected error while VideoCapture is closed: %v", err) + } +} + +func (o *OpencvCameraPart) publishFrame() { + o.muImgBuffered.Lock() + defer o.muImgBuffered.Unlock() + + o.vc.Read(o.imgBuffered) + img, err := gocv.IMEncode(gocv.JPEGFileExt, *o.imgBuffered) + if err != nil { + log.Printf("unable to convert image to jpeg: %v", err) + return + } + + o.pub.Publish(o.topic, img) +} diff --git a/camera/camera_test.go b/camera/camera_test.go new file mode 100644 index 0000000..4f806a8 --- /dev/null +++ b/camera/camera_test.go @@ -0,0 +1,57 @@ +package camera + +import ( + "bytes" + "github.com/cyrilix/robocar-base/testtools" + "gocv.io/x/gocv" + "image/jpeg" + "io" + "log" + "testing" + "time" +) + +type fakeVideoSource struct { + io.Closer +} + +func (f fakeVideoSource) Read(dest *gocv.Mat) bool { + img := gocv.IMRead("testdata/img.jpg", gocv.IMReadUnchanged) + if img.Total() == 0 { + log.Print("image read is empty") + return false + } + img.CopyTo(dest) + return true +} + +func TestOpencvCameraPart(t *testing.T) { + p := testtools.NewFakePublisher() + const topic = "topic/test/camera" + imgBuffer := gocv.NewMat() + + part := OpencvCameraPart{ + vc: fakeVideoSource{}, + pub: p, + topic: topic, + publishFrequency: 1000, + imgBuffered: &imgBuffer, + } + + go part.Start() + time.Sleep(1 * time.Millisecond) + + img := p.PublishedEvent(topic) + if img == nil { + t.Fatalf("event %s has not been published", topic) + } + content, err := img.ByteSliceValue() + if err != nil { + t.Errorf("unexpected error: %v", err) + } + + _, err = jpeg.Decode(bytes.NewReader(content)) + if err != nil { + t.Errorf("image published can't be decoded: %v", err) + } +} diff --git a/camera/testdata/img.jpg b/camera/testdata/img.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b112461e9d5531a8a3bb6ffaf9f82d7065bcb689 GIT binary patch literal 2105 zcmbW#X;hO}8VB(AC2uxJfIxtNkwAhhaj6MGh!7i~?4Vh|0#hABK$cnvQBfFi5-5m~ zEr3X=K#(PYxPer`r4-??|` z?$QKc9vT=D2!J2}fXf9e-3R;u6as-nz)?sf5{*U~WAIpvi3!Hm!qN=C(vD=m(vC=U za9Zc$Kwd*35?wvr)~u&77z~mNljTMCS?A86e>wz2qtO@>3;~NJ&>e}6^#3_aR{APfgC^#G*hd&0rr1N<|f5e$MOkSMgV$@0Jt=713hgBd|EI2?kOr?Z#) z0EB~EIMRF(mRtdnoQ|hU<@G3vUt6~o@760P_c(D5+SuBLU~9L^*~Qh3%JA6W>BZdW z|3yGxP;f{nKQe0Tm(ek?!uW)piAl*RyZ7wP*tb73EBD*H{6htYWo6|RM=Ot2eOG;= zp|Po1scLC$KiBcY`3s$07q4CK>Fv|>58Sw|8y*?GbNAlZh&ku@3Q|6mh*qf{ssHDYYf1^z~#q-;egM9=lZUFrGm5I z4Ee-dyzplAkwNZL&Xu8ckvNTW=W}1d;fy%V(_9YyO_n9c~rASSHndPOgDFleY^Sb>*rOR+7=A zurT*_L$V$k5m3Nj@h`DJ&GZ3d@iwnbBOyl%X8Y^?i?d`ql2=snP%T@(x!HM;d@e9_ z;y3)02c;9FYo&Ha9LY7EE&ar(RdpWpo3-xjn+^;7u4jM>W<`0Z4AjDi<#f^|K2j!_ zbGG}gW4+cZNM7m+s@B)V=KZWSs9)lDfKiX5`m)_XK2w~2)e1K_RTA1RGOvr3R$+$7 zZZ^}16XoYw)WpPLTah6`vYFYaD3y)|U)c^EMk-H8G*?E`@`P1;Vx;M=)XMYX< zOu{MxLTZz=K|eY0kBG1^n+#J{l9}xA{nBL5Ikt6HvD=kEZ=H3xSrfA)osCH~P43Sm z%YRHw&UI|f-%OCz{7KZULQ=?${>9@QNR`<=yVXK1^pS~~{M_56TJrlx>frbO{+4C# zFF4^Ef}xS@Ggp^FIy1?&5O3RTian4vh;D@LF+ZlD z3FW-PDGxKBMOWN5u{g=;#YeZHrLUH;naE~cRx}^;wn{vE#vCf#f!ZrI;(Y{tpPvs=T{1lppH_| zsa@L*jKo3?q)15lVh~i_F@D&0T={jJw31)zZMUt8(c_R!?ejEdL*_r_v3KV$MBUMZ zN-K5@!80Z!{Ce_?PF=)GMlvJQ=bPb)Ow}8AetY56Sbh9;4w)YKOypq27_cNP+$u(n zN}N)=6xq+xd~UH#xj6wI6^V@9$94Tq*{+0j7*6fSAipg^&r(ncO1-%irg5b+UVbkUY7TjTNd(LLF6sc}a zK+IU?f=n{AZ;EZ+Z+e^Bp%^)oRxwP!zyM?B%I8(zUx}tTy&h{wm}#O}eWmAb&RiHS z!(_aOSovN7$9L*=zItBev{c$+Bj+Yoi#O2N79##Q=b#{1IYX9+(%DcVDKD&e#BOn} zHypX;h7|kNd<(n(=Tn{pA + + +About + + +

About This Content

+ +

December 9, 2013

+

License

+ +

The Eclipse Foundation makes available all content in this plug-in ("Content"). Unless otherwise +indicated below, the Content is provided to you under the terms and conditions of the +Eclipse Public License Version 1.0 ("EPL") and Eclipse Distribution License Version 1.0 ("EDL"). +A copy of the EPL is available at +http://www.eclipse.org/legal/epl-v10.html +and a copy of the EDL is available at +http://www.eclipse.org/org/documents/edl-v10.php. +For purposes of the EPL, "Program" will mean the Content.

+ +

If you did not receive this Content directly from the Eclipse Foundation, the Content is +being redistributed by another party ("Redistributor") and different terms and conditions may +apply to your use of any object code in the Content. Check the Redistributor's license that was +provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise +indicated below, the terms and conditions of the EPL still apply to any source code in the Content +and such source code may be obtained at http://www.eclipse.org.

+ + +

Third Party Content

+

The Content includes items that have been sourced from third parties as set out below. If you + did not receive this Content directly from the Eclipse Foundation, the following is provided + for informational purposes only, and you should look to the Redistributor's license for + terms and conditions of use.

+

+ None

+

+

+ + + + diff --git a/vendor/github.com/eclipse/paho.mqtt.golang/client.go b/vendor/github.com/eclipse/paho.mqtt.golang/client.go new file mode 100644 index 0000000..24d56c1 --- /dev/null +++ b/vendor/github.com/eclipse/paho.mqtt.golang/client.go @@ -0,0 +1,759 @@ +/* + * Copyright (c) 2013 IBM Corp. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Seth Hoenig + * Allan Stockdill-Mander + * Mike Robertson + */ + +// Portions copyright © 2018 TIBCO Software Inc. + +// Package mqtt provides an MQTT v3.1.1 client library. +package mqtt + +import ( + "errors" + "fmt" + "net" + "strings" + "sync" + "sync/atomic" + "time" + + "github.com/eclipse/paho.mqtt.golang/packets" +) + +const ( + disconnected uint32 = iota + connecting + reconnecting + connected +) + +// Client is the interface definition for a Client as used by this +// library, the interface is primarily to allow mocking tests. +// +// It is an MQTT v3.1.1 client for communicating +// with an MQTT server using non-blocking methods that allow work +// to be done in the background. +// An application may connect to an MQTT server using: +// A plain TCP socket +// A secure SSL/TLS socket +// A websocket +// To enable ensured message delivery at Quality of Service (QoS) levels +// described in the MQTT spec, a message persistence mechanism must be +// used. This is done by providing a type which implements the Store +// interface. For convenience, FileStore and MemoryStore are provided +// implementations that should be sufficient for most use cases. More +// information can be found in their respective documentation. +// Numerous connection options may be specified by configuring a +// and then supplying a ClientOptions type. +type Client interface { + // IsConnected returns a bool signifying whether + // the client is connected or not. + IsConnected() bool + // IsConnectionOpen return a bool signifying wether the client has an active + // connection to mqtt broker, i.e not in disconnected or reconnect mode + IsConnectionOpen() bool + // Connect will create a connection to the message broker, by default + // it will attempt to connect at v3.1.1 and auto retry at v3.1 if that + // fails + Connect() Token + // Disconnect will end the connection with the server, but not before waiting + // the specified number of milliseconds to wait for existing work to be + // completed. + Disconnect(quiesce uint) + // Publish will publish a message with the specified QoS and content + // to the specified topic. + // Returns a token to track delivery of the message to the broker + Publish(topic string, qos byte, retained bool, payload interface{}) Token + // Subscribe starts a new subscription. Provide a MessageHandler to be executed when + // a message is published on the topic provided, or nil for the default handler + Subscribe(topic string, qos byte, callback MessageHandler) Token + // SubscribeMultiple starts a new subscription for multiple topics. Provide a MessageHandler to + // be executed when a message is published on one of the topics provided, or nil for the + // default handler + SubscribeMultiple(filters map[string]byte, callback MessageHandler) Token + // Unsubscribe will end the subscription from each of the topics provided. + // Messages published to those topics from other clients will no longer be + // received. + Unsubscribe(topics ...string) Token + // AddRoute allows you to add a handler for messages on a specific topic + // without making a subscription. For example having a different handler + // for parts of a wildcard subscription + AddRoute(topic string, callback MessageHandler) + // OptionsReader returns a ClientOptionsReader which is a copy of the clientoptions + // in use by the client. + OptionsReader() ClientOptionsReader +} + +// client implements the Client interface +type client struct { + lastSent atomic.Value + lastReceived atomic.Value + pingOutstanding int32 + status uint32 + sync.RWMutex + messageIds + conn net.Conn + ibound chan packets.ControlPacket + obound chan *PacketAndToken + oboundP chan *PacketAndToken + msgRouter *router + stopRouter chan bool + incomingPubChan chan *packets.PublishPacket + errors chan error + stop chan struct{} + persist Store + options ClientOptions + workers sync.WaitGroup +} + +// NewClient will create an MQTT v3.1.1 client with all of the options specified +// in the provided ClientOptions. The client must have the Connect method called +// on it before it may be used. This is to make sure resources (such as a net +// connection) are created before the application is actually ready. +func NewClient(o *ClientOptions) Client { + c := &client{} + c.options = *o + + if c.options.Store == nil { + c.options.Store = NewMemoryStore() + } + switch c.options.ProtocolVersion { + case 3, 4: + c.options.protocolVersionExplicit = true + case 0x83, 0x84: + c.options.protocolVersionExplicit = true + default: + c.options.ProtocolVersion = 4 + c.options.protocolVersionExplicit = false + } + c.persist = c.options.Store + c.status = disconnected + c.messageIds = messageIds{index: make(map[uint16]tokenCompletor)} + c.msgRouter, c.stopRouter = newRouter() + c.msgRouter.setDefaultHandler(c.options.DefaultPublishHandler) + if !c.options.AutoReconnect { + c.options.MessageChannelDepth = 0 + } + return c +} + +// AddRoute allows you to add a handler for messages on a specific topic +// without making a subscription. For example having a different handler +// for parts of a wildcard subscription +func (c *client) AddRoute(topic string, callback MessageHandler) { + if callback != nil { + c.msgRouter.addRoute(topic, callback) + } +} + +// IsConnected returns a bool signifying whether +// the client is connected or not. +func (c *client) IsConnected() bool { + c.RLock() + defer c.RUnlock() + status := atomic.LoadUint32(&c.status) + switch { + case status == connected: + return true + case c.options.AutoReconnect && status > connecting: + return true + default: + return false + } +} + +// IsConnectionOpen return a bool signifying whether the client has an active +// connection to mqtt broker, i.e not in disconnected or reconnect mode +func (c *client) IsConnectionOpen() bool { + c.RLock() + defer c.RUnlock() + status := atomic.LoadUint32(&c.status) + switch { + case status == connected: + return true + default: + return false + } +} + +func (c *client) connectionStatus() uint32 { + c.RLock() + defer c.RUnlock() + status := atomic.LoadUint32(&c.status) + return status +} + +func (c *client) setConnected(status uint32) { + c.Lock() + defer c.Unlock() + atomic.StoreUint32(&c.status, uint32(status)) +} + +//ErrNotConnected is the error returned from function calls that are +//made when the client is not connected to a broker +var ErrNotConnected = errors.New("Not Connected") + +// Connect will create a connection to the message broker, by default +// it will attempt to connect at v3.1.1 and auto retry at v3.1 if that +// fails +func (c *client) Connect() Token { + var err error + t := newToken(packets.Connect).(*ConnectToken) + DEBUG.Println(CLI, "Connect()") + + c.obound = make(chan *PacketAndToken, c.options.MessageChannelDepth) + c.oboundP = make(chan *PacketAndToken, c.options.MessageChannelDepth) + c.ibound = make(chan packets.ControlPacket) + + go func() { + c.persist.Open() + + c.setConnected(connecting) + c.errors = make(chan error, 1) + c.stop = make(chan struct{}) + + var rc byte + protocolVersion := c.options.ProtocolVersion + + if len(c.options.Servers) == 0 { + t.setError(fmt.Errorf("No servers defined to connect to")) + return + } + + for _, broker := range c.options.Servers { + cm := newConnectMsgFromOptions(&c.options, broker) + c.options.ProtocolVersion = protocolVersion + CONN: + DEBUG.Println(CLI, "about to write new connect msg") + c.conn, err = openConnection(broker, c.options.TLSConfig, c.options.ConnectTimeout, c.options.HTTPHeaders) + if err == nil { + DEBUG.Println(CLI, "socket connected to broker") + switch c.options.ProtocolVersion { + case 3: + DEBUG.Println(CLI, "Using MQTT 3.1 protocol") + cm.ProtocolName = "MQIsdp" + cm.ProtocolVersion = 3 + case 0x83: + DEBUG.Println(CLI, "Using MQTT 3.1b protocol") + cm.ProtocolName = "MQIsdp" + cm.ProtocolVersion = 0x83 + case 0x84: + DEBUG.Println(CLI, "Using MQTT 3.1.1b protocol") + cm.ProtocolName = "MQTT" + cm.ProtocolVersion = 0x84 + default: + DEBUG.Println(CLI, "Using MQTT 3.1.1 protocol") + c.options.ProtocolVersion = 4 + cm.ProtocolName = "MQTT" + cm.ProtocolVersion = 4 + } + cm.Write(c.conn) + + rc, t.sessionPresent = c.connect() + if rc != packets.Accepted { + if c.conn != nil { + c.conn.Close() + c.conn = nil + } + //if the protocol version was explicitly set don't do any fallback + if c.options.protocolVersionExplicit { + ERROR.Println(CLI, "Connecting to", broker, "CONNACK was not CONN_ACCEPTED, but rather", packets.ConnackReturnCodes[rc]) + continue + } + if c.options.ProtocolVersion == 4 { + DEBUG.Println(CLI, "Trying reconnect using MQTT 3.1 protocol") + c.options.ProtocolVersion = 3 + goto CONN + } + } + break + } else { + ERROR.Println(CLI, err.Error()) + WARN.Println(CLI, "failed to connect to broker, trying next") + rc = packets.ErrNetworkError + } + } + + if c.conn == nil { + ERROR.Println(CLI, "Failed to connect to a broker") + c.setConnected(disconnected) + c.persist.Close() + t.returnCode = rc + if rc != packets.ErrNetworkError { + t.setError(packets.ConnErrors[rc]) + } else { + t.setError(fmt.Errorf("%s : %s", packets.ConnErrors[rc], err)) + } + return + } + + c.options.protocolVersionExplicit = true + + if c.options.KeepAlive != 0 { + atomic.StoreInt32(&c.pingOutstanding, 0) + c.lastReceived.Store(time.Now()) + c.lastSent.Store(time.Now()) + c.workers.Add(1) + go keepalive(c) + } + + c.incomingPubChan = make(chan *packets.PublishPacket, c.options.MessageChannelDepth) + c.msgRouter.matchAndDispatch(c.incomingPubChan, c.options.Order, c) + + c.setConnected(connected) + DEBUG.Println(CLI, "client is connected") + if c.options.OnConnect != nil { + go c.options.OnConnect(c) + } + + c.workers.Add(4) + go errorWatch(c) + go alllogic(c) + go outgoing(c) + go incoming(c) + + // Take care of any messages in the store + if c.options.CleanSession == false { + c.resume(c.options.ResumeSubs) + } else { + c.persist.Reset() + } + + DEBUG.Println(CLI, "exit startClient") + t.flowComplete() + }() + return t +} + +// internal function used to reconnect the client when it loses its connection +func (c *client) reconnect() { + DEBUG.Println(CLI, "enter reconnect") + var ( + err error + + rc = byte(1) + sleep = time.Duration(1 * time.Second) + ) + + for rc != 0 && atomic.LoadUint32(&c.status) != disconnected { + for _, broker := range c.options.Servers { + cm := newConnectMsgFromOptions(&c.options, broker) + DEBUG.Println(CLI, "about to write new connect msg") + c.Lock() + c.conn, err = openConnection(broker, c.options.TLSConfig, c.options.ConnectTimeout, c.options.HTTPHeaders) + c.Unlock() + if err == nil { + DEBUG.Println(CLI, "socket connected to broker") + switch c.options.ProtocolVersion { + case 0x83: + DEBUG.Println(CLI, "Using MQTT 3.1b protocol") + cm.ProtocolName = "MQIsdp" + cm.ProtocolVersion = 0x83 + case 0x84: + DEBUG.Println(CLI, "Using MQTT 3.1.1b protocol") + cm.ProtocolName = "MQTT" + cm.ProtocolVersion = 0x84 + case 3: + DEBUG.Println(CLI, "Using MQTT 3.1 protocol") + cm.ProtocolName = "MQIsdp" + cm.ProtocolVersion = 3 + default: + DEBUG.Println(CLI, "Using MQTT 3.1.1 protocol") + cm.ProtocolName = "MQTT" + cm.ProtocolVersion = 4 + } + cm.Write(c.conn) + + rc, _ = c.connect() + if rc != packets.Accepted { + c.conn.Close() + c.conn = nil + //if the protocol version was explicitly set don't do any fallback + if c.options.protocolVersionExplicit { + ERROR.Println(CLI, "Connecting to", broker, "CONNACK was not Accepted, but rather", packets.ConnackReturnCodes[rc]) + continue + } + } + break + } else { + ERROR.Println(CLI, err.Error()) + WARN.Println(CLI, "failed to connect to broker, trying next") + rc = packets.ErrNetworkError + } + } + if rc != 0 { + DEBUG.Println(CLI, "Reconnect failed, sleeping for", int(sleep.Seconds()), "seconds") + time.Sleep(sleep) + if sleep < c.options.MaxReconnectInterval { + sleep *= 2 + } + + if sleep > c.options.MaxReconnectInterval { + sleep = c.options.MaxReconnectInterval + } + } + } + // Disconnect() must have been called while we were trying to reconnect. + if c.connectionStatus() == disconnected { + DEBUG.Println(CLI, "Client moved to disconnected state while reconnecting, abandoning reconnect") + return + } + + c.stop = make(chan struct{}) + + if c.options.KeepAlive != 0 { + atomic.StoreInt32(&c.pingOutstanding, 0) + c.lastReceived.Store(time.Now()) + c.lastSent.Store(time.Now()) + c.workers.Add(1) + go keepalive(c) + } + + c.setConnected(connected) + DEBUG.Println(CLI, "client is reconnected") + if c.options.OnConnect != nil { + go c.options.OnConnect(c) + } + + c.workers.Add(4) + go errorWatch(c) + go alllogic(c) + go outgoing(c) + go incoming(c) + + c.resume(false) +} + +// This function is only used for receiving a connack +// when the connection is first started. +// This prevents receiving incoming data while resume +// is in progress if clean session is false. +func (c *client) connect() (byte, bool) { + DEBUG.Println(NET, "connect started") + + ca, err := packets.ReadPacket(c.conn) + if err != nil { + ERROR.Println(NET, "connect got error", err) + return packets.ErrNetworkError, false + } + if ca == nil { + ERROR.Println(NET, "received nil packet") + return packets.ErrNetworkError, false + } + + msg, ok := ca.(*packets.ConnackPacket) + if !ok { + ERROR.Println(NET, "received msg that was not CONNACK") + return packets.ErrNetworkError, false + } + + DEBUG.Println(NET, "received connack") + return msg.ReturnCode, msg.SessionPresent +} + +// Disconnect will end the connection with the server, but not before waiting +// the specified number of milliseconds to wait for existing work to be +// completed. +func (c *client) Disconnect(quiesce uint) { + status := atomic.LoadUint32(&c.status) + if status == connected { + DEBUG.Println(CLI, "disconnecting") + c.setConnected(disconnected) + + dm := packets.NewControlPacket(packets.Disconnect).(*packets.DisconnectPacket) + dt := newToken(packets.Disconnect) + c.oboundP <- &PacketAndToken{p: dm, t: dt} + + // wait for work to finish, or quiesce time consumed + dt.WaitTimeout(time.Duration(quiesce) * time.Millisecond) + } else { + WARN.Println(CLI, "Disconnect() called but not connected (disconnected/reconnecting)") + c.setConnected(disconnected) + } + + c.disconnect() +} + +// ForceDisconnect will end the connection with the mqtt broker immediately. +func (c *client) forceDisconnect() { + if !c.IsConnected() { + WARN.Println(CLI, "already disconnected") + return + } + c.setConnected(disconnected) + c.conn.Close() + DEBUG.Println(CLI, "forcefully disconnecting") + c.disconnect() +} + +func (c *client) internalConnLost(err error) { + // Only do anything if this was called and we are still "connected" + // forceDisconnect can cause incoming/outgoing/alllogic to end with + // error from closing the socket but state will be "disconnected" + if c.IsConnected() { + c.closeStop() + c.conn.Close() + c.workers.Wait() + if c.options.CleanSession && !c.options.AutoReconnect { + c.messageIds.cleanUp() + } + if c.options.AutoReconnect { + c.setConnected(reconnecting) + go c.reconnect() + } else { + c.setConnected(disconnected) + } + if c.options.OnConnectionLost != nil { + go c.options.OnConnectionLost(c, err) + } + } +} + +func (c *client) closeStop() { + c.Lock() + defer c.Unlock() + select { + case <-c.stop: + DEBUG.Println("In disconnect and stop channel is already closed") + default: + if c.stop != nil { + close(c.stop) + } + } +} + +func (c *client) closeStopRouter() { + c.Lock() + defer c.Unlock() + select { + case <-c.stopRouter: + DEBUG.Println("In disconnect and stop channel is already closed") + default: + if c.stopRouter != nil { + close(c.stopRouter) + } + } +} + +func (c *client) closeConn() { + c.Lock() + defer c.Unlock() + if c.conn != nil { + c.conn.Close() + } +} + +func (c *client) disconnect() { + c.closeStop() + c.closeConn() + c.workers.Wait() + c.messageIds.cleanUp() + c.closeStopRouter() + DEBUG.Println(CLI, "disconnected") + c.persist.Close() +} + +// Publish will publish a message with the specified QoS and content +// to the specified topic. +// Returns a token to track delivery of the message to the broker +func (c *client) Publish(topic string, qos byte, retained bool, payload interface{}) Token { + token := newToken(packets.Publish).(*PublishToken) + DEBUG.Println(CLI, "enter Publish") + switch { + case !c.IsConnected(): + token.setError(ErrNotConnected) + return token + case c.connectionStatus() == reconnecting && qos == 0: + token.flowComplete() + return token + } + pub := packets.NewControlPacket(packets.Publish).(*packets.PublishPacket) + pub.Qos = qos + pub.TopicName = topic + pub.Retain = retained + switch payload.(type) { + case string: + pub.Payload = []byte(payload.(string)) + case []byte: + pub.Payload = payload.([]byte) + default: + token.setError(fmt.Errorf("Unknown payload type")) + return token + } + + if pub.Qos != 0 && pub.MessageID == 0 { + pub.MessageID = c.getID(token) + token.messageID = pub.MessageID + } + persistOutbound(c.persist, pub) + if c.connectionStatus() == reconnecting { + DEBUG.Println(CLI, "storing publish message (reconnecting), topic:", topic) + } else { + DEBUG.Println(CLI, "sending publish message, topic:", topic) + c.obound <- &PacketAndToken{p: pub, t: token} + } + return token +} + +// Subscribe starts a new subscription. Provide a MessageHandler to be executed when +// a message is published on the topic provided. +func (c *client) Subscribe(topic string, qos byte, callback MessageHandler) Token { + token := newToken(packets.Subscribe).(*SubscribeToken) + DEBUG.Println(CLI, "enter Subscribe") + if !c.IsConnected() { + token.setError(ErrNotConnected) + return token + } + sub := packets.NewControlPacket(packets.Subscribe).(*packets.SubscribePacket) + if err := validateTopicAndQos(topic, qos); err != nil { + token.setError(err) + return token + } + sub.Topics = append(sub.Topics, topic) + sub.Qoss = append(sub.Qoss, qos) + DEBUG.Println(CLI, sub.String()) + + if strings.HasPrefix(topic, "$share") { + topic = strings.Join(strings.Split(topic, "/")[2:], "/") + } + + if callback != nil { + c.msgRouter.addRoute(topic, callback) + } + + token.subs = append(token.subs, topic) + c.oboundP <- &PacketAndToken{p: sub, t: token} + DEBUG.Println(CLI, "exit Subscribe") + return token +} + +// SubscribeMultiple starts a new subscription for multiple topics. Provide a MessageHandler to +// be executed when a message is published on one of the topics provided. +func (c *client) SubscribeMultiple(filters map[string]byte, callback MessageHandler) Token { + var err error + token := newToken(packets.Subscribe).(*SubscribeToken) + DEBUG.Println(CLI, "enter SubscribeMultiple") + if !c.IsConnected() { + token.setError(ErrNotConnected) + return token + } + sub := packets.NewControlPacket(packets.Subscribe).(*packets.SubscribePacket) + if sub.Topics, sub.Qoss, err = validateSubscribeMap(filters); err != nil { + token.setError(err) + return token + } + + if callback != nil { + for topic := range filters { + c.msgRouter.addRoute(topic, callback) + } + } + token.subs = make([]string, len(sub.Topics)) + copy(token.subs, sub.Topics) + c.oboundP <- &PacketAndToken{p: sub, t: token} + DEBUG.Println(CLI, "exit SubscribeMultiple") + return token +} + +// Load all stored messages and resend them +// Call this to ensure QOS > 1,2 even after an application crash +func (c *client) resume(subscription bool) { + + storedKeys := c.persist.All() + for _, key := range storedKeys { + packet := c.persist.Get(key) + if packet == nil { + continue + } + details := packet.Details() + if isKeyOutbound(key) { + switch packet.(type) { + case *packets.SubscribePacket: + if subscription { + DEBUG.Println(STR, fmt.Sprintf("loaded pending subscribe (%d)", details.MessageID)) + token := newToken(packets.Subscribe).(*SubscribeToken) + c.oboundP <- &PacketAndToken{p: packet, t: token} + } + case *packets.UnsubscribePacket: + if subscription { + DEBUG.Println(STR, fmt.Sprintf("loaded pending unsubscribe (%d)", details.MessageID)) + token := newToken(packets.Unsubscribe).(*UnsubscribeToken) + c.oboundP <- &PacketAndToken{p: packet, t: token} + } + case *packets.PubrelPacket: + DEBUG.Println(STR, fmt.Sprintf("loaded pending pubrel (%d)", details.MessageID)) + select { + case c.oboundP <- &PacketAndToken{p: packet, t: nil}: + case <-c.stop: + } + case *packets.PublishPacket: + token := newToken(packets.Publish).(*PublishToken) + token.messageID = details.MessageID + c.claimID(token, details.MessageID) + DEBUG.Println(STR, fmt.Sprintf("loaded pending publish (%d)", details.MessageID)) + DEBUG.Println(STR, details) + c.obound <- &PacketAndToken{p: packet, t: token} + default: + ERROR.Println(STR, "invalid message type in store (discarded)") + c.persist.Del(key) + } + } else { + switch packet.(type) { + case *packets.PubrelPacket, *packets.PublishPacket: + DEBUG.Println(STR, fmt.Sprintf("loaded pending incomming (%d)", details.MessageID)) + select { + case c.ibound <- packet: + case <-c.stop: + } + default: + ERROR.Println(STR, "invalid message type in store (discarded)") + c.persist.Del(key) + } + } + } +} + +// Unsubscribe will end the subscription from each of the topics provided. +// Messages published to those topics from other clients will no longer be +// received. +func (c *client) Unsubscribe(topics ...string) Token { + token := newToken(packets.Unsubscribe).(*UnsubscribeToken) + DEBUG.Println(CLI, "enter Unsubscribe") + if !c.IsConnected() { + token.setError(ErrNotConnected) + return token + } + unsub := packets.NewControlPacket(packets.Unsubscribe).(*packets.UnsubscribePacket) + unsub.Topics = make([]string, len(topics)) + copy(unsub.Topics, topics) + + c.oboundP <- &PacketAndToken{p: unsub, t: token} + for _, topic := range topics { + c.msgRouter.deleteRoute(topic) + } + + DEBUG.Println(CLI, "exit Unsubscribe") + return token +} + +// OptionsReader returns a ClientOptionsReader which is a copy of the clientoptions +// in use by the client. +func (c *client) OptionsReader() ClientOptionsReader { + r := ClientOptionsReader{options: &c.options} + return r +} + +//DefaultConnectionLostHandler is a definition of a function that simply +//reports to the DEBUG log the reason for the client losing a connection. +func DefaultConnectionLostHandler(client Client, reason error) { + DEBUG.Println("Connection lost:", reason.Error()) +} diff --git a/vendor/github.com/eclipse/paho.mqtt.golang/components.go b/vendor/github.com/eclipse/paho.mqtt.golang/components.go new file mode 100644 index 0000000..01f5faf --- /dev/null +++ b/vendor/github.com/eclipse/paho.mqtt.golang/components.go @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2013 IBM Corp. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Seth Hoenig + * Allan Stockdill-Mander + * Mike Robertson + */ + +package mqtt + +type component string + +// Component names for debug output +const ( + NET component = "[net] " + PNG component = "[pinger] " + CLI component = "[client] " + DEC component = "[decode] " + MES component = "[message] " + STR component = "[store] " + MID component = "[msgids] " + TST component = "[test] " + STA component = "[state] " + ERR component = "[error] " +) diff --git a/vendor/github.com/eclipse/paho.mqtt.golang/edl-v10 b/vendor/github.com/eclipse/paho.mqtt.golang/edl-v10 new file mode 100644 index 0000000..cf989f1 --- /dev/null +++ b/vendor/github.com/eclipse/paho.mqtt.golang/edl-v10 @@ -0,0 +1,15 @@ + +Eclipse Distribution License - v 1.0 + +Copyright (c) 2007, Eclipse Foundation, Inc. and its licensors. + +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + Neither the name of the Eclipse Foundation, Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + diff --git a/vendor/github.com/eclipse/paho.mqtt.golang/epl-v10 b/vendor/github.com/eclipse/paho.mqtt.golang/epl-v10 new file mode 100644 index 0000000..79e486c --- /dev/null +++ b/vendor/github.com/eclipse/paho.mqtt.golang/epl-v10 @@ -0,0 +1,70 @@ +Eclipse Public License - v 1.0 + +THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. + +1. DEFINITIONS + +"Contribution" means: + +a) in the case of the initial Contributor, the initial code and documentation distributed under this Agreement, and +b) in the case of each subsequent Contributor: +i) changes to the Program, and +ii) additions to the Program; +where such changes and/or additions to the Program originate from and are distributed by that particular Contributor. A Contribution 'originates' from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. Contributions do not include additions to the Program which: (i) are separate modules of software distributed in conjunction with the Program under their own license agreement, and (ii) are not derivative works of the Program. +"Contributor" means any person or entity that distributes the Program. + +"Licensed Patents" mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program. + +"Program" means the Contributions distributed in accordance with this Agreement. + +"Recipient" means anyone who receives the Program under this Agreement, including all Contributors. + +2. GRANT OF RIGHTS + +a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, distribute and sublicense the Contribution of such Contributor, if any, and such derivative works, in source code and object code form. +b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in source code and object code form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder. +c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program. +d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement. +3. REQUIREMENTS + +A Contributor may choose to distribute the Program in object code form under its own license agreement, provided that: + +a) it complies with the terms and conditions of this Agreement; and +b) its license agreement: +i) effectively disclaims on behalf of all Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose; +ii) effectively excludes on behalf of all Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits; +iii) states that any provisions which differ from this Agreement are offered by that Contributor alone and not by any other party; and +iv) states that source code for the Program is available from such Contributor, and informs licensees how to obtain it in a reasonable manner on or through a medium customarily used for software exchange. +When the Program is made available in source code form: + +a) it must be made available under this Agreement; and +b) a copy of this Agreement must be included with each copy of the Program. +Contributors may not remove or alter any copyright notices contained within the Program. + +Each Contributor must identify itself as the originator of its Contribution, if any, in a manner that reasonably allows subsequent Recipients to identify the originator of the Contribution. + +4. COMMERCIAL DISTRIBUTION + +Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor ("Commercial Contributor") hereby agrees to defend and indemnify every other Contributor ("Indemnified Contributor") against any losses, damages and costs (collectively "Losses") arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense. + +For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages. + +5. NO WARRANTY + +EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement , including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations. + +6. DISCLAIMER OF LIABILITY + +EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + +7. GENERAL + +If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable. + +If Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed. + +All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive. + +Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to distribute the Program (including its Contributions) under the new version. Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved. + +This Agreement is governed by the laws of the State of New York and the intellectual property laws of the United States of America. No party to this Agreement will bring a legal action under this Agreement more than one year after the cause of action arose. Each party waives its rights to a jury trial in any resulting litigation. diff --git a/vendor/github.com/eclipse/paho.mqtt.golang/filestore.go b/vendor/github.com/eclipse/paho.mqtt.golang/filestore.go new file mode 100644 index 0000000..c4a0d36 --- /dev/null +++ b/vendor/github.com/eclipse/paho.mqtt.golang/filestore.go @@ -0,0 +1,255 @@ +/* + * Copyright (c) 2013 IBM Corp. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Seth Hoenig + * Allan Stockdill-Mander + * Mike Robertson + */ + +package mqtt + +import ( + "io/ioutil" + "os" + "path" + "sort" + "sync" + + "github.com/eclipse/paho.mqtt.golang/packets" +) + +const ( + msgExt = ".msg" + tmpExt = ".tmp" + corruptExt = ".CORRUPT" +) + +// FileStore implements the store interface using the filesystem to provide +// true persistence, even across client failure. This is designed to use a +// single directory per running client. If you are running multiple clients +// on the same filesystem, you will need to be careful to specify unique +// store directories for each. +type FileStore struct { + sync.RWMutex + directory string + opened bool +} + +// NewFileStore will create a new FileStore which stores its messages in the +// directory provided. +func NewFileStore(directory string) *FileStore { + store := &FileStore{ + directory: directory, + opened: false, + } + return store +} + +// Open will allow the FileStore to be used. +func (store *FileStore) Open() { + store.Lock() + defer store.Unlock() + // if no store directory was specified in ClientOpts, by default use the + // current working directory + if store.directory == "" { + store.directory, _ = os.Getwd() + } + + // if store dir exists, great, otherwise, create it + if !exists(store.directory) { + perms := os.FileMode(0770) + merr := os.MkdirAll(store.directory, perms) + chkerr(merr) + } + store.opened = true + DEBUG.Println(STR, "store is opened at", store.directory) +} + +// Close will disallow the FileStore from being used. +func (store *FileStore) Close() { + store.Lock() + defer store.Unlock() + store.opened = false + DEBUG.Println(STR, "store is closed") +} + +// Put will put a message into the store, associated with the provided +// key value. +func (store *FileStore) Put(key string, m packets.ControlPacket) { + store.Lock() + defer store.Unlock() + if !store.opened { + ERROR.Println(STR, "Trying to use file store, but not open") + return + } + full := fullpath(store.directory, key) + write(store.directory, key, m) + if !exists(full) { + ERROR.Println(STR, "file not created:", full) + } +} + +// Get will retrieve a message from the store, the one associated with +// the provided key value. +func (store *FileStore) Get(key string) packets.ControlPacket { + store.RLock() + defer store.RUnlock() + if !store.opened { + ERROR.Println(STR, "Trying to use file store, but not open") + return nil + } + filepath := fullpath(store.directory, key) + if !exists(filepath) { + return nil + } + mfile, oerr := os.Open(filepath) + chkerr(oerr) + msg, rerr := packets.ReadPacket(mfile) + chkerr(mfile.Close()) + + // Message was unreadable, return nil + if rerr != nil { + newpath := corruptpath(store.directory, key) + WARN.Println(STR, "corrupted file detected:", rerr.Error(), "archived at:", newpath) + os.Rename(filepath, newpath) + return nil + } + return msg +} + +// All will provide a list of all of the keys associated with messages +// currenly residing in the FileStore. +func (store *FileStore) All() []string { + store.RLock() + defer store.RUnlock() + return store.all() +} + +// Del will remove the persisted message associated with the provided +// key from the FileStore. +func (store *FileStore) Del(key string) { + store.Lock() + defer store.Unlock() + store.del(key) +} + +// Reset will remove all persisted messages from the FileStore. +func (store *FileStore) Reset() { + store.Lock() + defer store.Unlock() + WARN.Println(STR, "FileStore Reset") + for _, key := range store.all() { + store.del(key) + } +} + +// lockless +func (store *FileStore) all() []string { + var err error + var keys []string + var files fileInfos + + if !store.opened { + ERROR.Println(STR, "Trying to use file store, but not open") + return nil + } + + files, err = ioutil.ReadDir(store.directory) + chkerr(err) + sort.Sort(files) + for _, f := range files { + DEBUG.Println(STR, "file in All():", f.Name()) + name := f.Name() + if name[len(name)-4:len(name)] != msgExt { + DEBUG.Println(STR, "skipping file, doesn't have right extension: ", name) + continue + } + key := name[0 : len(name)-4] // remove file extension + keys = append(keys, key) + } + return keys +} + +// lockless +func (store *FileStore) del(key string) { + if !store.opened { + ERROR.Println(STR, "Trying to use file store, but not open") + return + } + DEBUG.Println(STR, "store del filepath:", store.directory) + DEBUG.Println(STR, "store delete key:", key) + filepath := fullpath(store.directory, key) + DEBUG.Println(STR, "path of deletion:", filepath) + if !exists(filepath) { + WARN.Println(STR, "store could not delete key:", key) + return + } + rerr := os.Remove(filepath) + chkerr(rerr) + DEBUG.Println(STR, "del msg:", key) + if exists(filepath) { + ERROR.Println(STR, "file not deleted:", filepath) + } +} + +func fullpath(store string, key string) string { + p := path.Join(store, key+msgExt) + return p +} + +func tmppath(store string, key string) string { + p := path.Join(store, key+tmpExt) + return p +} + +func corruptpath(store string, key string) string { + p := path.Join(store, key+corruptExt) + return p +} + +// create file called "X.[messageid].tmp" located in the store +// the contents of the file is the bytes of the message, then +// rename it to "X.[messageid].msg", overwriting any existing +// message with the same id +// X will be 'i' for inbound messages, and O for outbound messages +func write(store, key string, m packets.ControlPacket) { + temppath := tmppath(store, key) + f, err := os.Create(temppath) + chkerr(err) + werr := m.Write(f) + chkerr(werr) + cerr := f.Close() + chkerr(cerr) + rerr := os.Rename(temppath, fullpath(store, key)) + chkerr(rerr) +} + +func exists(file string) bool { + if _, err := os.Stat(file); err != nil { + if os.IsNotExist(err) { + return false + } + chkerr(err) + } + return true +} + +type fileInfos []os.FileInfo + +func (f fileInfos) Len() int { + return len(f) +} + +func (f fileInfos) Swap(i, j int) { + f[i], f[j] = f[j], f[i] +} + +func (f fileInfos) Less(i, j int) bool { + return f[i].ModTime().Before(f[j].ModTime()) +} diff --git a/vendor/github.com/eclipse/paho.mqtt.golang/memstore.go b/vendor/github.com/eclipse/paho.mqtt.golang/memstore.go new file mode 100644 index 0000000..499c490 --- /dev/null +++ b/vendor/github.com/eclipse/paho.mqtt.golang/memstore.go @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2013 IBM Corp. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Seth Hoenig + * Allan Stockdill-Mander + * Mike Robertson + */ + +package mqtt + +import ( + "sync" + + "github.com/eclipse/paho.mqtt.golang/packets" +) + +// MemoryStore implements the store interface to provide a "persistence" +// mechanism wholly stored in memory. This is only useful for +// as long as the client instance exists. +type MemoryStore struct { + sync.RWMutex + messages map[string]packets.ControlPacket + opened bool +} + +// NewMemoryStore returns a pointer to a new instance of +// MemoryStore, the instance is not initialized and ready to +// use until Open() has been called on it. +func NewMemoryStore() *MemoryStore { + store := &MemoryStore{ + messages: make(map[string]packets.ControlPacket), + opened: false, + } + return store +} + +// Open initializes a MemoryStore instance. +func (store *MemoryStore) Open() { + store.Lock() + defer store.Unlock() + store.opened = true + DEBUG.Println(STR, "memorystore initialized") +} + +// Put takes a key and a pointer to a Message and stores the +// message. +func (store *MemoryStore) Put(key string, message packets.ControlPacket) { + store.Lock() + defer store.Unlock() + if !store.opened { + ERROR.Println(STR, "Trying to use memory store, but not open") + return + } + store.messages[key] = message +} + +// Get takes a key and looks in the store for a matching Message +// returning either the Message pointer or nil. +func (store *MemoryStore) Get(key string) packets.ControlPacket { + store.RLock() + defer store.RUnlock() + if !store.opened { + ERROR.Println(STR, "Trying to use memory store, but not open") + return nil + } + mid := mIDFromKey(key) + m := store.messages[key] + if m == nil { + CRITICAL.Println(STR, "memorystore get: message", mid, "not found") + } else { + DEBUG.Println(STR, "memorystore get: message", mid, "found") + } + return m +} + +// All returns a slice of strings containing all the keys currently +// in the MemoryStore. +func (store *MemoryStore) All() []string { + store.RLock() + defer store.RUnlock() + if !store.opened { + ERROR.Println(STR, "Trying to use memory store, but not open") + return nil + } + keys := []string{} + for k := range store.messages { + keys = append(keys, k) + } + return keys +} + +// Del takes a key, searches the MemoryStore and if the key is found +// deletes the Message pointer associated with it. +func (store *MemoryStore) Del(key string) { + store.Lock() + defer store.Unlock() + if !store.opened { + ERROR.Println(STR, "Trying to use memory store, but not open") + return + } + mid := mIDFromKey(key) + m := store.messages[key] + if m == nil { + WARN.Println(STR, "memorystore del: message", mid, "not found") + } else { + delete(store.messages, key) + DEBUG.Println(STR, "memorystore del: message", mid, "was deleted") + } +} + +// Close will disallow modifications to the state of the store. +func (store *MemoryStore) Close() { + store.Lock() + defer store.Unlock() + if !store.opened { + ERROR.Println(STR, "Trying to close memory store, but not open") + return + } + store.opened = false + DEBUG.Println(STR, "memorystore closed") +} + +// Reset eliminates all persisted message data in the store. +func (store *MemoryStore) Reset() { + store.Lock() + defer store.Unlock() + if !store.opened { + ERROR.Println(STR, "Trying to reset memory store, but not open") + } + store.messages = make(map[string]packets.ControlPacket) + WARN.Println(STR, "memorystore wiped") +} diff --git a/vendor/github.com/eclipse/paho.mqtt.golang/message.go b/vendor/github.com/eclipse/paho.mqtt.golang/message.go new file mode 100644 index 0000000..903e5dc --- /dev/null +++ b/vendor/github.com/eclipse/paho.mqtt.golang/message.go @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2013 IBM Corp. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Seth Hoenig + * Allan Stockdill-Mander + * Mike Robertson + */ + +package mqtt + +import ( + "net/url" + + "github.com/eclipse/paho.mqtt.golang/packets" + "sync" +) + +// Message defines the externals that a message implementation must support +// these are received messages that are passed to the callbacks, not internal +// messages +type Message interface { + Duplicate() bool + Qos() byte + Retained() bool + Topic() string + MessageID() uint16 + Payload() []byte + Ack() +} + +type message struct { + duplicate bool + qos byte + retained bool + topic string + messageID uint16 + payload []byte + once sync.Once + ack func() +} + +func (m *message) Duplicate() bool { + return m.duplicate +} + +func (m *message) Qos() byte { + return m.qos +} + +func (m *message) Retained() bool { + return m.retained +} + +func (m *message) Topic() string { + return m.topic +} + +func (m *message) MessageID() uint16 { + return m.messageID +} + +func (m *message) Payload() []byte { + return m.payload +} + +func (m *message) Ack() { + m.once.Do(m.ack) +} + +func messageFromPublish(p *packets.PublishPacket, ack func()) Message { + return &message{ + duplicate: p.Dup, + qos: p.Qos, + retained: p.Retain, + topic: p.TopicName, + messageID: p.MessageID, + payload: p.Payload, + ack: ack, + } +} + +func newConnectMsgFromOptions(options *ClientOptions, broker *url.URL) *packets.ConnectPacket { + m := packets.NewControlPacket(packets.Connect).(*packets.ConnectPacket) + + m.CleanSession = options.CleanSession + m.WillFlag = options.WillEnabled + m.WillRetain = options.WillRetained + m.ClientIdentifier = options.ClientID + + if options.WillEnabled { + m.WillQos = options.WillQos + m.WillTopic = options.WillTopic + m.WillMessage = options.WillPayload + } + + username := options.Username + password := options.Password + if broker.User != nil { + username = broker.User.Username() + if pwd, ok := broker.User.Password(); ok { + password = pwd + } + } + if options.CredentialsProvider != nil { + username, password = options.CredentialsProvider() + } + + if username != "" { + m.UsernameFlag = true + m.Username = username + //mustn't have password without user as well + if password != "" { + m.PasswordFlag = true + m.Password = []byte(password) + } + } + + m.Keepalive = uint16(options.KeepAlive) + + return m +} diff --git a/vendor/github.com/eclipse/paho.mqtt.golang/messageids.go b/vendor/github.com/eclipse/paho.mqtt.golang/messageids.go new file mode 100644 index 0000000..9a5fa9f --- /dev/null +++ b/vendor/github.com/eclipse/paho.mqtt.golang/messageids.go @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2013 IBM Corp. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Seth Hoenig + * Allan Stockdill-Mander + * Mike Robertson + */ + +package mqtt + +import ( + "fmt" + "sync" + "time" +) + +// MId is 16 bit message id as specified by the MQTT spec. +// In general, these values should not be depended upon by +// the client application. +type MId uint16 + +type messageIds struct { + sync.RWMutex + index map[uint16]tokenCompletor +} + +const ( + midMin uint16 = 1 + midMax uint16 = 65535 +) + +func (mids *messageIds) cleanUp() { + mids.Lock() + for _, token := range mids.index { + switch token.(type) { + case *PublishToken: + token.setError(fmt.Errorf("Connection lost before Publish completed")) + case *SubscribeToken: + token.setError(fmt.Errorf("Connection lost before Subscribe completed")) + case *UnsubscribeToken: + token.setError(fmt.Errorf("Connection lost before Unsubscribe completed")) + case nil: + continue + } + token.flowComplete() + } + mids.index = make(map[uint16]tokenCompletor) + mids.Unlock() + DEBUG.Println(MID, "cleaned up") +} + +func (mids *messageIds) freeID(id uint16) { + mids.Lock() + delete(mids.index, id) + mids.Unlock() +} + +func (mids *messageIds) claimID(token tokenCompletor, id uint16) { + mids.Lock() + defer mids.Unlock() + if _, ok := mids.index[id]; !ok { + mids.index[id] = token + } else { + old := mids.index[id] + old.flowComplete() + mids.index[id] = token + } +} + +func (mids *messageIds) getID(t tokenCompletor) uint16 { + mids.Lock() + defer mids.Unlock() + for i := midMin; i < midMax; i++ { + if _, ok := mids.index[i]; !ok { + mids.index[i] = t + return i + } + } + return 0 +} + +func (mids *messageIds) getToken(id uint16) tokenCompletor { + mids.RLock() + defer mids.RUnlock() + if token, ok := mids.index[id]; ok { + return token + } + return &DummyToken{id: id} +} + +type DummyToken struct { + id uint16 +} + +func (d *DummyToken) Wait() bool { + return true +} + +func (d *DummyToken) WaitTimeout(t time.Duration) bool { + return true +} + +func (d *DummyToken) flowComplete() { + ERROR.Printf("A lookup for token %d returned nil\n", d.id) +} + +func (d *DummyToken) Error() error { + return nil +} + +func (d *DummyToken) setError(e error) {} diff --git a/vendor/github.com/eclipse/paho.mqtt.golang/net.go b/vendor/github.com/eclipse/paho.mqtt.golang/net.go new file mode 100644 index 0000000..3e6366b --- /dev/null +++ b/vendor/github.com/eclipse/paho.mqtt.golang/net.go @@ -0,0 +1,355 @@ +/* + * Copyright (c) 2013 IBM Corp. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Seth Hoenig + * Allan Stockdill-Mander + * Mike Robertson + */ + +package mqtt + +import ( + "crypto/tls" + "errors" + "fmt" + "net" + "net/http" + "net/url" + "os" + "reflect" + "sync/atomic" + "time" + + "github.com/eclipse/paho.mqtt.golang/packets" + "golang.org/x/net/proxy" + "golang.org/x/net/websocket" +) + +func signalError(c chan<- error, err error) { + select { + case c <- err: + default: + } +} + +func openConnection(uri *url.URL, tlsc *tls.Config, timeout time.Duration, headers http.Header) (net.Conn, error) { + switch uri.Scheme { + case "ws": + config, _ := websocket.NewConfig(uri.String(), fmt.Sprintf("http://%s", uri.Host)) + config.Protocol = []string{"mqtt"} + config.Header = headers + config.Dialer = &net.Dialer{Timeout: timeout} + conn, err := websocket.DialConfig(config) + if err != nil { + return nil, err + } + conn.PayloadType = websocket.BinaryFrame + return conn, err + case "wss": + config, _ := websocket.NewConfig(uri.String(), fmt.Sprintf("https://%s", uri.Host)) + config.Protocol = []string{"mqtt"} + config.TlsConfig = tlsc + config.Header = headers + config.Dialer = &net.Dialer{Timeout: timeout} + conn, err := websocket.DialConfig(config) + if err != nil { + return nil, err + } + conn.PayloadType = websocket.BinaryFrame + return conn, err + case "tcp": + allProxy := os.Getenv("all_proxy") + if len(allProxy) == 0 { + conn, err := net.DialTimeout("tcp", uri.Host, timeout) + if err != nil { + return nil, err + } + return conn, nil + } + proxyDialer := proxy.FromEnvironment() + + conn, err := proxyDialer.Dial("tcp", uri.Host) + if err != nil { + return nil, err + } + return conn, nil + case "unix": + conn, err := net.DialTimeout("unix", uri.Host, timeout) + if err != nil { + return nil, err + } + return conn, nil + case "ssl": + fallthrough + case "tls": + fallthrough + case "tcps": + allProxy := os.Getenv("all_proxy") + if len(allProxy) == 0 { + conn, err := tls.DialWithDialer(&net.Dialer{Timeout: timeout}, "tcp", uri.Host, tlsc) + if err != nil { + return nil, err + } + return conn, nil + } + proxyDialer := proxy.FromEnvironment() + + conn, err := proxyDialer.Dial("tcp", uri.Host) + if err != nil { + return nil, err + } + + tlsConn := tls.Client(conn, tlsc) + + err = tlsConn.Handshake() + if err != nil { + conn.Close() + return nil, err + } + + return tlsConn, nil + } + return nil, errors.New("Unknown protocol") +} + +// actually read incoming messages off the wire +// send Message object into ibound channel +func incoming(c *client) { + var err error + var cp packets.ControlPacket + + defer c.workers.Done() + + DEBUG.Println(NET, "incoming started") + + for { + if cp, err = packets.ReadPacket(c.conn); err != nil { + break + } + DEBUG.Println(NET, "Received Message") + select { + case c.ibound <- cp: + // Notify keepalive logic that we recently received a packet + if c.options.KeepAlive != 0 { + c.lastReceived.Store(time.Now()) + } + case <-c.stop: + // This avoids a deadlock should a message arrive while shutting down. + // In that case the "reader" of c.ibound might already be gone + WARN.Println(NET, "incoming dropped a received message during shutdown") + break + } + } + // We received an error on read. + // If disconnect is in progress, swallow error and return + select { + case <-c.stop: + DEBUG.Println(NET, "incoming stopped") + return + // Not trying to disconnect, send the error to the errors channel + default: + ERROR.Println(NET, "incoming stopped with error", err) + signalError(c.errors, err) + return + } +} + +// receive a Message object on obound, and then +// actually send outgoing message to the wire +func outgoing(c *client) { + defer c.workers.Done() + DEBUG.Println(NET, "outgoing started") + + for { + DEBUG.Println(NET, "outgoing waiting for an outbound message") + select { + case <-c.stop: + DEBUG.Println(NET, "outgoing stopped") + return + case pub := <-c.obound: + msg := pub.p.(*packets.PublishPacket) + + if c.options.WriteTimeout > 0 { + c.conn.SetWriteDeadline(time.Now().Add(c.options.WriteTimeout)) + } + + if err := msg.Write(c.conn); err != nil { + ERROR.Println(NET, "outgoing stopped with error", err) + pub.t.setError(err) + signalError(c.errors, err) + return + } + + if c.options.WriteTimeout > 0 { + // If we successfully wrote, we don't want the timeout to happen during an idle period + // so we reset it to infinite. + c.conn.SetWriteDeadline(time.Time{}) + } + + if msg.Qos == 0 { + pub.t.flowComplete() + } + DEBUG.Println(NET, "obound wrote msg, id:", msg.MessageID) + case msg := <-c.oboundP: + switch msg.p.(type) { + case *packets.SubscribePacket: + msg.p.(*packets.SubscribePacket).MessageID = c.getID(msg.t) + case *packets.UnsubscribePacket: + msg.p.(*packets.UnsubscribePacket).MessageID = c.getID(msg.t) + } + DEBUG.Println(NET, "obound priority msg to write, type", reflect.TypeOf(msg.p)) + if err := msg.p.Write(c.conn); err != nil { + ERROR.Println(NET, "outgoing stopped with error", err) + if msg.t != nil { + msg.t.setError(err) + } + signalError(c.errors, err) + return + } + switch msg.p.(type) { + case *packets.DisconnectPacket: + msg.t.(*DisconnectToken).flowComplete() + DEBUG.Println(NET, "outbound wrote disconnect, stopping") + return + } + } + // Reset ping timer after sending control packet. + if c.options.KeepAlive != 0 { + c.lastSent.Store(time.Now()) + } + } +} + +// receive Message objects on ibound +// store messages if necessary +// send replies on obound +// delete messages from store if necessary +func alllogic(c *client) { + defer c.workers.Done() + DEBUG.Println(NET, "logic started") + + for { + DEBUG.Println(NET, "logic waiting for msg on ibound") + + select { + case msg := <-c.ibound: + DEBUG.Println(NET, "logic got msg on ibound") + persistInbound(c.persist, msg) + switch m := msg.(type) { + case *packets.PingrespPacket: + DEBUG.Println(NET, "received pingresp") + atomic.StoreInt32(&c.pingOutstanding, 0) + case *packets.SubackPacket: + DEBUG.Println(NET, "received suback, id:", m.MessageID) + token := c.getToken(m.MessageID) + switch t := token.(type) { + case *SubscribeToken: + DEBUG.Println(NET, "granted qoss", m.ReturnCodes) + for i, qos := range m.ReturnCodes { + t.subResult[t.subs[i]] = qos + } + } + token.flowComplete() + c.freeID(m.MessageID) + case *packets.UnsubackPacket: + DEBUG.Println(NET, "received unsuback, id:", m.MessageID) + c.getToken(m.MessageID).flowComplete() + c.freeID(m.MessageID) + case *packets.PublishPacket: + DEBUG.Println(NET, "received publish, msgId:", m.MessageID) + DEBUG.Println(NET, "putting msg on onPubChan") + switch m.Qos { + case 2: + c.incomingPubChan <- m + DEBUG.Println(NET, "done putting msg on incomingPubChan") + case 1: + c.incomingPubChan <- m + DEBUG.Println(NET, "done putting msg on incomingPubChan") + case 0: + select { + case c.incomingPubChan <- m: + case <-c.stop: + } + DEBUG.Println(NET, "done putting msg on incomingPubChan") + } + case *packets.PubackPacket: + DEBUG.Println(NET, "received puback, id:", m.MessageID) + // c.receipts.get(msg.MsgId()) <- Receipt{} + // c.receipts.end(msg.MsgId()) + c.getToken(m.MessageID).flowComplete() + c.freeID(m.MessageID) + case *packets.PubrecPacket: + DEBUG.Println(NET, "received pubrec, id:", m.MessageID) + prel := packets.NewControlPacket(packets.Pubrel).(*packets.PubrelPacket) + prel.MessageID = m.MessageID + select { + case c.oboundP <- &PacketAndToken{p: prel, t: nil}: + case <-c.stop: + } + case *packets.PubrelPacket: + DEBUG.Println(NET, "received pubrel, id:", m.MessageID) + pc := packets.NewControlPacket(packets.Pubcomp).(*packets.PubcompPacket) + pc.MessageID = m.MessageID + persistOutbound(c.persist, pc) + select { + case c.oboundP <- &PacketAndToken{p: pc, t: nil}: + case <-c.stop: + } + case *packets.PubcompPacket: + DEBUG.Println(NET, "received pubcomp, id:", m.MessageID) + c.getToken(m.MessageID).flowComplete() + c.freeID(m.MessageID) + } + case <-c.stop: + WARN.Println(NET, "logic stopped") + return + } + } +} + +func (c *client) ackFunc(packet *packets.PublishPacket) func() { + return func() { + switch packet.Qos { + case 2: + pr := packets.NewControlPacket(packets.Pubrec).(*packets.PubrecPacket) + pr.MessageID = packet.MessageID + DEBUG.Println(NET, "putting pubrec msg on obound") + select { + case c.oboundP <- &PacketAndToken{p: pr, t: nil}: + case <-c.stop: + } + DEBUG.Println(NET, "done putting pubrec msg on obound") + case 1: + pa := packets.NewControlPacket(packets.Puback).(*packets.PubackPacket) + pa.MessageID = packet.MessageID + DEBUG.Println(NET, "putting puback msg on obound") + persistOutbound(c.persist, pa) + select { + case c.oboundP <- &PacketAndToken{p: pa, t: nil}: + case <-c.stop: + } + DEBUG.Println(NET, "done putting puback msg on obound") + case 0: + // do nothing, since there is no need to send an ack packet back + } + } +} + +func errorWatch(c *client) { + defer c.workers.Done() + select { + case <-c.stop: + WARN.Println(NET, "errorWatch stopped") + return + case err := <-c.errors: + ERROR.Println(NET, "error triggered, stopping") + go c.internalConnLost(err) + return + } +} diff --git a/vendor/github.com/eclipse/paho.mqtt.golang/notice.html b/vendor/github.com/eclipse/paho.mqtt.golang/notice.html new file mode 100644 index 0000000..f19c483 --- /dev/null +++ b/vendor/github.com/eclipse/paho.mqtt.golang/notice.html @@ -0,0 +1,108 @@ + + + + + +Eclipse Foundation Software User Agreement + + + +

Eclipse Foundation Software User Agreement

+

February 1, 2011

+ +

Usage Of Content

+ +

THE ECLIPSE FOUNDATION MAKES AVAILABLE SOFTWARE, DOCUMENTATION, INFORMATION AND/OR OTHER MATERIALS FOR OPEN SOURCE PROJECTS + (COLLECTIVELY "CONTENT"). USE OF THE CONTENT IS GOVERNED BY THE TERMS AND CONDITIONS OF THIS AGREEMENT AND/OR THE TERMS AND + CONDITIONS OF LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED BELOW. BY USING THE CONTENT, YOU AGREE THAT YOUR USE + OF THE CONTENT IS GOVERNED BY THIS AGREEMENT AND/OR THE TERMS AND CONDITIONS OF ANY APPLICABLE LICENSE AGREEMENTS OR + NOTICES INDICATED OR REFERENCED BELOW. IF YOU DO NOT AGREE TO THE TERMS AND CONDITIONS OF THIS AGREEMENT AND THE TERMS AND + CONDITIONS OF ANY APPLICABLE LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED BELOW, THEN YOU MAY NOT USE THE CONTENT.

+ +

Applicable Licenses

+ +

Unless otherwise indicated, all Content made available by the Eclipse Foundation is provided to you under the terms and conditions of the Eclipse Public License Version 1.0 + ("EPL"). A copy of the EPL is provided with this Content and is also available at http://www.eclipse.org/legal/epl-v10.html. + For purposes of the EPL, "Program" will mean the Content.

+ +

Content includes, but is not limited to, source code, object code, documentation and other files maintained in the Eclipse Foundation source code + repository ("Repository") in software modules ("Modules") and made available as downloadable archives ("Downloads").

+ +
    +
  • Content may be structured and packaged into modules to facilitate delivering, extending, and upgrading the Content. Typical modules may include plug-ins ("Plug-ins"), plug-in fragments ("Fragments"), and features ("Features").
  • +
  • Each Plug-in or Fragment may be packaged as a sub-directory or JAR (Java™ ARchive) in a directory named "plugins".
  • +
  • A Feature is a bundle of one or more Plug-ins and/or Fragments and associated material. Each Feature may be packaged as a sub-directory in a directory named "features". Within a Feature, files named "feature.xml" may contain a list of the names and version numbers of the Plug-ins + and/or Fragments associated with that Feature.
  • +
  • Features may also include other Features ("Included Features"). Within a Feature, files named "feature.xml" may contain a list of the names and version numbers of Included Features.
  • +
+ +

The terms and conditions governing Plug-ins and Fragments should be contained in files named "about.html" ("Abouts"). The terms and conditions governing Features and +Included Features should be contained in files named "license.html" ("Feature Licenses"). Abouts and Feature Licenses may be located in any directory of a Download or Module +including, but not limited to the following locations:

+ +
    +
  • The top-level (root) directory
  • +
  • Plug-in and Fragment directories
  • +
  • Inside Plug-ins and Fragments packaged as JARs
  • +
  • Sub-directories of the directory named "src" of certain Plug-ins
  • +
  • Feature directories
  • +
+ +

Note: if a Feature made available by the Eclipse Foundation is installed using the Provisioning Technology (as defined below), you must agree to a license ("Feature Update License") during the +installation process. If the Feature contains Included Features, the Feature Update License should either provide you with the terms and conditions governing the Included Features or +inform you where you can locate them. Feature Update Licenses may be found in the "license" property of files named "feature.properties" found within a Feature. +Such Abouts, Feature Licenses, and Feature Update Licenses contain the terms and conditions (or references to such terms and conditions) that govern your use of the associated Content in +that directory.

+ +

THE ABOUTS, FEATURE LICENSES, AND FEATURE UPDATE LICENSES MAY REFER TO THE EPL OR OTHER LICENSE AGREEMENTS, NOTICES OR TERMS AND CONDITIONS. SOME OF THESE +OTHER LICENSE AGREEMENTS MAY INCLUDE (BUT ARE NOT LIMITED TO):

+ + + +

IT IS YOUR OBLIGATION TO READ AND ACCEPT ALL SUCH TERMS AND CONDITIONS PRIOR TO USE OF THE CONTENT. If no About, Feature License, or Feature Update License is provided, please +contact the Eclipse Foundation to determine what terms and conditions govern that particular Content.

+ + +

Use of Provisioning Technology

+ +

The Eclipse Foundation makes available provisioning software, examples of which include, but are not limited to, p2 and the Eclipse + Update Manager ("Provisioning Technology") for the purpose of allowing users to install software, documentation, information and/or + other materials (collectively "Installable Software"). This capability is provided with the intent of allowing such users to + install, extend and update Eclipse-based products. Information about packaging Installable Software is available at http://eclipse.org/equinox/p2/repository_packaging.html + ("Specification").

+ +

You may use Provisioning Technology to allow other parties to install Installable Software. You shall be responsible for enabling the + applicable license agreements relating to the Installable Software to be presented to, and accepted by, the users of the Provisioning Technology + in accordance with the Specification. By using Provisioning Technology in such a manner and making it available in accordance with the + Specification, you further acknowledge your agreement to, and the acquisition of all necessary rights to permit the following:

+ +
    +
  1. A series of actions may occur ("Provisioning Process") in which a user may execute the Provisioning Technology + on a machine ("Target Machine") with the intent of installing, extending or updating the functionality of an Eclipse-based + product.
  2. +
  3. During the Provisioning Process, the Provisioning Technology may cause third party Installable Software or a portion thereof to be + accessed and copied to the Target Machine.
  4. +
  5. Pursuant to the Specification, you will provide to the user the terms and conditions that govern the use of the Installable + Software ("Installable Software Agreement") and such Installable Software Agreement shall be accessed from the Target + Machine in accordance with the Specification. Such Installable Software Agreement must inform the user of the terms and conditions that govern + the Installable Software and must solicit acceptance by the end user in the manner prescribed in such Installable Software Agreement. Upon such + indication of agreement by the user, the provisioning Technology will complete installation of the Installable Software.
  6. +
+ +

Cryptography

+ +

Content may contain encryption software. The country in which you are currently may have restrictions on the import, possession, and use, and/or re-export to + another country, of encryption software. BEFORE using any encryption software, please check the country's laws, regulations and policies concerning the import, + possession, or use, and re-export of encryption software, to see if this is permitted.

+ +

Java and all Java-based trademarks are trademarks of Oracle Corporation in the United States, other countries, or both.

+ + diff --git a/vendor/github.com/eclipse/paho.mqtt.golang/oops.go b/vendor/github.com/eclipse/paho.mqtt.golang/oops.go new file mode 100644 index 0000000..39630d7 --- /dev/null +++ b/vendor/github.com/eclipse/paho.mqtt.golang/oops.go @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2013 IBM Corp. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Seth Hoenig + * Allan Stockdill-Mander + * Mike Robertson + */ + +package mqtt + +func chkerr(e error) { + if e != nil { + panic(e) + } +} diff --git a/vendor/github.com/eclipse/paho.mqtt.golang/options.go b/vendor/github.com/eclipse/paho.mqtt.golang/options.go new file mode 100644 index 0000000..e96e9ed --- /dev/null +++ b/vendor/github.com/eclipse/paho.mqtt.golang/options.go @@ -0,0 +1,340 @@ +/* + * Copyright (c) 2013 IBM Corp. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Seth Hoenig + * Allan Stockdill-Mander + * Mike Robertson + */ + +// Portions copyright © 2018 TIBCO Software Inc. + +package mqtt + +import ( + "crypto/tls" + "net/http" + "net/url" + "strings" + "time" +) + +// CredentialsProvider allows the username and password to be updated +// before reconnecting. It should return the current username and password. +type CredentialsProvider func() (username string, password string) + +// MessageHandler is a callback type which can be set to be +// executed upon the arrival of messages published to topics +// to which the client is subscribed. +type MessageHandler func(Client, Message) + +// ConnectionLostHandler is a callback type which can be set to be +// executed upon an unintended disconnection from the MQTT broker. +// Disconnects caused by calling Disconnect or ForceDisconnect will +// not cause an OnConnectionLost callback to execute. +type ConnectionLostHandler func(Client, error) + +// OnConnectHandler is a callback that is called when the client +// state changes from unconnected/disconnected to connected. Both +// at initial connection and on reconnection +type OnConnectHandler func(Client) + +// ClientOptions contains configurable options for an Client. +type ClientOptions struct { + Servers []*url.URL + ClientID string + Username string + Password string + CredentialsProvider CredentialsProvider + CleanSession bool + Order bool + WillEnabled bool + WillTopic string + WillPayload []byte + WillQos byte + WillRetained bool + ProtocolVersion uint + protocolVersionExplicit bool + TLSConfig *tls.Config + KeepAlive int64 + PingTimeout time.Duration + ConnectTimeout time.Duration + MaxReconnectInterval time.Duration + AutoReconnect bool + Store Store + DefaultPublishHandler MessageHandler + OnConnect OnConnectHandler + OnConnectionLost ConnectionLostHandler + WriteTimeout time.Duration + MessageChannelDepth uint + ResumeSubs bool + HTTPHeaders http.Header +} + +// NewClientOptions will create a new ClientClientOptions type with some +// default values. +// Port: 1883 +// CleanSession: True +// Order: True +// KeepAlive: 30 (seconds) +// ConnectTimeout: 30 (seconds) +// MaxReconnectInterval 10 (minutes) +// AutoReconnect: True +func NewClientOptions() *ClientOptions { + o := &ClientOptions{ + Servers: nil, + ClientID: "", + Username: "", + Password: "", + CleanSession: true, + Order: true, + WillEnabled: false, + WillTopic: "", + WillPayload: nil, + WillQos: 0, + WillRetained: false, + ProtocolVersion: 0, + protocolVersionExplicit: false, + KeepAlive: 30, + PingTimeout: 10 * time.Second, + ConnectTimeout: 30 * time.Second, + MaxReconnectInterval: 10 * time.Minute, + AutoReconnect: true, + Store: nil, + OnConnect: nil, + OnConnectionLost: DefaultConnectionLostHandler, + WriteTimeout: 0, // 0 represents timeout disabled + MessageChannelDepth: 100, + ResumeSubs: false, + HTTPHeaders: make(map[string][]string), + } + return o +} + +// AddBroker adds a broker URI to the list of brokers to be used. The format should be +// scheme://host:port +// Where "scheme" is one of "tcp", "ssl", or "ws", "host" is the ip-address (or hostname) +// and "port" is the port on which the broker is accepting connections. +// +// Default values for hostname is "127.0.0.1", for schema is "tcp://". +// +// An example broker URI would look like: tcp://foobar.com:1883 +func (o *ClientOptions) AddBroker(server string) *ClientOptions { + if len(server) > 0 && server[0] == ':' { + server = "127.0.0.1" + server + } + if !strings.Contains(server, "://") { + server = "tcp://" + server + } + brokerURI, err := url.Parse(server) + if err != nil { + ERROR.Println(CLI, "Failed to parse %q broker address: %s", server, err) + return o + } + o.Servers = append(o.Servers, brokerURI) + return o +} + +// SetResumeSubs will enable resuming of stored (un)subscribe messages when connecting +// but not reconnecting if CleanSession is false. Otherwise these messages are discarded. +func (o *ClientOptions) SetResumeSubs(resume bool) *ClientOptions { + o.ResumeSubs = resume + return o +} + +// SetClientID will set the client id to be used by this client when +// connecting to the MQTT broker. According to the MQTT v3.1 specification, +// a client id mus be no longer than 23 characters. +func (o *ClientOptions) SetClientID(id string) *ClientOptions { + o.ClientID = id + return o +} + +// SetUsername will set the username to be used by this client when connecting +// to the MQTT broker. Note: without the use of SSL/TLS, this information will +// be sent in plaintext accross the wire. +func (o *ClientOptions) SetUsername(u string) *ClientOptions { + o.Username = u + return o +} + +// SetPassword will set the password to be used by this client when connecting +// to the MQTT broker. Note: without the use of SSL/TLS, this information will +// be sent in plaintext accross the wire. +func (o *ClientOptions) SetPassword(p string) *ClientOptions { + o.Password = p + return o +} + +// SetCredentialsProvider will set a method to be called by this client when +// connecting to the MQTT broker that provide the current username and password. +// Note: without the use of SSL/TLS, this information will be sent +// in plaintext accross the wire. +func (o *ClientOptions) SetCredentialsProvider(p CredentialsProvider) *ClientOptions { + o.CredentialsProvider = p + return o +} + +// SetCleanSession will set the "clean session" flag in the connect message +// when this client connects to an MQTT broker. By setting this flag, you are +// indicating that no messages saved by the broker for this client should be +// delivered. Any messages that were going to be sent by this client before +// diconnecting previously but didn't will not be sent upon connecting to the +// broker. +func (o *ClientOptions) SetCleanSession(clean bool) *ClientOptions { + o.CleanSession = clean + return o +} + +// SetOrderMatters will set the message routing to guarantee order within +// each QoS level. By default, this value is true. If set to false, +// this flag indicates that messages can be delivered asynchronously +// from the client to the application and possibly arrive out of order. +func (o *ClientOptions) SetOrderMatters(order bool) *ClientOptions { + o.Order = order + return o +} + +// SetTLSConfig will set an SSL/TLS configuration to be used when connecting +// to an MQTT broker. Please read the official Go documentation for more +// information. +func (o *ClientOptions) SetTLSConfig(t *tls.Config) *ClientOptions { + o.TLSConfig = t + return o +} + +// SetStore will set the implementation of the Store interface +// used to provide message persistence in cases where QoS levels +// QoS_ONE or QoS_TWO are used. If no store is provided, then the +// client will use MemoryStore by default. +func (o *ClientOptions) SetStore(s Store) *ClientOptions { + o.Store = s + return o +} + +// SetKeepAlive will set the amount of time (in seconds) that the client +// should wait before sending a PING request to the broker. This will +// allow the client to know that a connection has not been lost with the +// server. +func (o *ClientOptions) SetKeepAlive(k time.Duration) *ClientOptions { + o.KeepAlive = int64(k / time.Second) + return o +} + +// SetPingTimeout will set the amount of time (in seconds) that the client +// will wait after sending a PING request to the broker, before deciding +// that the connection has been lost. Default is 10 seconds. +func (o *ClientOptions) SetPingTimeout(k time.Duration) *ClientOptions { + o.PingTimeout = k + return o +} + +// SetProtocolVersion sets the MQTT version to be used to connect to the +// broker. Legitimate values are currently 3 - MQTT 3.1 or 4 - MQTT 3.1.1 +func (o *ClientOptions) SetProtocolVersion(pv uint) *ClientOptions { + if (pv >= 3 && pv <= 4) || (pv > 0x80) { + o.ProtocolVersion = pv + o.protocolVersionExplicit = true + } + return o +} + +// UnsetWill will cause any set will message to be disregarded. +func (o *ClientOptions) UnsetWill() *ClientOptions { + o.WillEnabled = false + return o +} + +// SetWill accepts a string will message to be set. When the client connects, +// it will give this will message to the broker, which will then publish the +// provided payload (the will) to any clients that are subscribed to the provided +// topic. +func (o *ClientOptions) SetWill(topic string, payload string, qos byte, retained bool) *ClientOptions { + o.SetBinaryWill(topic, []byte(payload), qos, retained) + return o +} + +// SetBinaryWill accepts a []byte will message to be set. When the client connects, +// it will give this will message to the broker, which will then publish the +// provided payload (the will) to any clients that are subscribed to the provided +// topic. +func (o *ClientOptions) SetBinaryWill(topic string, payload []byte, qos byte, retained bool) *ClientOptions { + o.WillEnabled = true + o.WillTopic = topic + o.WillPayload = payload + o.WillQos = qos + o.WillRetained = retained + return o +} + +// SetDefaultPublishHandler sets the MessageHandler that will be called when a message +// is received that does not match any known subscriptions. +func (o *ClientOptions) SetDefaultPublishHandler(defaultHandler MessageHandler) *ClientOptions { + o.DefaultPublishHandler = defaultHandler + return o +} + +// SetOnConnectHandler sets the function to be called when the client is connected. Both +// at initial connection time and upon automatic reconnect. +func (o *ClientOptions) SetOnConnectHandler(onConn OnConnectHandler) *ClientOptions { + o.OnConnect = onConn + return o +} + +// SetConnectionLostHandler will set the OnConnectionLost callback to be executed +// in the case where the client unexpectedly loses connection with the MQTT broker. +func (o *ClientOptions) SetConnectionLostHandler(onLost ConnectionLostHandler) *ClientOptions { + o.OnConnectionLost = onLost + return o +} + +// SetWriteTimeout puts a limit on how long a mqtt publish should block until it unblocks with a +// timeout error. A duration of 0 never times out. Default 30 seconds +func (o *ClientOptions) SetWriteTimeout(t time.Duration) *ClientOptions { + o.WriteTimeout = t + return o +} + +// SetConnectTimeout limits how long the client will wait when trying to open a connection +// to an MQTT server before timeing out and erroring the attempt. A duration of 0 never times out. +// Default 30 seconds. Currently only operational on TCP/TLS connections. +func (o *ClientOptions) SetConnectTimeout(t time.Duration) *ClientOptions { + o.ConnectTimeout = t + return o +} + +// SetMaxReconnectInterval sets the maximum time that will be waited between reconnection attempts +// when connection is lost +func (o *ClientOptions) SetMaxReconnectInterval(t time.Duration) *ClientOptions { + o.MaxReconnectInterval = t + return o +} + +// SetAutoReconnect sets whether the automatic reconnection logic should be used +// when the connection is lost, even if disabled the ConnectionLostHandler is still +// called +func (o *ClientOptions) SetAutoReconnect(a bool) *ClientOptions { + o.AutoReconnect = a + return o +} + +// SetMessageChannelDepth sets the size of the internal queue that holds messages while the +// client is temporairily offline, allowing the application to publish when the client is +// reconnecting. This setting is only valid if AutoReconnect is set to true, it is otherwise +// ignored. +func (o *ClientOptions) SetMessageChannelDepth(s uint) *ClientOptions { + o.MessageChannelDepth = s + return o +} + +// SetHTTPHeaders sets the additional HTTP headers that will be sent in the WebSocket +// opening handshake. +func (o *ClientOptions) SetHTTPHeaders(h http.Header) *ClientOptions { + o.HTTPHeaders = h + return o +} diff --git a/vendor/github.com/eclipse/paho.mqtt.golang/options_reader.go b/vendor/github.com/eclipse/paho.mqtt.golang/options_reader.go new file mode 100644 index 0000000..60144b9 --- /dev/null +++ b/vendor/github.com/eclipse/paho.mqtt.golang/options_reader.go @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2013 IBM Corp. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Seth Hoenig + * Allan Stockdill-Mander + * Mike Robertson + */ + +package mqtt + +import ( + "crypto/tls" + "net/http" + "net/url" + "time" +) + +// ClientOptionsReader provides an interface for reading ClientOptions after the client has been initialized. +type ClientOptionsReader struct { + options *ClientOptions +} + +//Servers returns a slice of the servers defined in the clientoptions +func (r *ClientOptionsReader) Servers() []*url.URL { + s := make([]*url.URL, len(r.options.Servers)) + + for i, u := range r.options.Servers { + nu := *u + s[i] = &nu + } + + return s +} + +//ResumeSubs returns true if resuming stored (un)sub is enabled +func (r *ClientOptionsReader) ResumeSubs() bool { + s := r.options.ResumeSubs + return s +} + +//ClientID returns the set client id +func (r *ClientOptionsReader) ClientID() string { + s := r.options.ClientID + return s +} + +//Username returns the set username +func (r *ClientOptionsReader) Username() string { + s := r.options.Username + return s +} + +//Password returns the set password +func (r *ClientOptionsReader) Password() string { + s := r.options.Password + return s +} + +//CleanSession returns whether Cleansession is set +func (r *ClientOptionsReader) CleanSession() bool { + s := r.options.CleanSession + return s +} + +func (r *ClientOptionsReader) Order() bool { + s := r.options.Order + return s +} + +func (r *ClientOptionsReader) WillEnabled() bool { + s := r.options.WillEnabled + return s +} + +func (r *ClientOptionsReader) WillTopic() string { + s := r.options.WillTopic + return s +} + +func (r *ClientOptionsReader) WillPayload() []byte { + s := r.options.WillPayload + return s +} + +func (r *ClientOptionsReader) WillQos() byte { + s := r.options.WillQos + return s +} + +func (r *ClientOptionsReader) WillRetained() bool { + s := r.options.WillRetained + return s +} + +func (r *ClientOptionsReader) ProtocolVersion() uint { + s := r.options.ProtocolVersion + return s +} + +func (r *ClientOptionsReader) TLSConfig() *tls.Config { + s := r.options.TLSConfig + return s +} + +func (r *ClientOptionsReader) KeepAlive() time.Duration { + s := time.Duration(r.options.KeepAlive * int64(time.Second)) + return s +} + +func (r *ClientOptionsReader) PingTimeout() time.Duration { + s := r.options.PingTimeout + return s +} + +func (r *ClientOptionsReader) ConnectTimeout() time.Duration { + s := r.options.ConnectTimeout + return s +} + +func (r *ClientOptionsReader) MaxReconnectInterval() time.Duration { + s := r.options.MaxReconnectInterval + return s +} + +func (r *ClientOptionsReader) AutoReconnect() bool { + s := r.options.AutoReconnect + return s +} + +func (r *ClientOptionsReader) WriteTimeout() time.Duration { + s := r.options.WriteTimeout + return s +} + +func (r *ClientOptionsReader) MessageChannelDepth() uint { + s := r.options.MessageChannelDepth + return s +} + +func (r *ClientOptionsReader) HTTPHeaders() http.Header { + h := r.options.HTTPHeaders + return h +} diff --git a/vendor/github.com/eclipse/paho.mqtt.golang/packets/connack.go b/vendor/github.com/eclipse/paho.mqtt.golang/packets/connack.go new file mode 100644 index 0000000..25cf30f --- /dev/null +++ b/vendor/github.com/eclipse/paho.mqtt.golang/packets/connack.go @@ -0,0 +1,55 @@ +package packets + +import ( + "bytes" + "fmt" + "io" +) + +//ConnackPacket is an internal representation of the fields of the +//Connack MQTT packet +type ConnackPacket struct { + FixedHeader + SessionPresent bool + ReturnCode byte +} + +func (ca *ConnackPacket) String() string { + str := fmt.Sprintf("%s", ca.FixedHeader) + str += " " + str += fmt.Sprintf("sessionpresent: %t returncode: %d", ca.SessionPresent, ca.ReturnCode) + return str +} + +func (ca *ConnackPacket) Write(w io.Writer) error { + var body bytes.Buffer + var err error + + body.WriteByte(boolToByte(ca.SessionPresent)) + body.WriteByte(ca.ReturnCode) + ca.FixedHeader.RemainingLength = 2 + packet := ca.FixedHeader.pack() + packet.Write(body.Bytes()) + _, err = packet.WriteTo(w) + + return err +} + +//Unpack decodes the details of a ControlPacket after the fixed +//header has been read +func (ca *ConnackPacket) Unpack(b io.Reader) error { + flags, err := decodeByte(b) + if err != nil { + return err + } + ca.SessionPresent = 1&flags > 0 + ca.ReturnCode, err = decodeByte(b) + + return err +} + +//Details returns a Details struct containing the Qos and +//MessageID of this ControlPacket +func (ca *ConnackPacket) Details() Details { + return Details{Qos: 0, MessageID: 0} +} diff --git a/vendor/github.com/eclipse/paho.mqtt.golang/packets/connect.go b/vendor/github.com/eclipse/paho.mqtt.golang/packets/connect.go new file mode 100644 index 0000000..cb03ebc --- /dev/null +++ b/vendor/github.com/eclipse/paho.mqtt.golang/packets/connect.go @@ -0,0 +1,154 @@ +package packets + +import ( + "bytes" + "fmt" + "io" +) + +//ConnectPacket is an internal representation of the fields of the +//Connect MQTT packet +type ConnectPacket struct { + FixedHeader + ProtocolName string + ProtocolVersion byte + CleanSession bool + WillFlag bool + WillQos byte + WillRetain bool + UsernameFlag bool + PasswordFlag bool + ReservedBit byte + Keepalive uint16 + + ClientIdentifier string + WillTopic string + WillMessage []byte + Username string + Password []byte +} + +func (c *ConnectPacket) String() string { + str := fmt.Sprintf("%s", c.FixedHeader) + str += " " + str += fmt.Sprintf("protocolversion: %d protocolname: %s cleansession: %t willflag: %t WillQos: %d WillRetain: %t Usernameflag: %t Passwordflag: %t keepalive: %d clientId: %s willtopic: %s willmessage: %s Username: %s Password: %s", c.ProtocolVersion, c.ProtocolName, c.CleanSession, c.WillFlag, c.WillQos, c.WillRetain, c.UsernameFlag, c.PasswordFlag, c.Keepalive, c.ClientIdentifier, c.WillTopic, c.WillMessage, c.Username, c.Password) + return str +} + +func (c *ConnectPacket) Write(w io.Writer) error { + var body bytes.Buffer + var err error + + body.Write(encodeString(c.ProtocolName)) + body.WriteByte(c.ProtocolVersion) + body.WriteByte(boolToByte(c.CleanSession)<<1 | boolToByte(c.WillFlag)<<2 | c.WillQos<<3 | boolToByte(c.WillRetain)<<5 | boolToByte(c.PasswordFlag)<<6 | boolToByte(c.UsernameFlag)<<7) + body.Write(encodeUint16(c.Keepalive)) + body.Write(encodeString(c.ClientIdentifier)) + if c.WillFlag { + body.Write(encodeString(c.WillTopic)) + body.Write(encodeBytes(c.WillMessage)) + } + if c.UsernameFlag { + body.Write(encodeString(c.Username)) + } + if c.PasswordFlag { + body.Write(encodeBytes(c.Password)) + } + c.FixedHeader.RemainingLength = body.Len() + packet := c.FixedHeader.pack() + packet.Write(body.Bytes()) + _, err = packet.WriteTo(w) + + return err +} + +//Unpack decodes the details of a ControlPacket after the fixed +//header has been read +func (c *ConnectPacket) Unpack(b io.Reader) error { + var err error + c.ProtocolName, err = decodeString(b) + if err != nil { + return err + } + c.ProtocolVersion, err = decodeByte(b) + if err != nil { + return err + } + options, err := decodeByte(b) + if err != nil { + return err + } + c.ReservedBit = 1 & options + c.CleanSession = 1&(options>>1) > 0 + c.WillFlag = 1&(options>>2) > 0 + c.WillQos = 3 & (options >> 3) + c.WillRetain = 1&(options>>5) > 0 + c.PasswordFlag = 1&(options>>6) > 0 + c.UsernameFlag = 1&(options>>7) > 0 + c.Keepalive, err = decodeUint16(b) + if err != nil { + return err + } + c.ClientIdentifier, err = decodeString(b) + if err != nil { + return err + } + if c.WillFlag { + c.WillTopic, err = decodeString(b) + if err != nil { + return err + } + c.WillMessage, err = decodeBytes(b) + if err != nil { + return err + } + } + if c.UsernameFlag { + c.Username, err = decodeString(b) + if err != nil { + return err + } + } + if c.PasswordFlag { + c.Password, err = decodeBytes(b) + if err != nil { + return err + } + } + + return nil +} + +//Validate performs validation of the fields of a Connect packet +func (c *ConnectPacket) Validate() byte { + if c.PasswordFlag && !c.UsernameFlag { + return ErrRefusedBadUsernameOrPassword + } + if c.ReservedBit != 0 { + //Bad reserved bit + return ErrProtocolViolation + } + if (c.ProtocolName == "MQIsdp" && c.ProtocolVersion != 3) || (c.ProtocolName == "MQTT" && c.ProtocolVersion != 4) { + //Mismatched or unsupported protocol version + return ErrRefusedBadProtocolVersion + } + if c.ProtocolName != "MQIsdp" && c.ProtocolName != "MQTT" { + //Bad protocol name + return ErrProtocolViolation + } + if len(c.ClientIdentifier) > 65535 || len(c.Username) > 65535 || len(c.Password) > 65535 { + //Bad size field + return ErrProtocolViolation + } + if len(c.ClientIdentifier) == 0 && !c.CleanSession { + //Bad client identifier + return ErrRefusedIDRejected + } + return Accepted +} + +//Details returns a Details struct containing the Qos and +//MessageID of this ControlPacket +func (c *ConnectPacket) Details() Details { + return Details{Qos: 0, MessageID: 0} +} diff --git a/vendor/github.com/eclipse/paho.mqtt.golang/packets/disconnect.go b/vendor/github.com/eclipse/paho.mqtt.golang/packets/disconnect.go new file mode 100644 index 0000000..e5c1869 --- /dev/null +++ b/vendor/github.com/eclipse/paho.mqtt.golang/packets/disconnect.go @@ -0,0 +1,36 @@ +package packets + +import ( + "fmt" + "io" +) + +//DisconnectPacket is an internal representation of the fields of the +//Disconnect MQTT packet +type DisconnectPacket struct { + FixedHeader +} + +func (d *DisconnectPacket) String() string { + str := fmt.Sprintf("%s", d.FixedHeader) + return str +} + +func (d *DisconnectPacket) Write(w io.Writer) error { + packet := d.FixedHeader.pack() + _, err := packet.WriteTo(w) + + return err +} + +//Unpack decodes the details of a ControlPacket after the fixed +//header has been read +func (d *DisconnectPacket) Unpack(b io.Reader) error { + return nil +} + +//Details returns a Details struct containing the Qos and +//MessageID of this ControlPacket +func (d *DisconnectPacket) Details() Details { + return Details{Qos: 0, MessageID: 0} +} diff --git a/vendor/github.com/eclipse/paho.mqtt.golang/packets/packets.go b/vendor/github.com/eclipse/paho.mqtt.golang/packets/packets.go new file mode 100644 index 0000000..42eeb46 --- /dev/null +++ b/vendor/github.com/eclipse/paho.mqtt.golang/packets/packets.go @@ -0,0 +1,346 @@ +package packets + +import ( + "bytes" + "encoding/binary" + "errors" + "fmt" + "io" +) + +//ControlPacket defines the interface for structs intended to hold +//decoded MQTT packets, either from being read or before being +//written +type ControlPacket interface { + Write(io.Writer) error + Unpack(io.Reader) error + String() string + Details() Details +} + +//PacketNames maps the constants for each of the MQTT packet types +//to a string representation of their name. +var PacketNames = map[uint8]string{ + 1: "CONNECT", + 2: "CONNACK", + 3: "PUBLISH", + 4: "PUBACK", + 5: "PUBREC", + 6: "PUBREL", + 7: "PUBCOMP", + 8: "SUBSCRIBE", + 9: "SUBACK", + 10: "UNSUBSCRIBE", + 11: "UNSUBACK", + 12: "PINGREQ", + 13: "PINGRESP", + 14: "DISCONNECT", +} + +//Below are the constants assigned to each of the MQTT packet types +const ( + Connect = 1 + Connack = 2 + Publish = 3 + Puback = 4 + Pubrec = 5 + Pubrel = 6 + Pubcomp = 7 + Subscribe = 8 + Suback = 9 + Unsubscribe = 10 + Unsuback = 11 + Pingreq = 12 + Pingresp = 13 + Disconnect = 14 +) + +//Below are the const definitions for error codes returned by +//Connect() +const ( + Accepted = 0x00 + ErrRefusedBadProtocolVersion = 0x01 + ErrRefusedIDRejected = 0x02 + ErrRefusedServerUnavailable = 0x03 + ErrRefusedBadUsernameOrPassword = 0x04 + ErrRefusedNotAuthorised = 0x05 + ErrNetworkError = 0xFE + ErrProtocolViolation = 0xFF +) + +//ConnackReturnCodes is a map of the error codes constants for Connect() +//to a string representation of the error +var ConnackReturnCodes = map[uint8]string{ + 0: "Connection Accepted", + 1: "Connection Refused: Bad Protocol Version", + 2: "Connection Refused: Client Identifier Rejected", + 3: "Connection Refused: Server Unavailable", + 4: "Connection Refused: Username or Password in unknown format", + 5: "Connection Refused: Not Authorised", + 254: "Connection Error", + 255: "Connection Refused: Protocol Violation", +} + +//ConnErrors is a map of the errors codes constants for Connect() +//to a Go error +var ConnErrors = map[byte]error{ + Accepted: nil, + ErrRefusedBadProtocolVersion: errors.New("Unnacceptable protocol version"), + ErrRefusedIDRejected: errors.New("Identifier rejected"), + ErrRefusedServerUnavailable: errors.New("Server Unavailable"), + ErrRefusedBadUsernameOrPassword: errors.New("Bad user name or password"), + ErrRefusedNotAuthorised: errors.New("Not Authorized"), + ErrNetworkError: errors.New("Network Error"), + ErrProtocolViolation: errors.New("Protocol Violation"), +} + +//ReadPacket takes an instance of an io.Reader (such as net.Conn) and attempts +//to read an MQTT packet from the stream. It returns a ControlPacket +//representing the decoded MQTT packet and an error. One of these returns will +//always be nil, a nil ControlPacket indicating an error occurred. +func ReadPacket(r io.Reader) (ControlPacket, error) { + var fh FixedHeader + b := make([]byte, 1) + + _, err := io.ReadFull(r, b) + if err != nil { + return nil, err + } + + err = fh.unpack(b[0], r) + if err != nil { + return nil, err + } + + cp, err := NewControlPacketWithHeader(fh) + if err != nil { + return nil, err + } + + packetBytes := make([]byte, fh.RemainingLength) + n, err := io.ReadFull(r, packetBytes) + if err != nil { + return nil, err + } + if n != fh.RemainingLength { + return nil, errors.New("Failed to read expected data") + } + + err = cp.Unpack(bytes.NewBuffer(packetBytes)) + return cp, err +} + +//NewControlPacket is used to create a new ControlPacket of the type specified +//by packetType, this is usually done by reference to the packet type constants +//defined in packets.go. The newly created ControlPacket is empty and a pointer +//is returned. +func NewControlPacket(packetType byte) ControlPacket { + switch packetType { + case Connect: + return &ConnectPacket{FixedHeader: FixedHeader{MessageType: Connect}} + case Connack: + return &ConnackPacket{FixedHeader: FixedHeader{MessageType: Connack}} + case Disconnect: + return &DisconnectPacket{FixedHeader: FixedHeader{MessageType: Disconnect}} + case Publish: + return &PublishPacket{FixedHeader: FixedHeader{MessageType: Publish}} + case Puback: + return &PubackPacket{FixedHeader: FixedHeader{MessageType: Puback}} + case Pubrec: + return &PubrecPacket{FixedHeader: FixedHeader{MessageType: Pubrec}} + case Pubrel: + return &PubrelPacket{FixedHeader: FixedHeader{MessageType: Pubrel, Qos: 1}} + case Pubcomp: + return &PubcompPacket{FixedHeader: FixedHeader{MessageType: Pubcomp}} + case Subscribe: + return &SubscribePacket{FixedHeader: FixedHeader{MessageType: Subscribe, Qos: 1}} + case Suback: + return &SubackPacket{FixedHeader: FixedHeader{MessageType: Suback}} + case Unsubscribe: + return &UnsubscribePacket{FixedHeader: FixedHeader{MessageType: Unsubscribe, Qos: 1}} + case Unsuback: + return &UnsubackPacket{FixedHeader: FixedHeader{MessageType: Unsuback}} + case Pingreq: + return &PingreqPacket{FixedHeader: FixedHeader{MessageType: Pingreq}} + case Pingresp: + return &PingrespPacket{FixedHeader: FixedHeader{MessageType: Pingresp}} + } + return nil +} + +//NewControlPacketWithHeader is used to create a new ControlPacket of the type +//specified within the FixedHeader that is passed to the function. +//The newly created ControlPacket is empty and a pointer is returned. +func NewControlPacketWithHeader(fh FixedHeader) (ControlPacket, error) { + switch fh.MessageType { + case Connect: + return &ConnectPacket{FixedHeader: fh}, nil + case Connack: + return &ConnackPacket{FixedHeader: fh}, nil + case Disconnect: + return &DisconnectPacket{FixedHeader: fh}, nil + case Publish: + return &PublishPacket{FixedHeader: fh}, nil + case Puback: + return &PubackPacket{FixedHeader: fh}, nil + case Pubrec: + return &PubrecPacket{FixedHeader: fh}, nil + case Pubrel: + return &PubrelPacket{FixedHeader: fh}, nil + case Pubcomp: + return &PubcompPacket{FixedHeader: fh}, nil + case Subscribe: + return &SubscribePacket{FixedHeader: fh}, nil + case Suback: + return &SubackPacket{FixedHeader: fh}, nil + case Unsubscribe: + return &UnsubscribePacket{FixedHeader: fh}, nil + case Unsuback: + return &UnsubackPacket{FixedHeader: fh}, nil + case Pingreq: + return &PingreqPacket{FixedHeader: fh}, nil + case Pingresp: + return &PingrespPacket{FixedHeader: fh}, nil + } + return nil, fmt.Errorf("unsupported packet type 0x%x", fh.MessageType) +} + +//Details struct returned by the Details() function called on +//ControlPackets to present details of the Qos and MessageID +//of the ControlPacket +type Details struct { + Qos byte + MessageID uint16 +} + +//FixedHeader is a struct to hold the decoded information from +//the fixed header of an MQTT ControlPacket +type FixedHeader struct { + MessageType byte + Dup bool + Qos byte + Retain bool + RemainingLength int +} + +func (fh FixedHeader) String() string { + return fmt.Sprintf("%s: dup: %t qos: %d retain: %t rLength: %d", PacketNames[fh.MessageType], fh.Dup, fh.Qos, fh.Retain, fh.RemainingLength) +} + +func boolToByte(b bool) byte { + switch b { + case true: + return 1 + default: + return 0 + } +} + +func (fh *FixedHeader) pack() bytes.Buffer { + var header bytes.Buffer + header.WriteByte(fh.MessageType<<4 | boolToByte(fh.Dup)<<3 | fh.Qos<<1 | boolToByte(fh.Retain)) + header.Write(encodeLength(fh.RemainingLength)) + return header +} + +func (fh *FixedHeader) unpack(typeAndFlags byte, r io.Reader) error { + fh.MessageType = typeAndFlags >> 4 + fh.Dup = (typeAndFlags>>3)&0x01 > 0 + fh.Qos = (typeAndFlags >> 1) & 0x03 + fh.Retain = typeAndFlags&0x01 > 0 + + var err error + fh.RemainingLength, err = decodeLength(r) + return err +} + +func decodeByte(b io.Reader) (byte, error) { + num := make([]byte, 1) + _, err := b.Read(num) + if err != nil { + return 0, err + } + + return num[0], nil +} + +func decodeUint16(b io.Reader) (uint16, error) { + num := make([]byte, 2) + _, err := b.Read(num) + if err != nil { + return 0, err + } + return binary.BigEndian.Uint16(num), nil +} + +func encodeUint16(num uint16) []byte { + bytes := make([]byte, 2) + binary.BigEndian.PutUint16(bytes, num) + return bytes +} + +func encodeString(field string) []byte { + return encodeBytes([]byte(field)) +} + +func decodeString(b io.Reader) (string, error) { + buf, err := decodeBytes(b) + return string(buf), err +} + +func decodeBytes(b io.Reader) ([]byte, error) { + fieldLength, err := decodeUint16(b) + if err != nil { + return nil, err + } + + field := make([]byte, fieldLength) + _, err = b.Read(field) + if err != nil { + return nil, err + } + + return field, nil +} + +func encodeBytes(field []byte) []byte { + fieldLength := make([]byte, 2) + binary.BigEndian.PutUint16(fieldLength, uint16(len(field))) + return append(fieldLength, field...) +} + +func encodeLength(length int) []byte { + var encLength []byte + for { + digit := byte(length % 128) + length /= 128 + if length > 0 { + digit |= 0x80 + } + encLength = append(encLength, digit) + if length == 0 { + break + } + } + return encLength +} + +func decodeLength(r io.Reader) (int, error) { + var rLength uint32 + var multiplier uint32 + b := make([]byte, 1) + for multiplier < 27 { //fix: Infinite '(digit & 128) == 1' will cause the dead loop + _, err := io.ReadFull(r, b) + if err != nil { + return 0, err + } + + digit := b[0] + rLength |= uint32(digit&127) << multiplier + if (digit & 128) == 0 { + break + } + multiplier += 7 + } + return int(rLength), nil +} diff --git a/vendor/github.com/eclipse/paho.mqtt.golang/packets/pingreq.go b/vendor/github.com/eclipse/paho.mqtt.golang/packets/pingreq.go new file mode 100644 index 0000000..5c3e88f --- /dev/null +++ b/vendor/github.com/eclipse/paho.mqtt.golang/packets/pingreq.go @@ -0,0 +1,36 @@ +package packets + +import ( + "fmt" + "io" +) + +//PingreqPacket is an internal representation of the fields of the +//Pingreq MQTT packet +type PingreqPacket struct { + FixedHeader +} + +func (pr *PingreqPacket) String() string { + str := fmt.Sprintf("%s", pr.FixedHeader) + return str +} + +func (pr *PingreqPacket) Write(w io.Writer) error { + packet := pr.FixedHeader.pack() + _, err := packet.WriteTo(w) + + return err +} + +//Unpack decodes the details of a ControlPacket after the fixed +//header has been read +func (pr *PingreqPacket) Unpack(b io.Reader) error { + return nil +} + +//Details returns a Details struct containing the Qos and +//MessageID of this ControlPacket +func (pr *PingreqPacket) Details() Details { + return Details{Qos: 0, MessageID: 0} +} diff --git a/vendor/github.com/eclipse/paho.mqtt.golang/packets/pingresp.go b/vendor/github.com/eclipse/paho.mqtt.golang/packets/pingresp.go new file mode 100644 index 0000000..39ebc00 --- /dev/null +++ b/vendor/github.com/eclipse/paho.mqtt.golang/packets/pingresp.go @@ -0,0 +1,36 @@ +package packets + +import ( + "fmt" + "io" +) + +//PingrespPacket is an internal representation of the fields of the +//Pingresp MQTT packet +type PingrespPacket struct { + FixedHeader +} + +func (pr *PingrespPacket) String() string { + str := fmt.Sprintf("%s", pr.FixedHeader) + return str +} + +func (pr *PingrespPacket) Write(w io.Writer) error { + packet := pr.FixedHeader.pack() + _, err := packet.WriteTo(w) + + return err +} + +//Unpack decodes the details of a ControlPacket after the fixed +//header has been read +func (pr *PingrespPacket) Unpack(b io.Reader) error { + return nil +} + +//Details returns a Details struct containing the Qos and +//MessageID of this ControlPacket +func (pr *PingrespPacket) Details() Details { + return Details{Qos: 0, MessageID: 0} +} diff --git a/vendor/github.com/eclipse/paho.mqtt.golang/packets/puback.go b/vendor/github.com/eclipse/paho.mqtt.golang/packets/puback.go new file mode 100644 index 0000000..7c0cd7e --- /dev/null +++ b/vendor/github.com/eclipse/paho.mqtt.golang/packets/puback.go @@ -0,0 +1,45 @@ +package packets + +import ( + "fmt" + "io" +) + +//PubackPacket is an internal representation of the fields of the +//Puback MQTT packet +type PubackPacket struct { + FixedHeader + MessageID uint16 +} + +func (pa *PubackPacket) String() string { + str := fmt.Sprintf("%s", pa.FixedHeader) + str += " " + str += fmt.Sprintf("MessageID: %d", pa.MessageID) + return str +} + +func (pa *PubackPacket) Write(w io.Writer) error { + var err error + pa.FixedHeader.RemainingLength = 2 + packet := pa.FixedHeader.pack() + packet.Write(encodeUint16(pa.MessageID)) + _, err = packet.WriteTo(w) + + return err +} + +//Unpack decodes the details of a ControlPacket after the fixed +//header has been read +func (pa *PubackPacket) Unpack(b io.Reader) error { + var err error + pa.MessageID, err = decodeUint16(b) + + return err +} + +//Details returns a Details struct containing the Qos and +//MessageID of this ControlPacket +func (pa *PubackPacket) Details() Details { + return Details{Qos: pa.Qos, MessageID: pa.MessageID} +} diff --git a/vendor/github.com/eclipse/paho.mqtt.golang/packets/pubcomp.go b/vendor/github.com/eclipse/paho.mqtt.golang/packets/pubcomp.go new file mode 100644 index 0000000..4f6f6e2 --- /dev/null +++ b/vendor/github.com/eclipse/paho.mqtt.golang/packets/pubcomp.go @@ -0,0 +1,45 @@ +package packets + +import ( + "fmt" + "io" +) + +//PubcompPacket is an internal representation of the fields of the +//Pubcomp MQTT packet +type PubcompPacket struct { + FixedHeader + MessageID uint16 +} + +func (pc *PubcompPacket) String() string { + str := fmt.Sprintf("%s", pc.FixedHeader) + str += " " + str += fmt.Sprintf("MessageID: %d", pc.MessageID) + return str +} + +func (pc *PubcompPacket) Write(w io.Writer) error { + var err error + pc.FixedHeader.RemainingLength = 2 + packet := pc.FixedHeader.pack() + packet.Write(encodeUint16(pc.MessageID)) + _, err = packet.WriteTo(w) + + return err +} + +//Unpack decodes the details of a ControlPacket after the fixed +//header has been read +func (pc *PubcompPacket) Unpack(b io.Reader) error { + var err error + pc.MessageID, err = decodeUint16(b) + + return err +} + +//Details returns a Details struct containing the Qos and +//MessageID of this ControlPacket +func (pc *PubcompPacket) Details() Details { + return Details{Qos: pc.Qos, MessageID: pc.MessageID} +} diff --git a/vendor/github.com/eclipse/paho.mqtt.golang/packets/publish.go b/vendor/github.com/eclipse/paho.mqtt.golang/packets/publish.go new file mode 100644 index 0000000..adc9adb --- /dev/null +++ b/vendor/github.com/eclipse/paho.mqtt.golang/packets/publish.go @@ -0,0 +1,88 @@ +package packets + +import ( + "bytes" + "fmt" + "io" +) + +//PublishPacket is an internal representation of the fields of the +//Publish MQTT packet +type PublishPacket struct { + FixedHeader + TopicName string + MessageID uint16 + Payload []byte +} + +func (p *PublishPacket) String() string { + str := fmt.Sprintf("%s", p.FixedHeader) + str += " " + str += fmt.Sprintf("topicName: %s MessageID: %d", p.TopicName, p.MessageID) + str += " " + str += fmt.Sprintf("payload: %s", string(p.Payload)) + return str +} + +func (p *PublishPacket) Write(w io.Writer) error { + var body bytes.Buffer + var err error + + body.Write(encodeString(p.TopicName)) + if p.Qos > 0 { + body.Write(encodeUint16(p.MessageID)) + } + p.FixedHeader.RemainingLength = body.Len() + len(p.Payload) + packet := p.FixedHeader.pack() + packet.Write(body.Bytes()) + packet.Write(p.Payload) + _, err = w.Write(packet.Bytes()) + + return err +} + +//Unpack decodes the details of a ControlPacket after the fixed +//header has been read +func (p *PublishPacket) Unpack(b io.Reader) error { + var payloadLength = p.FixedHeader.RemainingLength + var err error + p.TopicName, err = decodeString(b) + if err != nil { + return err + } + + if p.Qos > 0 { + p.MessageID, err = decodeUint16(b) + if err != nil { + return err + } + payloadLength -= len(p.TopicName) + 4 + } else { + payloadLength -= len(p.TopicName) + 2 + } + if payloadLength < 0 { + return fmt.Errorf("Error unpacking publish, payload length < 0") + } + p.Payload = make([]byte, payloadLength) + _, err = b.Read(p.Payload) + + return err +} + +//Copy creates a new PublishPacket with the same topic and payload +//but an empty fixed header, useful for when you want to deliver +//a message with different properties such as Qos but the same +//content +func (p *PublishPacket) Copy() *PublishPacket { + newP := NewControlPacket(Publish).(*PublishPacket) + newP.TopicName = p.TopicName + newP.Payload = p.Payload + + return newP +} + +//Details returns a Details struct containing the Qos and +//MessageID of this ControlPacket +func (p *PublishPacket) Details() Details { + return Details{Qos: p.Qos, MessageID: p.MessageID} +} diff --git a/vendor/github.com/eclipse/paho.mqtt.golang/packets/pubrec.go b/vendor/github.com/eclipse/paho.mqtt.golang/packets/pubrec.go new file mode 100644 index 0000000..483372b --- /dev/null +++ b/vendor/github.com/eclipse/paho.mqtt.golang/packets/pubrec.go @@ -0,0 +1,45 @@ +package packets + +import ( + "fmt" + "io" +) + +//PubrecPacket is an internal representation of the fields of the +//Pubrec MQTT packet +type PubrecPacket struct { + FixedHeader + MessageID uint16 +} + +func (pr *PubrecPacket) String() string { + str := fmt.Sprintf("%s", pr.FixedHeader) + str += " " + str += fmt.Sprintf("MessageID: %d", pr.MessageID) + return str +} + +func (pr *PubrecPacket) Write(w io.Writer) error { + var err error + pr.FixedHeader.RemainingLength = 2 + packet := pr.FixedHeader.pack() + packet.Write(encodeUint16(pr.MessageID)) + _, err = packet.WriteTo(w) + + return err +} + +//Unpack decodes the details of a ControlPacket after the fixed +//header has been read +func (pr *PubrecPacket) Unpack(b io.Reader) error { + var err error + pr.MessageID, err = decodeUint16(b) + + return err +} + +//Details returns a Details struct containing the Qos and +//MessageID of this ControlPacket +func (pr *PubrecPacket) Details() Details { + return Details{Qos: pr.Qos, MessageID: pr.MessageID} +} diff --git a/vendor/github.com/eclipse/paho.mqtt.golang/packets/pubrel.go b/vendor/github.com/eclipse/paho.mqtt.golang/packets/pubrel.go new file mode 100644 index 0000000..8590fd9 --- /dev/null +++ b/vendor/github.com/eclipse/paho.mqtt.golang/packets/pubrel.go @@ -0,0 +1,45 @@ +package packets + +import ( + "fmt" + "io" +) + +//PubrelPacket is an internal representation of the fields of the +//Pubrel MQTT packet +type PubrelPacket struct { + FixedHeader + MessageID uint16 +} + +func (pr *PubrelPacket) String() string { + str := fmt.Sprintf("%s", pr.FixedHeader) + str += " " + str += fmt.Sprintf("MessageID: %d", pr.MessageID) + return str +} + +func (pr *PubrelPacket) Write(w io.Writer) error { + var err error + pr.FixedHeader.RemainingLength = 2 + packet := pr.FixedHeader.pack() + packet.Write(encodeUint16(pr.MessageID)) + _, err = packet.WriteTo(w) + + return err +} + +//Unpack decodes the details of a ControlPacket after the fixed +//header has been read +func (pr *PubrelPacket) Unpack(b io.Reader) error { + var err error + pr.MessageID, err = decodeUint16(b) + + return err +} + +//Details returns a Details struct containing the Qos and +//MessageID of this ControlPacket +func (pr *PubrelPacket) Details() Details { + return Details{Qos: pr.Qos, MessageID: pr.MessageID} +} diff --git a/vendor/github.com/eclipse/paho.mqtt.golang/packets/suback.go b/vendor/github.com/eclipse/paho.mqtt.golang/packets/suback.go new file mode 100644 index 0000000..fc05724 --- /dev/null +++ b/vendor/github.com/eclipse/paho.mqtt.golang/packets/suback.go @@ -0,0 +1,60 @@ +package packets + +import ( + "bytes" + "fmt" + "io" +) + +//SubackPacket is an internal representation of the fields of the +//Suback MQTT packet +type SubackPacket struct { + FixedHeader + MessageID uint16 + ReturnCodes []byte +} + +func (sa *SubackPacket) String() string { + str := fmt.Sprintf("%s", sa.FixedHeader) + str += " " + str += fmt.Sprintf("MessageID: %d", sa.MessageID) + return str +} + +func (sa *SubackPacket) Write(w io.Writer) error { + var body bytes.Buffer + var err error + body.Write(encodeUint16(sa.MessageID)) + body.Write(sa.ReturnCodes) + sa.FixedHeader.RemainingLength = body.Len() + packet := sa.FixedHeader.pack() + packet.Write(body.Bytes()) + _, err = packet.WriteTo(w) + + return err +} + +//Unpack decodes the details of a ControlPacket after the fixed +//header has been read +func (sa *SubackPacket) Unpack(b io.Reader) error { + var qosBuffer bytes.Buffer + var err error + sa.MessageID, err = decodeUint16(b) + if err != nil { + return err + } + + _, err = qosBuffer.ReadFrom(b) + if err != nil { + return err + } + sa.ReturnCodes = qosBuffer.Bytes() + + return nil +} + +//Details returns a Details struct containing the Qos and +//MessageID of this ControlPacket +func (sa *SubackPacket) Details() Details { + return Details{Qos: 0, MessageID: sa.MessageID} +} diff --git a/vendor/github.com/eclipse/paho.mqtt.golang/packets/subscribe.go b/vendor/github.com/eclipse/paho.mqtt.golang/packets/subscribe.go new file mode 100644 index 0000000..0787ce0 --- /dev/null +++ b/vendor/github.com/eclipse/paho.mqtt.golang/packets/subscribe.go @@ -0,0 +1,72 @@ +package packets + +import ( + "bytes" + "fmt" + "io" +) + +//SubscribePacket is an internal representation of the fields of the +//Subscribe MQTT packet +type SubscribePacket struct { + FixedHeader + MessageID uint16 + Topics []string + Qoss []byte +} + +func (s *SubscribePacket) String() string { + str := fmt.Sprintf("%s", s.FixedHeader) + str += " " + str += fmt.Sprintf("MessageID: %d topics: %s", s.MessageID, s.Topics) + return str +} + +func (s *SubscribePacket) Write(w io.Writer) error { + var body bytes.Buffer + var err error + + body.Write(encodeUint16(s.MessageID)) + for i, topic := range s.Topics { + body.Write(encodeString(topic)) + body.WriteByte(s.Qoss[i]) + } + s.FixedHeader.RemainingLength = body.Len() + packet := s.FixedHeader.pack() + packet.Write(body.Bytes()) + _, err = packet.WriteTo(w) + + return err +} + +//Unpack decodes the details of a ControlPacket after the fixed +//header has been read +func (s *SubscribePacket) Unpack(b io.Reader) error { + var err error + s.MessageID, err = decodeUint16(b) + if err != nil { + return err + } + payloadLength := s.FixedHeader.RemainingLength - 2 + for payloadLength > 0 { + topic, err := decodeString(b) + if err != nil { + return err + } + s.Topics = append(s.Topics, topic) + qos, err := decodeByte(b) + if err != nil { + return err + } + s.Qoss = append(s.Qoss, qos) + payloadLength -= 2 + len(topic) + 1 //2 bytes of string length, plus string, plus 1 byte for Qos + } + + return nil +} + +//Details returns a Details struct containing the Qos and +//MessageID of this ControlPacket +func (s *SubscribePacket) Details() Details { + return Details{Qos: 1, MessageID: s.MessageID} +} diff --git a/vendor/github.com/eclipse/paho.mqtt.golang/packets/unsuback.go b/vendor/github.com/eclipse/paho.mqtt.golang/packets/unsuback.go new file mode 100644 index 0000000..4b40c27 --- /dev/null +++ b/vendor/github.com/eclipse/paho.mqtt.golang/packets/unsuback.go @@ -0,0 +1,45 @@ +package packets + +import ( + "fmt" + "io" +) + +//UnsubackPacket is an internal representation of the fields of the +//Unsuback MQTT packet +type UnsubackPacket struct { + FixedHeader + MessageID uint16 +} + +func (ua *UnsubackPacket) String() string { + str := fmt.Sprintf("%s", ua.FixedHeader) + str += " " + str += fmt.Sprintf("MessageID: %d", ua.MessageID) + return str +} + +func (ua *UnsubackPacket) Write(w io.Writer) error { + var err error + ua.FixedHeader.RemainingLength = 2 + packet := ua.FixedHeader.pack() + packet.Write(encodeUint16(ua.MessageID)) + _, err = packet.WriteTo(w) + + return err +} + +//Unpack decodes the details of a ControlPacket after the fixed +//header has been read +func (ua *UnsubackPacket) Unpack(b io.Reader) error { + var err error + ua.MessageID, err = decodeUint16(b) + + return err +} + +//Details returns a Details struct containing the Qos and +//MessageID of this ControlPacket +func (ua *UnsubackPacket) Details() Details { + return Details{Qos: 0, MessageID: ua.MessageID} +} diff --git a/vendor/github.com/eclipse/paho.mqtt.golang/packets/unsubscribe.go b/vendor/github.com/eclipse/paho.mqtt.golang/packets/unsubscribe.go new file mode 100644 index 0000000..2012c31 --- /dev/null +++ b/vendor/github.com/eclipse/paho.mqtt.golang/packets/unsubscribe.go @@ -0,0 +1,59 @@ +package packets + +import ( + "bytes" + "fmt" + "io" +) + +//UnsubscribePacket is an internal representation of the fields of the +//Unsubscribe MQTT packet +type UnsubscribePacket struct { + FixedHeader + MessageID uint16 + Topics []string +} + +func (u *UnsubscribePacket) String() string { + str := fmt.Sprintf("%s", u.FixedHeader) + str += " " + str += fmt.Sprintf("MessageID: %d", u.MessageID) + return str +} + +func (u *UnsubscribePacket) Write(w io.Writer) error { + var body bytes.Buffer + var err error + body.Write(encodeUint16(u.MessageID)) + for _, topic := range u.Topics { + body.Write(encodeString(topic)) + } + u.FixedHeader.RemainingLength = body.Len() + packet := u.FixedHeader.pack() + packet.Write(body.Bytes()) + _, err = packet.WriteTo(w) + + return err +} + +//Unpack decodes the details of a ControlPacket after the fixed +//header has been read +func (u *UnsubscribePacket) Unpack(b io.Reader) error { + var err error + u.MessageID, err = decodeUint16(b) + if err != nil { + return err + } + + for topic, err := decodeString(b); err == nil && topic != ""; topic, err = decodeString(b) { + u.Topics = append(u.Topics, topic) + } + + return err +} + +//Details returns a Details struct containing the Qos and +//MessageID of this ControlPacket +func (u *UnsubscribePacket) Details() Details { + return Details{Qos: 1, MessageID: u.MessageID} +} diff --git a/vendor/github.com/eclipse/paho.mqtt.golang/ping.go b/vendor/github.com/eclipse/paho.mqtt.golang/ping.go new file mode 100644 index 0000000..dcbcb1d --- /dev/null +++ b/vendor/github.com/eclipse/paho.mqtt.golang/ping.go @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2013 IBM Corp. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Seth Hoenig + * Allan Stockdill-Mander + * Mike Robertson + */ + +package mqtt + +import ( + "errors" + "sync/atomic" + "time" + + "github.com/eclipse/paho.mqtt.golang/packets" +) + +func keepalive(c *client) { + defer c.workers.Done() + DEBUG.Println(PNG, "keepalive starting") + var checkInterval int64 + var pingSent time.Time + + if c.options.KeepAlive > 10 { + checkInterval = 5 + } else { + checkInterval = c.options.KeepAlive / 2 + } + + intervalTicker := time.NewTicker(time.Duration(checkInterval * int64(time.Second))) + defer intervalTicker.Stop() + + for { + select { + case <-c.stop: + DEBUG.Println(PNG, "keepalive stopped") + return + case <-intervalTicker.C: + lastSent := c.lastSent.Load().(time.Time) + lastReceived := c.lastReceived.Load().(time.Time) + + DEBUG.Println(PNG, "ping check", time.Since(lastSent).Seconds()) + if time.Since(lastSent) >= time.Duration(c.options.KeepAlive*int64(time.Second)) || time.Since(lastReceived) >= time.Duration(c.options.KeepAlive*int64(time.Second)) { + if atomic.LoadInt32(&c.pingOutstanding) == 0 { + DEBUG.Println(PNG, "keepalive sending ping") + ping := packets.NewControlPacket(packets.Pingreq).(*packets.PingreqPacket) + //We don't want to wait behind large messages being sent, the Write call + //will block until it it able to send the packet. + atomic.StoreInt32(&c.pingOutstanding, 1) + ping.Write(c.conn) + c.lastSent.Store(time.Now()) + pingSent = time.Now() + } + } + if atomic.LoadInt32(&c.pingOutstanding) > 0 && time.Now().Sub(pingSent) >= c.options.PingTimeout { + CRITICAL.Println(PNG, "pingresp not received, disconnecting") + c.errors <- errors.New("pingresp not received, disconnecting") + return + } + } + } +} diff --git a/vendor/github.com/eclipse/paho.mqtt.golang/router.go b/vendor/github.com/eclipse/paho.mqtt.golang/router.go new file mode 100644 index 0000000..7b4e8f8 --- /dev/null +++ b/vendor/github.com/eclipse/paho.mqtt.golang/router.go @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2013 IBM Corp. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Seth Hoenig + * Allan Stockdill-Mander + * Mike Robertson + */ + +package mqtt + +import ( + "container/list" + "strings" + "sync" + + "github.com/eclipse/paho.mqtt.golang/packets" +) + +// route is a type which associates MQTT Topic strings with a +// callback to be executed upon the arrival of a message associated +// with a subscription to that topic. +type route struct { + topic string + callback MessageHandler +} + +// match takes a slice of strings which represent the route being tested having been split on '/' +// separators, and a slice of strings representing the topic string in the published message, similarly +// split. +// The function determines if the topic string matches the route according to the MQTT topic rules +// and returns a boolean of the outcome +func match(route []string, topic []string) bool { + if len(route) == 0 { + if len(topic) == 0 { + return true + } + return false + } + + if len(topic) == 0 { + if route[0] == "#" { + return true + } + return false + } + + if route[0] == "#" { + return true + } + + if (route[0] == "+") || (route[0] == topic[0]) { + return match(route[1:], topic[1:]) + } + return false +} + +func routeIncludesTopic(route, topic string) bool { + return match(routeSplit(route), strings.Split(topic, "/")) +} + +// removes $share and sharename when splitting the route to allow +// shared subscription routes to correctly match the topic +func routeSplit(route string) []string { + var result []string + if strings.HasPrefix(route, "$share") { + result = strings.Split(route, "/")[2:] + } else { + result = strings.Split(route, "/") + } + return result +} + +// match takes the topic string of the published message and does a basic compare to the +// string of the current Route, if they match it returns true +func (r *route) match(topic string) bool { + return r.topic == topic || routeIncludesTopic(r.topic, topic) +} + +type router struct { + sync.RWMutex + routes *list.List + defaultHandler MessageHandler + messages chan *packets.PublishPacket + stop chan bool +} + +// newRouter returns a new instance of a Router and channel which can be used to tell the Router +// to stop +func newRouter() (*router, chan bool) { + router := &router{routes: list.New(), messages: make(chan *packets.PublishPacket), stop: make(chan bool)} + stop := router.stop + return router, stop +} + +// addRoute takes a topic string and MessageHandler callback. It looks in the current list of +// routes to see if there is already a matching Route. If there is it replaces the current +// callback with the new one. If not it add a new entry to the list of Routes. +func (r *router) addRoute(topic string, callback MessageHandler) { + r.Lock() + defer r.Unlock() + for e := r.routes.Front(); e != nil; e = e.Next() { + if e.Value.(*route).match(topic) { + r := e.Value.(*route) + r.callback = callback + return + } + } + r.routes.PushBack(&route{topic: topic, callback: callback}) +} + +// deleteRoute takes a route string, looks for a matching Route in the list of Routes. If +// found it removes the Route from the list. +func (r *router) deleteRoute(topic string) { + r.Lock() + defer r.Unlock() + for e := r.routes.Front(); e != nil; e = e.Next() { + if e.Value.(*route).match(topic) { + r.routes.Remove(e) + return + } + } +} + +// setDefaultHandler assigns a default callback that will be called if no matching Route +// is found for an incoming Publish. +func (r *router) setDefaultHandler(handler MessageHandler) { + r.Lock() + defer r.Unlock() + r.defaultHandler = handler +} + +// matchAndDispatch takes a channel of Message pointers as input and starts a go routine that +// takes messages off the channel, matches them against the internal route list and calls the +// associated callback (or the defaultHandler, if one exists and no other route matched). If +// anything is sent down the stop channel the function will end. +func (r *router) matchAndDispatch(messages <-chan *packets.PublishPacket, order bool, client *client) { + go func() { + for { + select { + case message := <-messages: + sent := false + r.RLock() + m := messageFromPublish(message, client.ackFunc(message)) + handlers := []MessageHandler{} + for e := r.routes.Front(); e != nil; e = e.Next() { + if e.Value.(*route).match(message.TopicName) { + if order { + handlers = append(handlers, e.Value.(*route).callback) + } else { + hd := e.Value.(*route).callback + go func() { + hd(client, m) + m.Ack() + }() + } + sent = true + } + } + if !sent && r.defaultHandler != nil { + if order { + handlers = append(handlers, r.defaultHandler) + } else { + go func() { + r.defaultHandler(client, m) + m.Ack() + }() + } + } + r.RUnlock() + for _, handler := range handlers { + func() { + handler(client, m) + m.Ack() + }() + } + case <-r.stop: + return + } + } + }() +} diff --git a/vendor/github.com/eclipse/paho.mqtt.golang/store.go b/vendor/github.com/eclipse/paho.mqtt.golang/store.go new file mode 100644 index 0000000..24a76b7 --- /dev/null +++ b/vendor/github.com/eclipse/paho.mqtt.golang/store.go @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2013 IBM Corp. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Seth Hoenig + * Allan Stockdill-Mander + * Mike Robertson + */ + +package mqtt + +import ( + "fmt" + "strconv" + + "github.com/eclipse/paho.mqtt.golang/packets" +) + +const ( + inboundPrefix = "i." + outboundPrefix = "o." +) + +// Store is an interface which can be used to provide implementations +// for message persistence. +// Because we may have to store distinct messages with the same +// message ID, we need a unique key for each message. This is +// possible by prepending "i." or "o." to each message id +type Store interface { + Open() + Put(key string, message packets.ControlPacket) + Get(key string) packets.ControlPacket + All() []string + Del(key string) + Close() + Reset() +} + +// A key MUST have the form "X.[messageid]" +// where X is 'i' or 'o' +func mIDFromKey(key string) uint16 { + s := key[2:] + i, err := strconv.Atoi(s) + chkerr(err) + return uint16(i) +} + +// Return true if key prefix is outbound +func isKeyOutbound(key string) bool { + return key[:2] == outboundPrefix +} + +// Return true if key prefix is inbound +func isKeyInbound(key string) bool { + return key[:2] == inboundPrefix +} + +// Return a string of the form "i.[id]" +func inboundKeyFromMID(id uint16) string { + return fmt.Sprintf("%s%d", inboundPrefix, id) +} + +// Return a string of the form "o.[id]" +func outboundKeyFromMID(id uint16) string { + return fmt.Sprintf("%s%d", outboundPrefix, id) +} + +// govern which outgoing messages are persisted +func persistOutbound(s Store, m packets.ControlPacket) { + switch m.Details().Qos { + case 0: + switch m.(type) { + case *packets.PubackPacket, *packets.PubcompPacket: + // Sending puback. delete matching publish + // from ibound + s.Del(inboundKeyFromMID(m.Details().MessageID)) + } + case 1: + switch m.(type) { + case *packets.PublishPacket, *packets.PubrelPacket, *packets.SubscribePacket, *packets.UnsubscribePacket: + // Sending publish. store in obound + // until puback received + s.Put(outboundKeyFromMID(m.Details().MessageID), m) + default: + ERROR.Println(STR, "Asked to persist an invalid message type") + } + case 2: + switch m.(type) { + case *packets.PublishPacket: + // Sending publish. store in obound + // until pubrel received + s.Put(outboundKeyFromMID(m.Details().MessageID), m) + default: + ERROR.Println(STR, "Asked to persist an invalid message type") + } + } +} + +// govern which incoming messages are persisted +func persistInbound(s Store, m packets.ControlPacket) { + switch m.Details().Qos { + case 0: + switch m.(type) { + case *packets.PubackPacket, *packets.SubackPacket, *packets.UnsubackPacket, *packets.PubcompPacket: + // Received a puback. delete matching publish + // from obound + s.Del(outboundKeyFromMID(m.Details().MessageID)) + case *packets.PublishPacket, *packets.PubrecPacket, *packets.PingrespPacket, *packets.ConnackPacket: + default: + ERROR.Println(STR, "Asked to persist an invalid messages type") + } + case 1: + switch m.(type) { + case *packets.PublishPacket, *packets.PubrelPacket: + // Received a publish. store it in ibound + // until puback sent + s.Put(inboundKeyFromMID(m.Details().MessageID), m) + default: + ERROR.Println(STR, "Asked to persist an invalid messages type") + } + case 2: + switch m.(type) { + case *packets.PublishPacket: + // Received a publish. store it in ibound + // until pubrel received + s.Put(inboundKeyFromMID(m.Details().MessageID), m) + default: + ERROR.Println(STR, "Asked to persist an invalid messages type") + } + } +} diff --git a/vendor/github.com/eclipse/paho.mqtt.golang/token.go b/vendor/github.com/eclipse/paho.mqtt.golang/token.go new file mode 100644 index 0000000..0818553 --- /dev/null +++ b/vendor/github.com/eclipse/paho.mqtt.golang/token.go @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2014 IBM Corp. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Allan Stockdill-Mander + */ + +package mqtt + +import ( + "sync" + "time" + + "github.com/eclipse/paho.mqtt.golang/packets" +) + +// PacketAndToken is a struct that contains both a ControlPacket and a +// Token. This struct is passed via channels between the client interface +// code and the underlying code responsible for sending and receiving +// MQTT messages. +type PacketAndToken struct { + p packets.ControlPacket + t tokenCompletor +} + +// Token defines the interface for the tokens used to indicate when +// actions have completed. +type Token interface { + Wait() bool + WaitTimeout(time.Duration) bool + Error() error +} + +type TokenErrorSetter interface { + setError(error) +} + +type tokenCompletor interface { + Token + TokenErrorSetter + flowComplete() +} + +type baseToken struct { + m sync.RWMutex + complete chan struct{} + err error +} + +// Wait will wait indefinitely for the Token to complete, ie the Publish +// to be sent and confirmed receipt from the broker +func (b *baseToken) Wait() bool { + <-b.complete + return true +} + +// WaitTimeout takes a time.Duration to wait for the flow associated with the +// Token to complete, returns true if it returned before the timeout or +// returns false if the timeout occurred. In the case of a timeout the Token +// does not have an error set in case the caller wishes to wait again +func (b *baseToken) WaitTimeout(d time.Duration) bool { + b.m.Lock() + defer b.m.Unlock() + + timer := time.NewTimer(d) + select { + case <-b.complete: + if !timer.Stop() { + <-timer.C + } + return true + case <-timer.C: + } + + return false +} + +func (b *baseToken) flowComplete() { + select { + case <-b.complete: + default: + close(b.complete) + } +} + +func (b *baseToken) Error() error { + b.m.RLock() + defer b.m.RUnlock() + return b.err +} + +func (b *baseToken) setError(e error) { + b.m.Lock() + b.err = e + b.flowComplete() + b.m.Unlock() +} + +func newToken(tType byte) tokenCompletor { + switch tType { + case packets.Connect: + return &ConnectToken{baseToken: baseToken{complete: make(chan struct{})}} + case packets.Subscribe: + return &SubscribeToken{baseToken: baseToken{complete: make(chan struct{})}, subResult: make(map[string]byte)} + case packets.Publish: + return &PublishToken{baseToken: baseToken{complete: make(chan struct{})}} + case packets.Unsubscribe: + return &UnsubscribeToken{baseToken: baseToken{complete: make(chan struct{})}} + case packets.Disconnect: + return &DisconnectToken{baseToken: baseToken{complete: make(chan struct{})}} + } + return nil +} + +// ConnectToken is an extension of Token containing the extra fields +// required to provide information about calls to Connect() +type ConnectToken struct { + baseToken + returnCode byte + sessionPresent bool +} + +// ReturnCode returns the acknowlegement code in the connack sent +// in response to a Connect() +func (c *ConnectToken) ReturnCode() byte { + c.m.RLock() + defer c.m.RUnlock() + return c.returnCode +} + +// SessionPresent returns a bool representing the value of the +// session present field in the connack sent in response to a Connect() +func (c *ConnectToken) SessionPresent() bool { + c.m.RLock() + defer c.m.RUnlock() + return c.sessionPresent +} + +// PublishToken is an extension of Token containing the extra fields +// required to provide information about calls to Publish() +type PublishToken struct { + baseToken + messageID uint16 +} + +// MessageID returns the MQTT message ID that was assigned to the +// Publish packet when it was sent to the broker +func (p *PublishToken) MessageID() uint16 { + return p.messageID +} + +// SubscribeToken is an extension of Token containing the extra fields +// required to provide information about calls to Subscribe() +type SubscribeToken struct { + baseToken + subs []string + subResult map[string]byte +} + +// Result returns a map of topics that were subscribed to along with +// the matching return code from the broker. This is either the Qos +// value of the subscription or an error code. +func (s *SubscribeToken) Result() map[string]byte { + s.m.RLock() + defer s.m.RUnlock() + return s.subResult +} + +// UnsubscribeToken is an extension of Token containing the extra fields +// required to provide information about calls to Unsubscribe() +type UnsubscribeToken struct { + baseToken +} + +// DisconnectToken is an extension of Token containing the extra fields +// required to provide information about calls to Disconnect() +type DisconnectToken struct { + baseToken +} diff --git a/vendor/github.com/eclipse/paho.mqtt.golang/topic.go b/vendor/github.com/eclipse/paho.mqtt.golang/topic.go new file mode 100644 index 0000000..6fa3ad2 --- /dev/null +++ b/vendor/github.com/eclipse/paho.mqtt.golang/topic.go @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2014 IBM Corp. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Seth Hoenig + * Allan Stockdill-Mander + * Mike Robertson + */ + +package mqtt + +import ( + "errors" + "strings" +) + +//ErrInvalidQos is the error returned when an packet is to be sent +//with an invalid Qos value +var ErrInvalidQos = errors.New("Invalid QoS") + +//ErrInvalidTopicEmptyString is the error returned when a topic string +//is passed in that is 0 length +var ErrInvalidTopicEmptyString = errors.New("Invalid Topic; empty string") + +//ErrInvalidTopicMultilevel is the error returned when a topic string +//is passed in that has the multi level wildcard in any position but +//the last +var ErrInvalidTopicMultilevel = errors.New("Invalid Topic; multi-level wildcard must be last level") + +// Topic Names and Topic Filters +// The MQTT v3.1.1 spec clarifies a number of ambiguities with regard +// to the validity of Topic strings. +// - A Topic must be between 1 and 65535 bytes. +// - A Topic is case sensitive. +// - A Topic may contain whitespace. +// - A Topic containing a leading forward slash is different than a Topic without. +// - A Topic may be "/" (two levels, both empty string). +// - A Topic must be UTF-8 encoded. +// - A Topic may contain any number of levels. +// - A Topic may contain an empty level (two forward slashes in a row). +// - A TopicName may not contain a wildcard. +// - A TopicFilter may only have a # (multi-level) wildcard as the last level. +// - A TopicFilter may contain any number of + (single-level) wildcards. +// - A TopicFilter with a # will match the absense of a level +// Example: a subscription to "foo/#" will match messages published to "foo". + +func validateSubscribeMap(subs map[string]byte) ([]string, []byte, error) { + var topics []string + var qoss []byte + for topic, qos := range subs { + if err := validateTopicAndQos(topic, qos); err != nil { + return nil, nil, err + } + topics = append(topics, topic) + qoss = append(qoss, qos) + } + + return topics, qoss, nil +} + +func validateTopicAndQos(topic string, qos byte) error { + if len(topic) == 0 { + return ErrInvalidTopicEmptyString + } + + levels := strings.Split(topic, "/") + for i, level := range levels { + if level == "#" && i != len(levels)-1 { + return ErrInvalidTopicMultilevel + } + } + + if qos < 0 || qos > 2 { + return ErrInvalidQos + } + return nil +} diff --git a/vendor/github.com/eclipse/paho.mqtt.golang/trace.go b/vendor/github.com/eclipse/paho.mqtt.golang/trace.go new file mode 100644 index 0000000..195c817 --- /dev/null +++ b/vendor/github.com/eclipse/paho.mqtt.golang/trace.go @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2013 IBM Corp. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Seth Hoenig + * Allan Stockdill-Mander + * Mike Robertson + */ + +package mqtt + +type ( + // Logger interface allows implementations to provide to this package any + // object that implements the methods defined in it. + Logger interface { + Println(v ...interface{}) + Printf(format string, v ...interface{}) + } + + // NOOPLogger implements the logger that does not perform any operation + // by default. This allows us to efficiently discard the unwanted messages. + NOOPLogger struct{} +) + +func (NOOPLogger) Println(v ...interface{}) {} +func (NOOPLogger) Printf(format string, v ...interface{}) {} + +// Internal levels of library output that are initialised to not print +// anything but can be overridden by programmer +var ( + ERROR Logger = NOOPLogger{} + CRITICAL Logger = NOOPLogger{} + WARN Logger = NOOPLogger{} + DEBUG Logger = NOOPLogger{} +) diff --git a/vendor/gocv.io/x/gocv/.astylerc b/vendor/gocv.io/x/gocv/.astylerc new file mode 100644 index 0000000..e05f9df --- /dev/null +++ b/vendor/gocv.io/x/gocv/.astylerc @@ -0,0 +1,28 @@ +--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 diff --git a/vendor/gocv.io/x/gocv/.dockerignore b/vendor/gocv.io/x/gocv/.dockerignore new file mode 100644 index 0000000..1d085ca --- /dev/null +++ b/vendor/gocv.io/x/gocv/.dockerignore @@ -0,0 +1 @@ +** diff --git a/vendor/gocv.io/x/gocv/.gitignore b/vendor/gocv.io/x/gocv/.gitignore new file mode 100644 index 0000000..9e3a6e0 --- /dev/null +++ b/vendor/gocv.io/x/gocv/.gitignore @@ -0,0 +1,10 @@ +profile.cov +count.out +*.swp +*.snap +/parts +/prime +/stage +.vscode/ +/build +.idea/ diff --git a/vendor/gocv.io/x/gocv/.travis.yml b/vendor/gocv.io/x/gocv/.travis.yml new file mode 100644 index 0000000..5030bb0 --- /dev/null +++ b/vendor/gocv.io/x/gocv/.travis.yml @@ -0,0 +1,60 @@ +# Use new container infrastructure to enable caching +sudo: required +dist: trusty + +# language is go +language: go +go: + - "1.13" +go_import_path: gocv.io/x/gocv + +addons: + apt: + packages: + - libgmp-dev + - build-essential + - cmake + - git + - libgtk2.0-dev + - pkg-config + - libavcodec-dev + - libavformat-dev + - libswscale-dev + - libtbb2 + - libtbb-dev + - libjpeg-dev + - libpng-dev + - libtiff-dev + - libjasper-dev + - libdc1394-22-dev + - xvfb + +before_install: + - ./travis_build_opencv.sh + - export PKG_CONFIG_PATH=$(pkg-config --variable pc_path pkg-config):$HOME/usr/lib/pkgconfig + - export INCLUDE_PATH=$HOME/usr/include:${INCLUDE_PATH} + - export LD_LIBRARY_PATH=$HOME/usr/lib:${LD_LIBRARY_PATH} + - sudo ln /dev/null /dev/raw1394 + - export DISPLAY=:99.0 + - sh -e /etc/init.d/xvfb start + +before_cache: + - rm -f $HOME/fresh-cache + +script: + - export GOCV_CAFFE_TEST_FILES="${HOME}/testdata" + - export GOCV_TENSORFLOW_TEST_FILES="${HOME}/testdata" + - export OPENCV_ENABLE_NONFREE=ON + - echo "Ensuring code is well formatted"; ! gofmt -s -d . | read + - go test -v -coverprofile=coverage.txt -covermode=atomic -tags matprofile . + - go test -tags matprofile ./contrib -coverprofile=contrib.txt -covermode=atomic; cat contrib.txt >> coverage.txt; rm contrib.txt; + +after_success: + - bash <(curl -s https://codecov.io/bash) + +# Caching so the next build will be fast as possible. +cache: + timeout: 1000 + directories: + - $HOME/usr + - $HOME/testdata diff --git a/vendor/gocv.io/x/gocv/CHANGELOG.md b/vendor/gocv.io/x/gocv/CHANGELOG.md new file mode 100644 index 0000000..439b6d0 --- /dev/null +++ b/vendor/gocv.io/x/gocv/CHANGELOG.md @@ -0,0 +1,675 @@ +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 \ No newline at end of file diff --git a/vendor/gocv.io/x/gocv/CONTRIBUTING.md b/vendor/gocv.io/x/gocv/CONTRIBUTING.md new file mode 100644 index 0000000..3d1ae54 --- /dev/null +++ b/vendor/gocv.io/x/gocv/CONTRIBUTING.md @@ -0,0 +1,136 @@ +# 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 `master` 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 `CoCV`. 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`. diff --git a/vendor/gocv.io/x/gocv/Dockerfile b/vendor/gocv.io/x/gocv/Dockerfile new file mode 100644 index 0000000..f51e9f2 --- /dev/null +++ b/vendor/gocv.io/x/gocv/Dockerfile @@ -0,0 +1,60 @@ +FROM ubuntu:16.04 AS opencv +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 libtbb2 libtbb-dev \ + libjpeg-dev libpng-dev libtiff-dev libdc1394-22-dev && \ + rm -rf /var/lib/apt/lists/* + +ARG OPENCV_VERSION="4.0.1" +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 CMAKE_INSTALL_PREFIX=/usr/local \ + -D OPENCV_EXTRA_MODULES_PATH=../../opencv_contrib-${OPENCV_VERSION}/modules \ + -D WITH_JASPER=OFF \ + -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 --all) && \ + make preinstall && make install && ldconfig && \ + cd / && rm -rf opencv* + +################# +# Go + OpenCV # +################# +FROM opencv AS gocv +LABEL maintainer="hybridgroup" + +ARG GOVERSION="1.11.2" +ENV GOVERSION $GOVERSION + +RUN apt-get update && apt-get install -y --no-install-recommends \ + git software-properties-common && \ + curl -Lo go${GOVERSION}.linux-amd64.tar.gz https://dl.google.com/go/go${GOVERSION}.linux-amd64.tar.gz && \ + tar -C /usr/local -xzf go${GOVERSION}.linux-amd64.tar.gz && \ + rm go${GOVERSION}.linux-amd64.tar.gz && \ + rm -rf /var/lib/apt/lists/* + +ENV GOPATH /go +ENV PATH $GOPATH/bin:/usr/local/go/bin:$PATH + +RUN mkdir -p "$GOPATH/src" "$GOPATH/bin" && chmod -R 777 "$GOPATH" +WORKDIR $GOPATH + +RUN go get -u -d gocv.io/x/gocv && go run ${GOPATH}/src/gocv.io/x/gocv/cmd/version/main.go diff --git a/vendor/gocv.io/x/gocv/LICENSE.txt b/vendor/gocv.io/x/gocv/LICENSE.txt new file mode 100644 index 0000000..b68c83e --- /dev/null +++ b/vendor/gocv.io/x/gocv/LICENSE.txt @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright (c) 2017-2019 The Hybrid Group + +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. diff --git a/vendor/gocv.io/x/gocv/Makefile b/vendor/gocv.io/x/gocv/Makefile new file mode 100644 index 0000000..865e8c7 --- /dev/null +++ b/vendor/gocv.io/x/gocv/Makefile @@ -0,0 +1,138 @@ +.ONESHELL: +.PHONY: test deps download build clean astyle cmds docker + +# OpenCV version to use. +OPENCV_VERSION?=4.1.2 + +# Go version to use when building Docker image +GOVERSION?=1.13.1 + +# Temporary directory to put files into. +TMP_DIR?=/tmp/ + +# Package list for each well-known Linux distribution +RPMS=cmake curl git gtk2-devel libpng-devel libjpeg-devel libtiff-devel tbb tbb-devel libdc1394-devel unzip +DEBS=unzip 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 + +# Detect Linux distribution +distro_deps= +ifneq ($(shell which dnf 2>/dev/null),) + distro_deps=deps_fedora +else +ifneq ($(shell which apt-get 2>/dev/null),) + distro_deps=deps_debian +else +ifneq ($(shell which yum 2>/dev/null),) + distro_deps=deps_rh_centos +endif +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: + sudo apt-get -y update + sudo apt-get -y install $(DEBS) + + +# 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/$(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 - + +# Build OpenCV. +build: + cd $(TMP_DIR)opencv/opencv-$(OPENCV_VERSION) + mkdir build + cd build + cmake -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX=/usr/local -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=OFF -D BUILD_opencv_java=NO -D BUILD_opencv_python=NO -D BUILD_opencv_python2=NO -D BUILD_opencv_python3=NO -D WITH_JASPER=OFF -DOPENCV_GENERATE_PKGCONFIG=ON .. + $(MAKE) -j $(shell nproc --all) + $(MAKE) preinstall + cd - + +# Build OpenCV on Raspbian with ARM hardware optimizations. +build_raspi: + cd $(TMP_DIR)opencv/opencv-$(OPENCV_VERSION) + mkdir build + cd build + cmake -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX=/usr/local -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=OFF -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 .. + $(MAKE) -j $(shell nproc --all) + $(MAKE) preinstall + cd - + +# Build OpenCV with non-free contrib modules. +build_nonfree: + cd $(TMP_DIR)opencv/opencv-$(OPENCV_VERSION) + mkdir build + cd build + cmake -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX=/usr/local -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=OFF -D BUILD_opencv_java=NO -D BUILD_opencv_python=NO -D BUILD_opencv_python2=NO -D BUILD_opencv_python3=NO -D WITH_JASPER=OFF -DOPENCV_GENERATE_PKGCONFIG=ON -DOPENCV_ENABLE_NONFREE=ON .. + $(MAKE) -j $(shell nproc --all) + $(MAKE) preinstall + cd - + +# Build OpenCV with cuda. +build_cuda: + cd $(TMP_DIR)opencv/opencv-$(OPENCV_VERSION) + mkdir build + cd build + cmake -j $(shell nproc --all) -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX=/usr/local -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=OFF -D BUILD_opencv_java=NO -D BUILD_opencv_python=NO -D BUILD_opencv_python2=NO -D BUILD_opencv_python3=NO -D WITH_JASPER=OFF -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 .. + $(MAKE) -j $(shell nproc --all) + $(MAKE) preinstall + cd - + +# Cleanup temporary build files. +clean: + go clean --cache + rm -rf $(TMP_DIR)opencv + +# Do everything. +install: deps download build sudo_install clean verify + +# Do everything on Raspbian. +install_raspi: deps download build_raspi sudo_install clean verify + +# Do everything with cuda. +install_cuda: deps download build_cuda sudo_install clean verify + +# Install system wide. +sudo_install: + cd $(TMP_DIR)opencv/opencv-$(OPENCV_VERSION)/build + sudo $(MAKE) install + sudo ldconfig + cd - + +# Build a minimal Go app to confirm gocv works. +verify: + go run ./cmd/version/main.go + +# Runs tests. +# This assumes env.sh was already sourced. +# pvt is not tested here since it requires additional depenedences. +test: + go test . ./contrib + +docker: + docker build --build-arg OPENCV_VERSION=$(OPENCV_VERSION) --build-arg GOVERSION=$(GOVERSION) . + +astyle: + astyle --project=.astylerc --recursive *.cpp,*.h + +CMDS=basic-drawing caffe-classifier captest capwindow counter faceblur facedetect find-circles hand-gestures img-similarity mjpeg-streamer motion-detect pose saveimage savevideo showimage ssd-facedetect tf-classifier tracking version +cmds: + for cmd in $(CMDS) ; do \ + go build -o build/$$cmd cmd/$$cmd/main.go ; + done ; \ diff --git a/vendor/gocv.io/x/gocv/README.md b/vendor/gocv.io/x/gocv/README.md new file mode 100644 index 0000000..be63e22 --- /dev/null +++ b/vendor/gocv.io/x/gocv/README.md @@ -0,0 +1,565 @@ +# GoCV + +[![GoCV](https://raw.githubusercontent.com/hybridgroup/gocv/master/images/gocvlogo.jpg)](http://gocv.io/) + +[![GoDoc](https://godoc.org/gocv.io/x/gocv?status.svg)](https://godoc.org/github.com/hybridgroup/gocv) +[![Travis Build Status](https://travis-ci.org/hybridgroup/gocv.svg?branch=dev)](https://travis-ci.org/hybridgroup/gocv) +[![AppVeyor Build status](https://ci.appveyor.com/api/projects/status/9asd5foet54ru69q/branch/dev?svg=true)](https://ci.appveyor.com/project/deadprogram/gocv/branch/dev) +[![codecov](https://codecov.io/gh/hybridgroup/gocv/branch/dev/graph/badge.svg)](https://codecov.io/gh/hybridgroup/gocv) +[![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/master/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.1.2) on Linux, macOS, and Windows. We intend to make the Go language a "first-class" client compatible with the latest developments in the OpenCV ecosystem. + +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/master/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 Tensorflow for object classification](./cmd/tf-classifier). + +## How to install + +To install GoCV, run the following command: + +``` +go get -u -d gocv.io/x/gocv +``` + +To run code that uses the GoCV package, you must also install OpenCV 4.0.0 on your system. Here are instructions for Ubuntu, Raspian, macOS, and Windows. + +## Ubuntu/Linux + +### Installation + +You can use `make` to install OpenCV 4.1.2 with the handy `Makefile` included with this repo. If you already have installed OpenCV, you do not need to do so again. The installation performed by the `Makefile` is minimal, so it may remove OpenCV options such as Python or Java wrappers if you have already installed OpenCV some other way. + +#### Quick Install + +The following commands should do everything to download and install OpenCV 4.1.2 on Linux: + + cd $GOPATH/src/gocv.io/x/gocv + make install + +If it works correctly, at the end of the entire process, the following message should be displayed: + + gocv version: 0.21.0 + opencv lib version: 4.1.2 + +That's it, now you are ready to use GoCV. + +#### Complete Install + +If you have already done the "Quick Install" as described above, you do not need to run any further commands. For the curious, or for custom installations, here are the details for each of the steps that are performed when you run `make install`. + +##### Install required packages + +First, you need to change the current directory to the location of the GoCV repo, so you can access the `Makefile`: + + cd $GOPATH/src/gocv.io/x/gocv + +Next, you need to update the system, and install any required packages: + + make deps + +#### Download source + +Now, download the OpenCV 4.1.2 and OpenCV Contrib source code: + + make download + +#### Build + +Build everything. This will take quite a while: + + make build + +#### Install + +Once the code is built, you are ready to install: + + make sudo_install + +### Verifying the installation + +To verify your installation you can run one of the included examples. + +First, change the current directory to the location of the GoCV repo: + + cd $GOPATH/src/gocv.io/x/gocv + +Now you should be able to build or run any of the examples: + + go run ./cmd/version/main.go + +The version program should output the following: + + gocv version: 0.21.0 + opencv lib version: 4.1.2 + +#### Cleanup extra files + +After the installation is complete, you can remove the extra files and folders: + + make clean + +### Cache builds + +If you are running a version of Go older than v1.10 and not modifying GoCV source, precompile the GoCV package to significantly decrease your build times: + + go install gocv.io/x/gocv + +### Custom Environment + +By default, pkg-config is used to determine the correct flags for compiling and linking OpenCV. This behavior can be disabled by supplying `-tags customenv` when building/running your application. When building with this tag you will need to supply the CGO environment variables yourself. + +For example: + + export CGO_CPPFLAGS="-I/usr/local/include" + export CGO_LDFLAGS="-L/usr/local/lib -lopencv_core -lopencv_face -lopencv_videoio -lopencv_imgproc -lopencv_highgui -lopencv_imgcodecs -lopencv_objdetect -lopencv_features2d -lopencv_video -lopencv_dnn -lopencv_xfeatures2d" + +Please note that you will need to run these 2 lines of code one time in your current session in order to build or run the code, in order to setup the needed ENV variables. Once you have done so, you can execute code that uses GoCV with your custom environment like this: + + go run -tags customenv ./cmd/version/main.go + +### Docker + +The project now provides `Dockerfile` which lets you build [GoCV](https://gocv.io/) Docker image which you can then use to build and run `GoCV` applications in Docker containers. The `Makefile` contains `docker` target which lets you build Docker image with a single command: + +``` +make docker +``` + +By default Docker image built by running the command above ships [Go](https://golang.org/) version `1.11.2`, but if you would like to build an image which uses different version of `Go` you can override the default value when running the target command: + +``` +make docker GOVERSION='1.11.1' +``` + +#### Running GUI programs in Docker on macOS + +Sometimes your `GoCV` programs create graphical interfaces like windows eg. when you use `gocv.Window` type when you display an image or video stream. Running the programs which create graphical interfaces in Docker container on macOS is unfortunately a bit elaborate, but not impossible. First you need to satisfy the following prerequisites: +* install [xquartz](https://www.xquartz.org/). You can also install xquartz using [homebrew](https://brew.sh/) by running `brew cask install xquartz` +* install [socat](https://linux.die.net/man/1/socat) `brew install socat` + +Note, you will have to log out and log back in to your machine once you have installed `xquartz`. This is so the X window system is reloaded. + +Once you have installed all the prerequisites you need to allow connections from network clients to `xquartz`. Here is how you do that. First run the following command to open `xquart` so you can configure it: + +```shell +open -a xquartz +``` +Click on *Security* tab in preferences and check the "Allow connections" box: + +![app image](./images/xquartz.png) + +Next, you need to create a TCP proxy using `socat` which will stream [X Window](https://en.wikipedia.org/wiki/X_Window_System) data into `xquart`. Before you start the proxy you need to make sure that there is no process listening in port `6000`. The following command should **not** return any results: + +```shell +lsof -i TCP:6000 +``` +Now you can start a local proxy which will proxy the X Window traffic into xquartz which acts a your local X server: + +```shell +socat TCP-LISTEN:6000,reuseaddr,fork UNIX-CLIENT:\"$DISPLAY\" +``` + +You are now finally ready to run your `GoCV` GUI programs in Docker containers. In order to make everything work you must set `DISPLAY` environment variables as shown in a sample command below: + +```shell +docker run -it --rm -e DISPLAY=docker.for.mac.host.internal:0 your-gocv-app +``` + +**Note, since Docker for MacOS does not provide any video device support, you won't be able run GoCV apps which require camera.** + +### Alpine 3.7 Docker image + +There is a Docker image with Alpine 3.7 that has been created by project contributor [@denismakogon](https://github.com/denismakogon). You can find it located at [https://github.com/denismakogon/gocv-alpine](https://github.com/denismakogon/gocv-alpine). + +## Raspbian + +### Installation + +We have a special installation for the Raspberry Pi that includes some hardware optimizations. You use `make` to install OpenCV 4.1.2 with the handy `Makefile` included with this repo. If you already have installed OpenCV, you do not need to do so again. The installation performed by the `Makefile` is minimal, so it may remove OpenCV options such as Python or Java wrappers if you have already installed OpenCV some other way. + +#### Quick Install + +The following commands should do everything to download and install OpenCV 4.1.2 on Raspbian: + + cd $GOPATH/src/gocv.io/x/gocv + make install_raspi + +If it works correctly, at the end of the entire process, the following message should be displayed: + + gocv version: 0.21.0 + opencv lib version: 4.1.2 + +That's it, now you are ready to use GoCV. + +## macOS + +### Installation + +You can install OpenCV 4.1.2 using Homebrew. + +If you already have an earlier version of OpenCV (3.4.x) installed, you should probably remove it before installing the new version: + + brew uninstall opencv + +You can then install OpenCV 4.1.2: + + brew install opencv + +If you prefer, there is also an alternative Homebrew recipe will install only OpenCV 4.1.2 without all of the Python dependencies: + + brew install hybridgroup/tools/opencv + +NOTE: Do not install both of these. Choose one. + +### pkgconfig Installation +pkg-config is used to determine the correct flags for compiling and linking OpenCV. +You can install it by using Homebrew: + + brew install pkgconfig + +### Verifying the installation + +To verify your installation you can run one of the included examples. + +First, change the current directory to the location of the GoCV repo: + + cd $GOPATH/src/gocv.io/x/gocv + +Now you should be able to build or run any of the examples: + + go run ./cmd/version/main.go + +The version program should output the following: + + gocv version: 0.21.0 + opencv lib version: 4.1.2 + +### Cache builds + +If you are running a version of Go older than v1.10 and not modifying GoCV source, precompile the GoCV package to significantly decrease your build times: + + go install gocv.io/x/gocv + +### Custom Environment + +By default, pkg-config is used to determine the correct flags for compiling and linking OpenCV. This behavior can be disabled by supplying `-tags customenv` when building/running your application. When building with this tag you will need to supply the CGO environment variables yourself. + +For example: + + export CGO_CXXFLAGS="--std=c++11" + export CGO_CPPFLAGS="-I/usr/local/Cellar/opencv/4.1.2/include" + export CGO_LDFLAGS="-L/usr/local/Cellar/opencv/4.1.2/lib -lopencv_stitching -lopencv_superres -lopencv_videostab -lopencv_aruco -lopencv_bgsegm -lopencv_bioinspired -lopencv_ccalib -lopencv_dnn_objdetect -lopencv_dpm -lopencv_face -lopencv_photo -lopencv_fuzzy -lopencv_hfs -lopencv_img_hash -lopencv_line_descriptor -lopencv_optflow -lopencv_reg -lopencv_rgbd -lopencv_saliency -lopencv_stereo -lopencv_structured_light -lopencv_phase_unwrapping -lopencv_surface_matching -lopencv_tracking -lopencv_datasets -lopencv_dnn -lopencv_plot -lopencv_xfeatures2d -lopencv_shape -lopencv_video -lopencv_ml -lopencv_ximgproc -lopencv_calib3d -lopencv_features2d -lopencv_highgui -lopencv_videoio -lopencv_flann -lopencv_xobjdetect -lopencv_imgcodecs -lopencv_objdetect -lopencv_xphoto -lopencv_imgproc -lopencv_core" + +Please note that you will need to run these 3 lines of code one time in your current session in order to build or run the code, in order to setup the needed ENV variables. Once you have done so, you can execute code that uses GoCV with your custom environment like this: + + go run -tags customenv ./cmd/version/main.go + +## Windows + +### Installation + +The following assumes that you are running a 64-bit version of Windows 10. + +In order to build and install OpenCV 4.1.2 on Windows, you must first download and install MinGW-W64 and CMake, as follows. + +#### MinGW-W64 + +Download and run the MinGW-W64 compiler installer from [https://sourceforge.net/projects/mingw-w64/?source=typ_redirect](https://sourceforge.net/projects/mingw-w64/?source=typ_redirect). + +The latest version of the MinGW-W64 toolchain is `7.3.0`, but any version from `7.X` on should work. + +Choose the options for "posix" threads, and for "seh" exceptions handling, then install to the default location `c:\Program Files\mingw-w64\x86_64-7.3.0-posix-seh-rt_v5-rev2`. + +Add the `C:\Program Files\mingw-w64\x86_64-7.3.0-posix-seh-rt_v5-rev2\mingw64\bin` path to your System Path. + +#### CMake + +Download and install CMake [https://cmake.org/download/](https://cmake.org/download/) to the default location. CMake installer will add CMake to your system path. + +#### OpenCV 4.1.2 and OpenCV Contrib Modules + +The following commands should do everything to download and install OpenCV 4.1.2 on Windows: + + chdir %GOPATH%\src\gocv.io\x\gocv + win_build_opencv.cmd + +It might take up to one hour. + +Last, add `C:\opencv\build\install\x64\mingw\bin` to your System Path. + +### Verifying the installation + +Change the current directory to the location of the GoCV repo: + + chdir %GOPATH%\src\gocv.io\x\gocv + +Now you should be able to build or run any of the command examples: + + go run cmd\version\main.go + +The version program should output the following: + + gocv version: 0.21.0 + opencv lib version: 4.1.2 + +That's it, now you are ready to use GoCV. + +### Cache builds + +If you are running a version of Go older than v1.10 and not modifying GoCV source, precompile the GoCV package to significantly decrease your build times: + + go install gocv.io/x/gocv + +### Custom Environment + +By default, OpenCV is expected to be in `C:\opencv\build\install\include`. This behavior can be disabled by supplying `-tags customenv` when building/running your application. When building with this tag you will need to supply the CGO environment variables yourself. + +Due to the way OpenCV produces DLLs, including the version in the name, using this method is required if you're using a different version of OpenCV. + +For example: + + set CGO_CXXFLAGS="--std=c++11" + set CGO_CPPFLAGS=-IC:\opencv\build\install\include + set CGO_LDFLAGS=-LC:\opencv\build\install\x64\mingw\lib -lopencv_core412 -lopencv_face412 -lopencv_videoio412 -lopencv_imgproc412 -lopencv_highgui412 -lopencv_imgcodecs412 -lopencv_objdetect412 -lopencv_features2d412 -lopencv_video412 -lopencv_dnn412 -lopencv_xfeatures2d412 -lopencv_plot412 -lopencv_tracking412 -lopencv_img_hash412 + +Please note that you will need to run these 3 lines of code one time in your current session in order to build or run the code, in order to setup the needed ENV variables. Once you have done so, you can execute code that uses GoCV with your custom environment like this: + + go run -tags customenv cmd\version\main.go + +## 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/c19458cf64bd3e91faae85c3ac887481 + +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 does 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-2019 The Hybrid Group. + +Logo generated by GopherizeMe - https://gopherize.me diff --git a/vendor/gocv.io/x/gocv/ROADMAP.md b/vendor/gocv.io/x/gocv/ROADMAP.md new file mode 100644 index 0000000..4a8a6a4 --- /dev/null +++ b/vendor/gocv.io/x/gocv/ROADMAP.md @@ -0,0 +1,209 @@ +# 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** + - [ ] **Basic structures - WORK STARTED** + - [ ] **Operations on arrays - WORK STARTED**. The following functions still need implementation: + - [ ] [Mahalanobis](https://docs.opencv.org/master/d2/de8/group__core__array.html#ga4493aee129179459cbfc6064f051aa7d) + - [ ] [mixChannels](https://docs.opencv.org/master/d2/de8/group__core__array.html#ga51d768c270a1cdd3497255017c4504be) + - [ ] [mulTransposed](https://docs.opencv.org/master/d2/de8/group__core__array.html#gadc4e49f8f7a155044e3be1b9e3b270ab) + - [ ] [PCABackProject](https://docs.opencv.org/master/d2/de8/group__core__array.html#gab26049f30ee8e94f7d69d82c124faafc) + - [ ] [PCACompute](https://docs.opencv.org/master/d2/de8/group__core__array.html#ga4e2073c7311f292a0648f04c37b73781) + - [ ] [PCAProject](https://docs.opencv.org/master/d2/de8/group__core__array.html#ga6b9fbc7b3a99ebfd441bbec0a6bc4f88) + - [ ] [PSNR](https://docs.opencv.org/master/d2/de8/group__core__array.html#ga07aaf34ae31d226b1b847d8bcff3698f) + - [ ] [randn](https://docs.opencv.org/master/d2/de8/group__core__array.html#gaeff1f61e972d133a04ce3a5f81cf6808) + - [ ] [randShuffle](https://docs.opencv.org/master/d2/de8/group__core__array.html#ga6a789c8a5cb56c6dd62506179808f763) + - [ ] [randu](https://docs.opencv.org/master/d2/de8/group__core__array.html#ga1ba1026dca0807b27057ba6a49d258c0) + - [ ] [scaleAdd](https://docs.opencv.org/master/d2/de8/group__core__array.html#ga9e0845db4135f55dcf20227402f00d98) + - [ ] [setIdentity](https://docs.opencv.org/master/d2/de8/group__core__array.html#ga388d7575224a4a277ceb98ccaa327c99) + - [ ] [setRNGSeed](https://docs.opencv.org/master/d2/de8/group__core__array.html#ga757e657c037410d9e19e819569e7de0f) + - [ ] [SVBackSubst](https://docs.opencv.org/master/d2/de8/group__core__array.html#gab4e620e6fc6c8a27bb2be3d50a840c0b) + - [ ] [SVDecomp](https://docs.opencv.org/master/d2/de8/group__core__array.html#gab477b5b7b39b370bb03e75b19d2d5109) + - [ ] [theRNG](https://docs.opencv.org/master/d2/de8/group__core__array.html#ga75843061d150ad6564b5447e38e57722) + - [ ] XML/YAML Persistence + - [ ] **Clustering - WORK STARTED**. The following functions still need implementation: + - [ ] [partition](https://docs.opencv.org/master/d5/d38/group__core__cluster.html#ga2037c989e69b499c1aa271419f3a9b34) + + - [ ] Utility and system functions and macros + - [ ] OpenGL interoperability + - [ ] Intel IPP Asynchronous C/C++ Converters + - [ ] Optimization Algorithms + - [ ] OpenCL support + +- [ ] **imgproc. Image processing - WORK STARTED** + - [ ] **Image Filtering - WORK STARTED** The following functions still need implementation: + - [ ] [buildPyramid](https://docs.opencv.org/master/d4/d86/group__imgproc__filter.html#gacfdda2bc1ac55e96de7e9f0bce7238c0) + - [ ] [getDerivKernels](https://docs.opencv.org/master/d4/d86/group__imgproc__filter.html#ga6d6c23f7bd3f5836c31cfae994fc4aea) + - [ ] [getGaborKernel](https://docs.opencv.org/master/d4/d86/group__imgproc__filter.html#gae84c92d248183bd92fa713ce51cc3599) + - [ ] [getGaussianKernel](https://docs.opencv.org/master/d4/d86/group__imgproc__filter.html#gac05a120c1ae92a6060dd0db190a61afa) + - [ ] [morphologyExWithParams](https://docs.opencv.org/master/d4/d86/group__imgproc__filter.html#ga67493776e3ad1a3df63883829375201f) + - [ ] [pyrMeanShiftFiltering](https://docs.opencv.org/master/d4/d86/group__imgproc__filter.html#ga9fabdce9543bd602445f5db3827e4cc0) + + - [ ] **Geometric Image Transformations - WORK STARTED** The following functions still need implementation: + - [ ] [convertMaps](https://docs.opencv.org/master/da/d54/group__imgproc__transform.html#ga9156732fa8f01be9ebd1a194f2728b7f) + - [ ] [getAffineTransform](https://docs.opencv.org/master/da/d54/group__imgproc__transform.html#ga8f6d378f9f8eebb5cb55cd3ae295a999) + - [ ] [getDefaultNewCameraMatrix](https://docs.opencv.org/master/da/d54/group__imgproc__transform.html#ga744529385e88ef7bc841cbe04b35bfbf) + - [ ] [getRectSubPix](https://docs.opencv.org/master/da/d54/group__imgproc__transform.html#ga77576d06075c1a4b6ba1a608850cd614) + - [ ] [initUndistortRectifyMap](https://docs.opencv.org/master/da/d54/group__imgproc__transform.html#ga7dfb72c9cf9780a347fbe3d1c47e5d5a) + - [ ] [initWideAngleProjMap](https://docs.opencv.org/master/da/d54/group__imgproc__transform.html#gaceb049ec48898d1dadd5b50c604429c8) + - [ ] [invertAffineTransform](https://docs.opencv.org/master/da/d54/group__imgproc__transform.html#ga57d3505a878a7e1a636645727ca08f51) + - [ ] [linearPolar](https://docs.opencv.org/master/da/d54/group__imgproc__transform.html#gaa38a6884ac8b6e0b9bed47939b5362f3) + - [ ] [undistort](https://docs.opencv.org/master/da/d54/group__imgproc__transform.html#ga69f2545a8b62a6b0fc2ee060dc30559d) + - [ ] [undistortPoints](https://docs.opencv.org/master/da/d54/group__imgproc__transform.html#ga55c716492470bfe86b0ee9bf3a1f0f7e) + + - [ ] **Miscellaneous Image Transformations - WORK STARTED** The following functions still need implementation: + - [ ] [cvtColorTwoPlane](https://docs.opencv.org/master/d7/d1b/group__imgproc__misc.html#ga8e873314e72a1a6c0252375538fbf753) + - [ ] [floodFill](https://docs.opencv.org/master/d7/d1b/group__imgproc__misc.html#gaf1f55a048f8a45bc3383586e80b1f0d0) + + - [ ] **Drawing Functions - WORK STARTED** The following functions still need implementation: + - [ ] [clipLine](https://docs.opencv.org/master/d6/d6e/group__imgproc__draw.html#gaf483cb46ad6b049bc35ec67052ef1c2c) + - [ ] [drawMarker](https://docs.opencv.org/master/d6/d6e/group__imgproc__draw.html#ga482fa7b0f578fcdd8a174904592a6250) + - [ ] [ellipse2Poly](https://docs.opencv.org/master/d6/d6e/group__imgproc__draw.html#ga727a72a3f6a625a2ae035f957c61051f) + - [ ] [fillConvexPoly](https://docs.opencv.org/master/d6/d6e/group__imgproc__draw.html#ga906aae1606ea4ed2f27bec1537f6c5c2) + - [ ] [getFontScaleFromHeight](https://docs.opencv.org/master/d6/d6e/group__imgproc__draw.html#ga442ff925c1a957794a1309e0ed3ba2c3) + - [ ] [polylines](https://docs.opencv.org/master/d6/d6e/group__imgproc__draw.html#ga444cb8a2666320f47f09d5af08d91ffb) + + - [ ] ColorMaps in OpenCV + - [ ] Planar Subdivision + - [ ] **Histograms - WORK STARTED** The following functions still need implementation: + - [ ] [EMD](https://docs.opencv.org/master/d6/dc7/group__imgproc__hist.html#ga902b8e60cc7075c8947345489221e0e0) + - [ ] [wrapperEMD](https://docs.opencv.org/master/d6/dc7/group__imgproc__hist.html#ga31fdda0864e64ca6b9de252a2611758b) + + - [ ] **Structural Analysis and Shape Descriptors - WORK STARTED** The following functions still need implementation: + - [ ] [fitEllipse](https://docs.opencv.org/master/d3/dc0/group__imgproc__shape.html#gaf259efaad93098103d6c27b9e4900ffa) + - [ ] [fitEllipseAMS](https://docs.opencv.org/master/d3/dc0/group__imgproc__shape.html#ga69e90cda55c4e192a8caa0b99c3e4550) + - [ ] [fitEllipseDirect](https://docs.opencv.org/master/d3/dc0/group__imgproc__shape.html#ga6421884fd411923a74891998bbe9e813) + - [ ] [HuMoments](https://docs.opencv.org/master/d3/dc0/group__imgproc__shape.html#gab001db45c1f1af6cbdbe64df04c4e944) + - [ ] [intersectConvexConvex](https://docs.opencv.org/master/d3/dc0/group__imgproc__shape.html#ga8e840f3f3695613d32c052bec89e782c) + - [ ] [isContourConvex](https://docs.opencv.org/master/d3/dc0/group__imgproc__shape.html#ga8abf8010377b58cbc16db6734d92941b) + - [ ] [matchShapes](https://docs.opencv.org/master/d3/dc0/group__imgproc__shape.html#gaadc90cb16e2362c9bd6e7363e6e4c317) + - [ ] [minEnclosingTriangle](https://docs.opencv.org/master/d3/dc0/group__imgproc__shape.html#ga1513e72f6bbdfc370563664f71e0542f) + - [ ] [pointPolygonTest](https://docs.opencv.org/master/d3/dc0/group__imgproc__shape.html#ga1a539e8db2135af2566103705d7a5722) + - [ ] [rotatedRectangleIntersection](https://docs.opencv.org/master/d3/dc0/group__imgproc__shape.html#ga8740e7645628c59d238b0b22c2abe2d4) + + - [ ] Motion Analysis and Object Tracking + - [ ] **Feature Detection - WORK STARTED** The following functions still need implementation: + - [ ] [cornerEigenValsAndVecs](https://docs.opencv.org/master/dd/d1a/group__imgproc__feature.html#ga4055896d9ef77dd3cacf2c5f60e13f1c) + - [ ] [cornerHarris](https://docs.opencv.org/master/dd/d1a/group__imgproc__feature.html#gac1fc3598018010880e370e2f709b4345) + - [ ] [cornerMinEigenVal](https://docs.opencv.org/master/dd/d1a/group__imgproc__feature.html#ga3dbce297c1feb859ee36707e1003e0a8) + - [ ] [createLineSegmentDetector](https://docs.opencv.org/master/dd/d1a/group__imgproc__feature.html#ga6b2ad2353c337c42551b521a73eeae7d) + - [ ] [preCornerDetect](https://docs.opencv.org/master/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/master/dc/d6b/group__video__track.html#ga86640c1c470f87b2660c096d2b22b2ce) + - [ ] [estimateRigidTransform](https://docs.opencv.org/master/dc/d6b/group__video__track.html#ga762cbe5efd52cf078950196f3c616d48) + - [ ] [findTransformECC](https://docs.opencv.org/master/dc/d6b/group__video__track.html#ga7ded46f9a55c0364c92ccd2019d43e3a) + - [ ] [meanShift](https://docs.opencv.org/master/dc/d6b/group__video__track.html#ga7ded46f9a55c0364c92ccd2019d43e3a) + - [ ] [CamShift](https://docs.opencv.org/master/dc/d6b/group__video__track.html#gaef2bd39c8356f423124f1fe7c44d54a1) + - [ ] [DualTVL1OpticalFlow](https://docs.opencv.org/master/dc/d47/classcv_1_1DualTVL1OpticalFlow.html) + - [ ] [FarnebackOpticalFlow](https://docs.opencv.org/master/de/d9e/classcv_1_1FarnebackOpticalFlow.html) + - [ ] [KalmanFilter](https://docs.opencv.org/master/dd/d6a/classcv_1_1KalmanFilter.html) + - [ ] [SparsePyrLKOpticalFlow](https://docs.opencv.org/master/d7/d08/classcv_1_1SparsePyrLKOpticalFlow.html) + +- [ ] **calib3d. Camera Calibration and 3D Reconstruction - WORK STARTED**. The following functions still need implementation: + - [ ] Camera Calibration + - [ ] **Fisheye - WORK STARTED** The following functions still need implementation: + - [ ] [calibrate](https://docs.opencv.org/3.4.1/db/d58/group__calib3d__fisheye.html#gad626a78de2b1dae7489e152a5a5a89e1) + - [ ] [distortPoints](https://docs.opencv.org/3.4.1/db/d58/group__calib3d__fisheye.html#ga75d8877a98e38d0b29b6892c5f8d7765) + - [ ] [estimateNewCameraMatrixForUndistortRectify](https://docs.opencv.org/3.4.1/db/d58/group__calib3d__fisheye.html#ga384940fdf04c03e362e94b6eb9b673c9) + - [ ] [projectPoints](https://docs.opencv.org/3.4.1/db/d58/group__calib3d__fisheye.html#gab1ad1dc30c42ee1a50ce570019baf2c4) + - [ ] [stereoCalibrate](https://docs.opencv.org/3.4.1/db/d58/group__calib3d__fisheye.html#gadbb3a6ca6429528ef302c784df47949b) + - [ ] [stereoRectify](https://docs.opencv.org/3.4.1/db/d58/group__calib3d__fisheye.html#gac1af58774006689056b0f2ef1db55ecc) + - [ ] [undistortPoints](https://docs.opencv.org/3.4.1/db/d58/group__calib3d__fisheye.html#gab738cdf90ceee97b2b52b0d0e7511541) + +- [ ] **features2d. 2D Features Framework - WORK STARTED** + - [X] **Feature Detection and Description** + - [ ] **Descriptor Matchers - WORK STARTED** The following functions still need implementation: + - [ ] [FlannBasedMatcher](https://docs.opencv.org/master/dc/de2/classcv_1_1FlannBasedMatcher.html) + - [ ] **Drawing Function of Keypoints and Matches - WORK STARTED** The following function still needs implementation: + - [ ] [drawMatches](https://docs.opencv.org/master/d4/d5d/group__features2d__draw.html#ga7421b3941617d7267e3f2311582f49e1) + - [ ] Object Categorization + - [ ] [BOWImgDescriptorExtractor](https://docs.opencv.org/master/d2/d6b/classcv_1_1BOWImgDescriptorExtractor.html) + - [ ] [BOWKMeansTrainer](https://docs.opencv.org/master/d4/d72/classcv_1_1BOWKMeansTrainer.html) + +- [X] **objdetect. Object Detection** +- [ ] **dnn. Deep Neural Network module - WORK STARTED** The following functions still need implementation: + - [ ] [NMSBoxes](https://docs.opencv.org/master/d6/d0f/group__dnn.html#ga9d118d70a1659af729d01b10233213ee) + +- [ ] ml. Machine Learning +- [ ] flann. Clustering and Search in Multi-Dimensional Spaces +- [ ] photo. Computational Photography +- [ ] stitching. Images stitching +- [ ] cudaarithm. Operations on Matrices +- [ ] cudabgsegm. Background Segmentation +- [ ] cudacodec. Video Encoding/Decoding +- [ ] cudafeatures2d. Feature Detection and Description +- [ ] cudafilters. Image Filtering +- [ ] cudaimgproc. Image Processing +- [ ] cudalegacy. Legacy support +- [ ] cudaobjdetect. Object Detection +- [ ] **cudaoptflow. Optical Flow - WORK STARTED** + - [ ] [BroxOpticalFlow](https://docs.opencv.org/master/d7/d18/classcv_1_1cuda_1_1BroxOpticalFlow.html) + - [ ] [DenseOpticalFlow](https://docs.opencv.org/master/d6/d4a/classcv_1_1cuda_1_1DenseOpticalFlow.html) + - [ ] [DensePyrLKOpticalFlow](https://docs.opencv.org/master/d0/da4/classcv_1_1cuda_1_1DensePyrLKOpticalFlow.html) + - [ ] [FarnebackOpticalFlow](https://docs.opencv.org/master/d9/d30/classcv_1_1cuda_1_1FarnebackOpticalFlow.html) + - [ ] [NvidiaHWOpticalFlow](https://docs.opencv.org/master/d5/d26/classcv_1_1cuda_1_1NvidiaHWOpticalFlow.html) + - [ ] [NvidiaOpticalFlow_1_0](https://docs.opencv.org/master/dc/d9d/classcv_1_1cuda_1_1NvidiaOpticalFlow__1__0.html) + - [ ] [SparseOpticalFlow](https://docs.opencv.org/master/d5/dcf/classcv_1_1cuda_1_1SparseOpticalFlow.html) + - [ ] **[SparsePyrLKOpticalFlow](https://docs.opencv.org/master/d7/d05/classcv_1_1cuda_1_1SparsePyrLKOpticalFlow.html) - WORK STARTED** + +- [ ] cudastereo. Stereo Correspondence +- [X] **cudawarping. Image Warping** +- [ ] cudev. Device layer +- [ ] shape. Shape Distance and Matching +- [ ] superres. Super Resolution +- [ ] videostab. Video Stabilization +- [ ] viz. 3D Visualizer + +## Contrib modules list + +- [ ] aruco. ArUco Marker Detection +- [ ] bgsegm. Improved Background-Foreground Segmentation Methods +- [ ] 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 +- [ ] dpm. Deformable Part-based Models +- [ ] **face. Face Recognition - WORK STARTED** +- [ ] freetype. Drawing UTF-8 strings with freetype/harfbuzz +- [ ] fuzzy. Image processing based on fuzzy mathematics +- [ ] hdf. Hierarchical Data Format I/O routines +- [X] **img_hash. The module brings implementations of different image hashing algorithms.** +- [ ] line_descriptor. Binary descriptors for lines extracted from an image +- [ ] matlab. MATLAB Bridge +- [ ] optflow. Optical Flow Algorithms +- [ ] phase_unwrapping. Phase Unwrapping API +- [ ] plot. Plot function for Mat data +- [ ] reg. Image Registration +- [ ] rgbd. RGB-Depth Processing +- [ ] saliency. Saliency API +- [ ] sfm. Structure From Motion +- [ ] stereo. Stereo Correspondance Algorithms +- [ ] structured_light. Structured Light API +- [ ] surface_matching. Surface Matching +- [ ] text. Scene Text Detection and Recognition +- [ ] **tracking. Tracking API - WORK STARTED** +- [ ] **xfeatures2d. Extra 2D Features Framework - WORK STARTED** +- [ ] ximgproc. Extended Image Processing +- [ ] xobjdetect. Extended object detection +- [ ] xphoto. Additional photo processing algorithms diff --git a/vendor/gocv.io/x/gocv/appveyor.yml b/vendor/gocv.io/x/gocv/appveyor.yml new file mode 100644 index 0000000..4e98ade --- /dev/null +++ b/vendor/gocv.io/x/gocv/appveyor.yml @@ -0,0 +1,35 @@ +version: "{build}" + +clone_folder: c:\gopath\src\gocv.io\x\gocv + +platform: + - MinGW_x64 + +environment: + GOPATH: c:\gopath + GOROOT: c:\go + GOVERSION: 1.13 + TEST_EXTERNAL: 1 + APPVEYOR_SAVE_CACHE_ON_ERROR: true + +cache: + - C:\opencv -> appveyor_build_opencv.cmd + +install: + - if not exist "C:\opencv" appveyor_build_opencv.cmd + - set PATH=C:\Perl\site\bin;C:\Perl\bin;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Program Files\7-Zip;C:\Program Files\Microsoft\Web Platform Installer\;C:\Tools\PsTools;C:\Program Files (x86)\CMake\bin;C:\go\bin;C:\Tools\NuGet;C:\Program Files\LLVM\bin;C:\Tools\curl\bin;C:\ProgramData\chocolatey\bin;C:\Program Files (x86)\Yarn\bin;C:\Users\appveyor\AppData\Local\Yarn\bin;C:\Program Files\AppVeyor\BuildAgent\ + - set PATH=%PATH%;C:\mingw-w64\x86_64-6.3.0-posix-seh-rt_v5-rev1\mingw64\bin + - set PATH=%PATH%;C:\Tools\GitVersion;C:\Program Files\Git LFS;C:\Program Files\Git\cmd;C:\Program Files\Git\usr\bin;C:\opencv\build\install\x64\mingw\bin; + - echo %PATH% + - echo %GOPATH% + - go version + - cd c:\gopath\src\gocv.io\x\gocv + - go get -d . + - set GOCV_CAFFE_TEST_FILES=C:\opencv\testdata + - set GOCV_TENSORFLOW_TEST_FILES=C:\opencv\testdata + - set OPENCV_ENABLE_NONFREE=ON + - go env + +build_script: + - go test -tags matprofile -v . + - go test -tags matprofile -v ./contrib diff --git a/vendor/gocv.io/x/gocv/appveyor_build_opencv.cmd b/vendor/gocv.io/x/gocv/appveyor_build_opencv.cmd new file mode 100644 index 0000000..5cea632 --- /dev/null +++ b/vendor/gocv.io/x/gocv/appveyor_build_opencv.cmd @@ -0,0 +1,23 @@ +if not exist "C:\opencv" mkdir "C:\opencv" +if not exist "C:\opencv\build" mkdir "C:\opencv\build" +if not exist "C:\opencv\testdata" mkdir "C:\opencv\testdata" + +appveyor DownloadFile https://github.com/opencv/opencv/archive/4.1.2.zip -FileName c:\opencv\opencv-4.1.2.zip +7z x c:\opencv\opencv-4.1.2.zip -oc:\opencv -y +del c:\opencv\opencv-4.1.2.zip /q +appveyor DownloadFile https://github.com/opencv/opencv_contrib/archive/4.1.2.zip -FileName c:\opencv\opencv_contrib-4.1.2.zip +7z x c:\opencv\opencv_contrib-4.1.2.zip -oc:\opencv -y +del c:\opencv\opencv_contrib-4.1.2.zip /q +cd C:\opencv\build +set PATH=C:\Perl\site\bin;C:\Perl\bin;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Program Files\7-Zip;C:\Program Files\Microsoft\Web Platform Installer\;C:\Tools\PsTools;C:\Program Files (x86)\CMake\bin;C:\go\bin;C:\Tools\NuGet;C:\Program Files\LLVM\bin;C:\Tools\curl\bin;C:\ProgramData\chocolatey\bin;C:\Program Files (x86)\Yarn\bin;C:\Users\appveyor\AppData\Local\Yarn\bin;C:\Program Files\AppVeyor\BuildAgent\ +set PATH=%PATH%;C:\mingw-w64\x86_64-6.3.0-posix-seh-rt_v5-rev1\mingw64\bin +dir C:\opencv +cmake C:\opencv\opencv-4.1.2 -G "MinGW Makefiles" -BC:\opencv\build -DENABLE_CXX11=ON -DOPENCV_EXTRA_MODULES_PATH=C:\opencv\opencv_contrib-4.1.2\modules -DBUILD_SHARED_LIBS=ON -DWITH_IPP=OFF -DWITH_MSMF=OFF -DBUILD_EXAMPLES=OFF -DBUILD_TESTS=OFF -DBUILD_PERF_TESTS=OFF -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 -DCPU_DISPATCH= -DBUILD_opencv_gapi=OFF -DOPENCV_GENERATE_PKGCONFIG=ON -DOPENCV_ENABLE_NONFREE=ON -DWITH_OPENCL_D3D11_NV=OFF -Wno-dev +mingw32-make -j%NUMBER_OF_PROCESSORS% +mingw32-make install +appveyor DownloadFile https://raw.githubusercontent.com/opencv/opencv_extra/master/testdata/dnn/bvlc_googlenet.prototxt -FileName C:\opencv\testdata\bvlc_googlenet.prototxt +appveyor DownloadFile http://dl.caffe.berkeleyvision.org/bvlc_googlenet.caffemodel -FileName C:\opencv\testdata\bvlc_googlenet.caffemodel +appveyor DownloadFile https://storage.googleapis.com/download.tensorflow.org/models/inception5h.zip -FileName C:\opencv\testdata\inception5h.zip +7z x C:\opencv\testdata\inception5h.zip -oC:\opencv\testdata tensorflow_inception_graph.pb -y +rmdir c:\opencv\opencv-4.1.2 /s /q +rmdir c:\opencv\opencv_contrib-4.1.2 /s /q diff --git a/vendor/gocv.io/x/gocv/calib3d.cpp b/vendor/gocv.io/x/gocv/calib3d.cpp new file mode 100644 index 0000000..5428cb3 --- /dev/null +++ b/vendor/gocv.io/x/gocv/calib3d.cpp @@ -0,0 +1,29 @@ +#include "calib3d.h" + + +void Fisheye_UndistortImage(Mat distorted, Mat undistorted, Mat k, Mat d) { + cv::fisheye::undistortImage(*distorted, *undistorted, *k, *d); +} + +void Fisheye_UndistortImageWithParams(Mat distorted, Mat undistorted, Mat k, Mat d, Mat knew, Size size) { + cv::Size sz(size.width, size.height); + cv::fisheye::undistortImage(*distorted, *undistorted, *k, *d, *knew, sz); +} + +void InitUndistortRectifyMap(Mat cameraMatrix,Mat distCoeffs,Mat r,Mat newCameraMatrix,Size size,int m1type,Mat map1,Mat map2) { + cv::Size sz(size.width, size.height); + cv::initUndistortRectifyMap(*cameraMatrix,*distCoeffs,*r,*newCameraMatrix,sz,m1type,*map1,*map2); +} + +Mat GetOptimalNewCameraMatrixWithParams(Mat cameraMatrix,Mat distCoeffs,Size size,double alpha,Size newImgSize,Rect* validPixROI,bool centerPrincipalPoint) { + 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; +} + diff --git a/vendor/gocv.io/x/gocv/calib3d.go b/vendor/gocv.io/x/gocv/calib3d.go new file mode 100644 index 0000000..222be07 --- /dev/null +++ b/vendor/gocv.io/x/gocv/calib3d.go @@ -0,0 +1,99 @@ +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 +) + +// FisheyeUndistortImage transforms an image to compensate for fisheye lens distortion +func FisheyeUndistortImage(distorted Mat, undistorted *Mat, k, d Mat) { + 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) { + sz := C.struct_Size{ + width: C.int(size.X), + height: C.int(size.Y), + } + C.Fisheye_UndistortImageWithParams(distorted.Ptr(), undistorted.Ptr(), k.Ptr(), d.Ptr(), knew.Ptr(), sz) +} + +// 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) { + sz := C.struct_Size{ + width: C.int(size.X), + height: C.int(size.Y), + } + 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) +} diff --git a/vendor/gocv.io/x/gocv/calib3d.h b/vendor/gocv.io/x/gocv/calib3d.h new file mode 100644 index 0000000..31b5250 --- /dev/null +++ b/vendor/gocv.io/x/gocv/calib3d.h @@ -0,0 +1,25 @@ +#ifndef _OPENCV3_CALIB_H_ +#define _OPENCV3_CALIB_H_ + +#ifdef __cplusplus +#include +#include + + +extern "C" { +#endif + +#include "core.h" + +//Calib +void Fisheye_UndistortImage(Mat distorted, Mat undistorted, Mat k, Mat d); +void Fisheye_UndistortImageWithParams(Mat distorted, Mat undistorted, Mat k, Mat d, Mat knew, Size size); + +void 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); + +#ifdef __cplusplus +} +#endif + +#endif //_OPENCV3_CALIB_H diff --git a/vendor/gocv.io/x/gocv/cgo.go b/vendor/gocv.io/x/gocv/cgo.go new file mode 100644 index 0000000..a886502 --- /dev/null +++ b/vendor/gocv.io/x/gocv/cgo.go @@ -0,0 +1,13 @@ +// +build !customenv,!openvino + +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 +#cgo windows CPPFLAGS: -IC:/opencv/build/install/include +#cgo windows LDFLAGS: -LC:/opencv/build/install/x64/mingw/lib -lopencv_core412 -lopencv_face412 -lopencv_videoio412 -lopencv_imgproc412 -lopencv_highgui412 -lopencv_imgcodecs412 -lopencv_objdetect412 -lopencv_features2d412 -lopencv_video412 -lopencv_dnn412 -lopencv_xfeatures2d412 -lopencv_plot412 -lopencv_tracking412 -lopencv_img_hash412 -lopencv_calib3d412 +*/ +import "C" diff --git a/vendor/gocv.io/x/gocv/core.cpp b/vendor/gocv.io/x/gocv/core.cpp new file mode 100644 index 0000000..ab05ac1 --- /dev/null +++ b/vendor/gocv.io/x/gocv/core.cpp @@ -0,0 +1,742 @@ +#include "core.h" +#include + +// 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_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 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_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. +void Mat_CopyTo(Mat m, Mat dst) { + m->copyTo(*dst); +} + +// Mat_CopyToWithMask copies this Mat to another Mat while applying the mask +void Mat_CopyToWithMask(Mat m, Mat dst, Mat mask) { + m->copyTo(*dst, *mask); +} + +void Mat_ConvertTo(Mat m, Mat dst, int type) { + m->convertTo(*dst, type); +} + +// 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) { + return new cv::Mat(m->reshape(cn, rows)); +} + +void Mat_PatchNaNs(Mat m) { + cv::patchNaNs(*m); +} + +Mat Mat_ConvertFp16(Mat m) { + Mat dst = new cv::Mat(); + cv::convertFp16(*m, *dst); + return dst; +} + +Mat Mat_Sqrt(Mat m) { + Mat dst = new cv::Mat(); + cv::sqrt(*m, *dst); + return dst; +} + +// 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; +} + +void LUT(Mat src, Mat lut, Mat dst) { + cv::LUT(*src, *lut, *dst); +} + +// 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(); +} + +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; +} + +void Mat_AbsDiff(Mat src1, Mat src2, Mat dst) { + cv::absdiff(*src1, *src2, *dst); +} + +void Mat_Add(Mat src1, Mat src2, Mat dst) { + cv::add(*src1, *src2, *dst); +} + +void Mat_AddWeighted(Mat src1, double alpha, Mat src2, double beta, double gamma, Mat dst) { + cv::addWeighted(*src1, alpha, *src2, beta, gamma, *dst); +} + +void Mat_BitwiseAnd(Mat src1, Mat src2, Mat dst) { + cv::bitwise_and(*src1, *src2, *dst); +} + +void Mat_BitwiseAndWithMask(Mat src1, Mat src2, Mat dst, Mat mask){ + cv::bitwise_and(*src1, *src2, *dst, *mask); +} + +void Mat_BitwiseNot(Mat src1, Mat dst) { + cv::bitwise_not(*src1, *dst); +} + +void Mat_BitwiseNotWithMask(Mat src1, Mat dst, Mat mask) { + cv::bitwise_not(*src1, *dst, *mask); +} + +void Mat_BitwiseOr(Mat src1, Mat src2, Mat dst) { + cv::bitwise_or(*src1, *src2, *dst); +} + +void Mat_BitwiseOrWithMask(Mat src1, Mat src2, Mat dst, Mat mask) { + cv::bitwise_or(*src1, *src2, *dst, *mask); +} + +void Mat_BitwiseXor(Mat src1, Mat src2, Mat dst) { + cv::bitwise_xor(*src1, *src2, *dst); +} + +void Mat_BitwiseXorWithMask(Mat src1, Mat src2, Mat dst, Mat mask) { + cv::bitwise_xor(*src1, *src2, *dst, *mask); +} + +void Mat_BatchDistance(Mat src1, Mat src2, Mat dist, int dtype, Mat nidx, int normType, int K, + Mat mask, int update, bool crosscheck) { + cv::batchDistance(*src1, *src2, *dist, dtype, *nidx, normType, K, *mask, update, crosscheck); +} + +int Mat_BorderInterpolate(int p, int len, int borderType) { + return cv::borderInterpolate(p, len, borderType); +} + +void Mat_CalcCovarMatrix(Mat samples, Mat covar, Mat mean, int flags, int ctype) { + cv::calcCovarMatrix(*samples, *covar, *mean, flags, ctype); +} + +void Mat_CartToPolar(Mat x, Mat y, Mat magnitude, Mat angle, bool angleInDegrees) { + cv::cartToPolar(*x, *y, *magnitude, *angle, angleInDegrees); +} + +bool Mat_CheckRange(Mat m) { + return cv::checkRange(*m); +} + +void Mat_Compare(Mat src1, Mat src2, Mat dst, int ct) { + cv::compare(*src1, *src2, *dst, ct); +} + +int Mat_CountNonZero(Mat src) { + return cv::countNonZero(*src); +} + + +void Mat_CompleteSymm(Mat m, bool lowerToUpper) { + cv::completeSymm(*m, lowerToUpper); +} + +void Mat_ConvertScaleAbs(Mat src, Mat dst, double alpha, double beta) { + cv::convertScaleAbs(*src, *dst, alpha, beta); +} + +void Mat_CopyMakeBorder(Mat src, Mat dst, int top, int bottom, int left, int right, int borderType, + Scalar value) { + cv::Scalar c_value(value.val1, value.val2, value.val3, value.val4); + cv::copyMakeBorder(*src, *dst, top, bottom, left, right, borderType, c_value); +} + +void Mat_DCT(Mat src, Mat dst, int flags) { + cv::dct(*src, *dst, flags); +} + +double Mat_Determinant(Mat m) { + return cv::determinant(*m); +} + +void Mat_DFT(Mat m, Mat dst, int flags) { + cv::dft(*m, *dst, flags); +} + +void Mat_Divide(Mat src1, Mat src2, Mat dst) { + cv::divide(*src1, *src2, *dst); +} + +bool Mat_Eigen(Mat src, Mat eigenvalues, Mat eigenvectors) { + return cv::eigen(*src, *eigenvalues, *eigenvectors); +} + +void Mat_EigenNonSymmetric(Mat src, Mat eigenvalues, Mat eigenvectors) { + cv::eigenNonSymmetric(*src, *eigenvalues, *eigenvectors); +} + +void Mat_Exp(Mat src, Mat dst) { + cv::exp(*src, *dst); +} + +void Mat_ExtractChannel(Mat src, Mat dst, int coi) { + cv::extractChannel(*src, *dst, coi); +} + +void Mat_FindNonZero(Mat src, Mat idx) { + cv::findNonZero(*src, *idx); +} + +void Mat_Flip(Mat src, Mat dst, int flipCode) { + cv::flip(*src, *dst, flipCode); +} + +void Mat_Gemm(Mat src1, Mat src2, double alpha, Mat src3, double beta, Mat dst, int flags) { + cv::gemm(*src1, *src2, alpha, *src3, beta, *dst, flags); +} + +int Mat_GetOptimalDFTSize(int vecsize) { + return cv::getOptimalDFTSize(vecsize); +} + +void Mat_Hconcat(Mat src1, Mat src2, Mat dst) { + cv::hconcat(*src1, *src2, *dst); +} + +void Mat_Vconcat(Mat src1, Mat src2, Mat dst) { + cv::vconcat(*src1, *src2, *dst); +} + +void Rotate(Mat src, Mat dst, int rotateCode) { + cv::rotate(*src, *dst, rotateCode); +} + +void Mat_Idct(Mat src, Mat dst, int flags) { + cv::idct(*src, *dst, flags); +} + +void Mat_Idft(Mat src, Mat dst, int flags, int nonzeroRows) { + cv::idft(*src, *dst, flags, nonzeroRows); +} + +void Mat_InRange(Mat src, Mat lowerb, Mat upperb, Mat dst) { + cv::inRange(*src, *lowerb, *upperb, *dst); +} + +void Mat_InRangeWithScalar(Mat src, Scalar lowerb, Scalar upperb, Mat dst) { + 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); +} + +void Mat_InsertChannel(Mat src, Mat dst, int coi) { + cv::insertChannel(*src, *dst, coi); +} + +double Mat_Invert(Mat src, Mat dst, int flags) { + double ret = cv::invert(*src, *dst, flags); + return ret; +} + +double KMeans(Mat data, int k, Mat bestLabels, TermCriteria criteria, int attempts, int flags, Mat centers) { + double ret = cv::kmeans(*data, k, *bestLabels, *criteria, attempts, flags, *centers); + return ret; +} + +double KMeansPoints(Contour points, int k, Mat bestLabels, TermCriteria criteria, int attempts, int flags, Mat centers) { + std::vector pts; + + for (size_t i = 0; i < points.length; i++) { + pts.push_back(cv::Point2f(points.points[i].x, points.points[i].y)); + } + double ret = cv::kmeans(pts, k, *bestLabels, *criteria, attempts, flags, *centers); + return ret; +} + +void Mat_Log(Mat src, Mat dst) { + cv::log(*src, *dst); +} + +void Mat_Magnitude(Mat x, Mat y, Mat magnitude) { + cv::magnitude(*x, *y, *magnitude); +} + +void Mat_Max(Mat src1, Mat src2, Mat dst) { + cv::max(*src1, *src2, *dst); +} + +void Mat_MeanStdDev(Mat src, Mat dstMean, Mat dstStdDev) { + cv::meanStdDev(*src, *dstMean, *dstStdDev); +} + +void Mat_Merge(struct Mats mats, Mat dst) { + std::vector images; + + for (int i = 0; i < mats.length; ++i) { + images.push_back(*mats.mats[i]); + } + + cv::merge(images, *dst); +} + +void Mat_Min(Mat src1, Mat src2, Mat dst) { + cv::min(*src1, *src2, *dst); +} + +void Mat_MinMaxIdx(Mat m, double* minVal, double* maxVal, int* minIdx, int* maxIdx) { + cv::minMaxIdx(*m, minVal, maxVal, minIdx, maxIdx); +} + +void Mat_MinMaxLoc(Mat m, double* minVal, double* maxVal, Point* minLoc, Point* maxLoc) { + 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; +} + +void Mat_MulSpectrums(Mat a, Mat b, Mat c, int flags) { + cv::mulSpectrums(*a, *b, *c, flags); +} + +void Mat_Multiply(Mat src1, Mat src2, Mat dst) { + cv::multiply(*src1, *src2, *dst); +} + +void Mat_Normalize(Mat src, Mat dst, double alpha, double beta, int typ) { + cv::normalize(*src, *dst, alpha, beta, typ); +} + +double Norm(Mat src1, int normType) { + return cv::norm(*src1, normType); +} + +void Mat_PerspectiveTransform(Mat src, Mat dst, Mat tm) { + cv::perspectiveTransform(*src, *dst, *tm); +} + +bool Mat_Solve(Mat src1, Mat src2, Mat dst, int flags) { + return cv::solve(*src1, *src2, *dst, flags); +} + +int Mat_SolveCubic(Mat coeffs, Mat roots) { + return cv::solveCubic(*coeffs, *roots); +} + +double Mat_SolvePoly(Mat coeffs, Mat roots, int maxIters) { + return cv::solvePoly(*coeffs, *roots, maxIters); +} + +void Mat_Reduce(Mat src, Mat dst, int dim, int rType, int dType) { + cv::reduce(*src, *dst, dim, rType, dType); +} + +void Mat_Repeat(Mat src, int nY, int nX, Mat dst) { + cv::repeat(*src, nY, nX, *dst); +} + +void Mat_ScaleAdd(Mat src1, double alpha, Mat src2, Mat dst) { + cv::scaleAdd(*src1, alpha, *src2, *dst); +} + +void Mat_Sort(Mat src, Mat dst, int flags) { + cv::sort(*src, *dst, flags); +} + +void Mat_SortIdx(Mat src, Mat dst, int flags) { + cv::sortIdx(*src, *dst, flags); +} + +void Mat_Split(Mat src, struct Mats* mats) { + 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(); +} + +void Mat_Subtract(Mat src1, Mat src2, Mat dst) { + cv::subtract(*src1, *src2, *dst); +} + +Scalar Mat_Trace(Mat src) { + 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; +} + +void Mat_Transform(Mat src, Mat dst, Mat tm) { + cv::transform(*src, *dst, *tm); +} + +void Mat_Transpose(Mat src, Mat dst) { + cv::transpose(*src, *dst); +} + +void Mat_PolarToCart(Mat magnitude, Mat degree, Mat x, Mat y, bool angleInDegrees) { + cv::polarToCart(*magnitude, *degree, *x, *y, angleInDegrees); +} + +void Mat_Pow(Mat src, double power, Mat dst) { + cv::pow(*src, power, *dst); +} + +void Mat_Phase(Mat x, Mat y, Mat angle, bool angleInDegrees) { + cv::phase(*x, *y, *angle, angleInDegrees); +} + + +Scalar Mat_Sum(Mat src) { + 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; +} + +// TermCriteria_New creates a new TermCriteria +TermCriteria TermCriteria_New(int typ, int maxCount, double epsilon) { + return new cv::TermCriteria(typ, maxCount, epsilon); +} + +void Contours_Close(struct Contours cs) { + for (int i = 0; i < cs.length; i++) { + Points_Close(cs.contours[i]); + } + + delete[] cs.contours; +} + +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 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() { + return cv::getTickCount(); +} + +double GetTickFrequency() { + return cv::getTickFrequency(); +} diff --git a/vendor/gocv.io/x/gocv/core.go b/vendor/gocv.io/x/gocv/core.go new file mode 100644 index 0000000..87e9695 --- /dev/null +++ b/vendor/gocv.io/x/gocv/core.go @@ -0,0 +1,1869 @@ +package gocv + +/* +#include +#include "core.h" +*/ +import "C" +import ( + "errors" + "image" + "image/color" + "reflect" + "unsafe" +) + +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 = 1 + + // MatTypeCV16U is a Mat of 16-bit unsigned int + MatTypeCV16U = 2 + + // MatTypeCV16S is a Mat of 16-bit signed int + MatTypeCV16S = 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 = 4 + + // MatTypeCV32F is a Mat of 32-bit float + MatTypeCV32F = 5 + + // MatTypeCV64F is a Mat of 64-bit float + MatTypeCV64F = 6 + + // 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 +) + +// 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 = 1 + + // CompareGE src1 is greater than or equal to src2. + CompareGE = 2 + + // CompareLT src1 is less than src2. + CompareLT = 3 + + // CompareLE src1 is less than or equal to src2. + CompareLE = 4 + + // CompareNE src1 is unequal to src2. + CompareNE = 5 +) + +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 +} + +// NewMat returns a new empty Mat. +func NewMat() Mat { + return newMat(C.Mat_New()) +} + +// 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))) +} + +// 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 + } + return newMat(C.Mat_NewFromBytes(C.int(rows), C.int(cols), C.int(mt), *cBytes)), nil +} + +// 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 +} + +// 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) { + C.Mat_CopyTo(m.p, dst.p) + return +} + +// 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) { + C.Mat_CopyToWithMask(m.p, dst.p, mask.p) + return +} + +// 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) { + C.Mat_ConvertTo(m.p, dst.p, C.int(mt)) + return +} + +// 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) + + 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 { + 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)) +} + +// 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 { + 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)) +} + +// 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") + } + + 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") + } + + 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") + } + + 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") + } + + 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))) +} + +// 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() { + 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) { + 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)) +} + +// 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)) +} + +// ToImage converts a Mat to a image.Image. +func (m *Mat) ToImage() (image.Image, error) { + t := m.Type() + if t != MatTypeCV8UC1 && t != MatTypeCV8UC3 && t != MatTypeCV8UC4 { + return nil, errors.New("ToImage supports only MatType CV8UC1, CV8UC3 and CV8UC4") + } + + width := m.Cols() + height := m.Rows() + step := m.Step() + data := m.ToBytes() + channels := m.Channels() + + if t == MatTypeCV8UC1 { + img := image.NewGray(image.Rect(0, 0, width, height)) + c := color.Gray{Y: uint8(0)} + + for y := 0; y < height; y++ { + for x := 0; x < width; x++ { + c.Y = uint8(data[y*step+x]) + img.SetGray(x, y, c) + } + } + + return img, nil + } + + img := image.NewRGBA(image.Rect(0, 0, width, height)) + c := color.RGBA{ + R: uint8(0), + G: uint8(0), + B: uint8(0), + A: uint8(255), + } + + for y := 0; y < height; y++ { + for x := 0; x < step; x = x + channels { + c.B = uint8(data[y*step+x]) + c.G = uint8(data[y*step+x+1]) + c.R = uint8(data[y*step+x+2]) + if channels == 4 { + c.A = uint8(data[y*step+x+3]) + } + img.SetRGBA(int(x/channels), y, c) + } + } + + return img, 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() + data := make([]byte, 0, x*y*4) + for j := bounds.Min.Y; j < bounds.Max.Y; j++ { + for i := bounds.Min.X; i < bounds.Max.X; i++ { + r, g, b, a := img.At(i, j).RGBA() + data = append(data, byte(b>>8), byte(g>>8), byte(r>>8), byte(a>>8)) + } + } + return NewMatFromBytes(y, x, MatTypeCV8UC4, data) +} + +//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() + 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() + data := make([]byte, 0, x*y) + for j := bounds.Min.Y; j < bounds.Max.Y; j++ { + for i := bounds.Min.X; i < bounds.Max.X; i++ { + data = append(data, img.GrayAt(i, j).Y) + } + } + return NewMatFromBytes(y, x, MatTypeCV8UC1, data) +} + +// 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) { + 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) { + 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) { + 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) { + 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) { + 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) { + 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) { + 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) { + 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) { + 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) { + 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) { + 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 int, nidx Mat, normType int, K int, mask Mat, update int, crosscheck bool) { + 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 = 1 + + // CovarUseAvg indicates to use average covariation. + CovarUseAvg = 2 + + // CovarScale indicates to use scaled covariation. + CovarScale = 4 + + // CovarRows indicates to use covariation on rows. + CovarRows = 8 + + // CovarCols indicates to use covariation on columns. + CovarCols = 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 int) { + 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) { + 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) { + 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) { + 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) { + 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) { + + cValue := C.struct_Scalar{ + val1: C.double(value.B), + val2: C.double(value.G), + val3: C.double(value.R), + val4: C.double(value.A), + } + + 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 = 1 + + // DftScale scales the result: divide it by the number of array elements. Normally, it is combined with DFT_INVERSE. + DftScale = 2 + + // DftRows performs a forward or inverse transform of every individual row of the input matrix. + DftRows = 4 + + // DftComplexOutput performs a forward transformation of 1D or 2D real array; the result, though being a complex array, has complex-conjugate symmetry + DftComplexOutput = 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 = 32 + + // DftComplexInput specifies that input is complex input. If this flag is set, the input must have 2 channels. + DftComplexInput = 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) { + 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) { + 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) { + 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) { + C.Mat_EigenNonSymmetric(src.p, eigenvalues.p, eigenvectors.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) { + 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) { + 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) { + 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) { + 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) { + 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) { + 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) { + 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 = 1 + // Rotate90CounterClockwise allows to rotate 270 degrees clockwise + Rotate90CounterClockwise = 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) { + 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) { + 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) { + 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) { + 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) { + 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), + } + + 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) { + 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 int) 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 = 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 = 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 []image.Point, k int, bestLabels *Mat, criteria TermCriteria, attempts int, flags KMeansFlags, centers *Mat) float64 { + cPoints := toCPoints(points) + ret := C.KMeansPoints(cPoints, 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) { + 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) { + C.Mat_Magnitude(x.p, y.p, magnitude.p) +} + +// 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) { + 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) { + C.Mat_MeanStdDev(src.p, dst.p, dstStdDev.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) { + 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)), + } + + 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) { + 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 +} + +//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) { + 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) { + C.Mat_Multiply(src1.p, src2.p, dst.p) +} + +// 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 = 2 + + // NormL2 indicates use L2 normalization. + NormL2 = 4 + + // NormL2Sqr indicates use L2 squared normalization. + NormL2Sqr = 5 + + // NormHamming indicates use Hamming normalization. + NormHamming = 6 + + // NormHamming2 indicates use Hamming 2-bit normalization. + NormHamming2 = 7 + + // NormTypeMask indicates use type mask for normalization. + NormTypeMask = 7 + + // NormRelative indicates use relative normalization. + NormRelative = 8 + + // NormMinMax indicates use min/max normalization. + NormMinMax = 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) { + 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))) +} + +// 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) { + 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 = 1 + + // EPS is the desired accuracy or change in parameters at which the + // iterative algorithm stops. + EPS = 2 +) + +type SolveDecompositionFlags int + +const ( + // Gaussian elimination with the optimal pivot element chosen. + SolveDecompositionLu = 0 + + // Singular value decomposition (SVD) method. The system can be over-defined and/or the matrix src1 can be singular. + SolveDecompositionSvd = 1 + + // Eigenvalue decomposition. The matrix src1 must be symmetrical. + SolveDecompositionEing = 2 + + // Cholesky LL^T factorization. The matrix src1 must be symmetrical and positively defined. + SolveDecompositionCholesky = 3 + + // QR factorization. The system can be over-defined and/or the matrix src1 can be singular. + SolveDecompositionQr = 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 = 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 int) { + C.Mat_Reduce(src.p, dst.p, C.int(dim), C.int(rType), C.int(dType)) +} + +// 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) { + 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) { + C.Mat_ScaleAdd(src1.p, C.double(alpha), src2.p, dst.p) +} + +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) { + 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) { + C.Mat_SortIdx(src.p, dst.p, C.int(flags)) +} + +// Split creates an array of single channel images from a multi-channel image +// +// 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)) + mv = make([]Mat, cMats.length) + for i := C.int(0); i < cMats.length; i++ { + mv[i].p = C.Mats_get(cMats, i) + } + 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) { + 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) { + 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) { + C.Mat_Transpose(src.p, 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) { + 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) { + 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) { + 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))} +} + +// 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 +} + +// 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 +} + +// 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 +} + +// 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) +} + +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 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)), + } +} diff --git a/vendor/gocv.io/x/gocv/core.h b/vendor/gocv.io/x/gocv/core.h new file mode 100644 index 0000000..a0fa61f --- /dev/null +++ b/vendor/gocv.io/x/gocv/core.h @@ -0,0 +1,378 @@ +#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; + +// 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; + +// Contour is alias for Points +typedef Points Contour; + +// 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 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::RotatedRect +typedef struct RotatedRect { + Contour pts; + Rect boundingRect; + Point center; + Size size; + double angle; +} RotatedRect; + +// 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; + +// 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; + +#ifdef __cplusplus +typedef cv::Mat* Mat; +typedef cv::TermCriteria* TermCriteria; +#else +typedef void* Mat; +typedef void* TermCriteria; +#endif + +// 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 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_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_FromPtr(Mat m, int rows, int cols, int type, int prows, int pcols); +void Mat_Close(Mat m); +int Mat_Empty(Mat m); +Mat Mat_Clone(Mat m); +void Mat_CopyTo(Mat m, Mat dst); +int Mat_Total(Mat m); +void Mat_Size(Mat m, IntVector* res); +void Mat_CopyToWithMask(Mat m, Mat dst, Mat mask); +void Mat_ConvertTo(Mat m, Mat dst, int type); +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); +void 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); + +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); + +void LUT(Mat src, Mat lut, Mat dst); + +void Mat_AbsDiff(Mat src1, Mat src2, Mat dst); +void Mat_Add(Mat src1, Mat src2, Mat dst); +void Mat_AddWeighted(Mat src1, double alpha, Mat src2, double beta, double gamma, Mat dst); +void Mat_BitwiseAnd(Mat src1, Mat src2, Mat dst); +void Mat_BitwiseAndWithMask(Mat src1, Mat src2, Mat dst, Mat mask); +void Mat_BitwiseNot(Mat src1, Mat dst); +void Mat_BitwiseNotWithMask(Mat src1, Mat dst, Mat mask); +void Mat_BitwiseOr(Mat src1, Mat src2, Mat dst); +void Mat_BitwiseOrWithMask(Mat src1, Mat src2, Mat dst, Mat mask); +void Mat_BitwiseXor(Mat src1, Mat src2, Mat dst); +void Mat_BitwiseXorWithMask(Mat src1, Mat src2, Mat dst, Mat mask); +void Mat_Compare(Mat src1, Mat src2, Mat dst, int ct); +void 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); +void Mat_CalcCovarMatrix(Mat samples, Mat covar, Mat mean, int flags, int ctype); +void Mat_CartToPolar(Mat x, Mat y, Mat magnitude, Mat angle, bool angleInDegrees); +bool Mat_CheckRange(Mat m); +void Mat_CompleteSymm(Mat m, bool lowerToUpper); +void Mat_ConvertScaleAbs(Mat src, Mat dst, double alpha, double beta); +void Mat_CopyMakeBorder(Mat src, Mat dst, int top, int bottom, int left, int right, int borderType, + Scalar value); +int Mat_CountNonZero(Mat src); +void Mat_DCT(Mat src, Mat dst, int flags); +double Mat_Determinant(Mat m); +void Mat_DFT(Mat m, Mat dst, int flags); +void Mat_Divide(Mat src1, Mat src2, Mat dst); +bool Mat_Eigen(Mat src, Mat eigenvalues, Mat eigenvectors); +void Mat_EigenNonSymmetric(Mat src, Mat eigenvalues, Mat eigenvectors); +void Mat_Exp(Mat src, Mat dst); +void Mat_ExtractChannel(Mat src, Mat dst, int coi); +void Mat_FindNonZero(Mat src, Mat idx); +void Mat_Flip(Mat src, Mat dst, int flipCode); +void Mat_Gemm(Mat src1, Mat src2, double alpha, Mat src3, double beta, Mat dst, int flags); +int Mat_GetOptimalDFTSize(int vecsize); +void Mat_Hconcat(Mat src1, Mat src2, Mat dst); +void Mat_Vconcat(Mat src1, Mat src2, Mat dst); +void Rotate(Mat src, Mat dst, int rotationCode); +void Mat_Idct(Mat src, Mat dst, int flags); +void Mat_Idft(Mat src, Mat dst, int flags, int nonzeroRows); +void Mat_InRange(Mat src, Mat lowerb, Mat upperb, Mat dst); +void Mat_InRangeWithScalar(Mat src, const Scalar lowerb, const Scalar upperb, Mat dst); +void 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(Contour points, int k, Mat bestLabels, TermCriteria criteria, int attempts, int flags, Mat centers); +void Mat_Log(Mat src, Mat dst); +void Mat_Magnitude(Mat x, Mat y, Mat magnitude); +void Mat_Max(Mat src1, Mat src2, Mat dst); +void Mat_MeanStdDev(Mat src, Mat dstMean, Mat dstStdDev); +void Mat_Merge(struct Mats mats, Mat dst); +void Mat_Min(Mat src1, Mat src2, Mat dst); +void Mat_MinMaxIdx(Mat m, double* minVal, double* maxVal, int* minIdx, int* maxIdx); +void Mat_MinMaxLoc(Mat m, double* minVal, double* maxVal, Point* minLoc, Point* maxLoc); +void Mat_MulSpectrums(Mat a, Mat b, Mat c, int flags); +void Mat_Multiply(Mat src1, Mat src2, Mat dst); +void Mat_Subtract(Mat src1, Mat src2, Mat dst); +void Mat_Normalize(Mat src, Mat dst, double alpha, double beta, int typ); +double Norm(Mat src1, int normType); +void 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); +void Mat_Reduce(Mat src, Mat dst, int dim, int rType, int dType); +void Mat_Repeat(Mat src, int nY, int nX, Mat dst); +void Mat_ScaleAdd(Mat src1, double alpha, Mat src2, Mat dst); +void Mat_Sort(Mat src, Mat dst, int flags); +void Mat_SortIdx(Mat src, Mat dst, int flags); +void Mat_Split(Mat src, struct Mats* mats); +void Mat_Subtract(Mat src1, Mat src2, Mat dst); +Scalar Mat_Trace(Mat src); +void Mat_Transform(Mat src, Mat dst, Mat tm); +void Mat_Transpose(Mat src, Mat dst); +void Mat_PolarToCart(Mat magnitude, Mat degree, Mat x, Mat y, bool angleInDegrees); +void Mat_Pow(Mat src, double power, Mat dst); +void 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(); + +#ifdef __cplusplus +} +#endif + +#endif //_OPENCV3_CORE_H_ diff --git a/vendor/gocv.io/x/gocv/dnn.cpp b/vendor/gocv.io/x/gocv/dnn.cpp new file mode 100644 index 0000000..25ef502 --- /dev/null +++ b/vendor/gocv.io/x/gocv/dnn.cpp @@ -0,0 +1,169 @@ +#include "dnn.h" + +Net Net_ReadNet(const char* model, const char* config) { + Net n = new cv::dnn::Net(cv::dnn::readNet(model, config)); + return n; +} + +Net Net_ReadNetBytes(const char* framework, struct ByteArray model, struct ByteArray config) { + 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; +} + +Net Net_ReadNetFromCaffe(const char* prototxt, const char* caffeModel) { + Net n = new cv::dnn::Net(cv::dnn::readNetFromCaffe(prototxt, caffeModel)); + return n; +} + +Net Net_ReadNetFromCaffeBytes(struct ByteArray prototxt, struct ByteArray caffeModel) { + Net n = new cv::dnn::Net(cv::dnn::readNetFromCaffe(prototxt.data, prototxt.length, + caffeModel.data, caffeModel.length)); + return n; +} + +Net Net_ReadNetFromTensorflow(const char* model) { + Net n = new cv::dnn::Net(cv::dnn::readNetFromTensorflow(model)); + return n; +} + +Net Net_ReadNetFromTensorflowBytes(struct ByteArray model) { + Net n = new cv::dnn::Net(cv::dnn::readNetFromTensorflow(model.data, model.length)); + return n; +} + +void Net_Close(Net net) { + delete net; +} + +bool Net_Empty(Net net) { + return net->empty(); +} + +void Net_SetInput(Net net, Mat blob, const char* name) { + net->setInput(*blob, name); +} + +Mat Net_Forward(Net net, const char* outputName) { + return new cv::Mat(net->forward(outputName)); +} + +void Net_ForwardLayers(Net net, struct Mats* outputBlobs, struct CStrings outBlobNames) { + 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(); +} + +void Net_SetPreferableBackend(Net net, int backend) { + net->setPreferableBackend(backend); +} + +void Net_SetPreferableTarget(Net net, int target) { + net->setPreferableTarget(target); +} + +int64_t Net_GetPerfProfile(Net net) { + std::vector layersTimes; + return net->getPerfProfile(layersTimes); +} + +void Net_GetUnconnectedOutLayers(Net net, IntVector* res) { + 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; + return; +} + +Mat Net_BlobFromImage(Mat image, double scalefactor, Size size, Scalar mean, bool swapRB, + bool crop) { + cv::Size sz(size.width, size.height); + cv::Scalar cm = cv::Scalar(mean.val1, mean.val2, mean.val3, mean.val4); + + // TODO: handle different version signatures of this function v2 vs v3. + return new cv::Mat(cv::dnn::blobFromImage(*image, scalefactor, sz, cm, swapRB, crop)); +} + +void Net_BlobFromImages(struct Mats images, Mat blob, double scalefactor, Size size, + Scalar mean, bool swapRB, bool crop, int ddepth) { + 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); + + // TODO: handle different version signatures of this function v2 vs v3. + cv::dnn::blobFromImages(imgs, *blob, scalefactor, sz, cm, swapRB, crop, ddepth); +} + +void Net_ImagesFromBlob(Mat blob_, struct Mats* images_) { + 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(); +} + +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) { + return new cv::Ptr(net->getLayer(layerid)); +} + +void Layer_Close(Layer layer) { + delete layer; +} + +int Layer_InputNameToIndex(Layer layer, const char* name) { + return (*layer)->inputNameToIndex(name); +} + +int Layer_OutputNameToIndex(Layer layer, const char* name) { + return (*layer)->outputNameToIndex(name); +} + +const char* Layer_GetName(Layer layer) { + return (*layer)->name.c_str(); +} + +const char* Layer_GetType(Layer layer) { + return (*layer)->type.c_str(); +} diff --git a/vendor/gocv.io/x/gocv/dnn.go b/vendor/gocv.io/x/gocv/dnn.go new file mode 100644 index 0000000..8165ebe --- /dev/null +++ b/vendor/gocv.io/x/gocv/dnn.go @@ -0,0 +1,450 @@ +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 +) + +// ParseNetBackend returns a valid NetBackendType given a string. Valid values are: +// - halide +// - openvino +// - opencv +// - vulkan +// - default +func ParseNetBackend(backend string) NetBackendType { + switch backend { + case "halide": + return NetBackendHalide + case "openvino": + return NetBackendOpenVINO + case "opencv": + return NetBackendOpenCV + case "vulkan": + return NetBackendVKCOM + 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 +) + +// ParseNetTarget returns a valid NetTargetType given a string. Valid values are: +// - cpu +// - fp32 +// - fp16 +// - vpu +// - vulkan +// - fpga +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 + default: + return NetTargetCPU + } +} + +// 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) + } + 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 + } + bConfig, err := toByteArray(config) + if err != nil { + return Net{}, err + } + 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 +} + +// 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))) +} + +// 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 int) { + + 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)) +} + +// 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) + + h := &reflect.SliceHeader{ + Data: uintptr(unsafe.Pointer(cids.val)), + Len: int(cids.length), + Cap: int(cids.length), + } + pcids := *(*[]int)(unsafe.Pointer(h)) + + for i := 0; i < int(cids.length); i++ { + ids = append(ids, int(pcids[i])) + } + return +} + +// 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)) +} diff --git a/vendor/gocv.io/x/gocv/dnn.h b/vendor/gocv.io/x/gocv/dnn.h new file mode 100644 index 0000000..7112a4d --- /dev/null +++ b/vendor/gocv.io/x/gocv/dnn.h @@ -0,0 +1,57 @@ +#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); +Mat Net_BlobFromImage(Mat image, double scalefactor, Size size, Scalar mean, bool swapRB, + bool crop); +void Net_BlobFromImages(struct Mats images, Mat blob, double scalefactor, Size size, + Scalar mean, bool swapRB, bool crop, int ddepth); +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); + +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); + +#ifdef __cplusplus +} +#endif + +#endif //_OPENCV3_DNN_H_ diff --git a/vendor/gocv.io/x/gocv/dnn_ext.go b/vendor/gocv.io/x/gocv/dnn_ext.go new file mode 100644 index 0000000..9ac2517 --- /dev/null +++ b/vendor/gocv.io/x/gocv/dnn_ext.go @@ -0,0 +1,67 @@ +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() +} diff --git a/vendor/gocv.io/x/gocv/env.cmd b/vendor/gocv.io/x/gocv/env.cmd new file mode 100644 index 0000000..02babfd --- /dev/null +++ b/vendor/gocv.io/x/gocv/env.cmd @@ -0,0 +1,2 @@ +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. diff --git a/vendor/gocv.io/x/gocv/env.sh b/vendor/gocv.io/x/gocv/env.sh new file mode 100644 index 0000000..343148f --- /dev/null +++ b/vendor/gocv.io/x/gocv/env.sh @@ -0,0 +1,2 @@ +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." diff --git a/vendor/gocv.io/x/gocv/features2d.cpp b/vendor/gocv.io/x/gocv/features2d.cpp new file mode 100644 index 0000000..8e98c28 --- /dev/null +++ b/vendor/gocv.io/x/gocv/features2d.cpp @@ -0,0 +1,430 @@ +#include "features2d.h" + +AKAZE AKAZE_Create() { + // TODO: params + return new cv::Ptr(cv::AKAZE::create()); +} + +void AKAZE_Close(AKAZE a) { + delete a; +} + +struct KeyPoints AKAZE_Detect(AKAZE a, Mat src) { + 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; +} + +struct KeyPoints AKAZE_DetectAndCompute(AKAZE a, Mat src, Mat mask, Mat desc) { + 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; +} + +AgastFeatureDetector AgastFeatureDetector_Create() { + // TODO: params + return new cv::Ptr(cv::AgastFeatureDetector::create()); +} + +void AgastFeatureDetector_Close(AgastFeatureDetector a) { + delete a; +} + +struct KeyPoints AgastFeatureDetector_Detect(AgastFeatureDetector a, Mat src) { + 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; +} + +BRISK BRISK_Create() { + // TODO: params + return new cv::Ptr(cv::BRISK::create()); +} + +void BRISK_Close(BRISK b) { + delete b; +} + +struct KeyPoints BRISK_Detect(BRISK b, Mat src) { + 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; +} + +struct KeyPoints BRISK_DetectAndCompute(BRISK b, Mat src, Mat mask, Mat desc) { + 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; +} + +GFTTDetector GFTTDetector_Create() { + // TODO: params + return new cv::Ptr(cv::GFTTDetector::create()); +} + +void GFTTDetector_Close(GFTTDetector a) { + delete a; +} + +struct KeyPoints GFTTDetector_Detect(GFTTDetector a, Mat src) { + 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; +} + +KAZE KAZE_Create() { + // TODO: params + return new cv::Ptr(cv::KAZE::create()); +} + +void KAZE_Close(KAZE a) { + delete a; +} + +struct KeyPoints KAZE_Detect(KAZE a, Mat src) { + 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; +} + +struct KeyPoints KAZE_DetectAndCompute(KAZE a, Mat src, Mat mask, Mat desc) { + 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; +} + +MSER MSER_Create() { + // TODO: params + return new cv::Ptr(cv::MSER::create()); +} + +void MSER_Close(MSER a) { + delete a; +} + +struct KeyPoints MSER_Detect(MSER a, Mat src) { + 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; +} + +FastFeatureDetector FastFeatureDetector_Create() { + return new cv::Ptr(cv::FastFeatureDetector::create()); +} + +void FastFeatureDetector_Close(FastFeatureDetector f) { + delete f; +} + +FastFeatureDetector FastFeatureDetector_CreateWithParams(int threshold, bool nonmaxSuppression, int type) { + return new cv::Ptr(cv::FastFeatureDetector::create(threshold,nonmaxSuppression,static_cast(type))); +} + +struct KeyPoints FastFeatureDetector_Detect(FastFeatureDetector f, Mat src) { + 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; +} + +ORB ORB_Create() { + // TODO: params + return new cv::Ptr(cv::ORB::create()); +} + +void ORB_Close(ORB o) { + delete o; +} + +struct KeyPoints ORB_Detect(ORB o, Mat src) { + 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; +} + +struct KeyPoints ORB_DetectAndCompute(ORB o, Mat src, Mat mask, Mat desc) { + 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; +} + +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){ + cv::SimpleBlobDetector::Params actualParams; + return new cv::Ptr(cv::SimpleBlobDetector::create(ConvertCParamsToCPPParams(params))); +} + +SimpleBlobDetector SimpleBlobDetector_Create() { + return new cv::Ptr(cv::SimpleBlobDetector::create()); +} + +SimpleBlobDetectorParams SimpleBlobDetectorParams_Create() { + return ConvertCPPParamsToCParams(cv::SimpleBlobDetector::Params()); +} + +void SimpleBlobDetector_Close(SimpleBlobDetector b) { + delete b; +} + +struct KeyPoints SimpleBlobDetector_Detect(SimpleBlobDetector b, Mat src) { + 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; +} + +BFMatcher BFMatcher_Create() { + return new cv::Ptr(cv::BFMatcher::create()); +} + +BFMatcher BFMatcher_CreateWithParams(int normType, bool crossCheck) { + return new cv::Ptr(cv::BFMatcher::create(normType, crossCheck)); +} + +void BFMatcher_Close(BFMatcher b) { + delete b; +} + +struct MultiDMatches BFMatcher_KnnMatch(BFMatcher b, Mat query, Mat train, int k) { + 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; +} + +struct MultiDMatches BFMatcher_KnnMatchWithParams(BFMatcher b, Mat query, Mat train, int k, Mat mask, bool compactResult) { + 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; +} + +void DrawKeyPoints(Mat src, struct KeyPoints kp, Mat dst, Scalar s, int flags) { + 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)); +} diff --git a/vendor/gocv.io/x/gocv/features2d.go b/vendor/gocv.io/x/gocv/features2d.go new file mode 100644 index 0000000..f36d16e --- /dev/null +++ b/vendor/gocv.io/x/gocv/features2d.go @@ -0,0 +1,750 @@ +package gocv + +/* +#include +#include "features2d.h" +*/ +import "C" +import ( + "image/color" + "reflect" + "unsafe" +) + +// AKAZE is a wrapper around the cv::AKAZE algorithm. +type AKAZE struct { + // C.AKAZE + p unsafe.Pointer +} + +// 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())} +} + +// 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) +} + +// 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())} +} + +// 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 +} + +// NewBRISK returns a new BRISK algorithm +// +// For further details, please see: +// https://docs.opencv.org/master/d8/d30/classcv_1_1AKAZE.html +// +func NewBRISK() BRISK { + return BRISK{p: unsafe.Pointer(C.BRISK_Create())} +} + +// 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) +} + +// 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 = 1 + //FastFeatureDetectorType916 is an alias of FastFeatureDetector::TYPE_9_16 + FastFeatureDetectorType916 = 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 +} + +// 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())} +} + +// 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 +} + +// 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())} +} + +// 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) +} + +// 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())} +} + +// 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 +} + +// NewORB returns a new ORB algorithm +// +// For further details, please see: +// https://docs.opencv.org/master/d7/d19/classcv_1_1AgastFeatureDetector.html +// +func NewORB() ORB { + return ORB{p: unsafe.Pointer(C.ORB_Create())} +} + +// 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) +} + +// 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 +} + +// 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) +} + +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 = 1 + // NotDrawSinglePoints will not draw single points + NotDrawSinglePoints = 2 + // DrawRichKeyPoints draws the circle around each keypoint with keypoint size and orientation + DrawRichKeyPoints = 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.R), + val2: C.double(color.G), + val3: C.double(color.B), + val4: C.double(color.A), + } + + C.DrawKeyPoints(src.p, cKeyPoints, dst.p, scalar, C.int(flag)) +} diff --git a/vendor/gocv.io/x/gocv/features2d.h b/vendor/gocv.io/x/gocv/features2d.h new file mode 100644 index 0000000..8c68f93 --- /dev/null +++ b/vendor/gocv.io/x/gocv/features2d.h @@ -0,0 +1,89 @@ +#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; +#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; +#endif + +AKAZE AKAZE_Create(); +void AKAZE_Close(AKAZE a); +struct KeyPoints AKAZE_Detect(AKAZE a, Mat src); +struct KeyPoints AKAZE_DetectAndCompute(AKAZE a, Mat src, Mat mask, Mat desc); + +AgastFeatureDetector AgastFeatureDetector_Create(); +void AgastFeatureDetector_Close(AgastFeatureDetector a); +struct KeyPoints AgastFeatureDetector_Detect(AgastFeatureDetector a, Mat src); + +BRISK BRISK_Create(); +void BRISK_Close(BRISK b); +struct KeyPoints BRISK_Detect(BRISK b, Mat src); +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(); +void GFTTDetector_Close(GFTTDetector a); +struct KeyPoints GFTTDetector_Detect(GFTTDetector a, Mat src); + +KAZE KAZE_Create(); +void KAZE_Close(KAZE a); +struct KeyPoints KAZE_Detect(KAZE a, Mat src); +struct KeyPoints KAZE_DetectAndCompute(KAZE a, Mat src, Mat mask, Mat desc); + +MSER MSER_Create(); +void MSER_Close(MSER a); +struct KeyPoints MSER_Detect(MSER a, Mat src); + +ORB ORB_Create(); +void ORB_Close(ORB o); +struct KeyPoints ORB_Detect(ORB o, Mat src); +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 MultiDMatches BFMatcher_KnnMatch(BFMatcher b, Mat query, Mat train, int k); + +void DrawKeyPoints(Mat src, struct KeyPoints kp, Mat dst, const Scalar s, int flags); + +#ifdef __cplusplus +} +#endif + +#endif //_OPENCV3_FEATURES2D_H_ diff --git a/vendor/gocv.io/x/gocv/go.mod b/vendor/gocv.io/x/gocv/go.mod new file mode 100644 index 0000000..acb0abc --- /dev/null +++ b/vendor/gocv.io/x/gocv/go.mod @@ -0,0 +1,3 @@ +module gocv.io/x/gocv + +go 1.13 diff --git a/vendor/gocv.io/x/gocv/gocv.go b/vendor/gocv.io/x/gocv/gocv.go new file mode 100644 index 0000000..5d71b14 --- /dev/null +++ b/vendor/gocv.io/x/gocv/gocv.go @@ -0,0 +1,11 @@ +// Package gocv is a wrapper around the OpenCV 3.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" diff --git a/vendor/gocv.io/x/gocv/highgui.cpp b/vendor/gocv.io/x/gocv/highgui.cpp new file mode 100644 index 0000000..db31181 --- /dev/null +++ b/vendor/gocv.io/x/gocv/highgui.cpp @@ -0,0 +1,79 @@ +#include "highgui_gocv.h" + +// Window +void Window_New(const char* winname, int flags) { + cv::namedWindow(winname, flags); +} + +void Window_Close(const char* winname) { + cv::destroyWindow(winname); +} + +void Window_IMShow(const char* winname, Mat mat) { + cv::imshow(winname, *mat); +} + +double Window_GetProperty(const char* winname, int flag) { + return cv::getWindowProperty(winname, flag); +} + +void Window_SetProperty(const char* winname, int flag, double value) { + cv::setWindowProperty(winname, flag, value); +} + +void Window_SetTitle(const char* winname, const char* title) { + cv::setWindowTitle(winname, title); +} + +int Window_WaitKey(int delay = 0) { + return cv::waitKey(delay); +} + +void Window_Move(const char* winname, int x, int y) { + cv::moveWindow(winname, x, y); +} + +void Window_Resize(const char* winname, int width, int height) { + cv::resizeWindow(winname, width, height); +} + +struct Rect Window_SelectROI(const char* winname, Mat img) { + cv::Rect bRect = cv::selectROI(winname, *img); + Rect r = {bRect.x, bRect.y, bRect.width, bRect.height}; + return r; +} + +struct Rects Window_SelectROIs(const char* winname, Mat img) { + 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; +} + +// Trackbar +void Trackbar_Create(const char* winname, const char* trackname, int max) { + cv::createTrackbar(trackname, winname, NULL, max); +} + +int Trackbar_GetPos(const char* winname, const char* trackname) { + return cv::getTrackbarPos(trackname, winname); +} + +void Trackbar_SetPos(const char* winname, const char* trackname, int pos) { + cv::setTrackbarPos(trackname, winname, pos); +} + +void Trackbar_SetMin(const char* winname, const char* trackname, int pos) { + cv::setTrackbarMin(trackname, winname, pos); +} + +void Trackbar_SetMax(const char* winname, const char* trackname, int pos) { + cv::setTrackbarMax(trackname, winname, pos); +} diff --git a/vendor/gocv.io/x/gocv/highgui.go b/vendor/gocv.io/x/gocv/highgui.go new file mode 100644 index 0000000..84b8f6c --- /dev/null +++ b/vendor/gocv.io/x/gocv/highgui.go @@ -0,0 +1,323 @@ +package gocv + +/* +#include +#include "highgui_gocv.h" +*/ +import "C" +import ( + "image" + "runtime" + "unsafe" +) + +// 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)) + + 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 = 0 + + // WindowFullscreen indicates a full-screen window. + WindowFullscreen = 1 + + // WindowAutosize indicates a window sized based on the contents. + WindowAutosize = 1 + + // WindowFreeRatio indicates allow the user to resize without maintaining aspect ratio. + WindowFreeRatio = 0x00000100 + + // WindowKeepRatio indicates always maintain an aspect ratio that matches the contents. + WindowKeepRatio = 0 +) + +// 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 = 1 + + // WindowPropertyAspectRatio window's aspect ration + // (can be set to WINDOW_FREERATIO or WINDOW_KEEPRATIO). + WindowPropertyAspectRatio = 2 + + // WindowPropertyOpenGL opengl support. + WindowPropertyOpenGL = 3 + + // WindowPropertyVisible or not. + WindowPropertyVisible = 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) { + cName := C.CString(w.name) + defer C.free(unsafe.Pointer(cName)) + + 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) { + cName := C.CString(w.name) + defer C.free(unsafe.Pointer(cName)) + + cTitle := C.CString(title) + defer C.free(unsafe.Pointer(cTitle)) + + 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) { + cName := C.CString(w.name) + defer C.free(unsafe.Pointer(cName)) + + 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))) +} + +// 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) { + cName := C.CString(w.name) + defer C.free(unsafe.Pointer(cName)) + + 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) { + cName := C.CString(w.name) + defer C.free(unsafe.Pointer(cName)) + + 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 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 +} + +// 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 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} +} + +// 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)) +} diff --git a/vendor/gocv.io/x/gocv/highgui_gocv.h b/vendor/gocv.io/x/gocv/highgui_gocv.h new file mode 100644 index 0000000..58d9726 --- /dev/null +++ b/vendor/gocv.io/x/gocv/highgui_gocv.h @@ -0,0 +1,35 @@ +#ifndef _OPENCV3_HIGHGUI_H_ +#define _OPENCV3_HIGHGUI_H_ + +#ifdef __cplusplus +#include +extern "C" { +#endif + +#include "core.h" + +// Window +void Window_New(const char* winname, int flags); +void Window_Close(const char* winname); +void Window_IMShow(const char* winname, Mat mat); +double Window_GetProperty(const char* winname, int flag); +void Window_SetProperty(const char* winname, int flag, double value); +void Window_SetTitle(const char* winname, const char* title); +int Window_WaitKey(int); +void Window_Move(const char* winname, int x, int y); +void 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); +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_ diff --git a/vendor/gocv.io/x/gocv/imgcodecs.cpp b/vendor/gocv.io/x/gocv/imgcodecs.cpp new file mode 100644 index 0000000..47886d8 --- /dev/null +++ b/vendor/gocv.io/x/gocv/imgcodecs.cpp @@ -0,0 +1,51 @@ +#include "imgcodecs.h" + +// Image +Mat Image_IMRead(const char* filename, int flags) { + cv::Mat img = cv::imread(filename, flags); + return new cv::Mat(img); +} + + +bool Image_IMWrite(const char* filename, Mat img) { + return cv::imwrite(filename, *img); +} + +bool Image_IMWrite_WithParams(const char* filename, Mat img, IntVector params) { + 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); +} + +struct ByteArray Image_IMEncode(const char* fileExt, Mat img) { + std::vector data; + cv::imencode(fileExt, *img, data); + return toByteArray(reinterpret_cast(&data[0]), data.size()); +} + +struct ByteArray Image_IMEncode_WithParams(const char* fileExt, Mat img, IntVector params) { + std::vector data; + 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, data, compression_params); + return toByteArray(reinterpret_cast(&data[0]), data.size()); +} + +Mat Image_IMDecode(ByteArray buf, int flags) { + std::vector data; + + for (size_t i = 0; i < buf.length; i++) { + data.push_back(buf.data[i]); + } + + cv::Mat img = cv::imdecode(data, flags); + return new cv::Mat(img); +} diff --git a/vendor/gocv.io/x/gocv/imgcodecs.go b/vendor/gocv.io/x/gocv/imgcodecs.go new file mode 100644 index 0000000..dea467f --- /dev/null +++ b/vendor/gocv.io/x/gocv/imgcodecs.go @@ -0,0 +1,248 @@ +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 = 0 + + // IMReadColor always converts image to the 3 channel BGR color image. + IMReadColor = 1 + + // IMReadAnyDepth returns 16-bit/32-bit image when the input has the corresponding + // depth, otherwise convert it to 8-bit. + IMReadAnyDepth = 2 + + // IMReadAnyColor the image is read in any possible color format. + IMReadAnyColor = 4 + + // IMReadLoadGDAL uses the gdal driver for loading the image. + IMReadLoadGDAL = 8 + + // IMReadReducedGrayscale2 always converts image to the single channel grayscale image + // and the image size reduced 1/2. + IMReadReducedGrayscale2 = 16 + + // IMReadReducedColor2 always converts image to the 3 channel BGR color image and the + // image size reduced 1/2. + IMReadReducedColor2 = 17 + + // IMReadReducedGrayscale4 always converts image to the single channel grayscale image and + // the image size reduced 1/4. + IMReadReducedGrayscale4 = 32 + + // IMReadReducedColor4 always converts image to the 3 channel BGR color image and + // the image size reduced 1/4. + IMReadReducedColor4 = 33 + + // IMReadReducedGrayscale8 always convert image to the single channel grayscale image and + // the image size reduced 1/8. + IMReadReducedGrayscale8 = 64 + + // IMReadReducedColor8 always convert image to the 3 channel BGR color image and the + // image size reduced 1/8. + IMReadReducedColor8 = 65 + + // IMReadIgnoreOrientation do not rotate the image according to EXIF's orientation flag. + IMReadIgnoreOrientation = 128 + + //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))) +} + +// 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 []byte, err error) { + cfileExt := C.CString(string(fileExt)) + defer C.free(unsafe.Pointer(cfileExt)) + + b := C.Image_IMEncode(cfileExt, img.Ptr()) + defer C.ByteArray_Release(b) + return toGoBytes(b), nil +} + +// 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 []byte, 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 := C.Image_IMEncode_WithParams(cfileExt, img.Ptr(), paramsVector) + defer C.ByteArray_Release(b) + return toGoBytes(b), nil +} + +// 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))), nil +} diff --git a/vendor/gocv.io/x/gocv/imgcodecs.h b/vendor/gocv.io/x/gocv/imgcodecs.h new file mode 100644 index 0000000..ac4ad11 --- /dev/null +++ b/vendor/gocv.io/x/gocv/imgcodecs.h @@ -0,0 +1,24 @@ +#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); +bool Image_IMWrite(const char* filename, Mat img); +bool Image_IMWrite_WithParams(const char* filename, Mat img, IntVector params); +struct ByteArray Image_IMEncode(const char* fileExt, Mat img); +struct ByteArray Image_IMEncode_WithParams(const char* fileExt, Mat img, IntVector params); +Mat Image_IMDecode(ByteArray buf, int flags); + +#ifdef __cplusplus +} +#endif + +#endif //_OPENCV3_IMGCODECS_H_ diff --git a/vendor/gocv.io/x/gocv/imgproc.cpp b/vendor/gocv.io/x/gocv/imgproc.cpp new file mode 100644 index 0000000..b49bf40 --- /dev/null +++ b/vendor/gocv.io/x/gocv/imgproc.cpp @@ -0,0 +1,575 @@ +#include "imgproc.h" + +double ArcLength(Contour curve, bool is_closed) { + std::vector pts; + + for (size_t i = 0; i < curve.length; i++) { + pts.push_back(cv::Point(curve.points[i].x, curve.points[i].y)); + } + + return cv::arcLength(pts, is_closed); +} + +Contour ApproxPolyDP(Contour curve, double epsilon, bool closed) { + std::vector curvePts; + + for (size_t i = 0; i < curve.length; i++) { + curvePts.push_back(cv::Point(curve.points[i].x, curve.points[i].y)); + } + + std::vector approxCurvePts; + cv::approxPolyDP(curvePts, approxCurvePts, epsilon, closed); + + int length = approxCurvePts.size(); + Point* points = new Point[length]; + + for (size_t i = 0; i < length; i++) { + points[i] = (Point){approxCurvePts[i].x, approxCurvePts[i].y}; + } + + return (Contour){points, length}; +} + +void CvtColor(Mat src, Mat dst, int code) { + cv::cvtColor(*src, *dst, code); +} + +void EqualizeHist(Mat src, Mat dst) { + cv::equalizeHist(*src, *dst); +} + +void 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); + } + + cv::calcHist(images, channels, *mask, *hist, histSize, ranges, acc); +} + +void 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); + } + + cv::calcBackProject(images, channels, *hist, *backProject, ranges, uniform); +} + +double CompareHist(Mat hist1, Mat hist2, int method) { + return cv::compareHist(*hist1, *hist2, method); +} + +void ConvexHull(Contour points, Mat hull, bool clockwise, bool returnPoints) { + std::vector pts; + + for (size_t i = 0; i < points.length; i++) { + pts.push_back(cv::Point(points.points[i].x, points.points[i].y)); + } + + cv::convexHull(pts, *hull, clockwise, returnPoints); +} + +void ConvexityDefects(Contour points, Mat hull, Mat result) { + std::vector pts; + + for (size_t i = 0; i < points.length; i++) { + pts.push_back(cv::Point(points.points[i].x, points.points[i].y)); + } + + cv::convexityDefects(pts, *hull, *result); +} + +void BilateralFilter(Mat src, Mat dst, int d, double sc, double ss) { + cv::bilateralFilter(*src, *dst, d, sc, ss); +} + +void Blur(Mat src, Mat dst, Size ps) { + cv::Size sz(ps.width, ps.height); + cv::blur(*src, *dst, sz); +} + +void BoxFilter(Mat src, Mat dst, int ddepth, Size ps) { + cv::Size sz(ps.width, ps.height); + cv::boxFilter(*src, *dst, ddepth, sz); +} + +void SqBoxFilter(Mat src, Mat dst, int ddepth, Size ps) { + cv::Size sz(ps.width, ps.height); + cv::sqrBoxFilter(*src, *dst, ddepth, sz); +} + +void Dilate(Mat src, Mat dst, Mat kernel) { + cv::dilate(*src, *dst, *kernel); +} + +void DistanceTransform(Mat src, Mat dst, Mat labels, int distanceType, int maskSize, int labelType) { + cv::distanceTransform(*src, *dst, *labels, distanceType, maskSize, labelType); +} + +void Erode(Mat src, Mat dst, Mat kernel) { + cv::erode(*src, *dst, *kernel); +} + +void MatchTemplate(Mat image, Mat templ, Mat result, int method, Mat mask) { + cv::matchTemplate(*image, *templ, *result, method, *mask); +} + +struct Moment Moments(Mat src, bool binaryImage) { + 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; +} + +void PyrDown(Mat src, Mat dst, Size size, int borderType) { + cv::Size cvSize(size.width, size.height); + cv::pyrDown(*src, *dst, cvSize, borderType); +} + +void PyrUp(Mat src, Mat dst, Size size, int borderType) { + cv::Size cvSize(size.width, size.height); + cv::pyrUp(*src, *dst, cvSize, borderType); +} + +struct Rect BoundingRect(Contour con) { + std::vector pts; + + for (size_t i = 0; i < con.length; i++) { + pts.push_back(cv::Point(con.points[i].x, con.points[i].y)); + } + + cv::Rect bRect = cv::boundingRect(pts); + Rect r = {bRect.x, bRect.y, bRect.width, bRect.height}; + return r; +} + +void BoxPoints(RotatedRect rect, Mat boxPts){ + 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); +} + +double ContourArea(Contour con) { + std::vector pts; + + for (size_t i = 0; i < con.length; i++) { + pts.push_back(cv::Point(con.points[i].x, con.points[i].y)); + } + + return cv::contourArea(pts); +} + +struct RotatedRect MinAreaRect(Points points){ + std::vector pts; + + for (size_t i = 0; i < points.length; i++) { + pts.push_back(cv::Point(points.points[i].x, points.points[i].y)); + } + + 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; +} + +void MinEnclosingCircle(Points points, Point2f* center, float* radius){ + std::vector pts; + + for (size_t i = 0; i < points.length; i++) { + pts.push_back(cv::Point(points.points[i].x, points.points[i].y)); + } + + cv::Point2f center2f; + cv::minEnclosingCircle(pts, center2f, *radius); + center->x = center2f.x; + center->y = center2f.y; +} + +struct Contours FindContours(Mat src, int mode, int method) { + std::vector > contours; + cv::findContours(*src, contours, mode, method); + + Contour* points = new Contour[contours.size()]; + + for (size_t i = 0; i < contours.size(); i++) { + Point* pts = new Point[contours[i].size()]; + + for (size_t j = 0; j < contours[i].size(); j++) { + Point pt = {contours[i][j].x, contours[i][j].y}; + pts[j] = pt; + } + + points[i] = (Contour){pts, (int)contours[i].size()}; + } + + Contours cons = {points, (int)contours.size()}; + return cons; +} + +int ConnectedComponents(Mat src, Mat labels, int connectivity, int ltype, int ccltype){ + return cv::connectedComponents(*src, *labels, connectivity, ltype, ccltype); +} + + +int ConnectedComponentsWithStats(Mat src, Mat labels, Mat stats, Mat centroids, + int connectivity, int ltype, int ccltype){ + return cv::connectedComponentsWithStats(*src, *labels, *stats, *centroids, connectivity, ltype, ccltype); +} + +Mat GetStructuringElement(int shape, Size ksize) { + cv::Size sz(ksize.width, ksize.height); + return new cv::Mat(cv::getStructuringElement(shape, sz)); +} + +Scalar MorphologyDefaultBorderValue(){ + cv::Scalar cs = cv::morphologyDefaultBorderValue(); + return (Scalar){cs[0],cs[1],cs[2],cs[3]}; +} + +void MorphologyEx(Mat src, Mat dst, int op, Mat kernel) { + cv::morphologyEx(*src, *dst, op, *kernel); +} + +void MorphologyExWithParams(Mat src, Mat dst, int op, Mat kernel, Point pt, int iterations, int borderType) { + cv::Point pt1(pt.x, pt.y); + cv::morphologyEx(*src, *dst, op, *kernel, pt1, iterations, borderType); +} + +void GaussianBlur(Mat src, Mat dst, Size ps, double sX, double sY, int bt) { + cv::Size sz(ps.width, ps.height); + cv::GaussianBlur(*src, *dst, sz, sX, sY, bt); +} + +void Laplacian(Mat src, Mat dst, int dDepth, int kSize, double scale, double delta, + int borderType) { + cv::Laplacian(*src, *dst, dDepth, kSize, scale, delta, borderType); +} + +void Scharr(Mat src, Mat dst, int dDepth, int dx, int dy, double scale, double delta, + int borderType) { + cv::Scharr(*src, *dst, dDepth, dx, dy, scale, delta, borderType); +} + +void MedianBlur(Mat src, Mat dst, int ksize) { + cv::medianBlur(*src, *dst, ksize); +} + +void Canny(Mat src, Mat edges, double t1, double t2) { + cv::Canny(*src, *edges, t1, t2); +} + +void CornerSubPix(Mat img, Mat corners, Size winSize, Size zeroZone, TermCriteria criteria) { + cv::Size wsz(winSize.width, winSize.height); + cv::Size zsz(zeroZone.width, zeroZone.height); + cv::cornerSubPix(*img, *corners, wsz, zsz, *criteria); +} + +void GoodFeaturesToTrack(Mat img, Mat corners, int maxCorners, double quality, double minDist) { + cv::goodFeaturesToTrack(*img, *corners, maxCorners, quality, minDist); +} + +void GrabCut(Mat img, Mat mask, Rect r, Mat bgdModel, Mat fgdModel, int iterCount, int mode) { + cv::Rect cvRect = cv::Rect(r.x, r.y, r.width, r.height); + cv::grabCut(*img, *mask, cvRect, *bgdModel, *fgdModel, iterCount, mode); +} + +void HoughCircles(Mat src, Mat circles, int method, double dp, double minDist) { + cv::HoughCircles(*src, *circles, method, dp, minDist); +} + +void HoughCirclesWithParams(Mat src, Mat circles, int method, double dp, double minDist, + double param1, double param2, int minRadius, int maxRadius) { + cv::HoughCircles(*src, *circles, method, dp, minDist, param1, param2, minRadius, maxRadius); +} + +void HoughLines(Mat src, Mat lines, double rho, double theta, int threshold) { + cv::HoughLines(*src, *lines, rho, theta, threshold); +} + +void HoughLinesP(Mat src, Mat lines, double rho, double theta, int threshold) { + cv::HoughLinesP(*src, *lines, rho, theta, threshold); +} + +void HoughLinesPWithParams(Mat src, Mat lines, double rho, double theta, int threshold, double minLineLength, double maxLineGap) { + cv::HoughLinesP(*src, *lines, rho, theta, threshold, minLineLength, maxLineGap); +} + +void HoughLinesPointSet(Mat points, Mat lines, int linesMax, int threshold, + double minRho, double maxRho, double rhoStep, + double minTheta, double maxTheta, double thetaStep) { + cv::HoughLinesPointSet(*points, *lines, linesMax, threshold, + minRho, maxRho, rhoStep, minTheta, maxTheta, thetaStep ); +} + +void Integral(Mat src, Mat sum, Mat sqsum, Mat tilted) { + cv::integral(*src, *sum, *sqsum, *tilted); +} + +void Threshold(Mat src, Mat dst, double thresh, double maxvalue, int typ) { + cv::threshold(*src, *dst, thresh, maxvalue, typ); +} + +void AdaptiveThreshold(Mat src, Mat dst, double maxValue, int adaptiveMethod, int thresholdType, + int blockSize, double c) { + cv::adaptiveThreshold(*src, *dst, maxValue, adaptiveMethod, thresholdType, blockSize, c); +} + +void ArrowedLine(Mat img, Point pt1, Point pt2, Scalar color, int thickness) { + 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); +} + +void Circle(Mat img, Point center, int radius, Scalar color, int thickness) { + 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); +} + +void Ellipse(Mat img, Point center, Point axes, double angle, double + startAngle, double endAngle, Scalar color, int thickness) { + 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); +} + +void Line(Mat img, Point pt1, Point pt2, Scalar color, int thickness) { + 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); +} + +void Rectangle(Mat img, Rect r, Scalar color, int thickness) { + 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 + ); +} + +void FillPoly(Mat img, Contours points, Scalar color) { + std::vector > pts; + + 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)); + } + + pts.push_back(cntr); + } + + cv::Scalar c = cv::Scalar(color.val1, color.val2, color.val3, color.val4); + + cv::fillPoly(*img, pts, c); +} + +struct Size GetTextSize(const char* text, int fontFace, double fontScale, int thickness) { + cv::Size sz = cv::getTextSize(text, fontFace, fontScale, thickness, NULL); + Size size = {sz.width, sz.height}; + return size; +} + +void PutText(Mat img, const char* text, Point org, int fontFace, double fontScale, + Scalar color, int thickness) { + 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); +} + +void Resize(Mat src, Mat dst, Size dsize, double fx, double fy, int interp) { + cv::Size sz(dsize.width, dsize.height); + cv::resize(*src, *dst, sz, fx, fy, interp); +} + +Mat GetRotationMatrix2D(Point center, double angle, double scale) { + cv::Point pt(center.x, center.y); + return new cv::Mat(cv::getRotationMatrix2D(pt, angle, scale)); +} + +void WarpAffine(Mat src, Mat dst, Mat m, Size dsize) { + cv::Size sz(dsize.width, dsize.height); + cv::warpAffine(*src, *dst, *m, sz); +} + +void WarpAffineWithParams(Mat src, Mat dst, Mat rot_mat, Size dsize, int flags, int borderMode, + Scalar borderValue) { + 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); +} + +void WarpPerspective(Mat src, Mat dst, Mat m, Size dsize) { + cv::Size sz(dsize.width, dsize.height); + cv::warpPerspective(*src, *dst, *m, sz); +} + +void Watershed(Mat image, Mat markers) { + cv::watershed(*image, *markers); +} + +void ApplyColorMap(Mat src, Mat dst, int colormap) { + cv::applyColorMap(*src, *dst, colormap); +} + +void ApplyCustomColorMap(Mat src, Mat dst, Mat colormap) { + cv::applyColorMap(*src, *dst, *colormap); +} + +Mat GetPerspectiveTransform(Contour src, Contour dst) { + std::vector src_pts; + + for (size_t i = 0; i < src.length; i++) { + src_pts.push_back(cv::Point2f(src.points[i].x, src.points[i].y)); + } + + std::vector dst_pts; + + for (size_t i = 0; i < dst.length; i++) { + dst_pts.push_back(cv::Point2f(dst.points[i].x, dst.points[i].y)); + } + + return new cv::Mat(cv::getPerspectiveTransform(src_pts, dst_pts)); +} + +void DrawContours(Mat src, Contours contours, int contourIdx, Scalar color, int thickness) { + std::vector > cntrs; + + for (size_t i = 0; i < contours.length; i++) { + Contour contour = contours.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)); + } + + cntrs.push_back(cntr); + } + + cv::Scalar c = cv::Scalar(color.val1, color.val2, color.val3, color.val4); + cv::drawContours(*src, cntrs, contourIdx, c, thickness); +} + +void Sobel(Mat src, Mat dst, int ddepth, int dx, int dy, int ksize, double scale, double delta, int borderType) { + cv::Sobel(*src, *dst, ddepth, dx, dy, ksize, scale, delta, borderType); +} + +void SpatialGradient(Mat src, Mat dx, Mat dy, int ksize, int borderType) { + cv::spatialGradient(*src, *dx, *dy, ksize, borderType); +} + + +void Remap(Mat src, Mat dst, Mat map1, Mat map2, int interpolation, int borderMode, Scalar borderValue) { + cv::Scalar c = cv::Scalar(borderValue.val1, borderValue.val2, borderValue.val3, borderValue.val4); + cv::remap(*src, *dst, *map1, *map2, interpolation, borderMode, c); +} + +void Filter2D(Mat src, Mat dst, int ddepth, Mat kernel, Point anchor, double delta, int borderType) { + cv::Point anchorPt(anchor.x, anchor.y); + cv::filter2D(*src, *dst, ddepth, *kernel, anchorPt, delta, borderType); +} + +void SepFilter2D(Mat src, Mat dst, int ddepth, Mat kernelX, Mat kernelY, Point anchor, double delta, int borderType) { + cv::Point anchorPt(anchor.x, anchor.y); + cv::sepFilter2D(*src, *dst, ddepth, *kernelX, *kernelY, anchorPt, delta, borderType); +} + +void LogPolar(Mat src, Mat dst, Point center, double m, int flags) { + cv::Point2f centerPt(center.x, center.y); + cv::logPolar(*src, *dst, centerPt, m, flags); +} + +void FitLine(Contour points, Mat line, int distType, double param, double reps, double aeps) { + std::vector pts; + for (size_t i = 0; i < points.length; i++) { + pts.push_back(cv::Point(points.points[i].x, points.points[i].y)); + } + cv::fitLine(pts, *line, distType, param, reps, aeps); +} + +CLAHE CLAHE_Create() { + return new cv::Ptr(cv::createCLAHE()); +} + +CLAHE CLAHE_CreateWithParams(double clipLimit, Size tileGridSize) { + cv::Size sz(tileGridSize.width, tileGridSize.height); + return new cv::Ptr(cv::createCLAHE(clipLimit, sz)); +} + +void CLAHE_Close(CLAHE c) { + delete c; +} + +void CLAHE_Apply(CLAHE c, Mat src, Mat dst) { + (*c)->apply(*src, *dst); +} diff --git a/vendor/gocv.io/x/gocv/imgproc.go b/vendor/gocv.io/x/gocv/imgproc.go new file mode 100644 index 0000000..b3cc6ec --- /dev/null +++ b/vendor/gocv.io/x/gocv/imgproc.go @@ -0,0 +1,1667 @@ +package gocv + +/* +#include +#include "imgproc.h" +*/ +import "C" +import ( + "image" + "image/color" + "reflect" + "unsafe" +) + +func getPoints(pts *C.Point, l int) []C.Point { + h := &reflect.SliceHeader{ + Data: uintptr(unsafe.Pointer(pts)), + Len: l, + Cap: l, + } + return *(*[]C.Point)(unsafe.Pointer(h)) +} + +// 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 []image.Point, isClosed bool) float64 { + cPoints := toCPoints(curve) + arcLength := C.ArcLength(cPoints, C.bool(isClosed)) + return float64(arcLength) +} + +// 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 []image.Point, epsilon float64, closed bool) (approxCurve []image.Point) { + cCurve := toCPoints(curve) + + cApproxCurve := C.ApproxPolyDP(cCurve, C.double(epsilon), C.bool(closed)) + defer C.Points_Close(cApproxCurve) + + cApproxCurvePoints := getPoints(cApproxCurve.points, int(cApproxCurve.length)) + + approxCurve = make([]image.Point, cApproxCurve.length) + for i, cPoint := range cApproxCurvePoints { + approxCurve[i] = image.Pt(int(cPoint.x), int(cPoint.y)) + } + return approxCurve +} + +// 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 []image.Point, hull *Mat, clockwise bool, returnPoints bool) { + cPoints := toCPoints(points) + C.ConvexHull(cPoints, 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 []image.Point, hull Mat, result *Mat) { + cPoints := toCPoints(contour) + C.ConvexityDefects(cPoints, 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) { + C.CvtColor(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) { + 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) { + 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)) + + 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) { + 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)) + + 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 = 1 + + // HistCmpIntersect calculates the Intersection + HistCmpIntersect = 2 + + // HistCmpBhattacharya applies the HistCmpBhattacharya by calculating the Bhattacharya distance. + HistCmpBhattacharya = 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 = 4 + + // HistCmpKlDiv applies the Kullback-Liebler divergence comparison. + HistCmpKlDiv = 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))) +} + +// 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) { + 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) { + pSize := C.struct_Size{ + width: C.int(ksize.X), + height: C.int(ksize.Y), + } + + 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) { + pSize := C.struct_Size{ + height: C.int(ksize.X), + width: C.int(ksize.Y), + } + 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) { + pSize := C.struct_Size{ + height: C.int(ksize.X), + width: C.int(ksize.Y), + } + 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) { + C.Dilate(src.p, dst.p, kernel.p) +} + +// 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) { + 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) { + C.Erode(src.p, dst.p, kernel.p) +} + +// 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 = 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 = 2 + + // RetrievalTree retrieves all of the contours and reconstructs a full + // hierarchy of nested contours. + RetrievalTree = 3 + + // RetrievalFloodfill lacks a description in the original header. + RetrievalFloodfill = 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 = 2 + + // ChainApproxTC89L1 applies one of the flavors of the Teh-Chin chain + // approximation algorithms. + ChainApproxTC89L1 = 3 + + // ChainApproxTC89KCOS applies one of the flavors of the Teh-Chin chain + // approximation algorithms. + ChainApproxTC89KCOS = 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 []image.Point) image.Rectangle { + cContour := toCPoints(contour) + r := C.BoundingRect(cContour) + 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) { + + rPoints := toCPoints(rect.Contour) + + 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), + } + + C.BoxPoints(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 []image.Point) float64 { + cContour := toCPoints(contour) + result := C.ContourArea(cContour) + return float64(result) +} + +type RotatedRect struct { + Contour []image.Point + BoundingRect image.Rectangle + Center image.Point + Width int + Height int + Angle float64 +} + +// MinAreaRect finds a rotated rectangle of the minimum area enclosing the input 2D point set. +// +// For further details, please see: +// https://docs.opencv.org/3.3.0/d3/dc0/group__imgproc__shape.html#ga3d476a3417130ae5154aea421ca7ead9 +// +func MinAreaRect(points []image.Point) RotatedRect { + cPoints := toCPoints(points) + result := C.MinAreaRect(cPoints) + + defer C.Points_Close(result.pts) + pArray := result.pts.points + pLength := int(result.pts.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 RotatedRect{ + Contour: points4, + 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), + } +} + +// 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(points []image.Point) (x, y, radius float32) { + cPoints := toCPoints(points) + cCenterPoint := C.struct_Point2f{} + var cRadius C.float + C.MinEnclosingCircle(cPoints, &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/3.3.0/d3/dc0/group__imgproc__shape.html#ga17ed9f5d79ae97bd4c7cf18403e1689a +// +func FindContours(src Mat, mode RetrievalMode, method ContourApproximationMode) [][]image.Point { + ret := C.FindContours(src.p, C.int(mode), C.int(method)) + defer C.Contours_Close(ret) + + cArray := ret.contours + cLength := int(ret.length) + cHdr := reflect.SliceHeader{ + Data: uintptr(unsafe.Pointer(cArray)), + Len: cLength, + Cap: cLength, + } + sContours := *(*[]C.Points)(unsafe.Pointer(&cHdr)) + + contours := make([][]image.Point, cLength) + for i, pts := range sContours { + pArray := pts.points + pLength := int(pts.length) + pHdr := reflect.SliceHeader{ + Data: uintptr(unsafe.Pointer(pArray)), + Len: pLength, + Cap: pLength, + } + sPoints := *(*[]C.Point)(unsafe.Pointer(&pHdr)) + + points := make([]image.Point, pLength) + for j, pt := range sPoints { + points[j] = image.Pt(int(pt.x), int(pt.y)) + } + contours[i] = points + } + + return contours +} + +//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 = 1 + + // BBDT algorithm for 8-way connectivity, SAUF algorithm for 4-way connectivity + CCL_GRANA = 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 = 0 + + //The topmost (y) coordinate which is the inclusive start of the bounding box in the vertical direction. + CC_STAT_TOP = 1 + + // The horizontal size of the bounding box. + CC_STAT_WIDTH = 2 + + // The vertical size of the bounding box. + CC_STAT_HEIGHT = 3 + + // The total area (in pixels) of the connected component. + CC_STAT_AREA = 4 + + CC_STAT_MAX = 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 = 1 + // TmCcorr maps to TM_CCORR + TmCcorr = 2 + // TmCcorrNormed maps to TM_CCORR_NORMED + TmCcorrNormed = 3 + // TmCcoeff maps to TM_CCOEFF + TmCcoeff = 4 + // TmCcoeffNormed maps to TM_CCOEFF_NORMED + TmCcoeffNormed = 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) { + 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) { + pSize := C.struct_Size{ + height: C.int(ksize.X), + width: C.int(ksize.Y), + } + 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) { + pSize := C.struct_Size{ + height: C.int(ksize.X), + width: C.int(ksize.Y), + } + 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) { + 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) { + pt := C.struct_Point{ + x: C.int(-1), + y: C.int(-1), + } + 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 = 1 + + // MorphEllipse is the ellipse morph shape. + MorphEllipse = 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 = 1 + + // MorphOpen operation + MorphOpen = 2 + + // MorphClose operation + MorphClose = 3 + + // MorphGradient operation + MorphGradient = 4 + + // MorphTophat operation + MorphTophat = 5 + + // MorphBlackhat operation + MorphBlackhat = 6 + + // MorphHitmiss operation + MorphHitmiss = 7 +) + +// BorderType type of border. +type BorderType int + +const ( + // BorderConstant border type + BorderConstant BorderType = 0 + + // BorderReplicate border type + BorderReplicate = 1 + + // BorderReflect border type + BorderReflect = 2 + + // BorderWrap border type + BorderWrap = 3 + + // BorderReflect101 border type + BorderReflect101 = 4 + + // BorderTransparent border type + BorderTransparent = 5 + + // BorderDefault border type + BorderDefault = BorderReflect101 + + // BorderIsolated border type + BorderIsolated = 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) { + pSize := C.struct_Size{ + width: C.int(ksize.X), + height: C.int(ksize.Y), + } + + C.GaussianBlur(src.p, dst.p, pSize, C.double(sigmaX), C.double(sigmaY), C.int(borderType)) +} + +// 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, dx, dy, ksize int, scale, delta float64, borderType BorderType) { + 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 int, borderType BorderType) { + 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 int, size int, scale float64, + delta float64, borderType BorderType) { + 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 int, dx int, dy int, scale float64, + delta float64, borderType BorderType) { + 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) { + 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) { + 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) { + 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), + } + + C.CornerSubPix(img.p, corners.p, winSz, zeroSz, criteria.p) + return +} + +// 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) { + 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 = 1 + // GCEval means that the algorithm should just resume. + GCEval = 2 + // GCEvalFreezeModel means that the algorithm should just run a single iteration of the GrabCut algorithm + // with the fixed model + GCEvalFreezeModel = 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) { + 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), + } + + 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 = 1 + // HoughMultiScale is the multi-scale variant of the classical Hough + // transform. + HoughMultiScale = 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 = 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) { + 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) { + 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) { + 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) { + 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) { + 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) { + 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) { + 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 = 1 + + // ThresholdTrunc threshold type + ThresholdTrunc = 2 + + // ThresholdToZero threshold type + ThresholdToZero = 3 + + // ThresholdToZeroInv threshold type + ThresholdToZeroInv = 4 + + // ThresholdMask threshold type + ThresholdMask = 7 + + // ThresholdOtsu threshold type + ThresholdOtsu = 8 + + // ThresholdTriangle threshold type + ThresholdTriangle = 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) { + 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 = 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) { + 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) { + 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), + } + + 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) { + 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), + } + + C.Circle(img.p, pc, C.int(radius), 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 Ellipse(img *Mat, center, axes image.Point, angle, startAngle, endAngle float64, c color.RGBA, thickness int) { + 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), + } + + C.Ellipse(img.p, pc, pa, C.double(angle), C.double(startAngle), C.double(endAngle), sColor, C.int(thickness)) +} + +// 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) { + 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), + } + + 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) { + 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), + } + + C.Rectangle(img.p, cRect, sColor, C.int(thickness)) +} + +// 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 [][]image.Point, c color.RGBA) { + points := make([]C.struct_Points, len(pts)) + + for i, pt := range pts { + func() { + p := (*C.struct_Point)(C.malloc(C.size_t(C.sizeof_struct_Point * len(pt)))) + defer C.free(unsafe.Pointer(p)) + + pa := getPoints(p, len(pt)) + + 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)), + } + + sColor := C.struct_Scalar{ + val1: C.double(c.B), + val2: C.double(c.G), + val3: C.double(c.R), + val4: C.double(c.A), + } + + C.FillPoly(img.p, cPoints, sColor) +} + +// 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 = 1 + // FontHersheyDuplex normal size sans-serif font + // (more complex than FontHersheySIMPLEX). + FontHersheyDuplex = 2 + // FontHersheyComplex i a normal size serif font. + FontHersheyComplex = 3 + // FontHersheyTriplex is a normal size serif font + // (more complex than FontHersheyCOMPLEX). + FontHersheyTriplex = 4 + // FontHersheyComplexSmall is a smaller version of FontHersheyCOMPLEX. + FontHersheyComplexSmall = 5 + // FontHersheyScriptSimplex is a hand-writing style font. + FontHersheyScriptSimplex = 6 + // FontHersheyScriptComplex is a more complex variant of FontHersheyScriptSimplex. + FontHersheyScriptComplex = 7 + // FontItalic is the flag for italic font. + FontItalic = 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)) +} + +// 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) { + 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), + } + + C.PutText(img.p, cText, pOrg, C.int(fontFace), C.double(fontScale), sColor, C.int(thickness)) + return +} + +// 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 = 1 + + // InterpolationCubic is bicube interpolation. + InterpolationCubic = 2 + + // InterpolationArea uses pixel area relation. It is preferred for image + // decimation as it gives moire-free results. + InterpolationArea = 3 + + // InterpolationLanczos4 is Lanczos interpolation over 8x8 neighborhood. + InterpolationLanczos4 = 4 + + // InterpolationDefault is an alias for InterpolationLinear. + InterpolationDefault = InterpolationLinear + + // InterpolationMax indicates use maximum interpolation. + InterpolationMax = 7 +) + +// 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) { + pSize := C.struct_Size{ + width: C.int(sz.X), + height: C.int(sz.Y), + } + + C.Resize(src.p, dst.p, pSize, C.double(fx), C.double(fy), C.int(interp)) + return +} + +// 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) { + pSize := C.struct_Size{ + width: C.int(sz.X), + height: C.int(sz.Y), + } + + 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) { + 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), + } + 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 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) { + pSize := C.struct_Size{ + width: C.int(sz.X), + height: C.int(sz.Y), + } + + C.WarpPerspective(src.p, dst.p, m.p, pSize) +} + +// 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) { + 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 = 1 + ColormapJet = 2 + ColormapWinter = 3 + ColormapRainbow = 4 + ColormapOcean = 5 + ColormapSummer = 6 + ColormapSpring = 7 + ColormapCool = 8 + ColormapHsv = 9 + ColormapPink = 10 + ColormapHot = 11 + ColormapParula = 12 +) + +// 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) { + 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) { + C.ApplyCustomColorMap(src.p, dst.p, customColormap.p) +} + +// GetPerspectiveTransform returns 3x3 perspective transformation for the +// corresponding 4 point pairs. +// +// For further details, please see: +// https://docs.opencv.org/master/da/d54/group__imgproc__transform.html#ga8c1ae0e3589a9d77fffc962c49b22043 +func GetPerspectiveTransform(src, dst []image.Point) Mat { + srcPoints := toCPoints(src) + dstPoints := toCPoints(dst) + return newMat(C.GetPerspectiveTransform(srcPoints, dstPoints)) +} + +// DrawContours draws contours outlines or filled contours. +// +// For further details, please see: +// https://docs.opencv.org/3.3.1/d6/d6e/group__imgproc__draw.html#ga746c0625f1781f1ffc9056259103edbc +func DrawContours(img *Mat, contours [][]image.Point, contourIdx int, c color.RGBA, thickness int) { + cntrs := make([]C.struct_Points, len(contours)) + + for i, contour := range contours { + func() { + p := (*C.struct_Point)(C.malloc(C.size_t(C.sizeof_struct_Point * len(contour)))) + defer C.free(unsafe.Pointer(p)) + + pa := getPoints(p, len(contour)) + + for j, point := range contour { + pa[j] = C.struct_Point{ + x: C.int(point.X), + y: C.int(point.Y), + } + } + + cntrs[i] = C.struct_Points{ + points: (*C.Point)(p), + length: C.int(len(contour)), + } + }() + } + + cContours := C.struct_Contours{ + contours: (*C.struct_Points)(&cntrs[0]), + length: C.int(len(contours)), + } + + sColor := C.struct_Scalar{ + val1: C.double(c.B), + val2: C.double(c.G), + val3: C.double(c.R), + val4: C.double(c.A), + } + + C.DrawContours(img.p, cContours, C.int(contourIdx), sColor, C.int(thickness)) +} + +// 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) { + bv := C.struct_Scalar{ + val1: C.double(borderValue.B), + val2: C.double(borderValue.G), + val3: C.double(borderValue.R), + val4: C.double(borderValue.A), + } + 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 int, kernel Mat, anchor image.Point, delta float64, borderType BorderType) { + anchorP := C.struct_Point{ + x: C.int(anchor.X), + y: C.int(anchor.Y), + } + 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 int, kernelX, kernelY Mat, anchor image.Point, delta float64, borderType BorderType) { + anchorP := C.struct_Point{ + x: C.int(anchor.X), + y: C.int(anchor.Y), + } + 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) { + centerP := C.struct_Point{ + x: C.int(center.X), + y: C.int(center.Y), + } + C.LogPolar(src.p, dst.p, centerP, C.double(m), 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 = 1 + DistL2 = 2 + DistC = 3 + DistL12 = 4 + DistFair = 5 + DistWelsch = 6 + DistHuber = 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 []image.Point, line *Mat, distType DistanceTypes, param, reps, aeps float64) { + cPoints := toCPoints(pts) + C.FitLine(cPoints, line.p, C.int(distType), C.double(param), C.double(reps), C.double(aeps)) +} + +// 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) { + C.CLAHE_Apply((C.CLAHE)(c.p), src.p, dst.p) +} diff --git a/vendor/gocv.io/x/gocv/imgproc.h b/vendor/gocv.io/x/gocv/imgproc.h new file mode 100644 index 0000000..49f8f07 --- /dev/null +++ b/vendor/gocv.io/x/gocv/imgproc.h @@ -0,0 +1,113 @@ +#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(Contour curve, bool is_closed); +Contour ApproxPolyDP(Contour curve, double epsilon, bool closed); +void CvtColor(Mat src, Mat dst, int code); +void EqualizeHist(Mat src, Mat dst); +void CalcHist(struct Mats mats, IntVector chans, Mat mask, Mat hist, IntVector sz, FloatVector rng, bool acc); +void CalcBackProject(struct Mats mats, IntVector chans, Mat hist, Mat backProject, FloatVector rng, bool uniform); +double CompareHist(Mat hist1, Mat hist2, int method); +void ConvexHull(Contour points, Mat hull, bool clockwise, bool returnPoints); +void ConvexityDefects(Contour points, Mat hull, Mat result); +void BilateralFilter(Mat src, Mat dst, int d, double sc, double ss); +void Blur(Mat src, Mat dst, Size ps); +void BoxFilter(Mat src, Mat dst, int ddepth, Size ps); +void SqBoxFilter(Mat src, Mat dst, int ddepth, Size ps); +void Dilate(Mat src, Mat dst, Mat kernel); +void DistanceTransform(Mat src, Mat dst, Mat labels, int distanceType, int maskSize, int labelType); +void Erode(Mat src, Mat dst, Mat kernel); +void MatchTemplate(Mat image, Mat templ, Mat result, int method, Mat mask); +struct Moment Moments(Mat src, bool binaryImage); +void PyrDown(Mat src, Mat dst, Size dstsize, int borderType); +void PyrUp(Mat src, Mat dst, Size dstsize, int borderType); +struct Rect BoundingRect(Contour con); +void BoxPoints(RotatedRect rect, Mat boxPts); +double ContourArea(Contour con); +struct RotatedRect MinAreaRect(Points points); +void MinEnclosingCircle(Points points, Point2f* center, float* radius); +struct Contours FindContours(Mat src, int mode, int method); +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); + +void GaussianBlur(Mat src, Mat dst, Size ps, double sX, double sY, int bt); +void Laplacian(Mat src, Mat dst, int dDepth, int kSize, double scale, double delta, int borderType); +void 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(); +void MorphologyEx(Mat src, Mat dst, int op, Mat kernel); +void MorphologyExWithParams(Mat src, Mat dst, int op, Mat kernel, Point pt, int iterations, int borderType); +void MedianBlur(Mat src, Mat dst, int ksize); + +void Canny(Mat src, Mat edges, double t1, double t2); +void CornerSubPix(Mat img, Mat corners, Size winSize, Size zeroZone, TermCriteria criteria); +void GoodFeaturesToTrack(Mat img, Mat corners, int maxCorners, double quality, double minDist); +void GrabCut(Mat img, Mat mask, Rect rect, Mat bgdModel, Mat fgdModel, int iterCount, int mode); +void HoughCircles(Mat src, Mat circles, int method, double dp, double minDist); +void HoughCirclesWithParams(Mat src, Mat circles, int method, double dp, double minDist, + double param1, double param2, int minRadius, int maxRadius); +void HoughLines(Mat src, Mat lines, double rho, double theta, int threshold); +void HoughLinesP(Mat src, Mat lines, double rho, double theta, int threshold); +void HoughLinesPWithParams(Mat src, Mat lines, double rho, double theta, int threshold, double minLineLength, double maxLineGap); +void 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); +void Integral(Mat src, Mat sum, Mat sqsum, Mat tilted); +void Threshold(Mat src, Mat dst, double thresh, double maxvalue, int typ); +void AdaptiveThreshold(Mat src, Mat dst, double maxValue, int adaptiveTyp, int typ, int blockSize, + double c); + +void ArrowedLine(Mat img, Point pt1, Point pt2, Scalar color, int thickness); +void Circle(Mat img, Point center, int radius, Scalar color, int thickness); +void Ellipse(Mat img, Point center, Point axes, double angle, double + startAngle, double endAngle, Scalar color, int thickness); +void Line(Mat img, Point pt1, Point pt2, Scalar color, int thickness); +void Rectangle(Mat img, Rect rect, Scalar color, int thickness); +void FillPoly(Mat img, Contours points, Scalar color); +struct Size GetTextSize(const char* text, int fontFace, double fontScale, int thickness); +void PutText(Mat img, const char* text, Point org, int fontFace, double fontScale, + Scalar color, int thickness); +void Resize(Mat src, Mat dst, Size sz, double fx, double fy, int interp); +Mat GetRotationMatrix2D(Point center, double angle, double scale); +void WarpAffine(Mat src, Mat dst, Mat rot_mat, Size dsize); +void WarpAffineWithParams(Mat src, Mat dst, Mat rot_mat, Size dsize, int flags, int borderMode, + Scalar borderValue); +void WarpPerspective(Mat src, Mat dst, Mat m, Size dsize); +void Watershed(Mat image, Mat markers); +void ApplyColorMap(Mat src, Mat dst, int colormap); +void ApplyCustomColorMap(Mat src, Mat dst, Mat colormap); +Mat GetPerspectiveTransform(Contour src, Contour dst); +void DrawContours(Mat src, Contours contours, int contourIdx, Scalar color, int thickness); +void Sobel(Mat src, Mat dst, int ddepth, int dx, int dy, int ksize, double scale, double delta, int borderType); +void SpatialGradient(Mat src, Mat dx, Mat dy, int ksize, int borderType); +void Remap(Mat src, Mat dst, Mat map1, Mat map2, int interpolation, int borderMode, Scalar borderValue); +void Filter2D(Mat src, Mat dst, int ddepth, Mat kernel, Point anchor, double delta, int borderType); +void SepFilter2D(Mat src, Mat dst, int ddepth, Mat kernelX, Mat kernelY, Point anchor, double delta, int borderType); +void LogPolar(Mat src, Mat dst, Point center, double m, int flags); +void FitLine(Contour points, Mat line, int distType, double param, double reps, double aeps); +CLAHE CLAHE_Create(); +CLAHE CLAHE_CreateWithParams(double clipLimit, Size tileGridSize); +void CLAHE_Close(CLAHE c); +void CLAHE_Apply(CLAHE c, Mat src, Mat dst); + +#ifdef __cplusplus +} +#endif + +#endif //_OPENCV3_IMGPROC_H_ diff --git a/vendor/gocv.io/x/gocv/imgproc_colorcodes.go b/vendor/gocv.io/x/gocv/imgproc_colorcodes.go new file mode 100644 index 0000000..00f4315 --- /dev/null +++ b/vendor/gocv.io/x/gocv/imgproc_colorcodes.go @@ -0,0 +1,351 @@ +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 + + // ColorBGRAToBGR removes alpha channel from BGR image. + ColorBGRAToBGR = 1 + + // ColorBGRToRGBA converts from BGR to RGB with alpha channel. + ColorBGRToRGBA = 2 + + // ColorRGBAToBGR converts from RGB with alpha to BGR color space. + ColorRGBAToBGR = 3 + + // ColorBGRToRGB converts from BGR to RGB without alpha channel. + ColorBGRToRGB = 4 + + // ColorBGRAToRGBA converts from BGR with alpha channel + // to RGB with alpha channel. + ColorBGRAToRGBA = 5 + + // ColorBGRToGray converts from BGR to grayscale. + ColorBGRToGray = 6 + + // ColorRGBToGray converts from RGB to grayscale. + ColorRGBToGray = 7 + + // ColorGrayToBGR converts from grayscale to BGR. + ColorGrayToBGR = 8 + + // ColorGrayToBGRA converts from grayscale to BGR with alpha channel. + ColorGrayToBGRA = 9 + + // ColorBGRAToGray converts from BGR with alpha channel to grayscale. + ColorBGRAToGray = 10 + + // ColorRGBAToGray converts from RGB with alpha channel to grayscale. + ColorRGBAToGray = 11 + + // ColorBGRToBGR565 converts from BGR to BGR565 (16-bit images). + ColorBGRToBGR565 = 12 + + // ColorRGBToBGR565 converts from RGB to BGR565 (16-bit images). + ColorRGBToBGR565 = 13 + + // ColorBGR565ToBGR converts from BGR565 (16-bit images) to BGR. + ColorBGR565ToBGR = 14 + + // ColorBGR565ToRGB converts from BGR565 (16-bit images) to RGB. + ColorBGR565ToRGB = 15 + + // ColorBGRAToBGR565 converts from BGRA (with alpha channel) + // to BGR565 (16-bit images). + ColorBGRAToBGR565 = 16 + + // ColorRGBAToBGR565 converts from RGBA (with alpha channel) + // to BGR565 (16-bit images). + ColorRGBAToBGR565 = 17 + + // ColorBGR565ToBGRA converts from BGR565 (16-bit images) + // to BGRA (with alpha channel). + ColorBGR565ToBGRA = 18 + + // ColorBGR565ToRGBA converts from BGR565 (16-bit images) + // to RGBA (with alpha channel). + ColorBGR565ToRGBA = 19 + + // ColorGrayToBGR565 converts from grayscale + // to BGR565 (16-bit images). + ColorGrayToBGR565 = 20 + + // ColorBGR565ToGray converts from BGR565 (16-bit images) + // to grayscale. + ColorBGR565ToGray = 21 + + // ColorBGRToBGR555 converts from BGR to BGR555 (16-bit images). + ColorBGRToBGR555 = 22 + + // ColorRGBToBGR555 converts from RGB to BGR555 (16-bit images). + ColorRGBToBGR555 = 23 + + // ColorBGR555ToBGR converts from BGR555 (16-bit images) to BGR. + ColorBGR555ToBGR = 24 + + // ColorBGR555ToRGB converts from BGR555 (16-bit images) to RGB. + ColorBGR555ToRGB = 25 + + // ColorBGRAToBGR555 converts from BGRA (with alpha channel) + // to BGR555 (16-bit images). + ColorBGRAToBGR555 = 26 + + // ColorRGBAToBGR555 converts from RGBA (with alpha channel) + // to BGR555 (16-bit images). + ColorRGBAToBGR555 = 27 + + // ColorBGR555ToBGRA converts from BGR555 (16-bit images) + // to BGRA (with alpha channel). + ColorBGR555ToBGRA = 28 + + // ColorBGR555ToRGBA converts from BGR555 (16-bit images) + // to RGBA (with alpha channel). + ColorBGR555ToRGBA = 29 + + // ColorGrayToBGR555 converts from grayscale to BGR555 (16-bit images). + ColorGrayToBGR555 = 30 + + // ColorBGR555ToGRAY converts from BGR555 (16-bit images) to grayscale. + ColorBGR555ToGRAY = 31 + + // ColorBGRToXYZ converts from BGR to CIE XYZ. + ColorBGRToXYZ = 32 + + // ColorRGBToXYZ converts from RGB to CIE XYZ. + ColorRGBToXYZ = 33 + + // ColorXYZToBGR converts from CIE XYZ to BGR. + ColorXYZToBGR = 34 + + // ColorXYZToRGB converts from CIE XYZ to RGB. + ColorXYZToRGB = 35 + + // ColorBGRToYCrCb converts from BGR to luma-chroma (aka YCC). + ColorBGRToYCrCb = 36 + + // ColorRGBToYCrCb converts from RGB to luma-chroma (aka YCC). + ColorRGBToYCrCb = 37 + + // ColorYCrCbToBGR converts from luma-chroma (aka YCC) to BGR. + ColorYCrCbToBGR = 38 + + // ColorYCrCbToRGB converts from luma-chroma (aka YCC) to RGB. + ColorYCrCbToRGB = 39 + + // ColorBGRToHSV converts from BGR to HSV (hue saturation value). + ColorBGRToHSV = 40 + + // ColorRGBToHSV converts from RGB to HSV (hue saturation value). + ColorRGBToHSV = 41 + + // ColorBGRToLab converts from BGR to CIE Lab. + ColorBGRToLab = 44 + + // ColorRGBToLab converts from RGB to CIE Lab. + ColorRGBToLab = 45 + + // ColorBGRToLuv converts from BGR to CIE Luv. + ColorBGRToLuv = 50 + + // ColorRGBToLuv converts from RGB to CIE Luv. + ColorRGBToLuv = 51 + + // ColorBGRToHLS converts from BGR to HLS (hue lightness saturation). + ColorBGRToHLS = 52 + + // ColorRGBToHLS converts from RGB to HLS (hue lightness saturation). + ColorRGBToHLS = 53 + + // ColorHSVToBGR converts from HSV (hue saturation value) to BGR. + ColorHSVToBGR = 54 + + // ColorHSVToRGB converts from HSV (hue saturation value) to RGB. + ColorHSVToRGB = 55 + + // ColorLabToBGR converts from CIE Lab to BGR. + ColorLabToBGR = 56 + + // ColorLabToRGB converts from CIE Lab to RGB. + ColorLabToRGB = 57 + + // ColorLuvToBGR converts from CIE Luv to BGR. + ColorLuvToBGR = 58 + + // ColorLuvToRGB converts from CIE Luv to RGB. + ColorLuvToRGB = 59 + + // ColorHLSToBGR converts from HLS (hue lightness saturation) to BGR. + ColorHLSToBGR = 60 + + // ColorHLSToRGB converts from HLS (hue lightness saturation) to RGB. + ColorHLSToRGB = 61 + + // ColorBGRToHSVFull converts from BGR to HSV (hue saturation value) full. + ColorBGRToHSVFull = 66 + + // ColorRGBToHSVFull converts from RGB to HSV (hue saturation value) full. + ColorRGBToHSVFull = 67 + + // ColorBGRToHLSFull converts from BGR to HLS (hue lightness saturation) full. + ColorBGRToHLSFull = 68 + + // ColorRGBToHLSFull converts from RGB to HLS (hue lightness saturation) full. + ColorRGBToHLSFull = 69 + + // ColorHSVToBGRFull converts from HSV (hue saturation value) to BGR full. + ColorHSVToBGRFull = 70 + + // ColorHSVToRGBFull converts from HSV (hue saturation value) to RGB full. + ColorHSVToRGBFull = 71 + + // ColorHLSToBGRFull converts from HLS (hue lightness saturation) to BGR full. + ColorHLSToBGRFull = 72 + + // ColorHLSToRGBFull converts from HLS (hue lightness saturation) to RGB full. + ColorHLSToRGBFull = 73 + + // ColorLBGRToLab converts from LBGR to CIE Lab. + ColorLBGRToLab = 74 + + // ColorLRGBToLab converts from LRGB to CIE Lab. + ColorLRGBToLab = 75 + + // ColorLBGRToLuv converts from LBGR to CIE Luv. + ColorLBGRToLuv = 76 + + // ColorLRGBToLuv converts from LRGB to CIE Luv. + ColorLRGBToLuv = 77 + + // ColorLabToLBGR converts from CIE Lab to LBGR. + ColorLabToLBGR = 78 + + // ColorLabToLRGB converts from CIE Lab to LRGB. + ColorLabToLRGB = 79 + + // ColorLuvToLBGR converts from CIE Luv to LBGR. + ColorLuvToLBGR = 80 + + // ColorLuvToLRGB converts from CIE Luv to LRGB. + ColorLuvToLRGB = 81 + + // ColorBGRToYUV converts from BGR to YUV. + ColorBGRToYUV = 82 + + // ColorRGBToYUV converts from RGB to YUV. + ColorRGBToYUV = 83 + + // ColorYUVToBGR converts from YUV to BGR. + ColorYUVToBGR = 84 + + // ColorYUVToRGB converts from YUV to RGB. + ColorYUVToRGB = 85 + + // ColorYUVToRGBNV12 converts from YUV 4:2:0 to RGB NV12. + ColorYUVToRGBNV12 = 90 + + // ColorYUVToBGRNV12 converts from YUV 4:2:0 to BGR NV12. + ColorYUVToBGRNV12 = 91 + + // ColorYUVToRGBNV21 converts from YUV 4:2:0 to RGB NV21. + ColorYUVToRGBNV21 = 92 + + // ColorYUVToBGRNV21 converts from YUV 4:2:0 to BGR NV21. + ColorYUVToBGRNV21 = 93 + + // ColorYUVToRGBANV12 converts from YUV 4:2:0 to RGBA NV12. + ColorYUVToRGBANV12 = 94 + + // ColorYUVToBGRANV12 converts from YUV 4:2:0 to BGRA NV12. + ColorYUVToBGRANV12 = 95 + + // ColorYUVToRGBANV21 converts from YUV 4:2:0 to RGBA NV21. + ColorYUVToRGBANV21 = 96 + + // ColorYUVToBGRANV21 converts from YUV 4:2:0 to BGRA NV21. + ColorYUVToBGRANV21 = 97 + + ColorYUVToRGBYV12 = 98 + ColorYUVToBGRYV12 = 99 + ColorYUVToRGBIYUV = 100 + ColorYUVToBGRIYUV = 101 + + ColorYUVToRGBAYV12 = 102 + ColorYUVToBGRAYV12 = 103 + ColorYUVToRGBAIYUV = 104 + ColorYUVToBGRAIYUV = 105 + + ColorYUVToGRAY420 = 106 + + // YUV 4:2:2 family to RGB + ColorYUVToRGBUYVY = 107 + ColorYUVToBGRUYVY = 108 + + ColorYUVToRGBAUYVY = 111 + ColorYUVToBGRAUYVY = 112 + + ColorYUVToRGBYUY2 = 115 + ColorYUVToBGRYUY2 = 116 + ColorYUVToRGBYVYU = 117 + ColorYUVToBGRYVYU = 118 + + ColorYUVToRGBAYUY2 = 119 + ColorYUVToBGRAYUY2 = 120 + ColorYUVToRGBAYVYU = 121 + ColorYUVToBGRAYVYU = 122 + + ColorYUVToGRAYUYVY = 123 + ColorYUVToGRAYYUY2 = 124 + + // alpha premultiplication + ColorRGBATomRGBA = 125 + ColormRGBAToRGBA = 126 + + // RGB to YUV 4:2:0 family + ColorRGBToYUVI420 = 127 + ColorBGRToYUVI420 = 128 + + ColorRGBAToYUVI420 = 129 + ColorBGRAToYUVI420 = 130 + ColorRGBToYUVYV12 = 131 + ColorBGRToYUVYV12 = 132 + ColorRGBAToYUVYV12 = 133 + ColorBGRAToYUVYV12 = 134 + + // Demosaicing + ColorBayerBGToBGR = 46 + ColorBayerGBToBGR = 47 + ColorBayerRGToBGR = 48 + ColorBayerGRToBGR = 49 + + ColorBayerBGToGRAY = 86 + ColorBayerGBToGRAY = 87 + ColorBayerRGToGRAY = 88 + ColorBayerGRToGRAY = 89 + + // Demosaicing using Variable Number of Gradients + ColorBayerBGToBGRVNG = 62 + ColorBayerGBToBGRVNG = 63 + ColorBayerRGToBGRVNG = 64 + ColorBayerGRToBGRVNG = 65 + + // Edge-Aware Demosaicing + ColorBayerBGToBGREA = 135 + ColorBayerGBToBGREA = 136 + ColorBayerRGToBGREA = 137 + ColorBayerGRToBGREA = 138 + + // Demosaicing with alpha channel + ColorBayerBGToBGRA = 139 + ColorBayerGBToBGRA = 140 + ColorBayerRGToBGRA = 141 + ColorBayerGRToBGRA = 142 + + ColorCOLORCVTMAX = 143 +) diff --git a/vendor/gocv.io/x/gocv/mat_noprofile.go b/vendor/gocv.io/x/gocv/mat_noprofile.go new file mode 100644 index 0000000..0ae8a16 --- /dev/null +++ b/vendor/gocv.io/x/gocv/mat_noprofile.go @@ -0,0 +1,21 @@ +// +build !matprofile + +package gocv + +/* +#include +#include "core.h" +*/ +import "C" + +// 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 + return nil +} diff --git a/vendor/gocv.io/x/gocv/mat_profile.go b/vendor/gocv.io/x/gocv/mat_profile.go new file mode 100644 index 0000000..b921cab --- /dev/null +++ b/vendor/gocv.io/x/gocv/mat_profile.go @@ -0,0 +1,74 @@ +// +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) + } +} + +// 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 { + C.Mat_Close(m.p) + MatProfile.Remove(m.p) + m.p = nil + return nil +} diff --git a/vendor/gocv.io/x/gocv/objdetect.cpp b/vendor/gocv.io/x/gocv/objdetect.cpp new file mode 100644 index 0000000..e3bb4e7 --- /dev/null +++ b/vendor/gocv.io/x/gocv/objdetect.cpp @@ -0,0 +1,127 @@ +#include "objdetect.h" + +// CascadeClassifier + +CascadeClassifier CascadeClassifier_New() { + return new cv::CascadeClassifier(); +} + +void CascadeClassifier_Close(CascadeClassifier cs) { + delete cs; +} + +int CascadeClassifier_Load(CascadeClassifier cs, const char* name) { + return cs->load(name); +} + +struct Rects CascadeClassifier_DetectMultiScale(CascadeClassifier cs, Mat img) { + 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; +} + +struct Rects CascadeClassifier_DetectMultiScaleWithParams(CascadeClassifier cs, Mat img, + double scale, int minNeighbors, int flags, Size minSize, Size maxSize) { + + 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; +} + +// HOGDescriptor + +HOGDescriptor HOGDescriptor_New() { + return new cv::HOGDescriptor(); +} + +void HOGDescriptor_Close(HOGDescriptor hog) { + delete hog; +} + +int HOGDescriptor_Load(HOGDescriptor hog, const char* name) { + return hog->load(name); +} + +struct Rects HOGDescriptor_DetectMultiScale(HOGDescriptor hog, Mat img) { + 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; +} + +struct Rects HOGDescriptor_DetectMultiScaleWithParams(HOGDescriptor hog, Mat img, + double hitThresh, Size winStride, Size padding, double scale, double finalThresh, + bool useMeanshiftGrouping) { + + 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; +} + +Mat HOG_GetDefaultPeopleDetector() { + return new cv::Mat(cv::HOGDescriptor::getDefaultPeopleDetector()); +} + +void HOGDescriptor_SetSVMDetector(HOGDescriptor hog, Mat det) { + hog->setSVMDetector(*det); +} + +struct Rects GroupRectangles(struct Rects rects, int groupThreshold, double eps) { + 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; +} diff --git a/vendor/gocv.io/x/gocv/objdetect.go b/vendor/gocv.io/x/gocv/objdetect.go new file mode 100644 index 0000000..8a9b0ff --- /dev/null +++ b/vendor/gocv.io/x/gocv/objdetect.go @@ -0,0 +1,186 @@ +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) +} diff --git a/vendor/gocv.io/x/gocv/objdetect.h b/vendor/gocv.io/x/gocv/objdetect.h new file mode 100644 index 0000000..362510f --- /dev/null +++ b/vendor/gocv.io/x/gocv/objdetect.h @@ -0,0 +1,45 @@ +#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; +#else +typedef void* CascadeClassifier; +typedef void* HOGDescriptor; +#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); + +#ifdef __cplusplus +} +#endif + +#endif //_OPENCV3_OBJDETECT_H_ diff --git a/vendor/gocv.io/x/gocv/travis_build_opencv.sh b/vendor/gocv.io/x/gocv/travis_build_opencv.sh new file mode 100644 index 0000000..4357b24 --- /dev/null +++ b/vendor/gocv.io/x/gocv/travis_build_opencv.sh @@ -0,0 +1,79 @@ +#!/bin/bash +set -eux -o pipefail + +OPENCV_VERSION=${OPENCV_VERSION:-4.1.2} + +#GRAPHICAL=ON +GRAPHICAL=${GRAPHICAL:-OFF} + +# OpenCV looks for libjpeg in /usr/lib/libjpeg.so, for some reason. However, +# it does not seem to be there in 14.04. Create a link + +mkdir -p $HOME/usr/lib + +if [[ ! -f "$HOME/usr/lib/libjpeg.so" ]]; then + ln -s /usr/lib/x86_64-linux-gnu/libjpeg.so $HOME/usr/lib/libjpeg.so +fi + +# Same for libpng.so + +if [[ ! -f "$HOME/usr/lib/libpng.so" ]]; then + ln -s /usr/lib/x86_64-linux-gnu/libpng.so $HOME/usr/lib/libpng.so +fi + +# Build OpenCV +if [[ ! -e "$HOME/usr/installed-${OPENCV_VERSION}" ]]; then +TMP=$(mktemp -d) +if [[ ! -d "opencv-${OPENCV_VERSION}/build" ]]; then + curl -sL https://github.com/opencv/opencv/archive/${OPENCV_VERSION}.zip > ${TMP}/opencv.zip + unzip -q ${TMP}/opencv.zip + mkdir opencv-${OPENCV_VERSION}/build + rm ${TMP}/opencv.zip +fi + +if [[ ! -d "opencv_contrib-${OPENCV_VERSION}/modules" ]]; then + curl -sL https://github.com/opencv/opencv_contrib/archive/${OPENCV_VERSION}.zip > ${TMP}/opencv-contrib.zip + unzip -q ${TMP}/opencv-contrib.zip + rm ${TMP}/opencv-contrib.zip +fi +rmdir ${TMP} + +cd opencv-${OPENCV_VERSION}/build +cmake -D WITH_IPP=${GRAPHICAL} \ + -D WITH_OPENGL=${GRAPHICAL} \ + -D WITH_QT=${GRAPHICAL} \ + -D BUILD_EXAMPLES=OFF \ + -D BUILD_TESTS=OFF \ + -D BUILD_PERF_TESTS=OFF \ + -D BUILD_opencv_java=OFF \ + -D BUILD_opencv_python=OFF \ + -D BUILD_opencv_python2=OFF \ + -D BUILD_opencv_python3=OFF \ + -D OPENCV_GENERATE_PKGCONFIG=ON \ + -D CMAKE_INSTALL_PREFIX=$HOME/usr \ + -D OPENCV_ENABLE_NONFREE=ON \ + -D OPENCV_EXTRA_MODULES_PATH=../../opencv_contrib-${OPENCV_VERSION}/modules .. +make -j8 +make install && touch $HOME/usr/installed-${OPENCV_VERSION} + +# caffe test data +if [[ ! -d "${HOME}/testdata" ]]; then + mkdir ${HOME}/testdata +fi + +#if [[ ! -f "${HOME}/testdata/bvlc_googlenet.prototxt" ]]; then + curl -sL https://raw.githubusercontent.com/opencv/opencv_extra/master/testdata/dnn/bvlc_googlenet.prototxt > ${HOME}/testdata/bvlc_googlenet.prototxt +#fi + +#if [[ ! -f "${HOME}/testdata/bvlc_googlenet.caffemodel" ]]; then + curl -sL http://dl.caffe.berkeleyvision.org/bvlc_googlenet.caffemodel > ${HOME}/testdata/bvlc_googlenet.caffemodel +#fi + +#if [[ ! -f "${HOME}/testdata/tensorflow_inception_graph.pb" ]]; then + curl -sL https://storage.googleapis.com/download.tensorflow.org/models/inception5h.zip > ${HOME}/testdata/inception5h.zip + unzip -o ${HOME}/testdata/inception5h.zip tensorflow_inception_graph.pb -d ${HOME}/testdata +#fi + +cd ../.. +touch $HOME/fresh-cache +fi diff --git a/vendor/gocv.io/x/gocv/version.cpp b/vendor/gocv.io/x/gocv/version.cpp new file mode 100644 index 0000000..d4aa165 --- /dev/null +++ b/vendor/gocv.io/x/gocv/version.cpp @@ -0,0 +1,5 @@ +#include "version.h" + +const char* openCVVersion() { + return CV_VERSION; +} diff --git a/vendor/gocv.io/x/gocv/version.go b/vendor/gocv.io/x/gocv/version.go new file mode 100644 index 0000000..6be4c81 --- /dev/null +++ b/vendor/gocv.io/x/gocv/version.go @@ -0,0 +1,20 @@ +package gocv + +/* +#include +#include "version.h" +*/ +import "C" + +// GoCVVersion of this package, for display purposes. +const GoCVVersion = "0.21.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()) +} diff --git a/vendor/gocv.io/x/gocv/version.h b/vendor/gocv.io/x/gocv/version.h new file mode 100644 index 0000000..3372e57 --- /dev/null +++ b/vendor/gocv.io/x/gocv/version.h @@ -0,0 +1,17 @@ +#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_ diff --git a/vendor/gocv.io/x/gocv/video.cpp b/vendor/gocv.io/x/gocv/video.cpp new file mode 100644 index 0000000..29775e8 --- /dev/null +++ b/vendor/gocv.io/x/gocv/video.cpp @@ -0,0 +1,49 @@ +#include "video.h" + +BackgroundSubtractorMOG2 BackgroundSubtractorMOG2_Create() { + return new cv::Ptr(cv::createBackgroundSubtractorMOG2()); +} + +BackgroundSubtractorMOG2 BackgroundSubtractorMOG2_CreateWithParams(int history, double varThreshold, bool detectShadows) { + return new cv::Ptr(cv::createBackgroundSubtractorMOG2(history,varThreshold,detectShadows)); +} + +BackgroundSubtractorKNN BackgroundSubtractorKNN_Create() { + return new cv::Ptr(cv::createBackgroundSubtractorKNN()); +} + +BackgroundSubtractorKNN BackgroundSubtractorKNN_CreateWithParams(int history, double dist2Threshold, bool detectShadows) { + return new cv::Ptr(cv::createBackgroundSubtractorKNN(history,dist2Threshold,detectShadows)); +} + +void BackgroundSubtractorMOG2_Close(BackgroundSubtractorMOG2 b) { + delete b; +} + +void BackgroundSubtractorMOG2_Apply(BackgroundSubtractorMOG2 b, Mat src, Mat dst) { + (*b)->apply(*src, *dst); +} + +void BackgroundSubtractorKNN_Close(BackgroundSubtractorKNN k) { + delete k; +} + +void BackgroundSubtractorKNN_Apply(BackgroundSubtractorKNN k, Mat src, Mat dst) { + (*k)->apply(*src, *dst); +} + +void CalcOpticalFlowFarneback(Mat prevImg, Mat nextImg, Mat flow, double scale, int levels, + int winsize, int iterations, int polyN, double polySigma, int flags) { + cv::calcOpticalFlowFarneback(*prevImg, *nextImg, *flow, scale, levels, winsize, iterations, polyN, + polySigma, flags); +} + +void CalcOpticalFlowPyrLK(Mat prevImg, Mat nextImg, Mat prevPts, Mat nextPts, Mat status, Mat err) { + cv::calcOpticalFlowPyrLK(*prevImg, *nextImg, *prevPts, *nextPts, *status, *err); +} + +void CalcOpticalFlowPyrLKWithParams(Mat prevImg, Mat nextImg, Mat prevPts, Mat nextPts, Mat status, Mat err, Size winSize, int maxLevel, TermCriteria criteria, int flags, double minEigThreshold){ + cv::Size sz(winSize.width, winSize.height); + cv::calcOpticalFlowPyrLK(*prevImg, *nextImg, *prevPts, *nextPts, *status, *err, sz, maxLevel, *criteria, flags, minEigThreshold); +} + diff --git a/vendor/gocv.io/x/gocv/video.go b/vendor/gocv.io/x/gocv/video.go new file mode 100644 index 0000000..a202554 --- /dev/null +++ b/vendor/gocv.io/x/gocv/video.go @@ -0,0 +1,157 @@ +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 +) + +// 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) { + C.BackgroundSubtractorMOG2_Apply((C.BackgroundSubtractorMOG2)(b.p), src.p, dst.p) + return +} + +// 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) { + C.BackgroundSubtractorKNN_Apply((C.BackgroundSubtractorKNN)(k.p), src.p, dst.p) + return +} + +// 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) { + 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)) + return +} + +// 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) { + C.CalcOpticalFlowPyrLK(prevImg.p, nextImg.p, prevPts.p, nextPts.p, status.p, err.p) + return +} + +// 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) { + winSz := C.struct_Size{ + width: C.int(winSize.X), + height: C.int(winSize.Y), + } + 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)) + return +} diff --git a/vendor/gocv.io/x/gocv/video.h b/vendor/gocv.io/x/gocv/video.h new file mode 100644 index 0000000..10b0a1b --- /dev/null +++ b/vendor/gocv.io/x/gocv/video.h @@ -0,0 +1,38 @@ +#ifndef _OPENCV3_VIDEO_H_ +#define _OPENCV3_VIDEO_H_ + +#ifdef __cplusplus +#include +extern "C" { +#endif + +#include "core.h" + +#ifdef __cplusplus +typedef cv::Ptr* BackgroundSubtractorMOG2; +typedef cv::Ptr* BackgroundSubtractorKNN; +#else +typedef void* BackgroundSubtractorMOG2; +typedef void* BackgroundSubtractorKNN; +#endif + +BackgroundSubtractorMOG2 BackgroundSubtractorMOG2_Create(); +BackgroundSubtractorMOG2 BackgroundSubtractorMOG2_CreateWithParams(int history, double varThreshold, bool detectShadows); +void BackgroundSubtractorMOG2_Close(BackgroundSubtractorMOG2 b); +void BackgroundSubtractorMOG2_Apply(BackgroundSubtractorMOG2 b, Mat src, Mat dst); + +BackgroundSubtractorKNN BackgroundSubtractorKNN_Create(); +BackgroundSubtractorKNN BackgroundSubtractorKNN_CreateWithParams(int history, double dist2Threshold, bool detectShadows); + +void BackgroundSubtractorKNN_Close(BackgroundSubtractorKNN b); +void BackgroundSubtractorKNN_Apply(BackgroundSubtractorKNN b, Mat src, Mat dst); + +void CalcOpticalFlowPyrLK(Mat prevImg, Mat nextImg, Mat prevPts, Mat nextPts, Mat status, Mat err); +void CalcOpticalFlowPyrLKWithParams(Mat prevImg, Mat nextImg, Mat prevPts, Mat nextPts, Mat status, Mat err, Size winSize, int maxLevel, TermCriteria criteria, int flags, double minEigThreshold); +void CalcOpticalFlowFarneback(Mat prevImg, Mat nextImg, Mat flow, double pyrScale, int levels, + int winsize, int iterations, int polyN, double polySigma, int flags); +#ifdef __cplusplus +} +#endif + +#endif //_OPENCV3_VIDEO_H_ diff --git a/vendor/gocv.io/x/gocv/videoio.cpp b/vendor/gocv.io/x/gocv/videoio.cpp new file mode 100644 index 0000000..2090fd5 --- /dev/null +++ b/vendor/gocv.io/x/gocv/videoio.cpp @@ -0,0 +1,63 @@ +#include "videoio.h" + +// VideoWriter +VideoCapture VideoCapture_New() { + return new cv::VideoCapture(); +} + +void VideoCapture_Close(VideoCapture v) { + delete v; +} + +bool VideoCapture_Open(VideoCapture v, const char* uri) { + return v->open(uri); +} + +bool VideoCapture_OpenDevice(VideoCapture v, int device) { + return v->open(device); +} + +void VideoCapture_Set(VideoCapture v, int prop, double param) { + v->set(prop, param); +} + +double VideoCapture_Get(VideoCapture v, int prop) { + return v->get(prop); +} + +int VideoCapture_IsOpened(VideoCapture v) { + return v->isOpened(); +} + +int VideoCapture_Read(VideoCapture v, Mat buf) { + return v->read(*buf); +} + +void VideoCapture_Grab(VideoCapture v, int skip) { + for (int i = 0; i < skip; i++) { + v->grab(); + } +} + +// VideoWriter +VideoWriter VideoWriter_New() { + return new cv::VideoWriter(); +} + +void VideoWriter_Close(VideoWriter vw) { + delete vw; +} + +void VideoWriter_Open(VideoWriter vw, const char* name, const char* codec, double fps, int width, + int height, bool isColor) { + int codecCode = cv::VideoWriter::fourcc(codec[0], codec[1], codec[2], codec[3]); + vw->open(name, codecCode, fps, cv::Size(width, height), isColor); +} + +int VideoWriter_IsOpened(VideoWriter vw) { + return vw->isOpened(); +} + +void VideoWriter_Write(VideoWriter vw, Mat img) { + *vw << *img; +} diff --git a/vendor/gocv.io/x/gocv/videoio.go b/vendor/gocv.io/x/gocv/videoio.go new file mode 100644 index 0000000..13f7620 --- /dev/null +++ b/vendor/gocv.io/x/gocv/videoio.go @@ -0,0 +1,332 @@ +package gocv + +/* +#include +#include "videoio.h" +*/ +import "C" +import ( + "errors" + "fmt" + "strconv" + "sync" + "unsafe" +) + +// VideoCaptureProperties are the properties used for VideoCapture operations. +type VideoCaptureProperties int + +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 = 1 + + // VideoCapturePosAVIRatio relative position of the video file: + // 0=start of the film, 1=end of the film. + VideoCapturePosAVIRatio = 2 + + // VideoCaptureFrameWidth is width of the frames in the video stream. + VideoCaptureFrameWidth = 3 + + // VideoCaptureFrameHeight controls height of frames in the video stream. + VideoCaptureFrameHeight = 4 + + // VideoCaptureFPS controls capture frame rate. + VideoCaptureFPS = 5 + + // VideoCaptureFOURCC contains the 4-character code of codec. + // see VideoWriter::fourcc for details. + VideoCaptureFOURCC = 6 + + // VideoCaptureFrameCount contains number of frames in the video file. + VideoCaptureFrameCount = 7 + + // VideoCaptureFormat format of the Mat objects returned by + // VideoCapture::retrieve(). + VideoCaptureFormat = 8 + + // VideoCaptureMode contains backend-specific value indicating + // the current capture mode. + VideoCaptureMode = 9 + + // VideoCaptureBrightness is brightness of the image + // (only for those cameras that support). + VideoCaptureBrightness = 10 + + // VideoCaptureContrast is contrast of the image + // (only for cameras that support it). + VideoCaptureContrast = 11 + + // VideoCaptureSaturation saturation of the image + // (only for cameras that support). + VideoCaptureSaturation = 12 + + // VideoCaptureHue hue of the image (only for cameras that support). + VideoCaptureHue = 13 + + // VideoCaptureGain is the gain of the capture image. + // (only for those cameras that support). + VideoCaptureGain = 14 + + // VideoCaptureExposure is the exposure of the capture image. + // (only for those cameras that support). + VideoCaptureExposure = 15 + + // VideoCaptureConvertRGB is a boolean flags indicating whether + // images should be converted to RGB. + VideoCaptureConvertRGB = 16 + + // VideoCaptureWhiteBalanceBlueU is currently unsupported. + VideoCaptureWhiteBalanceBlueU = 17 + + // VideoCaptureRectification is the rectification flag for stereo cameras. + // Note: only supported by DC1394 v 2.x backend currently. + VideoCaptureRectification = 18 + + // VideoCaptureMonochrome indicates whether images should be + // converted to monochrome. + VideoCaptureMonochrome = 19 + + // VideoCaptureSharpness controls image capture sharpness. + VideoCaptureSharpness = 20 + + // VideoCaptureAutoExposure controls the DC1394 exposure control + // done by camera, user can adjust reference level using this feature. + VideoCaptureAutoExposure = 21 + + // VideoCaptureGamma controls video capture gamma. + VideoCaptureGamma = 22 + + // VideoCaptureTemperature controls video capture temperature. + VideoCaptureTemperature = 23 + + // VideoCaptureTrigger controls video capture trigger. + VideoCaptureTrigger = 24 + + // VideoCaptureTriggerDelay controls video capture trigger delay. + VideoCaptureTriggerDelay = 25 + + // VideoCaptureWhiteBalanceRedV controls video capture setting for + // white balance. + VideoCaptureWhiteBalanceRedV = 26 + + // VideoCaptureZoom controls video capture zoom. + VideoCaptureZoom = 27 + + // VideoCaptureFocus controls video capture focus. + VideoCaptureFocus = 28 + + // VideoCaptureGUID controls video capture GUID. + VideoCaptureGUID = 29 + + // VideoCaptureISOSpeed controls video capture ISO speed. + VideoCaptureISOSpeed = 30 + + // VideoCaptureBacklight controls video capture backlight. + VideoCaptureBacklight = 32 + + // VideoCapturePan controls video capture pan. + VideoCapturePan = 33 + + // VideoCaptureTilt controls video capture tilt. + VideoCaptureTilt = 34 + + // VideoCaptureRoll controls video capture roll. + VideoCaptureRoll = 35 + + // VideoCaptureIris controls video capture iris. + VideoCaptureIris = 36 + + // VideoCaptureSettings is the pop up video/camera filter dialog. Note: + // only supported by DSHOW backend currently. The property value is ignored. + VideoCaptureSettings = 37 + + // VideoCaptureBufferSize controls video capture buffer size. + VideoCaptureBufferSize = 38 + + // VideoCaptureAutoFocus controls video capture auto focus.. + VideoCaptureAutoFocus = 39 +) + +// 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 +} + +// 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 +} + +// 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) { + C.VideoCapture_Grab(v.p, C.int(skip)) +} + +// 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(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)) + + C.VideoWriter_Open(vw.p, cName, cCodec, C.double(fps), C.int(width), C.int(height), C.bool(isColor)) + 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() + C.VideoWriter_Write(vw.p, img.p) + return nil +} + +// 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") + } +} diff --git a/vendor/gocv.io/x/gocv/videoio.h b/vendor/gocv.io/x/gocv/videoio.h new file mode 100644 index 0000000..b779fd9 --- /dev/null +++ b/vendor/gocv.io/x/gocv/videoio.h @@ -0,0 +1,42 @@ +#ifndef _OPENCV3_VIDEOIO_H_ +#define _OPENCV3_VIDEOIO_H_ + +#ifdef __cplusplus +#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_OpenDevice(VideoCapture v, int device); +void 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); +void VideoCapture_Grab(VideoCapture v, int skip); + +// VideoWriter +VideoWriter VideoWriter_New(); +void VideoWriter_Close(VideoWriter vw); +void VideoWriter_Open(VideoWriter vw, const char* name, const char* codec, double fps, int width, + int height, bool isColor); +int VideoWriter_IsOpened(VideoWriter vw); +void VideoWriter_Write(VideoWriter vw, Mat img); + +#ifdef __cplusplus +} +#endif + +#endif //_OPENCV3_VIDEOIO_H_ diff --git a/vendor/gocv.io/x/gocv/win_build_opencv.cmd b/vendor/gocv.io/x/gocv/win_build_opencv.cmd new file mode 100644 index 0000000..feeca44 --- /dev/null +++ b/vendor/gocv.io/x/gocv/win_build_opencv.cmd @@ -0,0 +1,40 @@ +echo off + +if not exist "C:\opencv" mkdir "C:\opencv" +if not exist "C:\opencv\build" mkdir "C:\opencv\build" + +echo Downloading OpenCV sources +echo. +echo For monitoring the download progress please check the C:\opencv directory. +echo. + +REM This is why there is no progress bar: +REM https://github.com/PowerShell/PowerShell/issues/2138 + +echo Downloading: opencv-4.1.2.zip [91MB] +powershell -command "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $ProgressPreference = 'SilentlyContinue'; Invoke-WebRequest -Uri https://github.com/opencv/opencv/archive/4.1.2.zip -OutFile c:\opencv\opencv-4.1.2.zip" +echo Extracting... +powershell -command "$ProgressPreference = 'SilentlyContinue'; Expand-Archive -Path c:\opencv\opencv-4.1.2.zip -DestinationPath c:\opencv" +del c:\opencv\opencv-4.1.2.zip /q +echo. + +echo Downloading: opencv_contrib-4.1.2.zip [58MB] +powershell -command "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $ProgressPreference = 'SilentlyContinue'; Invoke-WebRequest -Uri https://github.com/opencv/opencv_contrib/archive/4.1.2.zip -OutFile c:\opencv\opencv_contrib-4.1.2.zip" +echo Extracting... +powershell -command "$ProgressPreference = 'SilentlyContinue'; Expand-Archive -Path c:\opencv\opencv_contrib-4.1.2.zip -DestinationPath c:\opencv" +del c:\opencv\opencv_contrib-4.1.2.zip /q +echo. + +echo Done with downloading and extracting sources. +echo. + +echo on + +cd /D C:\opencv\build +set PATH=%PATH%;C:\Program Files (x86)\CMake\bin;C:\mingw-w64\x86_64-6.3.0-posix-seh-rt_v5-rev1\mingw64\bin +cmake C:\opencv\opencv-4.1.2 -G "MinGW Makefiles" -BC:\opencv\build -DENABLE_CXX11=ON -DOPENCV_EXTRA_MODULES_PATH=C:\opencv\opencv_contrib-4.1.2\modules -DBUILD_SHARED_LIBS=ON -DWITH_IPP=OFF -DWITH_MSMF=OFF -DBUILD_EXAMPLES=OFF -DBUILD_TESTS=OFF -DBUILD_PERF_TESTS=OFF -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 -DCPU_DISPATCH= -DOPENCV_GENERATE_PKGCONFIG=ON -DWITH_OPENCL_D3D11_NV=OFF -Wno-dev +mingw32-make -j%NUMBER_OF_PROCESSORS% +mingw32-make install +rmdir c:\opencv\opencv-4.1.2 /s /q +rmdir c:\opencv\opencv_contrib-4.1.2 /s /q +chdir /D %GOPATH%\src\gocv.io\x\gocv diff --git a/vendor/golang.org/x/net/AUTHORS b/vendor/golang.org/x/net/AUTHORS new file mode 100644 index 0000000..15167cd --- /dev/null +++ b/vendor/golang.org/x/net/AUTHORS @@ -0,0 +1,3 @@ +# This source code refers to The Go Authors for copyright purposes. +# The master list of authors is in the main Go distribution, +# visible at http://tip.golang.org/AUTHORS. diff --git a/vendor/golang.org/x/net/CONTRIBUTORS b/vendor/golang.org/x/net/CONTRIBUTORS new file mode 100644 index 0000000..1c4577e --- /dev/null +++ b/vendor/golang.org/x/net/CONTRIBUTORS @@ -0,0 +1,3 @@ +# This source code was written by the Go contributors. +# The master list of contributors is in the main Go distribution, +# visible at http://tip.golang.org/CONTRIBUTORS. diff --git a/vendor/golang.org/x/net/LICENSE b/vendor/golang.org/x/net/LICENSE new file mode 100644 index 0000000..6a66aea --- /dev/null +++ b/vendor/golang.org/x/net/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2009 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/golang.org/x/net/PATENTS b/vendor/golang.org/x/net/PATENTS new file mode 100644 index 0000000..7330990 --- /dev/null +++ b/vendor/golang.org/x/net/PATENTS @@ -0,0 +1,22 @@ +Additional IP Rights Grant (Patents) + +"This implementation" means the copyrightable works distributed by +Google as part of the Go project. + +Google hereby grants to You a perpetual, worldwide, non-exclusive, +no-charge, royalty-free, irrevocable (except as stated in this section) +patent license to make, have made, use, offer to sell, sell, import, +transfer and otherwise run, modify and propagate the contents of this +implementation of Go, where such license applies only to those patent +claims, both currently owned or controlled by Google and acquired in +the future, licensable by Google that are necessarily infringed by this +implementation of Go. This grant does not include claims that would be +infringed only as a consequence of further modification of this +implementation. If you or your agent or exclusive licensee institute or +order or agree to the institution of patent litigation against any +entity (including a cross-claim or counterclaim in a lawsuit) alleging +that this implementation of Go or any code incorporated within this +implementation of Go constitutes direct or contributory patent +infringement, or inducement of patent infringement, then any patent +rights granted to you under this License for this implementation of Go +shall terminate as of the date such litigation is filed. diff --git a/vendor/golang.org/x/net/internal/socks/client.go b/vendor/golang.org/x/net/internal/socks/client.go new file mode 100644 index 0000000..3d6f516 --- /dev/null +++ b/vendor/golang.org/x/net/internal/socks/client.go @@ -0,0 +1,168 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package socks + +import ( + "context" + "errors" + "io" + "net" + "strconv" + "time" +) + +var ( + noDeadline = time.Time{} + aLongTimeAgo = time.Unix(1, 0) +) + +func (d *Dialer) connect(ctx context.Context, c net.Conn, address string) (_ net.Addr, ctxErr error) { + host, port, err := splitHostPort(address) + if err != nil { + return nil, err + } + if deadline, ok := ctx.Deadline(); ok && !deadline.IsZero() { + c.SetDeadline(deadline) + defer c.SetDeadline(noDeadline) + } + if ctx != context.Background() { + errCh := make(chan error, 1) + done := make(chan struct{}) + defer func() { + close(done) + if ctxErr == nil { + ctxErr = <-errCh + } + }() + go func() { + select { + case <-ctx.Done(): + c.SetDeadline(aLongTimeAgo) + errCh <- ctx.Err() + case <-done: + errCh <- nil + } + }() + } + + b := make([]byte, 0, 6+len(host)) // the size here is just an estimate + b = append(b, Version5) + if len(d.AuthMethods) == 0 || d.Authenticate == nil { + b = append(b, 1, byte(AuthMethodNotRequired)) + } else { + ams := d.AuthMethods + if len(ams) > 255 { + return nil, errors.New("too many authentication methods") + } + b = append(b, byte(len(ams))) + for _, am := range ams { + b = append(b, byte(am)) + } + } + if _, ctxErr = c.Write(b); ctxErr != nil { + return + } + + if _, ctxErr = io.ReadFull(c, b[:2]); ctxErr != nil { + return + } + if b[0] != Version5 { + return nil, errors.New("unexpected protocol version " + strconv.Itoa(int(b[0]))) + } + am := AuthMethod(b[1]) + if am == AuthMethodNoAcceptableMethods { + return nil, errors.New("no acceptable authentication methods") + } + if d.Authenticate != nil { + if ctxErr = d.Authenticate(ctx, c, am); ctxErr != nil { + return + } + } + + b = b[:0] + b = append(b, Version5, byte(d.cmd), 0) + if ip := net.ParseIP(host); ip != nil { + if ip4 := ip.To4(); ip4 != nil { + b = append(b, AddrTypeIPv4) + b = append(b, ip4...) + } else if ip6 := ip.To16(); ip6 != nil { + b = append(b, AddrTypeIPv6) + b = append(b, ip6...) + } else { + return nil, errors.New("unknown address type") + } + } else { + if len(host) > 255 { + return nil, errors.New("FQDN too long") + } + b = append(b, AddrTypeFQDN) + b = append(b, byte(len(host))) + b = append(b, host...) + } + b = append(b, byte(port>>8), byte(port)) + if _, ctxErr = c.Write(b); ctxErr != nil { + return + } + + if _, ctxErr = io.ReadFull(c, b[:4]); ctxErr != nil { + return + } + if b[0] != Version5 { + return nil, errors.New("unexpected protocol version " + strconv.Itoa(int(b[0]))) + } + if cmdErr := Reply(b[1]); cmdErr != StatusSucceeded { + return nil, errors.New("unknown error " + cmdErr.String()) + } + if b[2] != 0 { + return nil, errors.New("non-zero reserved field") + } + l := 2 + var a Addr + switch b[3] { + case AddrTypeIPv4: + l += net.IPv4len + a.IP = make(net.IP, net.IPv4len) + case AddrTypeIPv6: + l += net.IPv6len + a.IP = make(net.IP, net.IPv6len) + case AddrTypeFQDN: + if _, err := io.ReadFull(c, b[:1]); err != nil { + return nil, err + } + l += int(b[0]) + default: + return nil, errors.New("unknown address type " + strconv.Itoa(int(b[3]))) + } + if cap(b) < l { + b = make([]byte, l) + } else { + b = b[:l] + } + if _, ctxErr = io.ReadFull(c, b); ctxErr != nil { + return + } + if a.IP != nil { + copy(a.IP, b) + } else { + a.Name = string(b[:len(b)-2]) + } + a.Port = int(b[len(b)-2])<<8 | int(b[len(b)-1]) + return &a, nil +} + +func splitHostPort(address string) (string, int, error) { + host, port, err := net.SplitHostPort(address) + if err != nil { + return "", 0, err + } + portnum, err := strconv.Atoi(port) + if err != nil { + return "", 0, err + } + if 1 > portnum || portnum > 0xffff { + return "", 0, errors.New("port number out of range " + port) + } + return host, portnum, nil +} diff --git a/vendor/golang.org/x/net/internal/socks/socks.go b/vendor/golang.org/x/net/internal/socks/socks.go new file mode 100644 index 0000000..97db234 --- /dev/null +++ b/vendor/golang.org/x/net/internal/socks/socks.go @@ -0,0 +1,317 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package socks provides a SOCKS version 5 client implementation. +// +// SOCKS protocol version 5 is defined in RFC 1928. +// Username/Password authentication for SOCKS version 5 is defined in +// RFC 1929. +package socks + +import ( + "context" + "errors" + "io" + "net" + "strconv" +) + +// A Command represents a SOCKS command. +type Command int + +func (cmd Command) String() string { + switch cmd { + case CmdConnect: + return "socks connect" + case cmdBind: + return "socks bind" + default: + return "socks " + strconv.Itoa(int(cmd)) + } +} + +// An AuthMethod represents a SOCKS authentication method. +type AuthMethod int + +// A Reply represents a SOCKS command reply code. +type Reply int + +func (code Reply) String() string { + switch code { + case StatusSucceeded: + return "succeeded" + case 0x01: + return "general SOCKS server failure" + case 0x02: + return "connection not allowed by ruleset" + case 0x03: + return "network unreachable" + case 0x04: + return "host unreachable" + case 0x05: + return "connection refused" + case 0x06: + return "TTL expired" + case 0x07: + return "command not supported" + case 0x08: + return "address type not supported" + default: + return "unknown code: " + strconv.Itoa(int(code)) + } +} + +// Wire protocol constants. +const ( + Version5 = 0x05 + + AddrTypeIPv4 = 0x01 + AddrTypeFQDN = 0x03 + AddrTypeIPv6 = 0x04 + + CmdConnect Command = 0x01 // establishes an active-open forward proxy connection + cmdBind Command = 0x02 // establishes a passive-open forward proxy connection + + AuthMethodNotRequired AuthMethod = 0x00 // no authentication required + AuthMethodUsernamePassword AuthMethod = 0x02 // use username/password + AuthMethodNoAcceptableMethods AuthMethod = 0xff // no acceptable authentication methods + + StatusSucceeded Reply = 0x00 +) + +// An Addr represents a SOCKS-specific address. +// Either Name or IP is used exclusively. +type Addr struct { + Name string // fully-qualified domain name + IP net.IP + Port int +} + +func (a *Addr) Network() string { return "socks" } + +func (a *Addr) String() string { + if a == nil { + return "" + } + port := strconv.Itoa(a.Port) + if a.IP == nil { + return net.JoinHostPort(a.Name, port) + } + return net.JoinHostPort(a.IP.String(), port) +} + +// A Conn represents a forward proxy connection. +type Conn struct { + net.Conn + + boundAddr net.Addr +} + +// BoundAddr returns the address assigned by the proxy server for +// connecting to the command target address from the proxy server. +func (c *Conn) BoundAddr() net.Addr { + if c == nil { + return nil + } + return c.boundAddr +} + +// A Dialer holds SOCKS-specific options. +type Dialer struct { + cmd Command // either CmdConnect or cmdBind + proxyNetwork string // network between a proxy server and a client + proxyAddress string // proxy server address + + // ProxyDial specifies the optional dial function for + // establishing the transport connection. + ProxyDial func(context.Context, string, string) (net.Conn, error) + + // AuthMethods specifies the list of request authentication + // methods. + // If empty, SOCKS client requests only AuthMethodNotRequired. + AuthMethods []AuthMethod + + // Authenticate specifies the optional authentication + // function. It must be non-nil when AuthMethods is not empty. + // It must return an error when the authentication is failed. + Authenticate func(context.Context, io.ReadWriter, AuthMethod) error +} + +// DialContext connects to the provided address on the provided +// network. +// +// The returned error value may be a net.OpError. When the Op field of +// net.OpError contains "socks", the Source field contains a proxy +// server address and the Addr field contains a command target +// address. +// +// See func Dial of the net package of standard library for a +// description of the network and address parameters. +func (d *Dialer) DialContext(ctx context.Context, network, address string) (net.Conn, error) { + if err := d.validateTarget(network, address); err != nil { + proxy, dst, _ := d.pathAddrs(address) + return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err} + } + if ctx == nil { + proxy, dst, _ := d.pathAddrs(address) + return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: errors.New("nil context")} + } + var err error + var c net.Conn + if d.ProxyDial != nil { + c, err = d.ProxyDial(ctx, d.proxyNetwork, d.proxyAddress) + } else { + var dd net.Dialer + c, err = dd.DialContext(ctx, d.proxyNetwork, d.proxyAddress) + } + if err != nil { + proxy, dst, _ := d.pathAddrs(address) + return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err} + } + a, err := d.connect(ctx, c, address) + if err != nil { + c.Close() + proxy, dst, _ := d.pathAddrs(address) + return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err} + } + return &Conn{Conn: c, boundAddr: a}, nil +} + +// DialWithConn initiates a connection from SOCKS server to the target +// network and address using the connection c that is already +// connected to the SOCKS server. +// +// It returns the connection's local address assigned by the SOCKS +// server. +func (d *Dialer) DialWithConn(ctx context.Context, c net.Conn, network, address string) (net.Addr, error) { + if err := d.validateTarget(network, address); err != nil { + proxy, dst, _ := d.pathAddrs(address) + return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err} + } + if ctx == nil { + proxy, dst, _ := d.pathAddrs(address) + return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: errors.New("nil context")} + } + a, err := d.connect(ctx, c, address) + if err != nil { + proxy, dst, _ := d.pathAddrs(address) + return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err} + } + return a, nil +} + +// Dial connects to the provided address on the provided network. +// +// Unlike DialContext, it returns a raw transport connection instead +// of a forward proxy connection. +// +// Deprecated: Use DialContext or DialWithConn instead. +func (d *Dialer) Dial(network, address string) (net.Conn, error) { + if err := d.validateTarget(network, address); err != nil { + proxy, dst, _ := d.pathAddrs(address) + return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err} + } + var err error + var c net.Conn + if d.ProxyDial != nil { + c, err = d.ProxyDial(context.Background(), d.proxyNetwork, d.proxyAddress) + } else { + c, err = net.Dial(d.proxyNetwork, d.proxyAddress) + } + if err != nil { + proxy, dst, _ := d.pathAddrs(address) + return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err} + } + if _, err := d.DialWithConn(context.Background(), c, network, address); err != nil { + c.Close() + return nil, err + } + return c, nil +} + +func (d *Dialer) validateTarget(network, address string) error { + switch network { + case "tcp", "tcp6", "tcp4": + default: + return errors.New("network not implemented") + } + switch d.cmd { + case CmdConnect, cmdBind: + default: + return errors.New("command not implemented") + } + return nil +} + +func (d *Dialer) pathAddrs(address string) (proxy, dst net.Addr, err error) { + for i, s := range []string{d.proxyAddress, address} { + host, port, err := splitHostPort(s) + if err != nil { + return nil, nil, err + } + a := &Addr{Port: port} + a.IP = net.ParseIP(host) + if a.IP == nil { + a.Name = host + } + if i == 0 { + proxy = a + } else { + dst = a + } + } + return +} + +// NewDialer returns a new Dialer that dials through the provided +// proxy server's network and address. +func NewDialer(network, address string) *Dialer { + return &Dialer{proxyNetwork: network, proxyAddress: address, cmd: CmdConnect} +} + +const ( + authUsernamePasswordVersion = 0x01 + authStatusSucceeded = 0x00 +) + +// UsernamePassword are the credentials for the username/password +// authentication method. +type UsernamePassword struct { + Username string + Password string +} + +// Authenticate authenticates a pair of username and password with the +// proxy server. +func (up *UsernamePassword) Authenticate(ctx context.Context, rw io.ReadWriter, auth AuthMethod) error { + switch auth { + case AuthMethodNotRequired: + return nil + case AuthMethodUsernamePassword: + if len(up.Username) == 0 || len(up.Username) > 255 || len(up.Password) == 0 || len(up.Password) > 255 { + return errors.New("invalid username/password") + } + b := []byte{authUsernamePasswordVersion} + b = append(b, byte(len(up.Username))) + b = append(b, up.Username...) + b = append(b, byte(len(up.Password))) + b = append(b, up.Password...) + // TODO(mikio): handle IO deadlines and cancelation if + // necessary + if _, err := rw.Write(b); err != nil { + return err + } + if _, err := io.ReadFull(rw, b[:2]); err != nil { + return err + } + if b[0] != authUsernamePasswordVersion { + return errors.New("invalid username/password version") + } + if b[1] != authStatusSucceeded { + return errors.New("username/password authentication failed") + } + return nil + } + return errors.New("unsupported authentication method " + strconv.Itoa(int(auth))) +} diff --git a/vendor/golang.org/x/net/proxy/dial.go b/vendor/golang.org/x/net/proxy/dial.go new file mode 100644 index 0000000..811c2e4 --- /dev/null +++ b/vendor/golang.org/x/net/proxy/dial.go @@ -0,0 +1,54 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package proxy + +import ( + "context" + "net" +) + +// A ContextDialer dials using a context. +type ContextDialer interface { + DialContext(ctx context.Context, network, address string) (net.Conn, error) +} + +// Dial works like DialContext on net.Dialer but using a dialer returned by FromEnvironment. +// +// The passed ctx is only used for returning the Conn, not the lifetime of the Conn. +// +// Custom dialers (registered via RegisterDialerType) that do not implement ContextDialer +// can leak a goroutine for as long as it takes the underlying Dialer implementation to timeout. +// +// A Conn returned from a successful Dial after the context has been cancelled will be immediately closed. +func Dial(ctx context.Context, network, address string) (net.Conn, error) { + d := FromEnvironment() + if xd, ok := d.(ContextDialer); ok { + return xd.DialContext(ctx, network, address) + } + return dialContext(ctx, d, network, address) +} + +// WARNING: this can leak a goroutine for as long as the underlying Dialer implementation takes to timeout +// A Conn returned from a successful Dial after the context has been cancelled will be immediately closed. +func dialContext(ctx context.Context, d Dialer, network, address string) (net.Conn, error) { + var ( + conn net.Conn + done = make(chan struct{}, 1) + err error + ) + go func() { + conn, err = d.Dial(network, address) + close(done) + if conn != nil && ctx.Err() != nil { + conn.Close() + } + }() + select { + case <-ctx.Done(): + err = ctx.Err() + case <-done: + } + return conn, err +} diff --git a/vendor/golang.org/x/net/proxy/direct.go b/vendor/golang.org/x/net/proxy/direct.go new file mode 100644 index 0000000..3d66bde --- /dev/null +++ b/vendor/golang.org/x/net/proxy/direct.go @@ -0,0 +1,31 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package proxy + +import ( + "context" + "net" +) + +type direct struct{} + +// Direct implements Dialer by making network connections directly using net.Dial or net.DialContext. +var Direct = direct{} + +var ( + _ Dialer = Direct + _ ContextDialer = Direct +) + +// Dial directly invokes net.Dial with the supplied parameters. +func (direct) Dial(network, addr string) (net.Conn, error) { + return net.Dial(network, addr) +} + +// DialContext instantiates a net.Dialer and invokes its DialContext receiver with the supplied parameters. +func (direct) DialContext(ctx context.Context, network, addr string) (net.Conn, error) { + var d net.Dialer + return d.DialContext(ctx, network, addr) +} diff --git a/vendor/golang.org/x/net/proxy/per_host.go b/vendor/golang.org/x/net/proxy/per_host.go new file mode 100644 index 0000000..573fe79 --- /dev/null +++ b/vendor/golang.org/x/net/proxy/per_host.go @@ -0,0 +1,155 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package proxy + +import ( + "context" + "net" + "strings" +) + +// A PerHost directs connections to a default Dialer unless the host name +// requested matches one of a number of exceptions. +type PerHost struct { + def, bypass Dialer + + bypassNetworks []*net.IPNet + bypassIPs []net.IP + bypassZones []string + bypassHosts []string +} + +// NewPerHost returns a PerHost Dialer that directs connections to either +// defaultDialer or bypass, depending on whether the connection matches one of +// the configured rules. +func NewPerHost(defaultDialer, bypass Dialer) *PerHost { + return &PerHost{ + def: defaultDialer, + bypass: bypass, + } +} + +// Dial connects to the address addr on the given network through either +// defaultDialer or bypass. +func (p *PerHost) Dial(network, addr string) (c net.Conn, err error) { + host, _, err := net.SplitHostPort(addr) + if err != nil { + return nil, err + } + + return p.dialerForRequest(host).Dial(network, addr) +} + +// DialContext connects to the address addr on the given network through either +// defaultDialer or bypass. +func (p *PerHost) DialContext(ctx context.Context, network, addr string) (c net.Conn, err error) { + host, _, err := net.SplitHostPort(addr) + if err != nil { + return nil, err + } + d := p.dialerForRequest(host) + if x, ok := d.(ContextDialer); ok { + return x.DialContext(ctx, network, addr) + } + return dialContext(ctx, d, network, addr) +} + +func (p *PerHost) dialerForRequest(host string) Dialer { + if ip := net.ParseIP(host); ip != nil { + for _, net := range p.bypassNetworks { + if net.Contains(ip) { + return p.bypass + } + } + for _, bypassIP := range p.bypassIPs { + if bypassIP.Equal(ip) { + return p.bypass + } + } + return p.def + } + + for _, zone := range p.bypassZones { + if strings.HasSuffix(host, zone) { + return p.bypass + } + if host == zone[1:] { + // For a zone ".example.com", we match "example.com" + // too. + return p.bypass + } + } + for _, bypassHost := range p.bypassHosts { + if bypassHost == host { + return p.bypass + } + } + return p.def +} + +// AddFromString parses a string that contains comma-separated values +// specifying hosts that should use the bypass proxy. Each value is either an +// IP address, a CIDR range, a zone (*.example.com) or a host name +// (localhost). A best effort is made to parse the string and errors are +// ignored. +func (p *PerHost) AddFromString(s string) { + hosts := strings.Split(s, ",") + for _, host := range hosts { + host = strings.TrimSpace(host) + if len(host) == 0 { + continue + } + if strings.Contains(host, "/") { + // We assume that it's a CIDR address like 127.0.0.0/8 + if _, net, err := net.ParseCIDR(host); err == nil { + p.AddNetwork(net) + } + continue + } + if ip := net.ParseIP(host); ip != nil { + p.AddIP(ip) + continue + } + if strings.HasPrefix(host, "*.") { + p.AddZone(host[1:]) + continue + } + p.AddHost(host) + } +} + +// AddIP specifies an IP address that will use the bypass proxy. Note that +// this will only take effect if a literal IP address is dialed. A connection +// to a named host will never match an IP. +func (p *PerHost) AddIP(ip net.IP) { + p.bypassIPs = append(p.bypassIPs, ip) +} + +// AddNetwork specifies an IP range that will use the bypass proxy. Note that +// this will only take effect if a literal IP address is dialed. A connection +// to a named host will never match. +func (p *PerHost) AddNetwork(net *net.IPNet) { + p.bypassNetworks = append(p.bypassNetworks, net) +} + +// AddZone specifies a DNS suffix that will use the bypass proxy. A zone of +// "example.com" matches "example.com" and all of its subdomains. +func (p *PerHost) AddZone(zone string) { + if strings.HasSuffix(zone, ".") { + zone = zone[:len(zone)-1] + } + if !strings.HasPrefix(zone, ".") { + zone = "." + zone + } + p.bypassZones = append(p.bypassZones, zone) +} + +// AddHost specifies a host name that will use the bypass proxy. +func (p *PerHost) AddHost(host string) { + if strings.HasSuffix(host, ".") { + host = host[:len(host)-1] + } + p.bypassHosts = append(p.bypassHosts, host) +} diff --git a/vendor/golang.org/x/net/proxy/proxy.go b/vendor/golang.org/x/net/proxy/proxy.go new file mode 100644 index 0000000..9ff4b9a --- /dev/null +++ b/vendor/golang.org/x/net/proxy/proxy.go @@ -0,0 +1,149 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package proxy provides support for a variety of protocols to proxy network +// data. +package proxy // import "golang.org/x/net/proxy" + +import ( + "errors" + "net" + "net/url" + "os" + "sync" +) + +// A Dialer is a means to establish a connection. +// Custom dialers should also implement ContextDialer. +type Dialer interface { + // Dial connects to the given address via the proxy. + Dial(network, addr string) (c net.Conn, err error) +} + +// Auth contains authentication parameters that specific Dialers may require. +type Auth struct { + User, Password string +} + +// FromEnvironment returns the dialer specified by the proxy-related +// variables in the environment and makes underlying connections +// directly. +func FromEnvironment() Dialer { + return FromEnvironmentUsing(Direct) +} + +// FromEnvironmentUsing returns the dialer specify by the proxy-related +// variables in the environment and makes underlying connections +// using the provided forwarding Dialer (for instance, a *net.Dialer +// with desired configuration). +func FromEnvironmentUsing(forward Dialer) Dialer { + allProxy := allProxyEnv.Get() + if len(allProxy) == 0 { + return forward + } + + proxyURL, err := url.Parse(allProxy) + if err != nil { + return forward + } + proxy, err := FromURL(proxyURL, forward) + if err != nil { + return forward + } + + noProxy := noProxyEnv.Get() + if len(noProxy) == 0 { + return proxy + } + + perHost := NewPerHost(proxy, forward) + perHost.AddFromString(noProxy) + return perHost +} + +// proxySchemes is a map from URL schemes to a function that creates a Dialer +// from a URL with such a scheme. +var proxySchemes map[string]func(*url.URL, Dialer) (Dialer, error) + +// RegisterDialerType takes a URL scheme and a function to generate Dialers from +// a URL with that scheme and a forwarding Dialer. Registered schemes are used +// by FromURL. +func RegisterDialerType(scheme string, f func(*url.URL, Dialer) (Dialer, error)) { + if proxySchemes == nil { + proxySchemes = make(map[string]func(*url.URL, Dialer) (Dialer, error)) + } + proxySchemes[scheme] = f +} + +// FromURL returns a Dialer given a URL specification and an underlying +// Dialer for it to make network requests. +func FromURL(u *url.URL, forward Dialer) (Dialer, error) { + var auth *Auth + if u.User != nil { + auth = new(Auth) + auth.User = u.User.Username() + if p, ok := u.User.Password(); ok { + auth.Password = p + } + } + + switch u.Scheme { + case "socks5", "socks5h": + addr := u.Hostname() + port := u.Port() + if port == "" { + port = "1080" + } + return SOCKS5("tcp", net.JoinHostPort(addr, port), auth, forward) + } + + // If the scheme doesn't match any of the built-in schemes, see if it + // was registered by another package. + if proxySchemes != nil { + if f, ok := proxySchemes[u.Scheme]; ok { + return f(u, forward) + } + } + + return nil, errors.New("proxy: unknown scheme: " + u.Scheme) +} + +var ( + allProxyEnv = &envOnce{ + names: []string{"ALL_PROXY", "all_proxy"}, + } + noProxyEnv = &envOnce{ + names: []string{"NO_PROXY", "no_proxy"}, + } +) + +// envOnce looks up an environment variable (optionally by multiple +// names) once. It mitigates expensive lookups on some platforms +// (e.g. Windows). +// (Borrowed from net/http/transport.go) +type envOnce struct { + names []string + once sync.Once + val string +} + +func (e *envOnce) Get() string { + e.once.Do(e.init) + return e.val +} + +func (e *envOnce) init() { + for _, n := range e.names { + e.val = os.Getenv(n) + if e.val != "" { + return + } + } +} + +// reset is used by tests +func (e *envOnce) reset() { + e.once = sync.Once{} + e.val = "" +} diff --git a/vendor/golang.org/x/net/proxy/socks5.go b/vendor/golang.org/x/net/proxy/socks5.go new file mode 100644 index 0000000..c91651f --- /dev/null +++ b/vendor/golang.org/x/net/proxy/socks5.go @@ -0,0 +1,42 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package proxy + +import ( + "context" + "net" + + "golang.org/x/net/internal/socks" +) + +// SOCKS5 returns a Dialer that makes SOCKSv5 connections to the given +// address with an optional username and password. +// See RFC 1928 and RFC 1929. +func SOCKS5(network, address string, auth *Auth, forward Dialer) (Dialer, error) { + d := socks.NewDialer(network, address) + if forward != nil { + if f, ok := forward.(ContextDialer); ok { + d.ProxyDial = func(ctx context.Context, network string, address string) (net.Conn, error) { + return f.DialContext(ctx, network, address) + } + } else { + d.ProxyDial = func(ctx context.Context, network string, address string) (net.Conn, error) { + return dialContext(ctx, forward, network, address) + } + } + } + if auth != nil { + up := socks.UsernamePassword{ + Username: auth.User, + Password: auth.Password, + } + d.AuthMethods = []socks.AuthMethod{ + socks.AuthMethodNotRequired, + socks.AuthMethodUsernamePassword, + } + d.Authenticate = up.Authenticate + } + return d, nil +} diff --git a/vendor/golang.org/x/net/websocket/client.go b/vendor/golang.org/x/net/websocket/client.go new file mode 100644 index 0000000..69a4ac7 --- /dev/null +++ b/vendor/golang.org/x/net/websocket/client.go @@ -0,0 +1,106 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package websocket + +import ( + "bufio" + "io" + "net" + "net/http" + "net/url" +) + +// DialError is an error that occurs while dialling a websocket server. +type DialError struct { + *Config + Err error +} + +func (e *DialError) Error() string { + return "websocket.Dial " + e.Config.Location.String() + ": " + e.Err.Error() +} + +// NewConfig creates a new WebSocket config for client connection. +func NewConfig(server, origin string) (config *Config, err error) { + config = new(Config) + config.Version = ProtocolVersionHybi13 + config.Location, err = url.ParseRequestURI(server) + if err != nil { + return + } + config.Origin, err = url.ParseRequestURI(origin) + if err != nil { + return + } + config.Header = http.Header(make(map[string][]string)) + return +} + +// NewClient creates a new WebSocket client connection over rwc. +func NewClient(config *Config, rwc io.ReadWriteCloser) (ws *Conn, err error) { + br := bufio.NewReader(rwc) + bw := bufio.NewWriter(rwc) + err = hybiClientHandshake(config, br, bw) + if err != nil { + return + } + buf := bufio.NewReadWriter(br, bw) + ws = newHybiClientConn(config, buf, rwc) + return +} + +// Dial opens a new client connection to a WebSocket. +func Dial(url_, protocol, origin string) (ws *Conn, err error) { + config, err := NewConfig(url_, origin) + if err != nil { + return nil, err + } + if protocol != "" { + config.Protocol = []string{protocol} + } + return DialConfig(config) +} + +var portMap = map[string]string{ + "ws": "80", + "wss": "443", +} + +func parseAuthority(location *url.URL) string { + if _, ok := portMap[location.Scheme]; ok { + if _, _, err := net.SplitHostPort(location.Host); err != nil { + return net.JoinHostPort(location.Host, portMap[location.Scheme]) + } + } + return location.Host +} + +// DialConfig opens a new client connection to a WebSocket with a config. +func DialConfig(config *Config) (ws *Conn, err error) { + var client net.Conn + if config.Location == nil { + return nil, &DialError{config, ErrBadWebSocketLocation} + } + if config.Origin == nil { + return nil, &DialError{config, ErrBadWebSocketOrigin} + } + dialer := config.Dialer + if dialer == nil { + dialer = &net.Dialer{} + } + client, err = dialWithDialer(dialer, config) + if err != nil { + goto Error + } + ws, err = NewClient(config, client) + if err != nil { + client.Close() + goto Error + } + return + +Error: + return nil, &DialError{config, err} +} diff --git a/vendor/golang.org/x/net/websocket/dial.go b/vendor/golang.org/x/net/websocket/dial.go new file mode 100644 index 0000000..2dab943 --- /dev/null +++ b/vendor/golang.org/x/net/websocket/dial.go @@ -0,0 +1,24 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package websocket + +import ( + "crypto/tls" + "net" +) + +func dialWithDialer(dialer *net.Dialer, config *Config) (conn net.Conn, err error) { + switch config.Location.Scheme { + case "ws": + conn, err = dialer.Dial("tcp", parseAuthority(config.Location)) + + case "wss": + conn, err = tls.DialWithDialer(dialer, "tcp", parseAuthority(config.Location), config.TlsConfig) + + default: + err = ErrBadScheme + } + return +} diff --git a/vendor/golang.org/x/net/websocket/hybi.go b/vendor/golang.org/x/net/websocket/hybi.go new file mode 100644 index 0000000..8cffdd1 --- /dev/null +++ b/vendor/golang.org/x/net/websocket/hybi.go @@ -0,0 +1,583 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package websocket + +// This file implements a protocol of hybi draft. +// http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-17 + +import ( + "bufio" + "bytes" + "crypto/rand" + "crypto/sha1" + "encoding/base64" + "encoding/binary" + "fmt" + "io" + "io/ioutil" + "net/http" + "net/url" + "strings" +) + +const ( + websocketGUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" + + closeStatusNormal = 1000 + closeStatusGoingAway = 1001 + closeStatusProtocolError = 1002 + closeStatusUnsupportedData = 1003 + closeStatusFrameTooLarge = 1004 + closeStatusNoStatusRcvd = 1005 + closeStatusAbnormalClosure = 1006 + closeStatusBadMessageData = 1007 + closeStatusPolicyViolation = 1008 + closeStatusTooBigData = 1009 + closeStatusExtensionMismatch = 1010 + + maxControlFramePayloadLength = 125 +) + +var ( + ErrBadMaskingKey = &ProtocolError{"bad masking key"} + ErrBadPongMessage = &ProtocolError{"bad pong message"} + ErrBadClosingStatus = &ProtocolError{"bad closing status"} + ErrUnsupportedExtensions = &ProtocolError{"unsupported extensions"} + ErrNotImplemented = &ProtocolError{"not implemented"} + + handshakeHeader = map[string]bool{ + "Host": true, + "Upgrade": true, + "Connection": true, + "Sec-Websocket-Key": true, + "Sec-Websocket-Origin": true, + "Sec-Websocket-Version": true, + "Sec-Websocket-Protocol": true, + "Sec-Websocket-Accept": true, + } +) + +// A hybiFrameHeader is a frame header as defined in hybi draft. +type hybiFrameHeader struct { + Fin bool + Rsv [3]bool + OpCode byte + Length int64 + MaskingKey []byte + + data *bytes.Buffer +} + +// A hybiFrameReader is a reader for hybi frame. +type hybiFrameReader struct { + reader io.Reader + + header hybiFrameHeader + pos int64 + length int +} + +func (frame *hybiFrameReader) Read(msg []byte) (n int, err error) { + n, err = frame.reader.Read(msg) + if frame.header.MaskingKey != nil { + for i := 0; i < n; i++ { + msg[i] = msg[i] ^ frame.header.MaskingKey[frame.pos%4] + frame.pos++ + } + } + return n, err +} + +func (frame *hybiFrameReader) PayloadType() byte { return frame.header.OpCode } + +func (frame *hybiFrameReader) HeaderReader() io.Reader { + if frame.header.data == nil { + return nil + } + if frame.header.data.Len() == 0 { + return nil + } + return frame.header.data +} + +func (frame *hybiFrameReader) TrailerReader() io.Reader { return nil } + +func (frame *hybiFrameReader) Len() (n int) { return frame.length } + +// A hybiFrameReaderFactory creates new frame reader based on its frame type. +type hybiFrameReaderFactory struct { + *bufio.Reader +} + +// NewFrameReader reads a frame header from the connection, and creates new reader for the frame. +// See Section 5.2 Base Framing protocol for detail. +// http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-17#section-5.2 +func (buf hybiFrameReaderFactory) NewFrameReader() (frame frameReader, err error) { + hybiFrame := new(hybiFrameReader) + frame = hybiFrame + var header []byte + var b byte + // First byte. FIN/RSV1/RSV2/RSV3/OpCode(4bits) + b, err = buf.ReadByte() + if err != nil { + return + } + header = append(header, b) + hybiFrame.header.Fin = ((header[0] >> 7) & 1) != 0 + for i := 0; i < 3; i++ { + j := uint(6 - i) + hybiFrame.header.Rsv[i] = ((header[0] >> j) & 1) != 0 + } + hybiFrame.header.OpCode = header[0] & 0x0f + + // Second byte. Mask/Payload len(7bits) + b, err = buf.ReadByte() + if err != nil { + return + } + header = append(header, b) + mask := (b & 0x80) != 0 + b &= 0x7f + lengthFields := 0 + switch { + case b <= 125: // Payload length 7bits. + hybiFrame.header.Length = int64(b) + case b == 126: // Payload length 7+16bits + lengthFields = 2 + case b == 127: // Payload length 7+64bits + lengthFields = 8 + } + for i := 0; i < lengthFields; i++ { + b, err = buf.ReadByte() + if err != nil { + return + } + if lengthFields == 8 && i == 0 { // MSB must be zero when 7+64 bits + b &= 0x7f + } + header = append(header, b) + hybiFrame.header.Length = hybiFrame.header.Length*256 + int64(b) + } + if mask { + // Masking key. 4 bytes. + for i := 0; i < 4; i++ { + b, err = buf.ReadByte() + if err != nil { + return + } + header = append(header, b) + hybiFrame.header.MaskingKey = append(hybiFrame.header.MaskingKey, b) + } + } + hybiFrame.reader = io.LimitReader(buf.Reader, hybiFrame.header.Length) + hybiFrame.header.data = bytes.NewBuffer(header) + hybiFrame.length = len(header) + int(hybiFrame.header.Length) + return +} + +// A HybiFrameWriter is a writer for hybi frame. +type hybiFrameWriter struct { + writer *bufio.Writer + + header *hybiFrameHeader +} + +func (frame *hybiFrameWriter) Write(msg []byte) (n int, err error) { + var header []byte + var b byte + if frame.header.Fin { + b |= 0x80 + } + for i := 0; i < 3; i++ { + if frame.header.Rsv[i] { + j := uint(6 - i) + b |= 1 << j + } + } + b |= frame.header.OpCode + header = append(header, b) + if frame.header.MaskingKey != nil { + b = 0x80 + } else { + b = 0 + } + lengthFields := 0 + length := len(msg) + switch { + case length <= 125: + b |= byte(length) + case length < 65536: + b |= 126 + lengthFields = 2 + default: + b |= 127 + lengthFields = 8 + } + header = append(header, b) + for i := 0; i < lengthFields; i++ { + j := uint((lengthFields - i - 1) * 8) + b = byte((length >> j) & 0xff) + header = append(header, b) + } + if frame.header.MaskingKey != nil { + if len(frame.header.MaskingKey) != 4 { + return 0, ErrBadMaskingKey + } + header = append(header, frame.header.MaskingKey...) + frame.writer.Write(header) + data := make([]byte, length) + for i := range data { + data[i] = msg[i] ^ frame.header.MaskingKey[i%4] + } + frame.writer.Write(data) + err = frame.writer.Flush() + return length, err + } + frame.writer.Write(header) + frame.writer.Write(msg) + err = frame.writer.Flush() + return length, err +} + +func (frame *hybiFrameWriter) Close() error { return nil } + +type hybiFrameWriterFactory struct { + *bufio.Writer + needMaskingKey bool +} + +func (buf hybiFrameWriterFactory) NewFrameWriter(payloadType byte) (frame frameWriter, err error) { + frameHeader := &hybiFrameHeader{Fin: true, OpCode: payloadType} + if buf.needMaskingKey { + frameHeader.MaskingKey, err = generateMaskingKey() + if err != nil { + return nil, err + } + } + return &hybiFrameWriter{writer: buf.Writer, header: frameHeader}, nil +} + +type hybiFrameHandler struct { + conn *Conn + payloadType byte +} + +func (handler *hybiFrameHandler) HandleFrame(frame frameReader) (frameReader, error) { + if handler.conn.IsServerConn() { + // The client MUST mask all frames sent to the server. + if frame.(*hybiFrameReader).header.MaskingKey == nil { + handler.WriteClose(closeStatusProtocolError) + return nil, io.EOF + } + } else { + // The server MUST NOT mask all frames. + if frame.(*hybiFrameReader).header.MaskingKey != nil { + handler.WriteClose(closeStatusProtocolError) + return nil, io.EOF + } + } + if header := frame.HeaderReader(); header != nil { + io.Copy(ioutil.Discard, header) + } + switch frame.PayloadType() { + case ContinuationFrame: + frame.(*hybiFrameReader).header.OpCode = handler.payloadType + case TextFrame, BinaryFrame: + handler.payloadType = frame.PayloadType() + case CloseFrame: + return nil, io.EOF + case PingFrame, PongFrame: + b := make([]byte, maxControlFramePayloadLength) + n, err := io.ReadFull(frame, b) + if err != nil && err != io.EOF && err != io.ErrUnexpectedEOF { + return nil, err + } + io.Copy(ioutil.Discard, frame) + if frame.PayloadType() == PingFrame { + if _, err := handler.WritePong(b[:n]); err != nil { + return nil, err + } + } + return nil, nil + } + return frame, nil +} + +func (handler *hybiFrameHandler) WriteClose(status int) (err error) { + handler.conn.wio.Lock() + defer handler.conn.wio.Unlock() + w, err := handler.conn.frameWriterFactory.NewFrameWriter(CloseFrame) + if err != nil { + return err + } + msg := make([]byte, 2) + binary.BigEndian.PutUint16(msg, uint16(status)) + _, err = w.Write(msg) + w.Close() + return err +} + +func (handler *hybiFrameHandler) WritePong(msg []byte) (n int, err error) { + handler.conn.wio.Lock() + defer handler.conn.wio.Unlock() + w, err := handler.conn.frameWriterFactory.NewFrameWriter(PongFrame) + if err != nil { + return 0, err + } + n, err = w.Write(msg) + w.Close() + return n, err +} + +// newHybiConn creates a new WebSocket connection speaking hybi draft protocol. +func newHybiConn(config *Config, buf *bufio.ReadWriter, rwc io.ReadWriteCloser, request *http.Request) *Conn { + if buf == nil { + br := bufio.NewReader(rwc) + bw := bufio.NewWriter(rwc) + buf = bufio.NewReadWriter(br, bw) + } + ws := &Conn{config: config, request: request, buf: buf, rwc: rwc, + frameReaderFactory: hybiFrameReaderFactory{buf.Reader}, + frameWriterFactory: hybiFrameWriterFactory{ + buf.Writer, request == nil}, + PayloadType: TextFrame, + defaultCloseStatus: closeStatusNormal} + ws.frameHandler = &hybiFrameHandler{conn: ws} + return ws +} + +// generateMaskingKey generates a masking key for a frame. +func generateMaskingKey() (maskingKey []byte, err error) { + maskingKey = make([]byte, 4) + if _, err = io.ReadFull(rand.Reader, maskingKey); err != nil { + return + } + return +} + +// generateNonce generates a nonce consisting of a randomly selected 16-byte +// value that has been base64-encoded. +func generateNonce() (nonce []byte) { + key := make([]byte, 16) + if _, err := io.ReadFull(rand.Reader, key); err != nil { + panic(err) + } + nonce = make([]byte, 24) + base64.StdEncoding.Encode(nonce, key) + return +} + +// removeZone removes IPv6 zone identifer from host. +// E.g., "[fe80::1%en0]:8080" to "[fe80::1]:8080" +func removeZone(host string) string { + if !strings.HasPrefix(host, "[") { + return host + } + i := strings.LastIndex(host, "]") + if i < 0 { + return host + } + j := strings.LastIndex(host[:i], "%") + if j < 0 { + return host + } + return host[:j] + host[i:] +} + +// getNonceAccept computes the base64-encoded SHA-1 of the concatenation of +// the nonce ("Sec-WebSocket-Key" value) with the websocket GUID string. +func getNonceAccept(nonce []byte) (expected []byte, err error) { + h := sha1.New() + if _, err = h.Write(nonce); err != nil { + return + } + if _, err = h.Write([]byte(websocketGUID)); err != nil { + return + } + expected = make([]byte, 28) + base64.StdEncoding.Encode(expected, h.Sum(nil)) + return +} + +// Client handshake described in draft-ietf-hybi-thewebsocket-protocol-17 +func hybiClientHandshake(config *Config, br *bufio.Reader, bw *bufio.Writer) (err error) { + bw.WriteString("GET " + config.Location.RequestURI() + " HTTP/1.1\r\n") + + // According to RFC 6874, an HTTP client, proxy, or other + // intermediary must remove any IPv6 zone identifier attached + // to an outgoing URI. + bw.WriteString("Host: " + removeZone(config.Location.Host) + "\r\n") + bw.WriteString("Upgrade: websocket\r\n") + bw.WriteString("Connection: Upgrade\r\n") + nonce := generateNonce() + if config.handshakeData != nil { + nonce = []byte(config.handshakeData["key"]) + } + bw.WriteString("Sec-WebSocket-Key: " + string(nonce) + "\r\n") + bw.WriteString("Origin: " + strings.ToLower(config.Origin.String()) + "\r\n") + + if config.Version != ProtocolVersionHybi13 { + return ErrBadProtocolVersion + } + + bw.WriteString("Sec-WebSocket-Version: " + fmt.Sprintf("%d", config.Version) + "\r\n") + if len(config.Protocol) > 0 { + bw.WriteString("Sec-WebSocket-Protocol: " + strings.Join(config.Protocol, ", ") + "\r\n") + } + // TODO(ukai): send Sec-WebSocket-Extensions. + err = config.Header.WriteSubset(bw, handshakeHeader) + if err != nil { + return err + } + + bw.WriteString("\r\n") + if err = bw.Flush(); err != nil { + return err + } + + resp, err := http.ReadResponse(br, &http.Request{Method: "GET"}) + if err != nil { + return err + } + if resp.StatusCode != 101 { + return ErrBadStatus + } + if strings.ToLower(resp.Header.Get("Upgrade")) != "websocket" || + strings.ToLower(resp.Header.Get("Connection")) != "upgrade" { + return ErrBadUpgrade + } + expectedAccept, err := getNonceAccept(nonce) + if err != nil { + return err + } + if resp.Header.Get("Sec-WebSocket-Accept") != string(expectedAccept) { + return ErrChallengeResponse + } + if resp.Header.Get("Sec-WebSocket-Extensions") != "" { + return ErrUnsupportedExtensions + } + offeredProtocol := resp.Header.Get("Sec-WebSocket-Protocol") + if offeredProtocol != "" { + protocolMatched := false + for i := 0; i < len(config.Protocol); i++ { + if config.Protocol[i] == offeredProtocol { + protocolMatched = true + break + } + } + if !protocolMatched { + return ErrBadWebSocketProtocol + } + config.Protocol = []string{offeredProtocol} + } + + return nil +} + +// newHybiClientConn creates a client WebSocket connection after handshake. +func newHybiClientConn(config *Config, buf *bufio.ReadWriter, rwc io.ReadWriteCloser) *Conn { + return newHybiConn(config, buf, rwc, nil) +} + +// A HybiServerHandshaker performs a server handshake using hybi draft protocol. +type hybiServerHandshaker struct { + *Config + accept []byte +} + +func (c *hybiServerHandshaker) ReadHandshake(buf *bufio.Reader, req *http.Request) (code int, err error) { + c.Version = ProtocolVersionHybi13 + if req.Method != "GET" { + return http.StatusMethodNotAllowed, ErrBadRequestMethod + } + // HTTP version can be safely ignored. + + if strings.ToLower(req.Header.Get("Upgrade")) != "websocket" || + !strings.Contains(strings.ToLower(req.Header.Get("Connection")), "upgrade") { + return http.StatusBadRequest, ErrNotWebSocket + } + + key := req.Header.Get("Sec-Websocket-Key") + if key == "" { + return http.StatusBadRequest, ErrChallengeResponse + } + version := req.Header.Get("Sec-Websocket-Version") + switch version { + case "13": + c.Version = ProtocolVersionHybi13 + default: + return http.StatusBadRequest, ErrBadWebSocketVersion + } + var scheme string + if req.TLS != nil { + scheme = "wss" + } else { + scheme = "ws" + } + c.Location, err = url.ParseRequestURI(scheme + "://" + req.Host + req.URL.RequestURI()) + if err != nil { + return http.StatusBadRequest, err + } + protocol := strings.TrimSpace(req.Header.Get("Sec-Websocket-Protocol")) + if protocol != "" { + protocols := strings.Split(protocol, ",") + for i := 0; i < len(protocols); i++ { + c.Protocol = append(c.Protocol, strings.TrimSpace(protocols[i])) + } + } + c.accept, err = getNonceAccept([]byte(key)) + if err != nil { + return http.StatusInternalServerError, err + } + return http.StatusSwitchingProtocols, nil +} + +// Origin parses the Origin header in req. +// If the Origin header is not set, it returns nil and nil. +func Origin(config *Config, req *http.Request) (*url.URL, error) { + var origin string + switch config.Version { + case ProtocolVersionHybi13: + origin = req.Header.Get("Origin") + } + if origin == "" { + return nil, nil + } + return url.ParseRequestURI(origin) +} + +func (c *hybiServerHandshaker) AcceptHandshake(buf *bufio.Writer) (err error) { + if len(c.Protocol) > 0 { + if len(c.Protocol) != 1 { + // You need choose a Protocol in Handshake func in Server. + return ErrBadWebSocketProtocol + } + } + buf.WriteString("HTTP/1.1 101 Switching Protocols\r\n") + buf.WriteString("Upgrade: websocket\r\n") + buf.WriteString("Connection: Upgrade\r\n") + buf.WriteString("Sec-WebSocket-Accept: " + string(c.accept) + "\r\n") + if len(c.Protocol) > 0 { + buf.WriteString("Sec-WebSocket-Protocol: " + c.Protocol[0] + "\r\n") + } + // TODO(ukai): send Sec-WebSocket-Extensions. + if c.Header != nil { + err := c.Header.WriteSubset(buf, handshakeHeader) + if err != nil { + return err + } + } + buf.WriteString("\r\n") + return buf.Flush() +} + +func (c *hybiServerHandshaker) NewServerConn(buf *bufio.ReadWriter, rwc io.ReadWriteCloser, request *http.Request) *Conn { + return newHybiServerConn(c.Config, buf, rwc, request) +} + +// newHybiServerConn returns a new WebSocket connection speaking hybi draft protocol. +func newHybiServerConn(config *Config, buf *bufio.ReadWriter, rwc io.ReadWriteCloser, request *http.Request) *Conn { + return newHybiConn(config, buf, rwc, request) +} diff --git a/vendor/golang.org/x/net/websocket/server.go b/vendor/golang.org/x/net/websocket/server.go new file mode 100644 index 0000000..0895dea --- /dev/null +++ b/vendor/golang.org/x/net/websocket/server.go @@ -0,0 +1,113 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package websocket + +import ( + "bufio" + "fmt" + "io" + "net/http" +) + +func newServerConn(rwc io.ReadWriteCloser, buf *bufio.ReadWriter, req *http.Request, config *Config, handshake func(*Config, *http.Request) error) (conn *Conn, err error) { + var hs serverHandshaker = &hybiServerHandshaker{Config: config} + code, err := hs.ReadHandshake(buf.Reader, req) + if err == ErrBadWebSocketVersion { + fmt.Fprintf(buf, "HTTP/1.1 %03d %s\r\n", code, http.StatusText(code)) + fmt.Fprintf(buf, "Sec-WebSocket-Version: %s\r\n", SupportedProtocolVersion) + buf.WriteString("\r\n") + buf.WriteString(err.Error()) + buf.Flush() + return + } + if err != nil { + fmt.Fprintf(buf, "HTTP/1.1 %03d %s\r\n", code, http.StatusText(code)) + buf.WriteString("\r\n") + buf.WriteString(err.Error()) + buf.Flush() + return + } + if handshake != nil { + err = handshake(config, req) + if err != nil { + code = http.StatusForbidden + fmt.Fprintf(buf, "HTTP/1.1 %03d %s\r\n", code, http.StatusText(code)) + buf.WriteString("\r\n") + buf.Flush() + return + } + } + err = hs.AcceptHandshake(buf.Writer) + if err != nil { + code = http.StatusBadRequest + fmt.Fprintf(buf, "HTTP/1.1 %03d %s\r\n", code, http.StatusText(code)) + buf.WriteString("\r\n") + buf.Flush() + return + } + conn = hs.NewServerConn(buf, rwc, req) + return +} + +// Server represents a server of a WebSocket. +type Server struct { + // Config is a WebSocket configuration for new WebSocket connection. + Config + + // Handshake is an optional function in WebSocket handshake. + // For example, you can check, or don't check Origin header. + // Another example, you can select config.Protocol. + Handshake func(*Config, *http.Request) error + + // Handler handles a WebSocket connection. + Handler +} + +// ServeHTTP implements the http.Handler interface for a WebSocket +func (s Server) ServeHTTP(w http.ResponseWriter, req *http.Request) { + s.serveWebSocket(w, req) +} + +func (s Server) serveWebSocket(w http.ResponseWriter, req *http.Request) { + rwc, buf, err := w.(http.Hijacker).Hijack() + if err != nil { + panic("Hijack failed: " + err.Error()) + } + // The server should abort the WebSocket connection if it finds + // the client did not send a handshake that matches with protocol + // specification. + defer rwc.Close() + conn, err := newServerConn(rwc, buf, req, &s.Config, s.Handshake) + if err != nil { + return + } + if conn == nil { + panic("unexpected nil conn") + } + s.Handler(conn) +} + +// Handler is a simple interface to a WebSocket browser client. +// It checks if Origin header is valid URL by default. +// You might want to verify websocket.Conn.Config().Origin in the func. +// If you use Server instead of Handler, you could call websocket.Origin and +// check the origin in your Handshake func. So, if you want to accept +// non-browser clients, which do not send an Origin header, set a +// Server.Handshake that does not check the origin. +type Handler func(*Conn) + +func checkOrigin(config *Config, req *http.Request) (err error) { + config.Origin, err = Origin(config, req) + if err == nil && config.Origin == nil { + return fmt.Errorf("null origin") + } + return err +} + +// ServeHTTP implements the http.Handler interface for a WebSocket +func (h Handler) ServeHTTP(w http.ResponseWriter, req *http.Request) { + s := Server{Handler: h, Handshake: checkOrigin} + s.serveWebSocket(w, req) +} diff --git a/vendor/golang.org/x/net/websocket/websocket.go b/vendor/golang.org/x/net/websocket/websocket.go new file mode 100644 index 0000000..6c45c73 --- /dev/null +++ b/vendor/golang.org/x/net/websocket/websocket.go @@ -0,0 +1,451 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package websocket implements a client and server for the WebSocket protocol +// as specified in RFC 6455. +// +// This package currently lacks some features found in alternative +// and more actively maintained WebSocket packages: +// +// https://godoc.org/github.com/gorilla/websocket +// https://godoc.org/nhooyr.io/websocket +package websocket // import "golang.org/x/net/websocket" + +import ( + "bufio" + "crypto/tls" + "encoding/json" + "errors" + "io" + "io/ioutil" + "net" + "net/http" + "net/url" + "sync" + "time" +) + +const ( + ProtocolVersionHybi13 = 13 + ProtocolVersionHybi = ProtocolVersionHybi13 + SupportedProtocolVersion = "13" + + ContinuationFrame = 0 + TextFrame = 1 + BinaryFrame = 2 + CloseFrame = 8 + PingFrame = 9 + PongFrame = 10 + UnknownFrame = 255 + + DefaultMaxPayloadBytes = 32 << 20 // 32MB +) + +// ProtocolError represents WebSocket protocol errors. +type ProtocolError struct { + ErrorString string +} + +func (err *ProtocolError) Error() string { return err.ErrorString } + +var ( + ErrBadProtocolVersion = &ProtocolError{"bad protocol version"} + ErrBadScheme = &ProtocolError{"bad scheme"} + ErrBadStatus = &ProtocolError{"bad status"} + ErrBadUpgrade = &ProtocolError{"missing or bad upgrade"} + ErrBadWebSocketOrigin = &ProtocolError{"missing or bad WebSocket-Origin"} + ErrBadWebSocketLocation = &ProtocolError{"missing or bad WebSocket-Location"} + ErrBadWebSocketProtocol = &ProtocolError{"missing or bad WebSocket-Protocol"} + ErrBadWebSocketVersion = &ProtocolError{"missing or bad WebSocket Version"} + ErrChallengeResponse = &ProtocolError{"mismatch challenge/response"} + ErrBadFrame = &ProtocolError{"bad frame"} + ErrBadFrameBoundary = &ProtocolError{"not on frame boundary"} + ErrNotWebSocket = &ProtocolError{"not websocket protocol"} + ErrBadRequestMethod = &ProtocolError{"bad method"} + ErrNotSupported = &ProtocolError{"not supported"} +) + +// ErrFrameTooLarge is returned by Codec's Receive method if payload size +// exceeds limit set by Conn.MaxPayloadBytes +var ErrFrameTooLarge = errors.New("websocket: frame payload size exceeds limit") + +// Addr is an implementation of net.Addr for WebSocket. +type Addr struct { + *url.URL +} + +// Network returns the network type for a WebSocket, "websocket". +func (addr *Addr) Network() string { return "websocket" } + +// Config is a WebSocket configuration +type Config struct { + // A WebSocket server address. + Location *url.URL + + // A Websocket client origin. + Origin *url.URL + + // WebSocket subprotocols. + Protocol []string + + // WebSocket protocol version. + Version int + + // TLS config for secure WebSocket (wss). + TlsConfig *tls.Config + + // Additional header fields to be sent in WebSocket opening handshake. + Header http.Header + + // Dialer used when opening websocket connections. + Dialer *net.Dialer + + handshakeData map[string]string +} + +// serverHandshaker is an interface to handle WebSocket server side handshake. +type serverHandshaker interface { + // ReadHandshake reads handshake request message from client. + // Returns http response code and error if any. + ReadHandshake(buf *bufio.Reader, req *http.Request) (code int, err error) + + // AcceptHandshake accepts the client handshake request and sends + // handshake response back to client. + AcceptHandshake(buf *bufio.Writer) (err error) + + // NewServerConn creates a new WebSocket connection. + NewServerConn(buf *bufio.ReadWriter, rwc io.ReadWriteCloser, request *http.Request) (conn *Conn) +} + +// frameReader is an interface to read a WebSocket frame. +type frameReader interface { + // Reader is to read payload of the frame. + io.Reader + + // PayloadType returns payload type. + PayloadType() byte + + // HeaderReader returns a reader to read header of the frame. + HeaderReader() io.Reader + + // TrailerReader returns a reader to read trailer of the frame. + // If it returns nil, there is no trailer in the frame. + TrailerReader() io.Reader + + // Len returns total length of the frame, including header and trailer. + Len() int +} + +// frameReaderFactory is an interface to creates new frame reader. +type frameReaderFactory interface { + NewFrameReader() (r frameReader, err error) +} + +// frameWriter is an interface to write a WebSocket frame. +type frameWriter interface { + // Writer is to write payload of the frame. + io.WriteCloser +} + +// frameWriterFactory is an interface to create new frame writer. +type frameWriterFactory interface { + NewFrameWriter(payloadType byte) (w frameWriter, err error) +} + +type frameHandler interface { + HandleFrame(frame frameReader) (r frameReader, err error) + WriteClose(status int) (err error) +} + +// Conn represents a WebSocket connection. +// +// Multiple goroutines may invoke methods on a Conn simultaneously. +type Conn struct { + config *Config + request *http.Request + + buf *bufio.ReadWriter + rwc io.ReadWriteCloser + + rio sync.Mutex + frameReaderFactory + frameReader + + wio sync.Mutex + frameWriterFactory + + frameHandler + PayloadType byte + defaultCloseStatus int + + // MaxPayloadBytes limits the size of frame payload received over Conn + // by Codec's Receive method. If zero, DefaultMaxPayloadBytes is used. + MaxPayloadBytes int +} + +// Read implements the io.Reader interface: +// it reads data of a frame from the WebSocket connection. +// if msg is not large enough for the frame data, it fills the msg and next Read +// will read the rest of the frame data. +// it reads Text frame or Binary frame. +func (ws *Conn) Read(msg []byte) (n int, err error) { + ws.rio.Lock() + defer ws.rio.Unlock() +again: + if ws.frameReader == nil { + frame, err := ws.frameReaderFactory.NewFrameReader() + if err != nil { + return 0, err + } + ws.frameReader, err = ws.frameHandler.HandleFrame(frame) + if err != nil { + return 0, err + } + if ws.frameReader == nil { + goto again + } + } + n, err = ws.frameReader.Read(msg) + if err == io.EOF { + if trailer := ws.frameReader.TrailerReader(); trailer != nil { + io.Copy(ioutil.Discard, trailer) + } + ws.frameReader = nil + goto again + } + return n, err +} + +// Write implements the io.Writer interface: +// it writes data as a frame to the WebSocket connection. +func (ws *Conn) Write(msg []byte) (n int, err error) { + ws.wio.Lock() + defer ws.wio.Unlock() + w, err := ws.frameWriterFactory.NewFrameWriter(ws.PayloadType) + if err != nil { + return 0, err + } + n, err = w.Write(msg) + w.Close() + return n, err +} + +// Close implements the io.Closer interface. +func (ws *Conn) Close() error { + err := ws.frameHandler.WriteClose(ws.defaultCloseStatus) + err1 := ws.rwc.Close() + if err != nil { + return err + } + return err1 +} + +// IsClientConn reports whether ws is a client-side connection. +func (ws *Conn) IsClientConn() bool { return ws.request == nil } + +// IsServerConn reports whether ws is a server-side connection. +func (ws *Conn) IsServerConn() bool { return ws.request != nil } + +// LocalAddr returns the WebSocket Origin for the connection for client, or +// the WebSocket location for server. +func (ws *Conn) LocalAddr() net.Addr { + if ws.IsClientConn() { + return &Addr{ws.config.Origin} + } + return &Addr{ws.config.Location} +} + +// RemoteAddr returns the WebSocket location for the connection for client, or +// the Websocket Origin for server. +func (ws *Conn) RemoteAddr() net.Addr { + if ws.IsClientConn() { + return &Addr{ws.config.Location} + } + return &Addr{ws.config.Origin} +} + +var errSetDeadline = errors.New("websocket: cannot set deadline: not using a net.Conn") + +// SetDeadline sets the connection's network read & write deadlines. +func (ws *Conn) SetDeadline(t time.Time) error { + if conn, ok := ws.rwc.(net.Conn); ok { + return conn.SetDeadline(t) + } + return errSetDeadline +} + +// SetReadDeadline sets the connection's network read deadline. +func (ws *Conn) SetReadDeadline(t time.Time) error { + if conn, ok := ws.rwc.(net.Conn); ok { + return conn.SetReadDeadline(t) + } + return errSetDeadline +} + +// SetWriteDeadline sets the connection's network write deadline. +func (ws *Conn) SetWriteDeadline(t time.Time) error { + if conn, ok := ws.rwc.(net.Conn); ok { + return conn.SetWriteDeadline(t) + } + return errSetDeadline +} + +// Config returns the WebSocket config. +func (ws *Conn) Config() *Config { return ws.config } + +// Request returns the http request upgraded to the WebSocket. +// It is nil for client side. +func (ws *Conn) Request() *http.Request { return ws.request } + +// Codec represents a symmetric pair of functions that implement a codec. +type Codec struct { + Marshal func(v interface{}) (data []byte, payloadType byte, err error) + Unmarshal func(data []byte, payloadType byte, v interface{}) (err error) +} + +// Send sends v marshaled by cd.Marshal as single frame to ws. +func (cd Codec) Send(ws *Conn, v interface{}) (err error) { + data, payloadType, err := cd.Marshal(v) + if err != nil { + return err + } + ws.wio.Lock() + defer ws.wio.Unlock() + w, err := ws.frameWriterFactory.NewFrameWriter(payloadType) + if err != nil { + return err + } + _, err = w.Write(data) + w.Close() + return err +} + +// Receive receives single frame from ws, unmarshaled by cd.Unmarshal and stores +// in v. The whole frame payload is read to an in-memory buffer; max size of +// payload is defined by ws.MaxPayloadBytes. If frame payload size exceeds +// limit, ErrFrameTooLarge is returned; in this case frame is not read off wire +// completely. The next call to Receive would read and discard leftover data of +// previous oversized frame before processing next frame. +func (cd Codec) Receive(ws *Conn, v interface{}) (err error) { + ws.rio.Lock() + defer ws.rio.Unlock() + if ws.frameReader != nil { + _, err = io.Copy(ioutil.Discard, ws.frameReader) + if err != nil { + return err + } + ws.frameReader = nil + } +again: + frame, err := ws.frameReaderFactory.NewFrameReader() + if err != nil { + return err + } + frame, err = ws.frameHandler.HandleFrame(frame) + if err != nil { + return err + } + if frame == nil { + goto again + } + maxPayloadBytes := ws.MaxPayloadBytes + if maxPayloadBytes == 0 { + maxPayloadBytes = DefaultMaxPayloadBytes + } + if hf, ok := frame.(*hybiFrameReader); ok && hf.header.Length > int64(maxPayloadBytes) { + // payload size exceeds limit, no need to call Unmarshal + // + // set frameReader to current oversized frame so that + // the next call to this function can drain leftover + // data before processing the next frame + ws.frameReader = frame + return ErrFrameTooLarge + } + payloadType := frame.PayloadType() + data, err := ioutil.ReadAll(frame) + if err != nil { + return err + } + return cd.Unmarshal(data, payloadType, v) +} + +func marshal(v interface{}) (msg []byte, payloadType byte, err error) { + switch data := v.(type) { + case string: + return []byte(data), TextFrame, nil + case []byte: + return data, BinaryFrame, nil + } + return nil, UnknownFrame, ErrNotSupported +} + +func unmarshal(msg []byte, payloadType byte, v interface{}) (err error) { + switch data := v.(type) { + case *string: + *data = string(msg) + return nil + case *[]byte: + *data = msg + return nil + } + return ErrNotSupported +} + +/* +Message is a codec to send/receive text/binary data in a frame on WebSocket connection. +To send/receive text frame, use string type. +To send/receive binary frame, use []byte type. + +Trivial usage: + + import "websocket" + + // receive text frame + var message string + websocket.Message.Receive(ws, &message) + + // send text frame + message = "hello" + websocket.Message.Send(ws, message) + + // receive binary frame + var data []byte + websocket.Message.Receive(ws, &data) + + // send binary frame + data = []byte{0, 1, 2} + websocket.Message.Send(ws, data) + +*/ +var Message = Codec{marshal, unmarshal} + +func jsonMarshal(v interface{}) (msg []byte, payloadType byte, err error) { + msg, err = json.Marshal(v) + return msg, TextFrame, err +} + +func jsonUnmarshal(msg []byte, payloadType byte, v interface{}) (err error) { + return json.Unmarshal(msg, v) +} + +/* +JSON is a codec to send/receive JSON data in a frame from a WebSocket connection. + +Trivial usage: + + import "websocket" + + type T struct { + Msg string + Count int + } + + // receive JSON type T + var data T + websocket.JSON.Receive(ws, &data) + + // send JSON type T + websocket.JSON.Send(ws, data) +*/ +var JSON = Codec{jsonMarshal, jsonUnmarshal} diff --git a/vendor/modules.txt b/vendor/modules.txt new file mode 100644 index 0000000..79f5252 --- /dev/null +++ b/vendor/modules.txt @@ -0,0 +1,14 @@ +# github.com/cyrilix/robocar-base v0.0.0-20191218200846-a0dedb056b1a +github.com/cyrilix/robocar-base/cli +github.com/cyrilix/robocar-base/mode +github.com/cyrilix/robocar-base/mqttdevice +github.com/cyrilix/robocar-base/testtools +# github.com/eclipse/paho.mqtt.golang v1.2.0 +github.com/eclipse/paho.mqtt.golang +github.com/eclipse/paho.mqtt.golang/packets +# gocv.io/x/gocv v0.21.0 +gocv.io/x/gocv +# golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553 +golang.org/x/net/internal/socks +golang.org/x/net/proxy +golang.org/x/net/websocket