在基于 Android 相机预览的 CV 应用程序中使用 OpenCL

这篇具有很好参考价值的文章主要介绍了在基于 Android 相机预览的 CV 应用程序中使用 OpenCL。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

如何使用 OpenCL 构建自定义 OpenCV Android SDK

  1. 组装和配置 Android OpenCL SDK。示例的 JNI 部分依赖于标准 Khornos OpenCL 标头,以及 OpenCL 和 libOpenCL.so 的C++包装器。标准 OpenCL 标头可以从 OpenCV 存储库中的第三方目录或 Linux 发行版包中复制。C++包装器在Github上的官方Khronos存储库中可用。按以下方式将头文件复制到专用目录:
    cd your_path/ && mkdir ANDROID_OPENCL_SDK && mkdir ANDROID_OPENCL_SDK/include && cd ANDROID_OPENCL_SDK/include
    cp -r path_to_opencv/opencv/3rdparty/include/opencl/1.2/CL 。&& cd CL
    wget https://github.com/KhronosGroup/OpenCL-CLHPP/raw/main/include/CL/opencl.hpp
    wget https://github.com/KhronosGroup/OpenCL-CLHPP/raw/main/include/CL/cl2.hpp
    libOpenCL.so 可以随 BSP 一起提供,也可以从任何具有相关结构的 OpenCL cabaple Android 设备下载。
    CD your_path/ANDROID_OPENCL_SDK & MKDIR 库 && CD 库
    adb 拉 /system/vendor/lib64/libOpenCL.so
    libOpenCL.so 的系统版本可能具有许多特定于平台的依赖项。 标志允许忽略在构建过程中未使用的第三方符号。以下 CMake 行允许将 JNI 部分链接到标准 OpenCL,但不能将 loadLibrary 包含在应用程序包中。系统 OpenCL API 在运行时使用。-Wl,--allow-shlib-undefined
    target_link_libraries(${target} -lOpenCL)
  2. 使用 OpenCL 构建自定义 OpenCV Android SDK。默认情况下,OpenCL 支持 (T-API) 在 Android 操作系统的 OpenCV 版本中处于禁用状态。但是可以在启用 OpenCL/T-API 的情况下为 Android 本地重建 OpenCV:使用 CMake 选项。您还需要指定 CMake 的 Android OpenCL SDK: use 选项的路径。如果您正在使用 OpenCV 构建,请按照 wiki 上的说明进行操作。在 中设置这些 CMake 参数,例如:-DWITH_OPENCL=ON-DANDROID_OPENCL_SDK=path_to_your_Android_OpenCL_SDKbuild_sdk.py.config.pyndk-18-api-level-21.config.py
    ABI(“3”, “arm64-v8a”None, 21, cmake_vars=dict('WITH_OPENCL': 'ON', 'ANDROID_OPENCL_SDK': 'path_to_your_Android_OpenCL_SDK'))
    如果你使用 cmake/ninja 构建 OpenCV,请使用这个 bash 脚本(设置你的NDK_VERSION和路径,而不是路径示例):
    CD path_to_opencv & & mkdir 构建 && cd 构建
    导出NDK_VERSION=25.2.9519653
    导出 ANDROID_SDK=/home/user/Android/Sdk/
    导出 ANDROID_OPENCL_SDK=/path_to_ANDROID_OPENCL_SDK/
    导出 ANDROID_HOME=$ANDROID_SDK
    导出ANDROID_NDK_HOME=$ANDROID_SDK/ndk/$NDK_VERSION/
    cmake -GNinja -DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK_HOME/build/cmake/android.toolchain.cmake -DANDROID_STL=c++_shared -DANDROID_NATIVE_API_LEVEL=24
    -DANDROID_SDK=$ANDROID_SDK -DANDROID_NDK=$ANDROID_NDK_HOME -DBUILD_JAVA=ON -DANDROID_HOME=$ANDROID_SDK -DBUILD_ANDROID_EXAMPLES=ON
    -DINSTALL_ANDROID_EXAMPLES=ON -DANDROID_ABI=arm64-v8a -DWITH_OPENCL=ON -DANDROID_OPENCL_SDK=$ANDROID_OPENCL_SDK ..

前言

通过 OpenCL 使用 GPGPU 来增强应用程序性能现在已成为一种现代趋势。一些 CV 算法(例如图像过滤)在 GPU 上的运行速度比在 CPU 上快得多。最近,它在 Android 操作系统上成为可能。

