diff --git a/build.gradle b/build.gradle index cdacd209cf..7862c2648a 100644 --- a/build.gradle +++ b/build.gradle @@ -111,6 +111,157 @@ ext.useWpiUtil = { project -> // } } +ext.getOpenCvPlatformPackage = { targetPlatform -> + if (targetPlatform.architecture.arm) { + return 'linux-arm' + } else if (targetPlatform.operatingSystem.linux) { + if (targetPlatform.architecture.amd64) { + return 'linux-x86_64' + } else { + return 'linux-' + targetPlatform.architecture.name + } + } else if (targetPlatform.operatingSystem.windows) { + if (targetPlatform.architecture.amd64) { + return 'windows-x86_64' + } else { + return 'windows-' + targetPlatform.architecture.name + } + } else if (targetPlatform.operatingSystem.macOsX) { + if (targetPlatform.architecture.amd64) { + return 'osx-x86_64' + } else { + return 'osx-' + targetPlatform.architecture.name + } + } else { + return targetPlatform.operatingSystem.name + '-' + targetPlatform.architecture.name + } +} + +ext.useOpenCv = { project -> + def openCvUnzipLocation = "${project.buildDir}/opencv" + + if (project.tasks.findByPath("unzipOpenCvHeaders") == null) { + // opencv-headers + def openCvHeadersDependency = + project.dependencies.create("org.opencv:opencv-headers:3.1.0@jar") + def openCvHeadersConfig = project.configurations.detachedConfiguration(openCvHeadersDependency) + openCvHeadersConfig.setTransitive(false) + def openCvHeaders = openCvHeadersConfig.files[0].canonicalFile + + project.tasks.create(name: "unzipOpenCvHeaders", type: Copy) { + description = 'Unzips the OpenCV maven dependency so that the include files and libraries can be used' + group = 'OpenCv' + from zipTree(openCvHeaders) + into "${openCvUnzipLocation}/include" + } + } + + if (project.includeJava) { + if (project.tasks.findByPath("unzipOpenCvJava") == null) { + // opencv-java + def openCvJavaDependency = + project.dependencies.create("org.opencv:opencv-java:3.1.0@jar") + def openCvJavaConfig = project.configurations.detachedConfiguration(openCvJavaDependency) + openCvJavaConfig.setTransitive(false) + def openCvJava = openCvJavaConfig.files[0].canonicalFile + + project.tasks.create(name: "unzipOpenCvJava", type: Copy) { + description = 'Unzips the OpenCV maven dependency so that the include files and libraries can be used' + group = 'OpenCv' + from zipTree(openCvJava) + into "${openCvUnzipLocation}/java" + } + } + } + + project.ext.openCv = openCvUnzipLocation + project.ext.openCvInclude = "$openCvUnzipLocation/include" + + project.ext.addOpenCvLibraryLinks = { compileTask, linker, targetPlatform -> + def openCvPlatform = project.getOpenCvPlatformPackage(targetPlatform) + + if (project.tasks.findByPath("unzipOpenCvNatives${openCvPlatform}") == null) { + // opencv-natives + def openCvNativesDependency = + project.dependencies.create("org.opencv:opencv-natives:3.1.0:${openCvPlatform}@jar") + def openCvNativesConfig = project.configurations.detachedConfiguration(openCvNativesDependency) + openCvNativesConfig.setTransitive(false) + def openCvNatives = openCvNativesConfig.files[0].canonicalFile + + project.tasks.create(name: "unzipOpenCvNatives${openCvPlatform}", type: Copy) { + description = 'Unzips the OpenCV maven dependency so that the include files and libraries can be used' + group = 'OpenCv' + from zipTree(openCvNatives) + into "${project.openCv}/${openCvPlatform}" + } + } + + if (project.includeJava) { + if (project.tasks.findByPath("unzipOpenCvJni${openCvPlatform}") == null) { + // opencv-jni + def openCvJniDependency = + project.dependencies.create("org.opencv:opencv-jni:3.1.0:${openCvPlatform}@jar") + def openCvJniConfig = project.configurations.detachedConfiguration(openCvJniDependency) + openCvJniConfig.setTransitive(false) + def openCvJni = openCvJniConfig.files[0].canonicalFile + + project.tasks.create(name: "unzipOpenCvJni${openCvPlatform}", type: Copy) { + description = 'Unzips the OpenCV maven dependency so that the include files and libraries can be used' + group = 'OpenCv' + from zipTree(openCvJni) + into "${project.openCv}/${openCvPlatform}" + } + } + } + + compileTask.dependsOn "unzipOpenCvHeaders", "unzipOpenCvNatives${openCvPlatform}" + if (project.includeJava) { + compileTask.dependsOn "unzipOpenCvJava", "unzipOpenCvJni${openCvPlatform}" + } + if (targetPlatform.architecture.arm) { + linker.args "${project.openCv}/${openCvPlatform}/libopencv_calib3d.so" + linker.args "${project.openCv}/${openCvPlatform}/libopencv_core.so" + linker.args "${project.openCv}/${openCvPlatform}/libopencv_features2d.so" + linker.args "${project.openCv}/${openCvPlatform}/libopencv_flann.so" + linker.args "${project.openCv}/${openCvPlatform}/libopencv_highgui.so" + linker.args "${project.openCv}/${openCvPlatform}/libopencv_imgcodecs.so" + linker.args "${project.openCv}/${openCvPlatform}/libopencv_imgproc.so" + linker.args "${project.openCv}/${openCvPlatform}/libopencv_ml.so" + linker.args "${project.openCv}/${openCvPlatform}/libopencv_objdetect.so" + linker.args "${project.openCv}/${openCvPlatform}/libopencv_photo.so" + linker.args "${project.openCv}/${openCvPlatform}/libopencv_shape.so" + linker.args "${project.openCv}/${openCvPlatform}/libopencv_stitching.so" + linker.args "${project.openCv}/${openCvPlatform}/libopencv_superres.so" + linker.args "${project.openCv}/${openCvPlatform}/libopencv_video.so" + linker.args "${project.openCv}/${openCvPlatform}/libopencv_videoio.so" + linker.args "${project.openCv}/${openCvPlatform}/libopencv_videostab.so" + linker.args "-ldl" + linker.args "-lz" + } else if (targetPlatform.operatingSystem.windows) { + linker.args "${project.openCv}/${openCvPlatform}/opencv_core.lib" + } else { + linker.args "${project.openCv}/${openCvPlatform}/libopencv_calib3d.a" + linker.args "${project.openCv}/${openCvPlatform}/libopencv_core.a" + linker.args "${project.openCv}/${openCvPlatform}/libopencv_features2d.a" + linker.args "${project.openCv}/${openCvPlatform}/libopencv_flann.a" + linker.args "${project.openCv}/${openCvPlatform}/libopencv_highgui.a" + linker.args "${project.openCv}/${openCvPlatform}/libopencv_imgcodecs.a" + linker.args "${project.openCv}/${openCvPlatform}/libopencv_imgproc.a" + linker.args "${project.openCv}/${openCvPlatform}/libopencv_ml.a" + linker.args "${project.openCv}/${openCvPlatform}/libopencv_objdetect.a" + linker.args "${project.openCv}/${openCvPlatform}/libopencv_photo.a" + linker.args "${project.openCv}/${openCvPlatform}/libopencv_shape.a" + linker.args "${project.openCv}/${openCvPlatform}/libopencv_stitching.a" + linker.args "${project.openCv}/${openCvPlatform}/libopencv_superres.a" + linker.args "${project.openCv}/${openCvPlatform}/libopencv_video.a" + linker.args "${project.openCv}/${openCvPlatform}/libopencv_videoio.a" + linker.args "${project.openCv}/${openCvPlatform}/libopencv_videostab.a" + linker.args "-ldl" + linker.args "-lz" + } + } +} + ext.setupDefines = { project, binaries -> binaries.all { if (project.hasProperty('debug')) { @@ -120,6 +271,7 @@ ext.setupDefines = { project, binaries -> } tasks.withType(CppCompile) { project.addWpiUtilLibraryLinks(it, linker, targetPlatform) + project.addOpenCvLibraryLinks(it, linker, targetPlatform) } } } diff --git a/cameraserver.gradle b/cameraserver.gradle index 73b0eb8f20..a45cfdb774 100644 --- a/cameraserver.gradle +++ b/cameraserver.gradle @@ -36,7 +36,7 @@ def cameraserverSetupModel = { project -> includes = ['**/*.cpp'] } exportedHeaders { - srcDirs = ["${rootDir}/include", project.wpiUtilInclude] + srcDirs = ["${rootDir}/include", project.wpiUtilInclude, project.openCvInclude] if (includeJava) { project.jniHeadersCameraServer.outputs.files.each { file -> srcDirs file.getPath() @@ -181,6 +181,7 @@ if (buildArm) { cameraserverSetupExamplesModel(project) cameraserverZipTask(project) useWpiUtil(project) + useOpenCv(project) } } @@ -201,6 +202,7 @@ project(':native') { cameraserverSetupExamplesModel(project) cameraserverZipTask(project) useWpiUtil(project) + useOpenCv(project) } task cameraserverSourceZip(type: Zip) { diff --git a/include/cameraserver_cpp.h b/include/cameraserver_cpp.h index c5ebf35183..a178003fd5 100644 --- a/include/cameraserver_cpp.h +++ b/include/cameraserver_cpp.h @@ -134,7 +134,7 @@ void ReleaseSource(CS_Source source, CS_Status* status); // // OpenCV Source Functions // -void PutSourceFrame(CS_Source source, cv::Mat* image, CS_Status* status); +void PutSourceFrame(CS_Source source, cv::Mat& image, CS_Status* status); void NotifySourceError(CS_Source source, llvm::StringRef msg, CS_Status* status); void SetSourceConnected(CS_Source source, bool connected, CS_Status* status); @@ -178,7 +178,7 @@ void ReleaseSink(CS_Sink sink, CS_Status* status); // // OpenCV Sink Functions // -uint64_t GrabSinkFrame(CS_Sink sink, cv::Mat* image, CS_Status* status); +uint64_t GrabSinkFrame(CS_Sink sink, cv::Mat& image, CS_Status* status); std::string GetSinkError(CS_Sink sink, CS_Status* status); llvm::StringRef GetSinkError(CS_Sink sink, llvm::SmallVectorImpl& buf, CS_Status* status); diff --git a/include/cameraserver_oo.h b/include/cameraserver_oo.h index 054b9e7c6a..09ce81002d 100644 --- a/include/cameraserver_oo.h +++ b/include/cameraserver_oo.h @@ -214,7 +214,7 @@ class CvSource : public VideoSource { /// This is identical in behavior to calling PutImage(0, image) followed by /// NotifyFrame(). /// @param image OpenCV image - void PutFrame(cv::Mat* image); + void PutFrame(cv::Mat& image); /// Signal sinks that an error has occurred. This should be called instead /// of NotifyFrame when an error occurs. @@ -340,7 +340,7 @@ class CvSink : public VideoSink { /// Wait for the next frame and get the image. /// @return Frame time, or 0 on error (call GetError() to obtain the error /// message); - uint64_t GrabFrame(cv::Mat* image) const; + uint64_t GrabFrame(cv::Mat& image) const; /// Get error string. Call this if WaitForFrame() returns 0 to determine /// what the error is. diff --git a/include/cameraserver_oo.inl b/include/cameraserver_oo.inl index eaa2adc327..917ae67fa0 100644 --- a/include/cameraserver_oo.inl +++ b/include/cameraserver_oo.inl @@ -182,7 +182,7 @@ inline CvSource::CvSource(llvm::StringRef name, VideoMode::PixelFormat format, CreateCvSource(name, VideoMode{format, width, height, fps}, &m_status); } -inline void CvSource::PutFrame(cv::Mat* image) { +inline void CvSource::PutFrame(cv::Mat& image) { m_status = 0; PutSourceFrame(m_handle, image, &m_status); } @@ -284,7 +284,7 @@ inline CvSink::CvSink(llvm::StringRef name, m_handle = CreateCvSinkCallback(name, processFrame, &m_status); } -inline uint64_t CvSink::GrabFrame(cv::Mat* image) const { +inline uint64_t CvSink::GrabFrame(cv::Mat& image) const { m_status = 0; return GrabSinkFrame(m_handle, image, &m_status); } diff --git a/src/cameraserver_c.cpp b/src/cameraserver_c.cpp index 4186b8d693..635a7d53c3 100644 --- a/src/cameraserver_c.cpp +++ b/src/cameraserver_c.cpp @@ -10,6 +10,7 @@ #include #include +#include "opencv2/core/core.hpp" #include "llvm/SmallString.h" #include "cameraserver_cpp.h" @@ -183,7 +184,8 @@ void CS_ReleaseSource(CS_Source source, CS_Status* status) { void CS_PutSourceFrame(CS_Source source, struct CvMat* image, CS_Status* status) { - //TODO: return cs::PutSourceFrame(source, image, status); + auto mat = cv::cvarrToMat(image); + return cs::PutSourceFrame(source, mat, status); } void CS_NotifySourceError(CS_Source source, const char* msg, @@ -269,7 +271,8 @@ void CS_ReleaseSink(CS_Sink sink, CS_Status* status) { uint64_t CS_GrabSinkFrame(CS_Sink sink, struct CvMat* image, CS_Status* status) { - return 0; // TODO: cs::GrabSinkFrame(sink, image, status); + auto mat = cv::cvarrToMat(image); + return cs::GrabSinkFrame(sink, mat, status); } char* CS_GetSinkError(CS_Sink sink, CS_Status* status) { diff --git a/src/cameraserver_cpp.cpp b/src/cameraserver_cpp.cpp index 9d7cdc085f..7f733b2097 100644 --- a/src/cameraserver_cpp.cpp +++ b/src/cameraserver_cpp.cpp @@ -324,7 +324,7 @@ void ReleaseSource(CS_Source source, CS_Status* status) { // OpenCV Source Functions // -void PutSourceFrame(CS_Source source, cv::Mat* image, CS_Status* status) { +void PutSourceFrame(CS_Source source, cv::Mat& image, CS_Status* status) { // TODO } @@ -475,7 +475,7 @@ void ReleaseSink(CS_Sink sink, CS_Status* status) { // OpenCV Sink Functions // -uint64_t GrabSinkFrame(CS_Sink sink, cv::Mat* image, CS_Status* status) { +uint64_t GrabSinkFrame(CS_Sink sink, cv::Mat& image, CS_Status* status) { return 0; // TODO } diff --git a/test/tests.gradle b/test/tests.gradle index e8092ee501..1dc7d48940 100644 --- a/test/tests.gradle +++ b/test/tests.gradle @@ -13,7 +13,7 @@ model { includes = ['**/*.cpp'] } exportedHeaders { - srcDirs = ["${rootDir}/include", "${rootDir}/src", "${rootDir}/wpiutil/include", "${rootDir}/gmock/include", "${rootDir}/gmock/gtest/include"] + srcDirs = ["${rootDir}/include", "${rootDir}/src", "${rootDir}/gmock/include", "${rootDir}/gmock/gtest/include"] includes = ['**/*.h'] } } @@ -23,6 +23,7 @@ model { lib library: 'cameraserver', linkage: 'static' tasks.withType(CppCompile) { project.addWpiUtilLibraryLinks(it, linker, targetPlatform) + project.addOpenCvLibraryLinks(it, linker, targetPlatform) } } }