简介

前几版How-Old发布后,不少用户反馈,在显示结果的页面中,用于标注前面人年龄的标签,会遮挡住后面的人的脸。这是因为我们最初采用固定偏移的方式来放置年龄标签。

而怎么样让标签不遮挡住其他人的脸,则成为一个有趣的问题。最近我们发布了一次How-Old更新,正好用这篇文章,来记录一下我们对这一问题的实现。

先直观的看一下新版本的改变(左旧 右新):

问题

我们来抽象一下这个问题。

在服务器端识别出了照片中的脸后,会将识别数据传回客户端,其中包含了每个脸的边缘矩形的位置和大小信息(FaceRect)。

然后我们要为每个脸添加对应的标签(LabelRect)。LabelRect和FaceRect两两不重合,LaebelRect自身两两不重合。(FaceRect本身是有可能重合的)

并且我们希望每个标签都尽量离对应的脸比较近。

以上就是比较核心的问题描述。此外我们在实现中还加入了一些小小的增强体验的条件,在正文中会为大家叙述。

算法

准备

我们采用了平面分割标记的算法来布置LabelRect。

对于每个Rect(包括LabelRect,FaceRect),我们需要它的中心点RectCenter(x, y),我们需要确定的也正是每个LabelRect的中心点。

简单的分析一下,我们发现在每个Rect周围一定的区域内,是不能布置LabelCenter的,否则就会导致重合。

如下图所示:

亮蓝色是FaceRect,墨绿色是LabelRect,中间的绿点是LabelRect的中心。

粉红色的半透明区域就是那些不能放置LabelCenter的。这个区域的大小也由LabelRect的大小确定(此例中LabelRect的大小是我们设定好的,每个都一样)。

粉红区域是有FaceRect分别向左右各扩展LabelRect.Width/2,向上下各扩展LabelRect.Height/2确定的。可以看出只要在粉红区域以外放置LabelRect,就必然不会导致LabelRect和FaceRect相交。

我们简单的把每个粉红区域叫做一个ForbidRect。

这样我们就只需要在ForbidRect的边界上选出最合适的点作为LabelCenter就行了(比如离FaceRect最近的点)。

但实际上上图还有问题。还要保证LabelRect彼此不相交呢?

上图应该是这样:

为了方便,我们采用依次布置LabelRect的方式,先布置的一旦布置好就不再移动了,后布置的受限于前面布置的。(即不采用“在一个漏斗里倒入小球,小球会彼此挤开”这种方式)

现在我们提供一种逐步布置的过程,直观的理解一下:

最初从服务器传回的FaceRect。

============================

得出最初的ForbidRect集。

============================

布置第一个LabelRect。

============================

更新ForbidRect集。

============================

布置第2个LabelRect。

============================

再更新ForbidRect集就达到了我们之前那样的结果。

(此过程举例中先放哪个后放哪个,是随便选的)。

那,我们怎么确定该把LabelCenter放在哪呢?换言之,我们怎么出ForbidRect的边界上选出那个合适的点呢?

当时我们就想,怎么在非离散的二维平面上做这个?

分割

然后我们采用了分割平面的方法,就像上图那些重叠的半透明的粉红色块一样,将平面分成一块块的来遍历。

Like this:

(不重要的色块被淡化了。)

每个forbidRect都会引入4个分割线,横向俩,纵向俩。

同时每条分割线会包含引入这条线的ForbidRect编号,每条线都用一个二元组描述:

Tuple1= (offset, rect_id)。Offset是这条线在垂直方向上距原点的偏移量(就是“直线X=3”里面的那个“3”),rect_id就是引入它的ForbidRect编号。

横线,纵向分开统计。

举例:假设左上角那个forbidRect编号是0,右下角那个是1。当前纵向的分割线二元组数组为:L1 = {(1, 0), (5, 0), (4, 1), (8, 1)}

然后我们为了以防万一要处理一下,就是把偏移量相同的线归组(虽然不太可能有线重合,但这也是优化点之一,我们可以将forbidRect对齐到一些偏移量为某整数倍的位置)。

归组后的新二元组如下:

Tuple2=(offset,set<rect_id>)。二元组的第二个元素变成了forbidRect 编号的集合了。

此时我们有两个Tuple2数组了(横向的,纵向的),我们按照offset字段将它们排序(两个方向的分开进行)。