Android 操作设备最流行的 CV 应用场景是在预览模式下启动相机,将一些 CV 算法应用于每一帧,并显示由该 CV 算法修改的预览帧。

让我们考虑一下在这种情况下如何使用 OpenCL。具体来说,让我们尝试两种方式:直接调用 OpenCL API 和最近引入的 OpenCV T-API(又名透明 API)——一些 OpenCV 算法的隐式 OpenCL 加速。

应用程序结构

从 Android API 级别 11 (Android 3.0) 开始,相机 API 允许使用 OpenGL 纹理作为预览帧的目标。Android API 级别 21 带来了一个新的 Camera2 API,它提供了对相机设置和使用模式的更多控制,它允许预览帧和 OpenGL 纹理的多个目标。

在 OpenGL 纹理中拥有预览帧对于使用 OpenCL 来说是一笔不错的选择,因为有一个 OpenGL-OpenCL 互操作性 API (cl_khr_gl_sharing),允许与 OpenCL 函数共享 OpenGL 纹理数据而无需复制(当然有一些限制)。

让我们为我们的应用程序创建一个基础,它只将 Android 相机配置为将预览帧发送到 OpenGL 纹理,并在显示时显示这些帧,而无需任何处理。

用于此目的的最小类如下所示:Activity

​
公共类 Tutorial4Activity 扩展 Activity {
私人MyGLSurfaceView mView;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON,
WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
mView = 新的 MyGLSurfaceView(这个);
setContentView(mView);
}
@Override
受保护的无效 onPause() {
mView.onPause();
super.onPause();
}
@Override
受保护的无效 onResume() {
super.onResume();
mView.onResume();
}
}
和最小类:View

public class MyGLSurfaceView 扩展了 CameraGLSurfaceView 实现 CameraGLSurfaceView.CameraTextureListener {
static final String LOGTAG = “MyGLSurfaceView”;
受保护的 int procMode = NativePart.PROCESSING_MODE_NO_PROCESSING;
static final String[] procModeName = new String[] {“无处理”, “CPU”, “OpenCL Direct”, “OpenCL via OpenCV” };
受保护的 int frameCounter;
保护时间长NanoTime;
TextView mFpsText = 空;
公共MyGLSurfaceView(上下文,属性集属性){
super(上下文,属性);
}
@Override
公共布尔值 onTouchEvent(MotionEvent e) {
if(e.getAction() == MotionEvent.ACTION_DOWN)
((活动)getContext()).openOptionsMenu();
返回 true;
}
@Override
公共空隙 surfaceCreated(SurfaceHolder holder) {
super.surfaceCreated(持有人);
NativePart.initCL();
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
NativePart.closeCL();
super.surfaceDestroyed(持有人);
}
公共无效 setProcessingMode(int newMode) {
if(newMode>=0 && newMode<procModeName.length)
procMode = 新模式;
还
Log.e(LOGTAG, “忽略无效的处理模式: ” + newMode);
((活动) getContext()).runOnUiThread(new Runnable() {
公共无效运行() {
Toast.makeText(getContext(), “选择模式: ” + procModeName[procMode], Toast.LENGTH_LONG).show();
}
});
}
@Override
public void onCameraViewStarted(int width, int height) {
((活动) getContext()).runOnUiThread(new Runnable() {
公共无效运行() {
Toast.makeText(getContext(), “onCameraViewStarted”, Toast.LENGTH_SHORT).show();
}
});
如果 (NativePart.builtWithOpenCL())
NativePart.initCL();
frameCounter = 0;
lastNanoTime = System.nanoTime();
}
@Override
公共无效 onCameraViewStopped() {
((活动) getContext()).runOnUiThread(new Runnable() {
公共无效运行() {
Toast.makeText(getContext(), “onCameraViewStopped”, Toast.LENGTH_SHORT).show();
}
});
}
@Override
公共布尔值 onCameraTexture(int texIn, int texOut, int width, int height) {
转数快
frameCounter++;
if(frameCounter >= 30)
{
final int fps = (int) (frameCounter * 1e9 / (System.nanoTime() - lastNanoTime));
Log.i(LOGTAG, “drawFrame() FPS: ”+fps);
if(mFpsText != null) {
Runnable fpsUpdater = new Runnable() {
公共无效运行() {
mFpsText.setText(“FPS: ” + fps);
}
};
新增功能处理程序(Looper.getMainLooper()).post(fpsUpdater);
} 还 {
Log.d(LOGTAG, “mFpsText == null”);
mFpsText = (TextView)((活动) getContext()).findViewById(R.id.fps_text_view);
}
frameCounter = 0;
lastNanoTime = System.nanoTime();
}
if(procMode == NativePart.PROCESSING_MODE_NO_PROCESSING)
返回 false;
NativePart.processFrame(texIn, texOut, width, height, procMode);
返回 true;
}
}
​

