initial cuda implementation

This commit is contained in:
Kim Eik
2019-03-17 20:57:19 +01:00
committed by Ron Evans
parent e298534a2c
commit 355dd5435e
14 changed files with 437 additions and 2 deletions

View File

@@ -84,6 +84,16 @@ build_nonfree:
$(MAKE) preinstall $(MAKE) preinstall
cd - 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. # Cleanup temporary build files.
clean: clean:
rm -rf $(TMP_DIR)opencv rm -rf $(TMP_DIR)opencv
@@ -94,6 +104,9 @@ install: deps download build sudo_install clean verify
# Do everything on Raspbian. # Do everything on Raspbian.
install_raspi: deps download build_raspi sudo_install clean verify 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. # Install system wide.
sudo_install: sudo_install:
cd $(TMP_DIR)opencv/opencv-$(OPENCV_VERSION)/build cd $(TMP_DIR)opencv/opencv-$(OPENCV_VERSION)/build

2
cgo.go
View File

@@ -2,7 +2,7 @@
package gocv package gocv
// Changes here should be mirrored in contrib/cgo.go. // Changes here should be mirrored in contrib/cgo.go and cuda/cgo.go.
/* /*
#cgo !windows pkg-config: opencv4 #cgo !windows pkg-config: opencv4

28
cmd/cuda/main.go Normal file
View File

@@ -0,0 +1,28 @@
// What it does:
//
// This program outputs the current OpenCV library version and CUDA version the console.
//
// How to run:
//
// go run ./cmd/cuda/main.go
//
// +build example
package main
import (
"fmt"
"gocv.io/x/gocv"
"gocv.io/x/gocv/cuda"
)
func main() {
fmt.Printf("gocv version: %s\n", gocv.Version())
fmt.Println("cuda information:")
devices := cuda.GetCudaEnabledDeviceCount()
for i := 0; i < devices; i++ {
fmt.Print(" ")
cuda.PrintShortCudaDeviceInfo(i)
}
}

View File

@@ -2,7 +2,7 @@
package contrib package contrib
// Changes here should be mirrored in gocv/cgo.go. // Changes here should be mirrored in gocv/cgo.go and cuda/cgo.go
/* /*
#cgo !windows pkg-config: opencv4 #cgo !windows pkg-config: opencv4

24
cuda/README.md Normal file
View File

@@ -0,0 +1,24 @@
# Cuda (Experimental)
In order to use the cuda package, the cuda toolkit from nvidia needs to be installed on the host system.
Please see https://docs.nvidia.com/cuda/index.html for more information.
Furthermore opencv must be compiled with cuda support.
## Compiling opencv with cuda
For now we have included the make target `install_cuda` that compiles opencv with cuda. (For more details on the compilation process please see the `Makefile`)
Simply issue the command `make install_cuda` and you should be good to go.
Then finally verify that it is all working
cd $GOPATH/src/gocv.io/x/gocv
go run ./cmd/cuda/main.go
You should see something along the lines of:
gocv version: 0.19.0
cuda information:
Device 0: "GeForce MX150" 2003Mb, sm_61, Driver/Runtime ver.10.0/10.0

13
cuda/cgo.go Normal file
View File

@@ -0,0 +1,13 @@
// +build !customenv,!openvino
package cuda
// Changes here should be mirrored in gocv/cgo.go and contrib/cgo.go.
/*
#cgo !windows pkg-config: opencv4
#cgo CXXFLAGS: --std=c++11
#cgo windows CPPFLAGS: -IC:/opencv/build/install/include
#cgo windows LDFLAGS: -LC:/opencv/build/install/x64/mingw/lib -lopencv_core401 -lopencv_face401 -lopencv_videoio401 -lopencv_imgproc401 -lopencv_highgui401 -lopencv_imgcodecs401 -lopencv_objdetect401 -lopencv_features2d401 -lopencv_video401 -lopencv_dnn401 -lopencv_xfeatures2d401 -lopencv_plot401 -lopencv_tracking401 -lopencv_img_hash401 -lopencv_calib3d401
*/
import "C"

33
cuda/cuda.cpp Normal file
View File

