Android 使用OpenCV实现实时人脸识别,并绘制到SurfaceView上
1. 前言
上篇文章 我们已经通过一个简单的例子,在Android Studio中接入了OpenCV。
之前我们也 在Visual Studio上,使用OpenCV实现人脸识别 中实现了人脸识别的效果。
接着,我们就可以将OpenCV的人脸识别效果移植到Android中了。
1.1 环境说明
- 操作系统 :
windows 10 64位 Android Studio版本 :Android Studio Giraffe | 2022.3.1OpenCV版本 :OpenCV-4.8.0 (2023年7月最新版)
1.2 实现效果
先来看下实现效果,识别到的人脸会用红框框出来。

接下来我们来一步步实现上述的效果。
2. 前置操作
2.1 添加权限
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
ActivityCompat.requestPermissions(this@FaceDetectionActivity,arrayOf(Manifest.permission.CAMERA,Manifest.permission.WRITE_EXTERNAL_STORAGE,Manifest.permission.RECORD_AUDIO),1
)
2.2 新建FaceDetectionActivity
新建FaceDetectionActivity,并将其设为默认的Activity,然后修改其XML布局
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"xmlns:app="http://schemas.android.com/apk/res-auto"android:orientation="vertical"tools:context=".MainActivity"><androidx.constraintlayout.widget.ConstraintLayoutandroid:background="@color/black"android:layout_width="match_parent"android:layout_height="match_parent"><SurfaceViewandroid:id="@+id/surfaceView"android:layout_width="match_parent"android:layout_height="0dp"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintDimensionRatio="w,4:3"app:layout_constraintLeft_toLeftOf="parent"app:layout_constraintRight_toRightOf="parent"app:layout_constraintTop_toTopOf="parent" /></androidx.constraintlayout.widget.ConstraintLayout><LinearLayoutandroid:layout_width="match_parent"android:orientation="horizontal"android:layout_height="wrap_content"><Buttonandroid:text="切换摄像头"android:onClick="switchCamera"android:layout_width="wrap_content"android:layout_height="wrap_content" /></LinearLayout>
</RelativeLayout>
2.3 添加JNI方法
然后修改FaceDetectionActivity为如下代码,这里增加了三个JNI方法
init: 初始化OpenCV人脸识别setSurface: 设置SurfaceViewpostData: 发送视频帧数据
class FaceDetectionActivity : AppCompatActivity() {private lateinit var binding: ActivityFaceDetectionBindingoverride fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)binding = ActivityFaceDetectionBinding.inflate(layoutInflater)setContentView(binding.root)//这里省略了申请权限的代码...}//初始化OpenCVexternal fun init(path: String?)//向OpenCV发送一帧的图像数据external fun postData(data: ByteArray?, width: Int, height: Int, cameraId: Int)//设置SurfaceViewexternal fun setSurface(surface: Surface?)companion object {init {System.loadLibrary("myopencvtest")}}
}
同时,需要在native-lib.cpp中添加这三个JNI方法,这里的com_heiko_myopencvtest_FaceDetectionActivity需要改为你实际的包名和类名。
extern "C"
JNIEXPORT void JNICALL
Java_com_heiko_myopencvtest_FaceDetectionActivity_init(JNIEnv *env, jobject thiz, jstring path) {}
extern "C"
JNIEXPORT void JNICALL
Java_com_heiko_myopencvtest_FaceDetectionActivity_postData(JNIEnv *env, jobject thiz,jbyteArray data, jint width, jint height,jint camera_id) {
}
extern "C"
JNIEXPORT void JNICALL
Java_com_heiko_myopencvtest_FaceDetectionActivity_setSurface(JNIEnv *env, jobject thiz,jobject surface) {
}
2.4 实现相机预览功能
这里用到了Camera1 API,直接使用CameraHelper这个工具类接入即可,这部分详见我的另一篇博客 Android 使用Camera1的工具类CameraHelper快速实现相机预览、拍照功能
override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)binding = ActivityFaceDetectionBinding.inflate(layoutInflater)setContentView(binding.root)//这里省略了申请权限的代码...val surfaceView = findViewById<SurfaceView>(R.id.surfaceView)surfaceView.holder.addCallback(this)cameraHelper = CameraHelper(cameraId)cameraHelper.setPreviewCallback(this)
}
3. 初始化OpenCV
3.1 配置OpenCV
接着,我们不要忘了配置OpenCV,这部分详见我的另一篇博客 : Android Studio 接入OpenCV最简单的例子 : 实现灰度图效果
3.2 赋值级联分类器文件
配置好OpenCV,我们要将模型,也就是人脸识别的级联分类器文件haarcascade_frontalface_alt.xml复制到asserts文件夹下。
当我们启动App的时候,需要将该文件复制到外置存储中。
override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)//省略了其他代码...//Utils类可以在本文末尾复制Utils.copyAssets(this@FaceDetectionActivity, "haarcascade_frontalface_alt.xml")
}
拷贝完成后,调用init()方法,传入路径
override fun onResume() {super.onResume()//省略了其他代码...//Utils类可以在本文末尾复制val path = Utils.getModelFile(this@FaceDetectionActivity,"haarcascade_frontalface_alt.xml").absolutePathinit(path)}
4. 实现CascadeDetectorAdapter
这里我们需要将我的另一篇博客中的 在Visual Studio上,使用OpenCV实现人脸识别 (下面统称为VS实现) 中的代码移植过来。
这里创建了CascadeDetectorAdapter,实现了DetectionBasedTracker::IDetector接口,和VS实现上代码是一样的。
class CascadeDetectorAdapter : public DetectionBasedTracker::IDetector
{
public:CascadeDetectorAdapter(cv::Ptr<cv::CascadeClassifier> detector) :IDetector(),Detector(detector){CV_Assert(detector);}void detect(const cv::Mat& Image, std::vector<cv::Rect>& objects){Detector->detectMultiScale(Image, objects, scaleFactor, minNeighbours, 0, minObjSize, maxObjSize);}virtual ~CascadeDetectorAdapter(){}private:CascadeDetectorAdapter();cv::Ptr<cv::CascadeClassifier> Detector;
};cv::Ptr<DetectionBasedTracker> tracker;
5. 实现init方法
init方法也是一样的,声明tracker对象,并调用run()方法,会启动一个异步线程,后面的人脸检测会在这个异步线程进行检测了。(这个是保障实时人脸检测不卡的前提)
//cv::Ptr<DetectionBasedTracker> tracker;
DetectionBasedTracker *tracker = 0;extern "C"
JNIEXPORT void JNICALL
Java_com_heiko_myopencvtest_FaceDetectionActivity_init(JNIEnv *env, jobject thiz, jstring path) {string stdFileName = env->GetStringUTFChars(path, 0);//创建一个主检测适配器cv::Ptr<CascadeDetectorAdapter> mainDetector = makePtr<CascadeDetectorAdapter>(makePtr<CascadeClassifier>(stdFileName));//创建一个跟踪检测适配器cv::Ptr<CascadeDetectorAdapter> trackingDetector = makePtr<CascadeDetectorAdapter>(makePtr<CascadeClassifier>(stdFileName));//创建跟踪器DetectionBasedTracker::Parameters DetectorParams;//tracker = makePtr<DetectionBasedTracker>(mainDetector, trackingDetector, DetectorParams);tracker= new DetectionBasedTracker(mainDetector, trackingDetector, DetectorParams);tracker->run();
}
5. 设置Surface
在 Android NDK 中,ANativeWindow 是一个C/C++接口,它提供了一种在 C 或 C++ 代码中访问 Android Surface 的方式。通过使用ANativeWindow接口,开发者可以在NDK中直接访问和操作Android窗口系统,实现图形处理和渲染操作。
这里我们将SurfaceView传到JNI中,方便C/C++代码后边将图像实时渲染到Android SurfaceView上。
#include <android/native_window_jni.h>ANativeWindow *window = 0;extern "C"
JNIEXPORT void JNICALL
Java_com_heiko_myopencvtest_FaceDetectionActivity_setSurface(JNIEnv *env, jobject thiz,jobject surface) {if (window) {ANativeWindow_release(window);window = 0;}window = ANativeWindow_fromSurface(env, surface);
}
6. 处理数据并实现人脸识别
处理图像数据的部分我们在postData中实现,这部分会先对图像进行处理,然后进行人脸识别,并渲染到SurfaceView上。
extern "C"
JNIEXPORT void JNICALL
Java_com_heiko_myopencvtest_FaceDetectionActivity_postData(JNIEnv *env, jobject instance, jbyteArray data_,jint w, jint h, jint cameraId) {//待实现的代码
}
6.1 将图片转化为Mat
参数中的jbyteArray data_,是从Android Java层中获取到的。
然后转化为jbyte *data这个字节数组,接着将其转为一个Mat矩阵。
Mat是是OpenCV最基本的数据结构。它用于存储图像数据。
需要注意的是,由于传入的数据是YUV420,每个像素占1.5byte,
所以这个图像的宽度需要传入实际宽度*1.5,宽度不变。
这里的CV_8UC1是单通道的意思,就是说无论是Y分量还是U、V分量,都存储在同一个通道里。
jbyte *data = env->GetByteArrayElements(data_, NULL);
Mat src(h + h / 2, w, CV_8UC1, data);
要获取Mat对象中每个通道的数据,可以使用OpenCV提供的函数和方法。
对于一个BGR图像(即具有三个通道的图像),每个通道的数据可以分别获取并进行处理。
以下是一些示例代码,演示如何获取每个通道的数据:// 假设img是包含BGR图像的Mat对象 // 获取B通道数据 Mat bChannel = img.channel(0); // 获取G通道数据 Mat gChannel = img.channel(1); //获取R通道数据 Mat rChannel = img.channel(2);
6.2 将YUV转为RGBA
接着,需要将YUV格式转化为RGBA格式,方便后续的操作。
这里的COLOR_YUV2RGBA_NV21表示原始是NV21的YUV格式,将其转为RGBA格式。
cvtColor(src, src, COLOR_YUV2RGBA_NV21);
6.3 对图像做翻转和镜像
由于手机摄像头硬件安装在手机里时,和屏幕的方向并不是一致的,所以需要将摄像头拍摄的画面进行旋转。
- 如果是前置摄像头 : 需要将画面逆时针旋转
90度,并做左右镜像操作 - 如果是后置摄像头 : 需要将画面顺时针旋转
90度
if (cameraId == 1) {//前置摄像头rotate(src, src, ROTATE_90_COUNTERCLOCKWISE);//1:左右镜像//0:上下镜像flip(src, src, 1);
} else {//顺时针旋转90度rotate(src, src, ROTATE_90_CLOCKWISE);
}
6.4 转为灰度图并进行直方图均衡化处理
接着需要对图像进行灰度和直方图均衡化处理,以便提高人脸识别的准确性和可靠性,这部分和VS实现上是一样。
Mat gray;
//转为灰度图
cvtColor(src, gray, COLOR_RGBA2GRAY);
//直方图均衡化
equalizeHist(gray, gray);
6.5 进行人脸检测
接着就可以调用tracker->process来建人脸检测了。
检测完成后,接着调用tracker->getObjects将检测的人脸位置赋值给faces。
std::vector<Rect> faces;
tracker->process(gray);
tracker->getObjects(faces);
6.6 将人脸用红框框出来
接着,将识别到的人脸,用红色的矩形框绘制出来,rectangle方法就是用来绘制一个矩形框的方法。
for (Rect face : faces) {rectangle(src, face, Scalar(255, 0, 0));
}
6.7 将图像渲染到SurfaceView上
6.7.1 设置窗口缓冲区
ANativeWindow_setBuffersGeometry是设置Android Native窗口的缓冲区的大小和像素格式。
if (window) {ANativeWindow_setBuffersGeometry(window, src.cols, src.rows, WINDOW_FORMAT_RGBA_8888);//后续代码在这里编写...
}
6.7.2 将图像数据填充到窗口的缓冲区
这里是个while循环,会不断地将图像数据(RGBA),填充到窗口的缓冲区,最后调用ANativeWindow_unlockAndPost提交刷新,图像就渲染到SurfaceView上了。
ANativeWindow_Buffer window_buffer;
do {//如果 lock 失败,直接 breakif (ANativeWindow_lock(window, &window_buffer, 0)) {ANativeWindow_release(window);window = 0;break;}//将window_buffer.bits转化为 uint8_t *uint8_t *dst_data = static_cast<uint8_t *>(window_buffer.bits);//stride : 一行多少个数据 (RGBA) * 4int dst_linesize = window_buffer.stride * 4;//一行一行拷贝for (int i = 0; i < window_buffer.height; ++i) {memcpy(dst_data + i * dst_linesize, src.data + i * src.cols * 4, dst_linesize);}//提交刷新ANativeWindow_unlockAndPost(window);
} while (0);
6.8 回收资源
最后,别忘了回收资源
src.release();
gray.release();
env->ReleaseByteArrayElements(data_, data, 0);
7. 运行项目
我们可以看到效果如下,至此我们就完成在Android上,使用OpenCV实现实时的人脸识别了。

8. 本文源码下载
Android和Windows下,使用OpenCV实现人脸识别 示例 Demo
9. OpenCV系列文章
Visual Studio 2022 cmake配置opencv开发环境_opencv visualstudio配置_氦客的博客-CSDN博客
在Visual Studio上,使用OpenCV实现人脸识别_氦客的博客-CSDN博客
Android Studio 接入OpenCV,并实现灰度图效果_氦客的博客-CSDN博客
Android 使用OpenCV实现实时人脸识别,并绘制到SurfaceView上_氦客的博客-CSDN博客
❤️ 如果觉得这篇博文写的不错,对你有所帮助,帮忙点个赞👍
⭐ 这是对我持续输出高质量博文的最好鼓励。😄
相关文章:
Android 使用OpenCV实现实时人脸识别,并绘制到SurfaceView上
1. 前言 上篇文章 我们已经通过一个简单的例子,在Android Studio中接入了OpenCV。 之前我们也 在Visual Studio上,使用OpenCV实现人脸识别 中实现了人脸识别的效果。 接着,我们就可以将OpenCV的人脸识别效果移植到Android中了。 1.1 环境说…...
【自然语言处理】关系抽取 —— GDPNet 讲解
GDPNet 论文信息 标题:GDPNet: Refining Latent Multi-View Graph for Relation Extraction 作者:Fuzhao Xue, Aixin Sun, Hao Zhang, Eng Siong Chng 期刊:AAAI 2021 发布时间与更新时间:2020.12.12 主题:自然语言处理、关系抽取、对话场景、BERT、GCN arXiv:[2012.0678…...
【小沐学NLP】Python使用NLTK库的入门教程
文章目录 1、简介2、安装2.1 安装nltk库2.2 安装nltk语料库 3、测试3.1 分句分词3.2 停用词过滤3.3 词干提取3.4 词形/词干还原3.5 同义词与反义词3.6 语义相关性3.7 词性标注3.8 命名实体识别3.9 Text对象3.10 文本分类3.11 其他分类器3.12 数据清洗 结语 1、简介 NLTK - 自然…...
Angular安全专辑之三 —— 授权绕过,利用漏洞控制管理员账户
这篇文章是针对实际项目中所出现的问题所做的一个总结。简单来说,就是授权绕过问题,管理员帐户被错误的接管。 详细情况是这样的,我们的项目中通常都会有用户身份验证功能,不同的用户拥有不同的权限。相对来说管理员账户所对应的…...
使用Sumo以及traci实现交叉口信号灯自适应控制
使用Sumo以及traci实现交叉口信号灯自适应控制 文章目录 使用Sumo以及traci实现交叉口信号灯自适应控制 使用Sumo以及traci实现交叉口信号灯感应控制一、什么是交叉口感应控制二、Traci中的感应控制实现流程1.感应控制逻辑2.仿真过程 使用Sumo以及traci实现交叉口信号灯感应控制…...
自定义类型:结构体、枚举、联合
目录 结构体 结构体的基础知识 结构的声明 特殊的声明 结构体的自引用 结构体变量的定义和初始化 结构体内存对齐 修改默认对齐数 结构体传参 位段 什么是位段 位段的内存分配 位段的跨平台问题 位段的应用 枚举 枚举类型的定义 枚举的优点 联合体(共…...
如何使用ZIP方式安装MySQL:简单、快速、高效的安装方法
下载MySQL的zip文件:从官方网站 https://dev.mysql.com/downloads/mysql/ 下载适用于您的操作系统的MySQL zip压缩包。 版本介绍(zip一般选第ZIP Archive版本) “Windows (x86, 64-bit), ZIP Archive” 是MySQL的发布版本,提供了MySQL服务器和相关的工具…...
python嵌套循环
在 Python 中,你可以使用嵌套循环来创建双循环,也就是一个循环包含在另一个循环中。通常有两种类型的双循环:嵌套循环和同时迭代多个迭代器的循环。我会详细说明这两种情况。 1. 嵌套循环: 嵌套循环是指一个循环嵌套在另一个循环…...
一文速学-让神经网络不再神秘,一天速学神经网络基础(五)-最优化
前言 思索了很久到底要不要出深度学习内容,毕竟在数学建模专栏里边的机器学习内容还有一大半算法没有更新,很多坑都没有填满,而且现在深度学习的文章和学习课程都十分的多,我考虑了很久决定还是得出神经网络系列文章,…...
【AWS实验】 配置中转网关及对等连接
文章目录 实验概览目标实验环境任务 1:查看网络拓扑并创建基准任务 2:创建中转网关任务 3:创建中转网关挂载任务 4:创建中转网关路由表任务 4.1:创建路由表关联任务 4.2:创建路由传播 任务 5:更…...
47、springboot 的 国际化消息支持--就是根据浏览器选择的语言,项目上的一些提示信息根据语言的选择进行对应的显示
springboot的国际化也是基于spring mvc 的。 springboot 的 国际化消息支持–就是根据浏览器选择的语言,项目上的一些提示信息根据语言的选择进行对应的显示。 总结下国家化自动配置: 功能实现就是: 比如一个登录页面,我们在浏览…...
重要变更 | Hugging Face Hub 的 Git 操作不再支持使用密码验证
在 Hugging Face,我们一直致力于提升服务安全性,因此,我们将修改 Hugging Face Hub 的 Git 交互认证方式。 从 2023 年 10 月 1 日 开始,我们将不再接受密码作为命令行 Git 操作的认证方式。我们推荐使用更安全的认证方法…...
为什么删除Windows 11上的Bloatware可以帮助加快你的电脑速度
如果你感觉你的电脑迟钝,彻底清除软件会有所帮助,而且这个过程对Windows用户来说越来越容易。 微软正在使删除以前难以删除的其他预装Windows应用程序成为可能。专家表示,这项新功能可能会改变用户的游戏规则。 科技公司Infatica的主管Vlad…...
PCL点云处理之计算两条直线间最短连线的端点 (二百零三)
PCL点云处理之计算两条直线间最短连线的端点 (二百零三) 一、算法目的二、具体实现1.代码2.结果一、算法目的 条件:给定两条直线,直线采用直线上一点和直线方向来确定 要求:求两条直线间的最短连线线段,获取它的两个端点 具体的算法实现如下,提供了示例直线和计算结果进…...
纵行科技与山鹰绿能达成合作,提供物联网资产管理数据服务
近日,纵行科技与山鹰绿能宣布双方达成深度合作关系,纵行科技将为山鹰绿能提供专业的物联网技术服务,使用物联网技术帮助山鹰绿能对循环包装载具等资产进行在线管理和数字化运营。 据悉,山鹰绿能是一家由山鹰国际控股的全资子公司…...
【2511. 最多可以摧毁的敌人城堡数目】
来源:力扣(LeetCode) 描述: 给你一个长度为 n ,下标从 0 开始的整数数组 forts ,表示一些城堡。forts[i] 可以是 -1 ,0 或者 1 ,其中: -1 表示第 i 个位置 没有 城堡。…...
stm32f1xx单片机拦截中断源代码
这个是实现后的效果,可以看到已经没有中断的效果了 这个是拦截前的效果可以看到电平是在变化的 实现原理非常简单:一句话搞定: if(TIM2->CNTTIM2->ARR-5)TIM2->CNT-5; 以下是完整的代码:是用来补充说明和筹字数的 /* …...
C++(21):特殊工具与技术
控制内存分配 某些应用程序对内存分配有特殊需求,无法直接应用标准内存管理机制。需要自定义内存分配的细节。 重载 new 和 delete void* operator new(std::size_t size) {// 自定义内存分配逻辑void* ptr std::malloc(size);if (!ptr) {throw std::bad_alloc(…...
go读取yaml,json,ini等配置文件
实际项目中,要读取一些json等配置文件。今天就来说一说,Golang 是如何读取YAML,JSON,INI等配置文件的。 一. go读取json配置文件 JSON 应该比较熟悉,它是一种轻量级的数据交换格式。层次结构简洁清晰 ,易于阅读和编写࿰…...
一、安装GoLang环境和开发工具
一、安装GoLang环境 GoLang中国镜像站 下载后对应的环境包以后,一路下一步就好了,安装路径的话,尽量就安装到默认的文件目录下。 二、配置Go的环境变量 右击此电脑–>属性–>高级系统设置–>环境变量,打开环境变量设置…...
观成科技:隐蔽隧道工具Ligolo-ng加密流量分析
1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具,该工具基于TUN接口实现其功能,利用反向TCP/TLS连接建立一条隐蔽的通信信道,支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式,适应复杂网…...
如何在看板中体现优先级变化
在看板中有效体现优先级变化的关键措施包括:采用颜色或标签标识优先级、设置任务排序规则、使用独立的优先级列或泳道、结合自动化规则同步优先级变化、建立定期的优先级审查流程。其中,设置任务排序规则尤其重要,因为它让看板视觉上直观地体…...
UDP(Echoserver)
网络命令 Ping 命令 检测网络是否连通 使用方法: ping -c 次数 网址ping -c 3 www.baidu.comnetstat 命令 netstat 是一个用来查看网络状态的重要工具. 语法:netstat [选项] 功能:查看网络状态 常用选项: n 拒绝显示别名&#…...
【Zephyr 系列 10】实战项目:打造一个蓝牙传感器终端 + 网关系统(完整架构与全栈实现)
🧠关键词:Zephyr、BLE、终端、网关、广播、连接、传感器、数据采集、低功耗、系统集成 📌目标读者:希望基于 Zephyr 构建 BLE 系统架构、实现终端与网关协作、具备产品交付能力的开发者 📊篇幅字数:约 5200 字 ✨ 项目总览 在物联网实际项目中,**“终端 + 网关”**是…...
pikachu靶场通关笔记22-1 SQL注入05-1-insert注入(报错法)
目录 一、SQL注入 二、insert注入 三、报错型注入 四、updatexml函数 五、源码审计 六、insert渗透实战 1、渗透准备 2、获取数据库名database 3、获取表名table 4、获取列名column 5、获取字段 本系列为通过《pikachu靶场通关笔记》的SQL注入关卡(共10关࿰…...
精益数据分析(97/126):邮件营销与用户参与度的关键指标优化指南
精益数据分析(97/126):邮件营销与用户参与度的关键指标优化指南 在数字化营销时代,邮件列表效度、用户参与度和网站性能等指标往往决定着创业公司的增长成败。今天,我们将深入解析邮件打开率、网站可用性、页面参与时…...
视频行为标注工具BehaviLabel(源码+使用介绍+Windows.Exe版本)
前言: 最近在做行为检测相关的模型,用的是时空图卷积网络(STGCN),但原有kinetic-400数据集数据质量较低,需要进行细粒度的标注,同时粗略搜了下已有开源工具基本都集中于图像分割这块,…...
Yolov8 目标检测蒸馏学习记录
yolov8系列模型蒸馏基本流程,代码下载:这里本人提交了一个demo:djdll/Yolov8_Distillation: Yolov8轻量化_蒸馏代码实现 在轻量化模型设计中,**知识蒸馏(Knowledge Distillation)**被广泛应用,作为提升模型…...
招商蛇口 | 执笔CID,启幕低密生活新境
作为中国城市生长的力量,招商蛇口以“美好生活承载者”为使命,深耕全球111座城市,以央企担当匠造时代理想人居。从深圳湾的开拓基因到西安高新CID的战略落子,招商蛇口始终与城市发展同频共振,以建筑诠释对土地与生活的…...
莫兰迪高级灰总结计划简约商务通用PPT模版
莫兰迪高级灰总结计划简约商务通用PPT模版,莫兰迪调色板清新简约工作汇报PPT模版,莫兰迪时尚风极简设计PPT模版,大学生毕业论文答辩PPT模版,莫兰迪配色总结计划简约商务通用PPT模版,莫兰迪商务汇报PPT模版,…...