注意

我们使用两个渲染器类:一个用于旧版 Camera API,另一个用于现代 Camera2。

最小的类可以在 Java 中实现(OpenGL ES 2.0 在 Java 中可用),但由于我们将使用 OpenCL 修改预览纹理,因此让我们将 OpenGL 内容移动到 JNI。下面是 JNI 内容的简单 Java 包装器:Renderer

公共类 NativePart {
静态的
{
System.loadLibrary(“opencv_java4”);
System.loadLibrary(“JNIpart”));
}

public static final int PROCESSING_MODE_NO_PROCESSING = 0;
公共静态最终 int PROCESSING_MODE_CPU = 1;
public static final int PROCESSING_MODE_OCL_DIRECT = 2;
public static final int PROCESSING_MODE_OCL_OCV = 3;

公共静态原生布尔值 builtWithOpenCL();
公共静态原生 int initCL();
公共静态原生 void closeCL();
public static native void processFrame(int tex1, int tex2, int w, int h, int mode);
}

由于 和 API 在相机设置和控制方面存在显著差异,因此让我们为两个相应的渲染器创建一个基类:CameraCamera2

​
公共抽象类 MyGLRendererBase 实现 GLSurfaceView.Renderer, SurfaceTexture.OnFrameAvailableListener {
受保护的最终字符串 LOGTAG = “MyGLRendererBase”;
保护表面纹理 mSTex;
保护MyGLSurfaceView mView;
受保护的布尔值 mGLInit = false;
受保护的布尔值 mTexUpdate = false;
MyGLRendererBase(MyGLSurfaceView 视图) {
mView = 视图;
}
受保护的抽象 void openCamera();
受保护的抽象 void closeCamera();
受保护的抽象 void setCameraPreviewSize(int width, int height);
公共无效 onResume() {
Log.i(LOGTAG, “onResume”);
}
公共无效 onPause() {
Log.i(LOGTAG, “onPause”);
mGLInit = 假;
mTexUpdate = 假;
closeCamera();
if(mSTex != 空) {
mSTex.release();
mSTex = 空;
NativeGLRenderer.closeGL();
}
}
@Override
公共同步 void onFrameAvailable(SurfaceTexture surfaceTexture) {
Log.i(LOGTAG, “onFrameAvailable”);
mTexUpdate = 真;
mView.requestRender();
}
@Override
公共无效 onDrawFrame(GL10 gl) {
Log.i(LOGTAG, “onDrawFrame”);
如果 (!mGLInit)
返回;
已同步(此) {
如果 (mTexUpdate) {
mSTex.updateTexImage();
mTexUpdate = 假;
}
}
NativeGLRenderer.drawFrame();
}
@Override
公共空隙 onSurfaceChanged(GL10 gl, int surfaceWidth, int surfaceHeight) {
Log.i(LOGTAG, “onSurfaceChanged(”+surfaceWidth+“x”+surfaceHeight+")");
NativeGLRenderer.changeSize(surfaceWidth, surfaceHeight);
setCameraPreviewSize(surfaceWidth, surfaceHeight);
}
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig 配置) {
Log.i(LOGTAG, “onSurfaceCreated”);
字符串 strGLVersion = GLES20.glGetString(GLES20.GL_VERSION);
if (strGLVersion != null)
Log.i(LOGTAG, “OpenGL ES 版本: ” + strGLVersion);
int hTex = NativeGLRenderer.initGL();
mSTex = 新 SurfaceTexture(hTex);
mSTex.setOnFrameAvailableListener(这个);
openCamera();
mGLInit = 真;
}
}
​

如您所见,和 API 的继承者应该实现以下抽象方法:CameraCamera2