@@ -0,0 +1,33 @@
#include "cuda.h"
GpuMat GpuMat_New() {
return new cv::cuda::GpuMat();
}
void GpuMat_Upload(GpuMat m,Mat data){
m->upload(*data);
}
void GpuMat_Download(GpuMat m,Mat dst){
m->download(*dst);
}
int GpuMat_Empty(GpuMat m){
return m->empty();
}
void GpuMat_Close(GpuMat m){
delete m;
}
void PrintCudaDeviceInfo(int device){
cv::cuda::printCudaDeviceInfo(device);
}
void PrintShortCudaDeviceInfo(int device){
cv::cuda::printShortCudaDeviceInfo(device);
}
int GetCudaEnabledDeviceCount(){
return cv::cuda::getCudaEnabledDeviceCount();
}

76
cuda/cuda.go Normal file
View File

@@ -0,0 +1,76 @@
// Package cuda is the GoCV wrapper around OpenCV cuda.
//
// For further details, please see:
// https://github.com/opencv/c
//
// import "gocv.io/x/gocv/cuda"
package cuda
/*
#include <stdlib.h>
#include "cuda.h"
*/
import "C"
import "gocv.io/x/gocv"
// GpuMat is the GPU version of a Mat
//
// For further details, please see:
// https://docs.opencv.org/master/d0/d60/classcv_1_1cuda_1_1GpuMat.html
type GpuMat struct {
p C.GpuMat
}
// Upload performs data upload to GpuMat (Blocking call)
//
// For further details, please see:
// https://docs.opencv.org/master/d0/d60/classcv_1_1cuda_1_1GpuMat.html#a00ef5bfe18d14623dcf578a35e40a46b
//
func (g *GpuMat) Upload(data gocv.Mat) {
C.GpuMat_Upload(g.p, C.Mat(data.Ptr()))
}
// Download performs data download from GpuMat (Blocking call)
//
// For further details, please see:
// https://docs.opencv.org/master/d0/d60/classcv_1_1cuda_1_1GpuMat.html#a027e74e4364ddfd9687b58aa5db8d4e8
func (g *GpuMat) Download(dst *gocv.Mat) {
C.GpuMat_Download(g.p, C.Mat(dst.Ptr()))
}
// Empty returns true if GpuMat is empty
func (g *GpuMat) Empty() bool {
return C.GpuMat_Empty(g.p) != 0
}
// Close the GpuMat object
func (g *GpuMat) Close() error {
C.GpuMat_Close(g.p)
g.p = nil
return nil
}
// NewGpuMat Returns a new empty GpuMat
func NewGpuMat() GpuMat {
return newGpuMat(C.GpuMat_New())
}
func newGpuMat(p C.GpuMat) GpuMat {
return GpuMat{p: p}
}
// PrintCudaDeviceInfo prints extensive cuda device information
func PrintCudaDeviceInfo(device int) {
C.PrintCudaDeviceInfo(C.int(device))
}
// PrintShortCudaDeviceInfo prints a small amount of cuda device information
func PrintShortCudaDeviceInfo(device int) {
C.PrintShortCudaDeviceInfo(C.int(device))
}
// GetCudaEnabledDeviceCount returns the number of cuda enabled devices on the
// system
func GetCudaEnabledDeviceCount() int {
return int(C.GetCudaEnabledDeviceCount())
}

32
cuda/cuda.h Normal file
View File

@@ -0,0 +1,32 @@
#ifndef _OPENCV3_CUDA_H_
#define _OPENCV3_CUDA_H_
#ifdef __cplusplus
#include <opencv2/opencv.hpp>
#include <opencv2/core/cuda.hpp>
extern "C" {
#endif
#include "../core.h"
#ifdef __cplusplus
typedef cv::cuda::GpuMat* GpuMat;
#else
typedef void* GpuMat;
#endif
GpuMat GpuMat_New();
void GpuMat_Upload(GpuMat m,Mat data);
void GpuMat_Download(GpuMat m,Mat dst);
void GpuMat_Close(GpuMat m);
int GpuMat_Empty(GpuMat m);
void PrintCudaDeviceInfo(int device);
void PrintShortCudaDeviceInfo(int device);
int GetCudaEnabledDeviceCount();
#ifdef __cplusplus
}
#endif
#endif //_OPENCV3_CUDA_H_

