项目实训—基于AI的智能视频剪辑器项目架构搭建
Posted Winter-tea
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了项目实训—基于AI的智能视频剪辑器项目架构搭建相关的知识,希望对你有一定的参考价值。
文章目录
前言
本次项目实训目标打造一款智能视频剪辑APP,所提供的基本功能为:由用户选择本地视频进行上传,并且提供希望剪辑的主要人物图像,系统将智能检测出人物所在视频片段,并且合成人物cut视频,用户自行选择下载。
在本次实训中,我所负责的部分是移动端代码的编程,本周主要完成的工作是项目基本架构的搭建。
一、项目架构搭建
1.项目目录结构
项目意图打造一款 android 端app,移动端目录结构基本如下:
- activity 目录:主要活动的集合,项目预计采用XPage框架,将以少量主要的Activity控制多个Fragment页面
- adapter 目录:适配器类集合,用于连接后端数据和前端显示
- core 目录:核心类的集合,包括一些基类以及框架的核心类
- fragment 目录:嵌入Activity的UI片段的集合
- utils 目录:工具类的集合
- widget 目录:widget小控件类的集合
- MyApp:Application类
- res 目录:存放定义应用程序菜单资源的XML文件
- AndroidManifest.xml:整个Android项目的配置文件,注册四大组件,为应用程序添加权限声明
2. 主要框架引入
项目中主要使用了X系列的框架,包括:
XUI | 一个简洁的Android原生UI框架,包括UI组件、UI主题样式、UI资源和UI辅助工具 |
XPage | 一个方便的fragment页面框架,以通用的Activity作为壳,Fragment作为页面填充展示,并且能够像Activity那样自由的切换和数据交互 |
XRouter | 一个轻量级的Android路由框架,基于ARouter上进行改良,优化Fragment的使用,可结合XPage使用 |
XHttp2 | 一个功能强大的网络请求库,使用RxJava2 + Retrofit2 + OKHttp组合进行封装。支持多种Http请求方式,提供大量丰富的网络请求拦截器 |
XUtil | 一个方便实用的Android工具类库。收录了Android开发过程中常用的工具类,并进行简单的分类,易于查询使用 |
XUpdate | 一个轻量级、高可用性的Android版本更新框架 |
XAOP | 一个轻量级的AOP(面向切片编程)应用框架 |
创建 x-library.gradle 文件,以引入X系列框架,并将X-Library依赖添加到 build.gradle 文件中
apply plugin: 'com.xuexiang.xaop' //引用XAOP插件
apply plugin: 'com.xuexiang.xrouter' //引用XRouter-plugin插件实现自动注册
//自动添加依赖
configurations.each configuration ->
def dependencies = getProject().dependencies
if (configuration.name == "implementation")
//为Project加入X-Library依赖
//XUI框架
configuration.dependencies.add(dependencies.create(deps.xlibrary.xui))
configuration.dependencies.add(dependencies.create(deps.androidx.appcompat))
configuration.dependencies.add(dependencies.create(deps.androidx.recyclerview))
configuration.dependencies.add(dependencies.create(deps.androidx.design))
configuration.dependencies.add(dependencies.create(deps.glide))
//XUtil工具类
configuration.dependencies.add(dependencies.create(deps.xlibrary.xutil_core))
//XAOP切片
configuration.dependencies.add(dependencies.create(deps.xlibrary.xaop_runtime))
//XUpdate版本更新
configuration.dependencies.add(dependencies.create(deps.xlibrary.xupdate))
//XHttp2
configuration.dependencies.add(dependencies.create(deps.xlibrary.xhttp2))
configuration.dependencies.add(dependencies.create(deps.rxjava2))
configuration.dependencies.add(dependencies.create(deps.rxandroid))
configuration.dependencies.add(dependencies.create(deps.okhttp3))
configuration.dependencies.add(dependencies.create(deps.gson))
//XPage
configuration.dependencies.add(dependencies.create(deps.xlibrary.xpage_lib))
//页面路由
configuration.dependencies.add(dependencies.create(deps.xlibrary.xrouter_runtime))
if (configuration.name == "annotationProcessor")
//XPage
configuration.dependencies.add(dependencies.create(deps.xlibrary.xpage_compiler))
//页面路由
configuration.dependencies.add(dependencies.create(deps.xlibrary.xrouter_compiler))
if (configuration.name == "debugImplementation")
//内存泄漏监测leak
configuration.dependencies.add(dependencies.create(deps.leakcanary))
configurations.all
resolutionStrategy.force deps.okhttp3
在 util 文件夹下,创建 XBasicLibInit.java 文件,来完成X系列基础库的初始化,在 MyApp.java 中调用 init 函数,使得项目运行即可初始化基础库
public final class XBasicLibInit
private XBasicLibInit()
throw new UnsupportedOperationException("u can't instantiate me...");
/**
* 初始化基础库SDK
*/
public static void init(Application application)
//工具类
initXUtil(application);
//网络请求框架
initXHttp2(application);
//页面框架
initXPage(application);
//切片框架
initXAOP(application);
//UI框架
initXUI(application);
//路由框架
initRouter(application);
/**
* 初始化XUtil工具类
*/
private static void initXUtil(Application application)
XUtil.init(application);
XUtil.debug(MyApp.isDebug());
TokenUtils.init(application);
/**
* 初始化XHttp2
*/
private static void initXHttp2(Application application)
//初始化网络请求框架,必须首先执行
XHttpSDK.init(application);
//需要调试的时候执行
if (MyApp.isDebug())
XHttpSDK.debug();
// XHttpSDK.debug(new CustomLoggingInterceptor()); //设置自定义的日志打印拦截器
//设置网络请求的全局基础地址
XHttpSDK.setBaseUrl("https://gitee.com/");
// //设置动态参数添加拦截器
// XHttpSDK.addInterceptor(new CustomDynamicInterceptor());
// //请求失效校验拦截器
// XHttpSDK.addInterceptor(new CustomExpiredInterceptor());
/**
* 初始化XPage页面框架
*/
private static void initXPage(Application application)
PageConfig.getInstance()
.debug(MyApp.isDebug())
.setContainActivityClazz(BaseActivity.class)
.init(application);
/**
* 初始化XAOP
*/
private static void initXAOP(Application application)
XAOP.init(application);
XAOP.debug(MyApp.isDebug());
//设置动态申请权限切片 申请权限被拒绝的事件响应监听
XAOP.setOnPermissionDeniedListener(permissionsDenied -> XToastUtils.error("权限申请被拒绝:" + StringUtils.listToString(permissionsDenied, ",")));
/**
* 初始化XUI框架
*/
private static void initXUI(Application application)
XUI.init(application);
XUI.debug(MyApp.isDebug());
/**
* 初始化路由框架
*/
private static void initRouter(Application application)
// 这两行必须写在init之前,否则这些配置在init过程中将无效
if (MyApp.isDebug())
XRouter.openLog(); // 打印日志
XRouter.openDebug(); // 开启调试模式(如果在InstantRun模式下运行,必须开启调试模式!线上版本需要关闭,否则有安全风险)
XRouter.init(application);
二、Viewbinding视图绑定
View Binding是Android Studio 3.6推出的新特性,目的是为了替代findViewById(内部实现还是使用findViewById)。。在启动视图绑定后,系统会为改模块中的每个xml文件生成一个绑定类,绑定类的实例包含对在相应布局中具有 ID 的所有视图的直接引用。
通过 Viewbinding 创建 Activity 的基类
public class BaseActivity<Binding extends ViewBinding> extends XPageActivity
/**
* 是否支持侧滑返回
*/
public static final String KEY_SUPPORT_SLIDE_BACK = "key_support_slide_back";
/**
* ViewBinding
*/
protected Binding binding;
@Override
protected void attachBaseContext(Context newBase)
//注入字体
super.attachBaseContext(ViewPumpContextWrapper.wrap(newBase));
@Override
protected View getCustomRootView()
binding = viewBindingInflate(getLayoutInflater());
return binding != null ? binding.getRoot() : null;
@Override
protected void onCreate(Bundle savedInstanceState)
initStatusBarStyle();
super.onCreate(savedInstanceState);
registerSlideBack();
/**
* 构建ViewBinding
*
* @param inflater inflater
* @return ViewBinding
*/
@Nullable
protected Binding viewBindingInflate(LayoutInflater inflater)
return null;
/**
* 获取Binding
*
* @return Binding
*/
public Binding getBinding()
return binding;
/**
* 初始化状态栏的样式
*/
protected void initStatusBarStyle()
/**
* 打开fragment
*
* @param clazz 页面类
* @param addToBackStack 是否添加到栈中
* @return 打开的fragment对象
*/
public <T extends XPageFragment> T openPage(Class<T> clazz, boolean addToBackStack)
CoreSwitchBean page = new CoreSwitchBean(clazz)
.setAddToBackStack(addToBackStack);
return (T) openPage(page);
/**
* 打开fragment
*
* @return 打开的fragment对象
*/
public <T extends XPageFragment> T openNewPage(Class<T> clazz)
CoreSwitchBean page = new CoreSwitchBean(clazz)
.setNewActivity(true);
return (T) openPage(page);
public <T extends XPageFragment> T openNewPage(Class<T> clazz, Bundle bundle)
CoreSwitchBean page = new CoreSwitchBean(clazz, bundle)
.setNewActivity(true);
return (T) openPage(page);
/**
* 切换fragment
*
* @param clazz 页面类
* @return 打开的fragment对象
*/
public <T extends XPageFragment> T switchPage(Class<T> clazz)
return openPage(clazz, false);
/**
* 序列化对象
*
* @param object
* @return
*/
public String serializeObject(Object object)
return XRouter.getInstance().navigation(SerializationService.class).object2Json(object);
@Override
protected void onRelease()
unregisterSlideBack();
super.onRelease();
/**
* 注册侧滑回调
*/
protected void registerSlideBack()
if (isSupportSlideBack())
SlideBack.with(this)
.haveScroll(true)
.edgeMode(ResUtils.isRtl() ? SlideBack.EDGE_RIGHT : SlideBack.EDGE_LEFT)
.callBack(this::popPage)
.register();
/**
* 注销侧滑回调
*/
protected void unregisterSlideBack()
if (isSupportSlideBack())
SlideBack.unregister(this);
/**
* @return 是否支持侧滑返回
*/
protected boolean isSupportSlideBack()
CoreSwitchBean page = getIntent().getParcelableExtra(CoreSwitchBean.KEY_SWITCH_BEAN);
return page == null || page.getBundle() == null || page.getBundle().getBoolean(KEY_SUPPORT_SLIDE_BACK, true);
通过 Viewbinding 创建 Fragment 的基类(使用XPage框架搭建)
public abstract class BaseFragment<Binding extends ViewBinding> extends XPageFragment
private IProgressLoader mIProgressLoader;
/**
* ViewBinding
*/
protected Binding binding;
@Override
protected View inflateView(LayoutInflater inflater, ViewGroup container)
binding = viewBindingInflate(inflater, container);
return binding.getRoot();
/**
* 构建ViewBinding
*
* @param inflater inflater
* @param container 容器
* @return ViewBinding
*/
@NonNull
protected abstract Binding viewBindingInflate(LayoutInflater inflater, ViewGroup container);
/**
* 获取Binding
*
* @return Binding
*/
public Binding getBinding()
return binding;
@Override
protected void initPage()
initTitle();
initViews();
initListeners();
protected TitleBar initTitle()
return TitleUtils.addTitleBarDynamic((ViewGroup) getRootView(), getPageTitle(), v -> popToBack());
@Override
protected void initListeners()
/**
* 获取进度条加载者
*
* @return 进度条加载者
*/
public IProgressLoader getProgressLoader()
if (mIProgressLoader == null)
mIProgressLoader = ProgressLoader.create(getContext());
return mIProgressLoader;
/**
* 获取进度条加载者
*
* @param message 提示信息
* @return 进度条加载者
*/
public IProgressLoader getProgressLoader(String message)
if (mIProgressLoader == null)
mIProgressLoader = ProgressLoader.create(getContext(), message);
else
mIProgressLoader.updateMessage(message);
return mIProgressLoader;
@Override
public void onConfigurationChanged(@NonNull Configuration newConfig)
//屏幕旋转时刷新一下title
super.onConfigurationChanged(newConfig);
ViewGroup root = (ViewGroup) getRootView();
if (root.getChildAt(0) instanceof TitleBar)
root.removeViewAt(0);
initTitle();
@Override
public void onDestroyView()
if (mIProgressLoader != null)
mIProgressLoader.dismissLoading();
super.onDestroyView();
binding = null;
@Override
public void onResume()
super.onResume();
MobclickAgent.onPageStart(getPageName());
@Override
public void onPause()
super.onPause();
MobclickAgent.onPageEnd(getPageName());
//==============================页面跳转api===================================//
/**
* 打开一个新的页面【建议只在主tab页使用】
*
* @param clazz 页面的类
* @param <T>
* @return
*/
public <T extends XPageFragment> Fragment openNewPage(Class<T> clazz)
return new PageOption(clazz)
.setNewActivity(true)
.open(this);
/**
* 打开一个新的页面【建议只在主tab页使用】
*
* @param pageName 页面名
* @param <T>
* @return
*/
public <T extends XPageFragment> Fragment openNewPage(String pageName)
return new PageOption(pageName)
.setAnim(CoreAnim.slide)
.setNewActivity(true)
.open(this);
/**
* 打开一个新的页面【建议只在主tab页使用】
*
* @param clazz 页面的类
* @param containActivityClazz 页面容器
* @param <T>
* @return
*/
public <T extends XPageFragment> Fragment openNewPage(Class<爱科研 | 基于卷积神经网络的验证码识别 (人工智能项目,十一科研实训)
制作 | 爱科研
研究目标和意义
本研究项目意在通过基于卷积神经网络的深度学习方法和计算机视觉应用的场景结合,来精确识别以计算机图形形式存在的验证码;
同时通过Python编程实战,让学员对于人工智能理论及应用产生认识,并解决现实中的有意思的问题,积攒该领域科研实战经验,为今后的科研、留学和工作打造背景。
导师简介
清华大学博士
长期从事青少年编程(Python/C++)、人工智能课程讲授与项目辅导的教学工作,擅长以独特的教学方式直击人工智能核心,让学生在数学知识与编程技巧尚不充足的情况下,也能对人工智能的学科前沿产生清晰的认识,从而撰写出高质量高水准的学术报告。
目前已经辅导数十名高中生和大学生完成人工智能、机器学习与计算机视觉相关的科研实训。
适合人群
1、希望申请国外计算机科学(CS)、商业分析(BA)、数据科学(DS)等相关学科,但是相关经历不够丰富,甚至相关经历(转专业的同学)为零的;
2、对于人工智能(AI)感兴趣,但是一直无法深入做一段科研项目的同学(对于特别优秀的高中生,我们也非常欢迎)
科研地点
●线上预习
●清华大学实地实训(一周)
●线上实验报告撰写和指导
项目安排
1、报名后9月20日至9月30日,学员预习+远程辅导:学习解析几何与概率论的相关知识,并学习Python编程入门,以及科研项目的相关背景知识,为正式的清华科研之旅扫清知识障碍;
2、10月1日至10月5日,导师教授:深入学习Python+学习pandas、scikit-learn等机器学习库+人工智能中的监督学习模型+深入学习卷积神经网络原理;以及综合实战:搭建卷积神经网络完成验证码的识别;
3、授课结束后,一周内,学员远程根据导师要求,完成实验报告:【爱科研】出具Cerfiticate证明学员人工智能科研经历,对于表现特别优异的同学(通常为top 15%),导师会认真书写英文推荐信,为学员未来的出国深造等增砖添瓦。
项目价格
人民币15000元
9月13日前报名,9折优惠
9月20日截止报名
报名方式
咨询请加科研实训小助手二维码,并注明
"爱科研 + 十一科研实训"
项目延展阅读
近年来,随着互联网技术的飞速发展,网络安全逐渐进入公众的视野,并成为与人们日常生活密切相关的一部分。自从互联网普及以来,网络资源的滥用导致了自动化软件的泛滥。为了抵御恶意机器人程序、防止论坛中的垃圾评论、过滤垃圾邮件、保证在线投票真实性以及防止恶意批量注册网站等等,验证码应运而生。
现如今,验证码在全球超过350万的网站论坛中随处可见,人们日常处理的验证码数量多达300万次以上。由此可见,验证码识别技术的研究有益于验证现如今各种验证码的安全,帮助设计更可靠安全的验证码。不仅如此,验证码识别结合了图像处理、模式识别等多个领域的研究,对于促进各个领域的技术研究具有重要意义。
本项目通过学习深度学习技术亲手实现一个验证码识别器,一方面全面掌握Python编程技巧,为以后进一步学习计算机科学打下坚实的基础;另一方面深入了解机器学习的基础理论,对人工智能的学科前沿产生全面的认知。
以上是关于项目实训—基于AI的智能视频剪辑器项目架构搭建的主要内容,如果未能解决你的问题,请参考以下文章
AI人工智能之基于OpenCV+face_recognition实现人脸识别
山东大学项目实训四——Face_Recognition 使用Opencv和Dlib实现基于视频的人脸识别