受保护的抽象 void openCamera();
受保护的抽象 void closeCamera();
受保护的抽象 void setCameraPreviewSize(int width, int height);

让我们在本教程之外留下它们实现的细节,请参考源代码查看它们。

预览帧修改

OpenGL ES 2.0 初始化的细节也相当简单和嘈杂,但这里重要的一点是,作为相机预览目标的 OpeGL 纹理应该是类型(不是),内部它以 YUV 格式保存图片数据。这使得无法通过 CL-GL 互操作 () 共享它并通过 C/C++ 代码访问其像素数据。为了克服这个限制,我们必须使用 FrameBuffer 对象(又名 FBO)将 OpenGL 渲染从这个纹理到另一个常规纹理。GL_TEXTURE_EXTERNAL_OESGL_TEXTURE_2Dcl_khr_gl_sharingGL_TEXTURE_2D

C/C++ 代码

之后,我们可以通过 从 C/C++ 读取(复制)像素数据,并在修改后通过 将它们写回纹理。glReadPixels()glTexSubImage2D()

直接 OpenCL 调用

此外,该纹理可以在不复制的情况下与 OpenCL 共享,但我们必须为此以特殊方式创建 OpenCL 上下文:GL_TEXTURE_2D

​
int initCL()
{
dumpCLinfo();
LOGE(“initCL:启动initCL”);
EGLDisplay mEglDisplay = eglGetCurrentDisplay();
如果 (mEglDisplay == EGL_NO_DISPLAY)
LOGE(“initCL: eglGetCurrentDisplay() returned 'EGL_NO_DISPLAY', error = %x”, eglGetError());
EGLContext mEglContext = eglGetCurrentContext();
如果 (mEglContext == EGL_NO_CONTEXT)
LOGE(“initCL: eglGetCurrentContext() returned 'EGL_NO_CONTEXT', error = %x”, eglGetError());
cl_context_properties props[] =
{ CL_GL_CONTEXT_KHR, (cl_context_properties) mEglContext,
CL_EGL_DISPLAY_KHR、(cl_context_properties) mEglDisplay、
CL_CONTEXT_PLATFORM、0、
0 };
尝试
{
haveOpenCL = 假;
cl::P latform p = cl::P latform::getDefault();
std::string ext = p.getInfo<CL_PLATFORM_EXTENSIONS>();
if(ext.find(“cl_khr_gl_sharing”) == std::string::npos)
LOGE(“警告:PLATFORM不支持CL-GL共享”);
道具[5] = (cl_context_properties) p();
theContext = cl::Context(CL_DEVICE_TYPE_GPU, props);
std::vector<cl::D evice> devs = theContext.getInfo<CL_CONTEXT_DEVICES>();
LOGD(“上下文返回了 %d 个设备,取第一个设备”, devs.size());
ext = devs[0].getInfo<CL_DEVICE_EXTENSIONS>();
if(ext.find(“cl_khr_gl_sharing”) == std::string::npos)
LOGE(“警告:DEVICE不支持CL-GL共享”);
theQueue = cl::CommandQueue(theContext, devs[0]);
cl::P rogram::Sources src(1, std::make_pair(oclProgI2I, sizeof(oclProgI2I)));
theProgI2I = cl::P rogram(theContext, src);
progI2I.build(devs);
cv::ocl::attachContext(p.getInfo<CL_PLATFORM_NAME>(), p(), theContext(), devs[0]());
if( cv::ocl::useOpenCL() )
LOGD(“OpenCV+OpenCL 工作正常!”);
还
LOGE(“无法使用 OpenCL TAPI 初始化 OpenCV”);
haveOpenCL = 真;
}
catch(const cl::Error&e)
{
LOGE(“cl::错误:%s (%d)”, e.what(), e.err());
返回 1;
}
catch(const std::exception&e)
{
LOGE(“std::exception: %s”, e.what());
返回 2;
}
捕获(...)
{
LOGE( “OpenCL 信息:初始化 OpenCL 内容时出现未知错误” );
返回 3;
}
LOGD(“initCL 已完成”);
如果(haveOpenCL)
返回 0;
还
返回 4;
}
然后,纹理可以被对象包装,并通过 OpenCL 调用进行处理:cl::ImageGL