20
cuda/cuda_test.go Normal file
View File

@@ -0,0 +1,20 @@
package cuda
import (
"testing"
)
func TestNewGpuMat(t *testing.T) {
mat := NewGpuMat()
defer mat.Close()
if !mat.Empty() {
t.Error("New Mat should be empty")
}
}
func TestGetCudaEnabledDeviceCount(t *testing.T) {
if GetCudaEnabledDeviceCount() < 1 {
t.Fatal("expected atleast one cuda enabled device")
}
}

25
cuda/cudabgsegm.cpp Normal file
View File

@@ -0,0 +1,25 @@
#include "cudabgsegm.h"
CudaBackgroundSubtractorMOG2 CudaBackgroundSubtractorMOG2_Create() {
return new cv::Ptr<cv::cuda::BackgroundSubtractorMOG2>(cv::cuda::createBackgroundSubtractorMOG2());
}
void CudaBackgroundSubtractorMOG2_Close(CudaBackgroundSubtractorMOG2 b) {
delete b;
}
void CudaBackgroundSubtractorMOG2_Apply(CudaBackgroundSubtractorMOG2 b, GpuMat src, GpuMat dst) {
(*b)->apply(*src, *dst);
}
CudaBackgroundSubtractorMOG CudaBackgroundSubtractorMOG_Create() {
return new cv::Ptr<cv::cuda::BackgroundSubtractorMOG>(cv::cuda::createBackgroundSubtractorMOG());
}
void CudaBackgroundSubtractorMOG_Close(CudaBackgroundSubtractorMOG b) {
delete b;
}
void CudaBackgroundSubtractorMOG_Apply(CudaBackgroundSubtractorMOG b, GpuMat src, GpuMat dst) {
(*b)->apply(*src, *dst);
}

76
cuda/cudabgsegm.go Normal file
View File

@@ -0,0 +1,76 @@
package cuda
/*
#include <stdlib.h>
#include "cudabgsegm.h"
*/
import "C"
import "unsafe"
// BackgroundSubtractorMOG2 is a wrapper around the cv::cuda::BackgroundSubtractorMOG2.
type BackgroundSubtractorMOG2 struct {
// C.BackgroundSubtractorMOG2
p unsafe.Pointer
}
// BackgroundSubtractorMOG is a wrapper around the cv::cuda::BackgroundSubtractorMOG.
type BackgroundSubtractorMOG struct {
// C.BackgroundSubtractorMOG
p unsafe.Pointer
}
// NewBackgroundSubtractorMOG2 returns a new BackgroundSubtractor algorithm
// of type MOG2. MOG2 is a Gaussian Mixture-based Background/Foreground
// Segmentation Algorithm.
//
// For further details, please see:
// https://docs.opencv.org/master/dc/d3d/cudabgsegm_8hpp.html
//
func NewBackgroundSubtractorMOG2() BackgroundSubtractorMOG2 {
return BackgroundSubtractorMOG2{p: unsafe.Pointer(C.CudaBackgroundSubtractorMOG2_Create())}
}
// Close BackgroundSubtractorMOG2.
func (b *BackgroundSubtractorMOG2) Close() error {
C.CudaBackgroundSubtractorMOG2_Close((C.CudaBackgroundSubtractorMOG2)(b.p))
b.p = nil
return nil
}
// Apply computes a foreground mask using the current BackgroundSubtractorMOG2.
//
// For further details, please see:
// https://docs.opencv.org/master/df/d23/classcv_1_1cuda_1_1BackgroundSubtractorMOG2.html#a92408f07bf1268c1b778cb186b3113b0
//
func (b *BackgroundSubtractorMOG2) Apply(src GpuMat, dst *GpuMat) {
C.CudaBackgroundSubtractorMOG2_Apply((C.CudaBackgroundSubtractorMOG2)(b.p), src.p, dst.p)
return
}
// NewBackgroundSubtractorMOG returns a new BackgroundSubtractor algorithm
// of type MOG. MOG is a Gaussian Mixture-based Background/Foreground
// Segmentation Algorithm.
//
// For further details, please see:
// https://docs.opencv.org/master/dc/d3d/cudabgsegm_8hpp.html
//
func NewBackgroundSubtractorMOG() BackgroundSubtractorMOG {
return BackgroundSubtractorMOG{p: unsafe.Pointer(C.CudaBackgroundSubtractorMOG_Create())}
}
// Close BackgroundSubtractorMOG.
func (b *BackgroundSubtractorMOG) Close() error {
C.CudaBackgroundSubtractorMOG_Close((C.CudaBackgroundSubtractorMOG)(b.p))
b.p = nil
return nil
}
// Apply computes a foreground mask using the current BackgroundSubtractorMOG.
//
// For further details, please see:
// https://docs.opencv.org/master/d1/dfe/classcv_1_1cuda_1_1BackgroundSubtractorMOG.html#a8f52d2f7abd1c77c84243efc53972cbf
//
func (b *BackgroundSubtractorMOG) Apply(src GpuMat, dst *GpuMat) {
C.CudaBackgroundSubtractorMOG_Apply((C.CudaBackgroundSubtractorMOG)(b.p), src.p, dst.p)
return
}