举例,排序后的纵向线的数组为:L2 = {(1, {0}), (4, {1}), (5, {0}), (8, {1})}

这时我们要遍历一下排序后的数组,收集一些信息,通过类似栈的方式获取每个forbidRect覆盖的分割线在分割线数组中的索引(从0开始)。因为分割线排好序了,我们就记一个区间好了。

举例:forbidRect 0 的“覆盖线”的索引区间为: [0, 2]。

但是我们是为了分割平面才引入的分割线,因为水平方向上索引为2的线(第三条线)之后已经不是forbidRect 0 的范围了,所以这个索引区间的意义实际上是[0, 2)——不再是分割线的索引,而是横向上的小平面区域的索引。

同时,我们还有一个映射M1:(index1, index2) -> isDirty。映射源是一个被横纵线分割出的小矩形(Cell)的横纵向索引,映射目标是一个boolean量,用来表示这个Cell是否属于一个ForbidRect。

举例:(0,0)->true, (1,0)->true, (2,0)->false. (2,2)->true.

做好这些准备后,就是我们最后的布局阶段了。

放置

在How-Old实际使用的算法中,

我们依照距离所有faceRect重心(是“重心”)最小的顺序为FaceRect排序,也就是越靠近中心的越先处理

对每个faceRect,找到它的ForbidRect。通过ForbidRect在X Y方向上的“覆盖Cell”索引区间,找出位于该Forbidrect边界上的Cell。

举例:ForbidRect 0 边界上的Cell有:(0, -1) (1, -1) (-1, 0) (-1, 1) (2, 0) (2, 1) (0, 2) (1, 2)

就是图中这四个黄色块标示的8个Cell(最左边和最上边的就为它们编号-1)。

===================================

其中有几个Cell是Dirty的:

===================================

也就是说,我们只要在这6条线段(蓝色标出)上找LabelCenter就可以了

===================================

我们当前的策略是:先上,再左,再右,最后下方。

对每个线段,判断它的两个顶点,是在FaceRect与线段垂直的轴线的一左一右?一上一下?还是在同一侧?——这样就能判断最优的点(距离最近)。每个线段有一个最优解,再从中得出全局最优解。

(如果在上方就能得出这样的解,直接就用它做全局解。不然依次继续左、右、下方中找。下方的点,我们不喜欢,设置一个值去抑制它成为全局最优解)。

但,如果一个forbidRect四面受敌,一条这样的边界线段也没有怎么办呢?

此时我们通过一个forbidRect相交矩阵,广度优先,遍历每个和它直接或间接相接的forbidRect,从这些ForbidRect的边界线段上,找出最优的那个点,作为LabelCenter。

之后我们将这个LabelRect对应的ForbidRect加入ForbidRect集,并对下一个Face(按距重心排序地)进行同样的过程。直到所有Face都处理完成。

总结

这个算法的大致流程就是这样,其中也还有一些地方值得继续优化。当然我们还对标签大小,标签偏移等属性进行了微调。

希望这篇文章能抛砖引玉,如果大家有更好的算法或者想法,欢迎和我们交流。也欢迎下载最新版的How-Old进行各种各样图片的测试。

最后 向量子力学致敬:)

并附上我们的微软颜龄的 应用下载地址:https://www.windowsphone.com/zh-cn/store/app/%E5%BE%AE%E8%BD%AF%E9%A2%9C%E9%BE%84/8f4e7547-7ecb-4736-8306-11b97ba293e1

转载于:https://www.cnblogs.com/ms-uap/p/4725314.html