cl::ImageGL imgIn (theContext, CL_MEM_READ_ONLY, GL_TEXTURE_2D, 0, texIn);
cl::ImageGL imgOut(theContext, CL_MEM_WRITE_ONLY, GL_TEXTURE_2D, 0, texOut);
std::vector < cl::Memory >图像;
images.push_back(imgIn);
images.push_back(imgOut);
int64_t t = getTimeMs();
theQueue.enqueueAcquireGLObjects(&images);
theQueue.finish();
LOGD(“enqueueAcquireGLObjects() 成本 %d ms”, getTimeInterval(t));
t = getTimeMs();
cl::Kernel Laplacian(theProgI2I, “拉普拉斯”);TODO:可以做一次
拉普拉斯.setArg(0, imgIn);
Laplacian.setArg(1, imgOut);
theQueue.finish();
LOGD(“Kernel() 成本 %d ms”, getTimeInterval(t));
t = getTimeMs();
theQueue.enqueueNDRangeKernel(拉普拉斯, cl::NullRange, cl::NDRange(w, h), cl::NullRange);
theQueue.finish();
LOGD(“enqueueNDRangeKernel() 成本 %d 毫秒”, getTimeInterval(t));
t = getTimeMs();
theQueue.enqueueReleaseGLObjects(&images);
theQueue.finish();
LOGD(“enqueueReleaseGLObjects() 成本 %d ms”, getTimeInterval(t));
​

OpenCV T-API

但是,您可能希望使用隐式调用 OpenCL 的 OpenCV T-API,而不是自己编写 OpenCL 代码。您只需要将创建的 OpenCL 上下文传递给 OpenCV(通过 ),并以某种方式将 OpenGL 纹理包装成 .不幸的是,OpenCL 缓冲区在内部保留,无法包裹在 OpenGL 纹理或 OpenCL 图像上 - 因此我们必须在此处复制图像数据:cv::ocl::attachContext()cv::UMatUMat

int64_t t = getTimeMs();
cl::ImageGL imgIn (theContext, CL_MEM_READ_ONLY, GL_TEXTURE_2D, 0, texIn);
std::vector < cl::Memory > images(1, imgIn);
theQueue.enqueueAcquireGLObjects(&images);
theQueue.finish();
cv::UMat uIn、uOut、uTmp;
cv::ocl::convertFromImage(imgIn(), uIn);
LOGD(“将纹理数据加载到 OpenCV UMat 成本 %d ms”, getTimeInterval(t));
theQueue.enqueueReleaseGLObjects(&images);
t = getTimeMs();
cv::blur(uIn, uOut, cv::Size(5, 5));
cv::拉普拉斯(uIn, uTmp, CV_8U);
cv:乘法(uTmp, 10, uOut);
cv::ocl::完成();
LOGD(“OpenCV 处理成本 %d ms”, getTimeInterval(t));
t = getTimeMs();
cl::ImageGL imgOut(theContext, CL_MEM_WRITE_ONLY, GL_TEXTURE_2D, 0, texOut);
图像.clear();
images.push_back(imgOut);
theQueue.enqueueAcquireGLObjects(&images);
cl_mem clBuffer = (cl_mem)uOut。手柄(cv::ACCESS_READ);
cl_command_queue q = (cl_command_queue)cv::ocl::Queue::getDefault()。PTR的();
size_t偏移量 = 0;
size_t origin[3] = { 0, 0, 0 };
size_t region[3] = { (size_t)w, (size_t)h, 1 };
CV_Assert(clEnqueueCopyBufferToImage (q, clBuffer, imgOut(), offset, origin, region, 0, NULL, NULL) == CL_SUCCESS);
theQueue.enqueueReleaseGLObjects(&images);
cv::ocl::完成();
LOGD(“将结果上传到纹理成本 %d ms”, getTimeInterval(t));

注意

当通过 OpenCL 图像包装器将修改后的图像放回原始 OpenGL 纹理时,我们必须再复制一个图像数据。

性能说明