33
cuda/cudabgsegm.h Normal file
View File

@@ -0,0 +1,33 @@
#ifndef _OPENCV3_CUDABGSEGM_H_
#define _OPENCV3_CUDABGSEGM_H_
#ifdef __cplusplus
#include <opencv2/opencv.hpp>
extern "C" {
#endif
#include "../core.h"
#include "cuda.h"
#ifdef __cplusplus
typedef cv::Ptr<cv::cuda::BackgroundSubtractorMOG2>* CudaBackgroundSubtractorMOG2;
typedef cv::Ptr<cv::cuda::BackgroundSubtractorMOG>* CudaBackgroundSubtractorMOG;
#else
typedef void* CudaBackgroundSubtractorMOG2;
typedef void* CudaBackgroundSubtractorMOG;
#endif
CudaBackgroundSubtractorMOG2 CudaBackgroundSubtractorMOG2_Create();
void CudaBackgroundSubtractorMOG2_Close(CudaBackgroundSubtractorMOG2 b);
void CudaBackgroundSubtractorMOG2_Apply(CudaBackgroundSubtractorMOG2 b, GpuMat src, GpuMat dst);
CudaBackgroundSubtractorMOG CudaBackgroundSubtractorMOG_Create();
void CudaBackgroundSubtractorMOG_Close(CudaBackgroundSubtractorMOG b);
void CudaBackgroundSubtractorMOG_Apply(CudaBackgroundSubtractorMOG b, GpuMat src, GpuMat dst);
#ifdef __cplusplus
}
#endif
#endif //_OPENCV3_CUDABGSEGM_H_

62
cuda/cudabgsegm_test.go Normal file
View File

@@ -0,0 +1,62 @@
package cuda
import (
"gocv.io/x/gocv"
"testing"
)
func TestCudaMOG2(t *testing.T) {
img := gocv.IMRead("../images/face.jpg", gocv.IMReadColor)
if img.Empty() {
t.Error("Invalid Mat in CudaMOG2 test")
}
defer img.Close()
var cimg, dimg = NewGpuMat(), NewGpuMat()
defer cimg.Close()
defer dimg.Close()
cimg.Upload(img)
dst := gocv.NewMat()
defer dst.Close()
mog2 := NewBackgroundSubtractorMOG2()
defer mog2.Close()
mog2.Apply(cimg, &dimg)
dimg.Download(&dst)
if dst.Empty() {
t.Error("Error in TestCudaMOG2 test")
}
}
func TestCudaMOG(t *testing.T) {
img := gocv.IMRead("../images/face.jpg", gocv.IMReadColor)
if img.Empty() {
t.Error("Invalid Mat in CudaMOG test")
}
defer img.Close()
var cimg, dimg = NewGpuMat(), NewGpuMat()
defer cimg.Close()
defer dimg.Close()
cimg.Upload(img)
dst := gocv.NewMat()
defer dst.Close()
mog2 := NewBackgroundSubtractorMOG()
defer mog2.Close()
mog2.Apply(cimg, &dimg)
dimg.Download(&dst)
if dst.Empty() {
t.Error("Error in TestCudaMOG test")
}
}