微软颜龄 维护小记——布局的小智慧相关推荐

  1. 微软颜龄Windows Phone版开发小记

    随着微软颜龄中文网cn.how-old.net的上线,她也顺势来到了3大移动平台. 用户在微软颜龄这一应用中选择一张包含若干人脸的照片,就可以通过云计算得到他们的性别和年龄. 今天我们就和大家分享一下 ...

  2. MSRA副院长郭百宁:20+行代码就能写出微软颜龄机器人

    近年来的计算机视觉(CV)无疑是深度学习的天下,微软亚洲研究院(MSRA)去年公布的152层残差网络(ResNet)更是大幅推动计算机视觉的进展.日前,微软亚洲研究院常务副院长郭百宁博士向CSDN记者 ...

  3. Android:相对布局综合小演练—智能家居,按键快速美化的小技巧

    一.相对布局综合小演练-智能家居 需要用到的图片 新建一个工程 首先,里面的                 android:paddingBottom="@dimen/activity_v ...

  4. mpvue还在维护吗_mpvue 微信小程序开发之生命周期

    最近在开发小程序,尝试性地使用了一下 mpvue 是一个使用 Vue.js 开发小程序的前端框架.框架基于 Vue.js 核心,mpvue 修改了 Vue.js 的 runtime 和 compile ...

  5. 轻松学习 Flex 布局的小游戏

    轻松学习 Flex 布局的小游戏 Flexbox Froggy,帮助你学习前端 Flex 布局的小游戏,难度不高,趣味性极强! Flexbox Froggy(弹性盒小青蛙)是一个帮助你快速学习前端 F ...

  6. pygame的字体画不出来_微软的python3教学的pygame的小游戏解析和学习

    1.微软的python教学的pygame的小游戏 1.1 小球自弹跳代码:(微软官方网站给的) import sys, pygame #导出模块pygame.init() #初始化#定义界面参数siz ...

  7. 微软的语音交互“滑铁卢”:Cortana小娜悲惨收场,未来路在何方?

    热点追踪 / 深度探讨 / 实地探访 / 商务合作 "hi Siri,给我讲个笑话""天猫精灵,今天天气怎样""小度,为我导航最近的加油站" ...

  8. php 邮币卡源码,如何使用CSS的Grid布局实现小松鼠邮票的效果(附源码)

    本篇文章给大家带来的内容是关于如何使用CSS的Grid布局实现小松鼠邮票的效果(附源码),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助. 效果预览 源代码下载 每日前端实战系列的全部源 ...

  9. 微软的一道经典逻辑推理题:小明和小强都是张老师的学生,张老师的生日是M月N日

    微软的一道经典逻辑推理题:小明和小强都是张老师的学生,张老师的生日是M月N日 分类: 天下杂侃 2008-08-07 23:37 17495人阅读 评论(21) 收藏 举报 题目是这样的: 小明和小强 ...

最新文章

  1. html5字体颜色自动转换,【转】js里alert里的字体颜色怎么设置:字体颜色方法;fontcolor(color)...
  2. Android AlarmManager 使用指南
  3. centos7.5 部署flask+nginx+uwsgi+python3
  4. c语言中用gaminv,轻松上手游泳模式,用Garmin腕表一定要知道的五件事
  5. [DeeplearningAI笔记]改善深层神经网络_深度学习的实用层面1.10_1.12/梯度消失/梯度爆炸/权重初始化...
  6. Linux设备驱动(转)
  7. Android利用canvas画各种图形(点、直线、弧、圆、椭圆、文字、矩形、多边形、曲线、圆角矩形...
  8. keyboard dialog 仿微博表情键盘输入框
  9. oracle 脚本定时,Oracle定时任务备份脚本
  10. 突然间的一个阿里电话面试
  11. 全网最详细教程(上):教你如何从0-1制作出一张可视化大屏
  12. C语言 —— do while循环语句用法与例题
  13. taobao.trades.sold.get-查询卖家已卖出的交易数据API接口,店铺交易API接口,店铺订单交易API接口,订单详情API接口,r2接口,淘宝oAuth2.0接口
  14. 理解Monitor监视器锁原理
  15. 笔记本锁定计算机功能键,笔记本电脑键盘锁的设置方法以及解锁步骤【图文教程】...
  16. python Png图片压缩工具
  17. 服务器cpu e3系列型号,Intel发布至强E3-1200 v3全系列型号
  18. android工具am的用法,Android中AM、PM、dumpsys命令使用总结
  19. 区块链软件开发:区块链颠覆性渐渐开始  2019年需求侧开始涌现出大量需求...
  20. MATLAB中randi函数的用法

热门文章

  1. 机器学习笔记:线性SVM推导
  2. onvif device test tool
  3. 洛谷 P3953 逛公园
  4. Unity FSM(有限状态机)
  5. 「微信群合影2.5.0」- 微信网页版账号不能登录解决办法,扫码登录
  6. 2018年AI趋势盘点(02)| Hinton、吴恩达、李飞飞…… | 解读行业
  7. spss时间序列预测
  8. DateSerial 函数
  9. 智能合约被忽视的一面
  10. 推荐系统1-基本概念