为了比较我们在索尼Xperia Z3上以720p相机分辨率测量的相同预览帧修改(拉普拉斯)的性能,这些修改是通过C / C++代码(调用with),直接OpenCL调用(使用OpenCL图像进行输入和输出)和OpenCV T-API(调用with)完成的:cv::Laplaciancv::Matcv::Laplaciancv::UMat

  • C/C++ 版本显示 3-4 fps
  • 直接 OpenCL 调用显示 25-27 fps
  • OpenCV T-API 显示 11-13 fps(由于额外的往返复制)cl_imagecl_buffer

   在线教程

  • 麻省理工学院人工智能视频教程 – 麻省理工人工智能课程
  • 人工智能入门 – 人工智能基础学习。Peter Norvig举办的课程
  • EdX 人工智能 – 此课程讲授人工智能计算机系统设计的基本概念和技术。
  • 人工智能中的计划 – 计划是人工智能系统的基础部分之一。在这个课程中,你将会学习到让机器人执行一系列动作所需要的基本算法。
  • 机器人人工智能 – 这个课程将会教授你实现人工智能的基本方法,包括:概率推算,计划和搜索,本地化,跟踪和控制,全部都是围绕有关机器人设计。
  • 机器学习 – 有指导和无指导情况下的基本机器学习算法
  • 机器学习中的神经网络 – 智能神经网络上的算法和实践经验
  • 斯坦福统计学习

有需要的小伙伴,可以点击下方链接免费领取或者V扫描下方二维码免费领取🆓

在基于 Android 相机预览的 CV 应用程序中使用 OpenCL,android,数码相机,人工智能,开发语言,opencv

在基于 Android 相机预览的 CV 应用程序中使用 OpenCL,android,数码相机,人工智能,开发语言,opencv

人工智能书籍

  • OpenCV(中文版).(布拉德斯基等)
  • OpenCV+3计算机视觉++Python语言实现+第二版
  • OpenCV3编程入门 毛星云编著
  • 数字图像处理_第三版
  • 人工智能:一种现代的方法
  • 深度学习面试宝典
  • 深度学习之PyTorch物体检测实战
  • 吴恩达DeepLearning.ai中文版笔记
  • 计算机视觉中的多视图几何
  • PyTorch-官方推荐教程-英文版
  • 《神经网络与深度学习》(邱锡鹏-20191121)

  • 在基于 Android 相机预览的 CV 应用程序中使用 OpenCL,android,数码相机,人工智能,开发语言,opencv

第一阶段:零基础入门(3-6个月)

新手应首先通过少而精的学习,看到全景图,建立大局观。 通过完成小实验,建立信心,才能避免“从入门到放弃”的尴尬。因此,第一阶段只推荐4本最必要的书(而且这些书到了第二、三阶段也能继续用),入门以后,在后续学习中再“哪里不会补哪里”即可。

在基于 Android 相机预览的 CV 应用程序中使用 OpenCL,android,数码相机,人工智能,开发语言,opencv

第二阶段:基础进阶(3-6个月)

熟读《机器学习算法的数学解析与Python实现》并动手实践后,你已经对机器学习有了基本的了解,不再是小白了。这时可以开始触类旁通,学习热门技术,加强实践水平。在深入学习的同时,也可以探索自己感兴趣的方向,为求职面试打好基础。

在基于 Android 相机预览的 CV 应用程序中使用 OpenCL,android,数码相机,人工智能,开发语言,opencv

第三阶段:工作应用

在基于 Android 相机预览的 CV 应用程序中使用 OpenCL,android,数码相机,人工智能,开发语言,opencv

这一阶段你已经不再需要引导,只需要一些推荐书目。如果你从入门时就确认了未来的工作方向,可以在第二阶段就提前阅读相关入门书籍(对应“商业落地五大方向”中的前两本),然后再“哪里不会补哪里”。

 有需要的小伙伴,可以点击下方链接免费领取或者V扫描下方二维码免费领取🆓

在基于 Android 相机预览的 CV 应用程序中使用 OpenCL,android,数码相机,人工智能,开发语言,opencv

在基于 Android 相机预览的 CV 应用程序中使用 OpenCL,android,数码相机,人工智能,开发语言,opencv

在基于 Android 相机预览的 CV 应用程序中使用 OpenCL,android,数码相机,人工智能,开发语言,opencv

 文章来源地址https://www.toymoban.com/news/detail-811558.html

到了这里,关于在基于 Android 相机预览的 CV 应用程序中使用 OpenCL的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Elasticsearch:使用 Elastic APM 监控 Android 应用程序(二)

    在我之前的文章 “Elasticsearch:使用 Elastic APM 监控 Android 应用程序(一)” 中,我详述了如何使用 Elastic APM 来监控 Android 应用程序。在今天的文章中,我来详述如何部署 Elastic Stack,并使用文章中的示例代码来进行展示。为了展示方便,在今天的展示中,我将所有的组件都安

    2023年04月22日
    浏览(46)
  • 如何使用KoodousFinder搜索和分析Android应用程序中的安全威胁

    KoodousFinder是一款功能强大的Android应用程序安全工具,在该工具的帮助下,广大研究人员可以轻松对目标Android应用程序执行安全研究和分析任务,并寻找出目标应用程序中潜在的安全威胁和安全漏洞。 在使用该工具之前,我们首选需要访问该工具的【开发者门户】创建一个

    2024年02月13日
    浏览(64)
  • android excludeFromRecents将activity在最近的使用的应用程序列表中不显示

    excludeFromRecents 是Android应用程序清单文件(AndroidManifest.xml)中的一个属性,用于控制应用程序是否在最近使用的应用程序列表中显示。通过将 excludeFromRecents 属性设置为 true ,可以将应用程序从最近使用的应用程序列表中排除。 以下是将应用程序排除在最近使用的应用程序列

    2024年02月15日
    浏览(57)
  • nodejs+python+php+微信小程序-基于安卓android的健身服务应用APP-计算机毕业设计

    考虑到实际生活中在健身服务应用方面的需要以及对该系统认真的分析,将系统权限按管理员和用户这两类涉及用户划分。  则对于进一步提高健身服务应用发展,丰富健身服务应用经验能起到不少的促进作用。 健身服务应用APP能够通过互联网得到广泛的、全面的宣传,让

    2024年02月07日
    浏览(55)
  • Android应用程序中使用 Gemini Pro AI开发——2年工作经验如何淘汰10年工作经验的Android开发?

    上周,谷歌推出了最强大的基础模型 Gemini 。 Gemini 是多模式的AI——它可以接受文本和图像输入。 谷歌为 Android 开发者引入了一种在设备上,利用最小模型Gemini Nano的方法。此功能可通过 AICore 在部分设备上使用,这是一项处理模型管理、运行时、安全功能等的系统服务,可

    2024年01月18日
    浏览(68)
  • Android 使用Camera1实现相机预览、拍照、录像

    本文介绍如何从零开始,在 Android 中实现 Camera1 的接入,并在文末提供 Camera1Manager 工具类,可以用于快速接入 Camera1 。 Android Camera1 API 虽然已经被 Google 废弃,但有些场景下不得不使用。 并且 Camera1 返回的帧数据是 NV21 ,不像 Camera2 、 CameraX 那样,需要自己再转一层,才能得

    2024年02月08日
    浏览(51)
  • 保护您的Android应用程序:Android应用程序安全一览

    我们都知道Android是为所有人设计的——开放、面向开发者、面向用户,这种开放性为今天和明天的移动技术提供了很多便利。然而,开放性也带来了需要妥善处理的安全风险。 安全是我们所有人都关注的重要问题。无论是我们的个人数据、电子邮件、电话号码、凭证、服务

    2024年02月03日
    浏览(72)
  • ChatGPT 使用 拓展资料:吴恩达大咖 基于LangChain的LLM应用程序开发-1

    ChatGPT 使用 拓展资料:吴恩达大咖 基于LangChain的LLM应用程序开发 基于LangChain的LLM应用程序开发 LangChain for LLM Application Development [https://www.deeplearning.ai/short-courses/langchain-for-llm-application-development/] LangChain for LLM Application Development https://www.deeplearning.ai/short-courses/langchain-for-llm-app

    2024年02月07日
    浏览(54)
  • Android 使用Camera2 API 和 GLSurfaceView实现相机预览

    GLSurfaceView 和 SurfaceView 是 Android 中用于显示图像的两个视图类,它们在实现方式和使用场景上有一些区别。 实现方式:GLSurfaceView 基于 OpenGL ES 技术实现,可以通过 OpenGL ES 渲染图像。而 SurfaceView 则是通过基于线程的绘制方式,可以在独立的线程中进行绘制操作。 性能:由于

    2024年02月09日
    浏览(46)
  • 【Android笔记98】Android小案例之APP应用程序管理(获取已安装应用、卸载应用)

    这篇文章,主要介绍Android小案例之APP应用程序管理(获取已安装应用、卸载应用)。 目录 一、应用管理APP小案例 1.1、运行效果 1.2、使用技术 1.3、案例代码

    2024年02月02日
    浏览(56)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包