送外卖也要“黑科技”?阿里移动感知技术应用揭秘

送外卖也要“黑科技”?阿里移动感知技术应用揭秘

一 背景

作为本地生活的一个重要组成部分,外卖已经进入千千万万的家庭。相信很多小伙伴已经注意到,饿了么的每一个订单,我们都会及时向用户通知这一单现在所处的状态,比如“商户接单”,“骑手到店”,“骑手送达”等。这个实时状态的更新,不仅能让用户及时了解自己外卖到了哪里,对于整个平台的骑手调度和时间预估都有着重要意义。

而在所有的节点中,骑手到店前后的两个节点“骑手到店”和“骑手取餐”对于整个平台的价值就更为重要,主要体现在以下三个方面:

时间预估

骑手到店的时间是骑手从接单位置到商户位置的终止时间,而骑手离店的时间则是骑手从商户位置到用户位置的起始时间。掌握这些准确的时间,能给时间预估模型提供准确的标签用于模型训练。我们在APP里看到的“预估配送时间”就是这样计算出来的。同时,知道骑手在商户位置等了多长时间,我们就可以知道商户准备这一单需要多长时间,也就是商户的“出餐时间”。而掌握了准确的出餐时间,我们在给某一单找合适骑手的时候就能更加地游刃有余了。

骑手调度

当用户在外卖平台下单后,平台就会开始为这一单寻找合适的骑手来配送,这个过程就叫骑手调度。骑手调度是一个复杂的过程,需要考虑同时考虑商户,骑手和用户的位置,还要考虑骑手身上已有的单和商户正在准备的单。一个总的原则是,让更近的,更顺路的骑手去取单。如果我们知道了骑手到店的准确时间,我们就可以知道骑手在当前时刻的具体位置,并且能够预估出骑手在未来一段时间的大概位置。这就给我们的骑手调度提供了准确可靠的数据源。

超时单判责

虽然调度系统会尽力保证每一单都尽快送达,但还是会有一些情况导致少部分运单会超时,给用户带来不好的体验。为了提升调度系统的性能,减少超时单。我们首先需要知道超时的原因,从而在未来的调度中作出改进。超时的两个主要原因是“商户已出餐但骑手未到店”和“骑手已到店但商户未出餐”。在没有明确数据的情况下,这两个对立的原因往往会出现“公说公有理,婆说婆有理”的情况。如果我们能够准确获得骑手到店的时间,这一困境就会迎刃而解。

二 挑战

既然获取准确的骑手到店时间是如此重要的问题,为什么现有的方法还是无法很好的解决这个问题呢?这是因为考虑到本地生活的场景,要获得准确的骑手到店时间,面临着以下几方面的挑战:

GPS在室内的漂移

现在手机定位最常用的方法就是GPS定位。但无论是GPS,还是我们最近刚组网成功的北斗系统,其本质上都需要手机里的芯片来接收地球上方的卫星信号。但商户的位置往往是在室内,当我们在室内环境时,GPS信号会受到建筑物的遮挡,导致GPS信号微弱甚至完全失去信号。这个时候GPS的精确度就会从几米扩大到几百米甚至几公里,导致GPS信号出现漂移。因为这一漂移现象的存在,我们需要划定一个范围来判断骑手是否到达了商户。当我们用一个较小的范围时,可能会出现“骑手已到店但我们认为没到”,如果我们用一个较大的范围,那么骑手到店时间的准确性则会大打折扣。

商户在不同楼层的垂直分布

在GPS漂移之外,商户在不同楼层的垂直分布也会给骑手到店的准确判定带来困难。当商户分布在不同楼层时,即使我们通过GPS判断出骑手已经在水平方向上到达商户附近,但由于没有垂直方向的信息,我们仍然无法准确判断出骑手到店的具体时间。如今越来越多的商户都分布在商场的不同楼层,这部分订单的骑手到店时间就很难观测。虽然GPS会返回一个海拔信息,但在实际的应用中我们发现这个值往往是不够准确的。

商户环境的动态性和骑手手机的多样性

一些室内定位的方法通过收集特定环境的声音指纹,光指纹或者磁场强度指纹来建立指纹库,然后通过指纹对比来判断手机所处的位置。理论上如果我们能够采集商户环境的指纹,并和骑手手机收到的信号进行比对,就可以判断骑手是否已经到达商户。但由于商户环境的动态性,比如装修改造和人来人往带来的实时扰动,我们很难建立一个稳定的指纹库来进行比对。同时,由于声光磁的指纹收集受到手机硬件的影响,骑手手机的多样性也对指纹库的建立带来很大挑战。

基于Wi-Fi的方法的局限性

随着越来越多的室内环境有Wi-Fi信号的覆盖,基于Wi-Fi信号的室内定位也得到了充分研究。但基于Wi-Fi方法也有两个局限性:一是持续的Wi-Fi扫描会带来极大的能耗负担,这对于工作极度依赖手机的骑手很不友好;二是出于隐私保护等原因,iOS系统只支持获取当前连接的Wi-Fi信息,而不支持获取Wi-Fi扫描的列表,但骑手在取餐过程中很少连接商户的Wi-Fi。这两个原因导致了基于Wi-Fi的定位方法无法适用于骑手到店的场景。

三 解决方案

当我们把骑手到店观测问题抽象出来,可以发现这是移动感知(Mobile Sensing)领域经典的“室内定位(Indoor Localization)”或者“存在监测(Presence Detection)”的问题。移动感知是指利用移动设备上的网络信号或声光电磁等传感器信号对用户的位置,行为,场景等进行感知的技术。手机上的计步功能,以及智能手表提供的心率监测和睡眠监测等功能,都是移动感知技术在生活中的具体应用。近些年来,随着移动设备的升级,研究者们也在探索移动感知的新应用,比如用Wi-Fi信号感知键盘敲击和老人摔倒,用手机话筒来检测醉驾,用新的传感器来感知用户的情绪和压力状态等。

这些研究也给我们的到店观测问题提供了很多思路,比如基于Wi-Fi的室内定位,基于特定光信号和声信号的定位方法等。但是通过上面的讨论我们可以看出,这些方法都难以很好地解决骑手到店观测问题。针对这一情况,我们设计并部署了aBeacon系统,一个基于蓝牙信号的移动感知系统,来解决骑手到店观测的问题。其实基于蓝牙的移动感知并不是一个全新的技术,苹果公司在2013年提出基于蓝牙的iBeacon协议用于移动感知[1],2016年蓝牙5.0中的新特征(更低功耗,更大范围)真正让蓝牙感知技术得以落地。蓝牙移动感知的原理就是通过在特定位置部署一些持续发送蓝牙信号的Beacon设备,同时手机进行持续的扫描来感知周围的蓝牙Beacon信号,从而来判断手机是否到达了特定位置。

基于这样的感知技术,我们建立了aBeacon系统,如图1所示,系统由三部分组成:部署在商户的蓝牙Beacon硬件、骑手APP内的蓝牙监听模块和平台服务器上的后端模块。在骑手配送过程中,APP上的蓝牙监听模块会持续监听周围的蓝牙Beacon信号,当骑手到达商户附近(比如10米范围内)时,手机会监听到该商户内的蓝牙Beacon信号,并把该数据和当前时间戳上传到服务器,服务器通过和预置的Beacon地图进行比对,就可以得到该骑手到达该商户的准确时间。在Beacon硬件方面,我们采用了自主定制的硬件,在降低成本的同时保证了蓝牙广播的质量,同时引入了加密技术来保护商户的位置隐私。在手机监听模块方面,我们通过设计一个动态监听模块,在保证到店判断能力的前提下降低了能耗。

对比前面提到的几个挑战,我们可以发现,因为蓝牙信号自身的特性,Beacon信号在室内环境的传播仅限于几米到几十米的范围(相信大家使用蓝牙耳机和鼠标都有类似的感受),因此基于蓝牙的到店判断不会出现GPS那样几百米的误差,可以极大提高骑手到店观测的准确性。同时,因为蓝牙信号的穿墙能力较差,因此只有当骑手到达商户所在的楼层时才会接收到蓝牙信号,这样就避免了商户楼层带来的影响。此外,我们通过标准化的部署流程,使得Beacon硬件部署在商户的骑手取餐处的上方,避免了商户内动态环境的改变对信号的影响。蓝牙协议的标准化和手机硬件的成熟化也降低了骑手手机硬件对到店观测的影响。此外,因为蓝牙监听属于非连接通信,骑手使用蓝牙耳机的功能也不会受到影响。最后,和Wi-Fi相比,蓝牙监听的功耗也很低,我们的实验证明,Beacon监听每天只会给骑手手机带来3%的额外功耗负担。

总体来说,aBeacon系统的主要贡献在于将蓝牙感知的技术真正应用到骑手到店观测的问题中,并解决了一系列实际应用中的挑战,比如能耗,可靠性,隐私保护等,并且从理论层面上对系统的成本和效用进行分析,从而指导今后大规模感知系统的落地。

在系统的设计中,我们考虑了下面的一些指标:

成本

成本是我们上线一个商业化的系统所必须考虑的因素之一。aBeacon系统的成本包括两部分:aBeacon设备的硬件成本,和大规模部署的成本。在硬件成本方面,我们通过对硬件的定制来降低成本。在部署成本方面,我们通过简化硬件部署的流程,从而在业务经理的帮助下降低部署成本。

寿命

出于易用性的考虑,我们的aBeacon硬件采用了电池供电的方式。这样电池的容量就成为了限制系统寿命的主要因素。但在两年的运行之后,我们发现除了电池的寿命,环境变化也是影响系统寿命的重要因素。

可靠性

可靠性是指在所有的骑手到店行为中,有多大比例可以被aBeacon系统观测到。在实际中,可靠性受到包括部署质量,商户环境,骑手手机等诸多因素的影响。

效用

骑手到店观测给整个系统提供了更准确的数据,它带来的效用是基础但难以直接衡量的,因此我们采用超时率这一衡量整个调度系统的指标来评估aBeacon的效用。

在系统的设计过程中,我们首先量化了上面的四个指标,然后建立这四个指标和我们要优化的终极目标——aBeacon带来的累积收益——之间的量化关系。因此,我们可以在这个量化关系的指导下对各个因素进行权衡。

在这样的设计思路的指导下,aBeacon系统的部署和运行主要包含了两个主要环节:

设计与测试

基于成本和设计自由度的考虑,我们选择自主定制aBeacon设备,同时自主定制还能让我们嵌入隐私保护等其他功能。在大规模的部署前,我们挑选了几个商场进行小规模的测试。在测试中,我们将自主定制的aBeacon设备和另一种商用的Beacon设备同时部署在商户里。通过对比测试,我们发现采用自主定制的aBeacon设备可以在压缩成本的同时达到和商用Beacon设备同样的可靠性。

部署与运行

在小规模测试后,从2018年1月开始,如图2所示,我们在上海的12000余家商户里部署了aBeacon设备。我们用一份包含“部署在哪里”、“怎么固定”、“如何绑定”等问题的部署手册来指导业务经理进行部署。在运行过程中,我们通过后台收集的数据,可以对所有设备进行实时监控,所有设备被分类为“健康”、“部署错误”、“下线”等状态。我们针对不同的设备还可以采取不同的维护措施,比如针对“部署错误”的设备进行重新部署。

另一个很重要的问题是系统安全和隐私保护,这也是我们在aBeacon设备的定制过程中作出的重要改进之一。因为传统的iBeacon协议是固定ID的明文广播,可能导致系统的安全性漏洞。比如:

  • 未授权的用户可能通过战争驾驶(wardriving)[2] 的方法来反推出Beacon设备的位置,并用于其他目的。
  • 恶意攻击者可能通过在异地复制已有Beacon设备的蓝牙广播,向系统中注入错误的位置数据。

针对这一问题,我们在自主定制的设备中对蓝牙广播进行加密,通过一种TOTP[3]的加密算法,让所有aBeacon设备广播的ID内容定时进行变更,而ID和设备位置的映射关系存在只有授权用户可以访问服务器。这样极大地提高了系统的安全性。

四 效果

为了评估aBeacon系统给整个配送过程带来的效果,我们采用了“超时率”这一总体指标作为指标。我们用上海未部署aBeacon设备的一万多家商户作为参照,来评估部署了aBeacon设备的商户在部署前后超时率的变化。通过对比我们发现,在总体上,通过一年的运行,aBeacon系统可以将超时率降低0.24%,这使得我们每年可以减少超过7余万超时配送订单。

同时我们还发现,aBeacon系统在不同楼层和不同的地区体现出较大的差异性。如图3所示,部署在B2层和4/5层的设备可以带来更大的效用,这其实也印证了我们前面的分析,骑手在这些楼层商户的准确到店时间更难观测,通过部署aBeacon设备,我们可以在这些商户取得更大的效用。

迄今为止,aBeacon系统为上海超过10万骑手提供准确的到店观测分析,通过不断优化骑手配送流程,每年可减少超过7余万超时配送订单,为超过700万的用户人群提供更优质服务。

五 讨论与发现

作为一篇介绍移动感知技术大规模应用的文章,我们在系统设计和部署过程中的发现希望能给后来者的工作带来更多启发。总的来说,我们的发现包括以下两个方面:

(1) 系统可靠性。在移动感知领域,研究者们为我们带来了很多新的想法。但这些想法在实际落地的过程中都会遇到可靠性的问题,我们用aBeacon系统的部署过程说明了,即使是用蓝牙信号进行存在感知这样一个简单的应用,系统的可靠性也会受到硬件设备的部署和用户手机硬件等诸多因素的影响。因此在以后的研究中,我们需要在系统设计的过程中更多地考虑这些因素,让系统就有更强的鲁棒性。

(2) aBeacon系统的局限之一就是我们还需要部署和维护硬件设备,在后来的工作中,我们仍在探索采用已有的终端设备作为虚拟的aBeacon设备用以辅助骑手的定位。基于此,我们正在开展aBeacon+系统的研究工作,解决一些相关的问题,比如终端设备自身定位,以及隐私保护等。

六 总结

基于aBeacon系统,阿里本地生活科技中心的论文“From Conception to Retirement : a Lifetime Story of a 3-Year-Old Operational Wireless Beacon System in the Wild” 被计算机网络系统领域的顶级会议NSDI’21收录。作为首篇基于本地生活场景的系统论文,这也代表了阿里本地生活科技中心在移动感知方面的工作得到了来自网络系统领域顶级会议的认可。在落地应用后,通过获取更准确的骑手到店和离店时间,该系统为全国超过10万骑手提供准确的到店观测分析,通过不断优化骑手配送流程,每年可减少超过7余万超时配送订单,为超过700万的用户人群提供优质服务。未来,在阿里巴巴本地生活和新零售的业务布局下,我们还会持续加强相关领域的研究,将更多前沿技术投入到更多场景的运营分析中,发挥出更多作用,用技术服务用户。

参考文献:

[1] Apple Inc. iBeacon. https://developer.apple.com/ibeacon/ , 2020 [2] Wikipedia, Wardriving, https://en.wikipedia.org/wiki/Wardriving, 2020 [3] Wikipedia. Time-based one-time password, https://en.wikipedia.org/wiki/Time-based_One-time_Password_algorithm , 2020........

原文链接

本文为阿里云原创内容,未经允许不得转载。

相关内容

阿里根据截图查到泄露者,用的什么黑科技?(数字盲水印)

https://stgod.com/1482

本文分为五个部分,第一部分综述;第二部分频域数字盲水印制作原理介绍;第三部分盲水印攻击性实验;第四部分总结;第五部分附录(源代码)。

一、综述

本文提供的一种实现“阿里通过肉眼无法识别的标识码追踪员工”的技术手段。通过看其他答主的分析,阿里可能还没用到频域加水印的技术。

在原答案中,存在措辞欠妥之处,对此表示由衷的歉意。

相对于空域方法,频域加盲水印的方法隐匿性更强,抵抗攻击能力更强。这类算法解水印困难,你不知道水印加在那个频段,而且受到攻击往往会破坏图像原本内容。本文简要科普通过频域手段添加数字盲水印。对于web,可以添加一个背景图片,来追踪截图者。

所谓盲水印,是指人感知不到的水印,包括看不到或听不见(没错,数字盲水印也能够用于音频)。其主要应用于音像作品、数字图书等,目的是,在不破坏原始作品的情况下,实现版权的防护与追踪。

添加数字盲水印的方法简单可分为空域方法和频域方法,这两种方法添加了冗余信息,但在编码和压缩情况不变的情况下,不会使原始图像大小产生变化(原来是10MB添加盲水印之后还是10MB)。

空域是指空间域,我们日常所见的图像就是空域。空域添加数字水印的方法是在空间域直接对图像操作(之所以说的这么绕,是因为不仅仅原图是空域,原图的差分等等也是空域),比如将水印直接叠加在图像上。

我们常说一个音有多高,这个音高是指频率;同样,图像灰度变化强烈的情况,也可以视为图像的频率。频域添加数字水印的方法,是指通过某种变换手段(傅里叶变换,离散余弦变换,小波变换等)将图像变换到频域(小波域),在频域对图像添加水印,再通过逆变换,将图像转换为空间域。相对于空域手段,频域手段隐匿性更强,抗攻击性更高。

所谓对水印的攻击,是指破坏水印,包括涂抹,剪切,放缩,旋转,压缩,加噪,滤波等。数字盲水印不仅仅要敏捷性高(不被人抓到),也要防御性强(抗打)。就像Dota的敏捷英雄往往是脆皮,数字盲水印的隐匿性和鲁棒性是互斥的。(鲁棒性是抗攻击性的学术名字)

二、频域制作数字盲水印的方法

信号是有频率的,一个信号可以看做是无数个不同阶的正弦信号的的叠加。

技术分享

上式为傅里叶变换公式,?(t) 是指时域信号(对于信号我们说时域,因为是与时间有关的,而图像我们往往说空域,与空间有关),ω 是指频率。想要对傅里叶变换有深入了解的同学,建议看一下《信号与系统》或者《数字信号处理》的教材,里面系统介绍了傅里叶变换、快速傅里叶变换、拉普拉斯变换、z变换等。

简而言之,我们有方法将时域信号转换成为频域,同样,我们也能将二维信号(图像)转换为频域。在上文中提到,图像的频率是指图像灰度变换的强烈情况。关于此方面更系统的知识,参见冈萨雷斯的《图像处理》。

下面以傅里叶变换为例,介绍通过频域给图像添加数字盲水印的方法。注意,因为图像是离散信号,我们实际用的是离散傅里叶变换,在本文采用的都是二维快速傅里叶变换,快速傅里叶变换与离散时间傅里叶变换等价,通过蝶型归并的手段,速度更快。下文中傅里叶变换均为二维快速傅里叶变换。

技术分享

上图为叠加数字盲水印的基本流程。编码的目的有二,一是对水印加密,二控制水印能量的分布。以下是叠加数字盲水印的实验。这是原图像,尺寸300*240 (不要问我为什么不用Lena,那是我前女友),

技术分享

之后进行傅里叶变换,下图变换后的频域图像,

技术分享

这是我想加的水印,尺寸200*100,

技术分享

这是我编码后的水印,编码方式采用随机序列编码,通过编码,水印分布到随机分布到各个频率,并且对水印进行了加密,

技术分享

将上图与原图的频谱叠加,可见图像的频谱已经发生了巨大的变化,

技术分享

之后,将叠加水印的频谱进行傅里叶逆变换,得到叠加数字水印后的图像,

技术分享

肉眼几乎看不出叠加水印后的图像与原图的差异,这样,数字盲水印已经叠加到图像中去。实际上,我们是把水印以噪声的形式添加到原图像中。下图是在空域上的加水印图与原图的残差(调整了对比度,不然残差调小看不见),

技术分享

可以看出,实际上上述方法是通过频域添加冗余信息(像噪声一样)。这些噪声遍布全图,在空域上并不容易破坏。

最终,均方误差(MSE)为0.0244

信噪比(PSNR)为64.2dB那么,为什么频谱发生了巨大的变化,而在空域却变化如此小呢?这是因为我们避开了图像的主要频率。下图是原图频谱竖过来的样子,其能量主要集中在低频。

技术分享

水印提取是水印叠加的逆过程,

技术分享

经提取后,我们得到如下水印,问:为什么水印要对称呢?嘿嘿,大家想想看。

技术分享

三、攻击性实验

本部分进行攻击性实验,来验证通过频域手段叠加数字盲水印的鲁棒性。

1.进行涂抹攻击,这是攻击后的图片:
技术分享

再进行水印提取:

技术分享

2.进行剪切攻击,就是网上经常用的截图截取一部分的情况:

技术分享

进行循环补全:

技术分享

提取水印:

技术分享

3.伸缩攻击(这个实验明码做的,水印能量较高,隐匿性不强):

技术分享

提取水印(水印加的不好,混频挺严重的):

技术分享

4.旋转攻击(明码):

技术分享

提取水印:

技术分享

5.JPEG压缩后(这个实验我好像是拿明码做的,能量主要加在了高频):

技术分享

提取结果:

技术分享

6.PS 4像素马赛克/均值滤波等,攻击后图像(这是我女朋友吗?丑死了):

技术分享

提取水印后图像:

技术分享

7.截屏,

截屏后我手动抠出要测试的图像区域,并且抽样或者插值到原图尺寸:

技术分享

测试结果:

技术分享

8. 亮度调节(明码):

技术分享

水印提取:

技术分享

9.色相调节(明码):

技术分享

水印提取:

技术分享

10.饱和度调节(明码):

技术分享

水印:
技术分享

11.对比度(明码):

技术分享

水印:

技术分享

12.评论区用waifu2x去噪后图片:

技术分享

解水印:

技术分享

13.美图秀秀,我对我女票一键美颜,美白,磨皮,加腮红,加唇彩(有一种很羞耻的感觉,捂脸):

技术分享

提取水印:

技术分享

14.对于背景纯色的图其实也是无所谓的

技术分享

能量系数为10时加水印图片:觉得太显噪就把能量系数调低,不过水印的隐秘性和鲁棒性是互斥的

技术分享

最终提取出的水印:

技术分享

15.我用将RGB>600的像素设置成为(0,255,0)来模拟PS魔术手,

技术分享

提取水印为:

技术分享

16.屏摄,好吧,这个实验我做哭了

屏摄图:

技术分享

实验结果:

技术分享

我把水印能量系数调整到2000都没有用。

屏摄之后与原图信噪比为4dB左右,我用多抽样滤波的方式试过,滤不掉屏摄引入的噪声。屏摄不仅引入了椒盐噪声,乘性噪声,还有有规律的雪花纹理(摩尔纹)。

四、总结

基于频域的盲水印方法隐藏性强,鲁棒性高,能够抵御大部分攻击。但是,对于盲水印算法,健壮性和隐匿性是互斥的。

本文方法针对屏摄不行,我多次实验没有成功,哪位大神可以做一下或者讨论讨论。还有二值化不行,这是我想当然的,觉得肯定不行所以没做实验。其他的我试了试,用给出的方法调整一下能量系数都可以。我想大家最关心的是什么最安全,不会被追踪。

不涉及图像的都安全,比如拿笔记下来。涉及图像的屏摄最安全,截屏十分不安全。

=====彩蛋(加密过的测试图)====
技术分享

我在上图明码写入了信息。为了抵抗jpg压缩,我水印能量较高,并且因为没有编码,能量分布不均。图中规律性纹路,就是你懂的。嘿嘿,你懂的,解开看看吧。

五、附录/源码分享

  1. %% 傅里叶变换加水印源代码
  2. %% 运行环境 Matlab2010a
  3. clc;clear;close all;
  4. alpha = 1;
  5. %% read data
  6. im = double(imread(‘gl1.jpg‘))/255;
  7. mark = double(imread(‘watermark.jpg‘))/255;
  8. figure, imshow(im),title(‘original image‘);
  9. figure, imshow(mark),title(‘watermark‘);
  10. %% encode mark
  11. imsize = size(im);
  12. %random
  13. TH=zeros(imsize(1)*0.5,imsize(2),imsize(3));
  14. TH1 = TH;
  15. TH1(1:size(mark,1),1:size(mark,2),:) = mark;
  16. M=randperm(0.5*imsize(1));
  17. N=randperm(imsize(2));
  18. save(‘encode.mat‘,‘M‘,‘N‘);
  19. for i=1:imsize(1)*0.5
  20. for j=1:imsize(2)
  21. TH(i,j,:)=TH1(M(i),N(j),:);
  22. end
  23. end
  24. % symmetric
  25. mark_ = zeros(imsize(1),imsize(2),imsize(3));
  26. mark_(1:imsize(1)*0.5,1:imsize(2),:)=TH;
  27. for i=1:imsize(1)*0.5
  28. for j=1:imsize(2)
  29. mark_(imsize(1)+1-i,imsize(2)+1-j,:)=TH(i,j,:);
  30. end
  31. end
  32. figure,imshow(mark_),title(‘encoded watermark‘);
  33. %imwrite(mark_,‘encoded watermark.jpg‘);
  34. %% add watermark
  35. FA=fft2(im);
  36. figure,imshow(FA);title(‘spectrum of original image‘);
  37. FB=FA+alpha*double(mark_);
  38. figure,imshow(FB); title(‘spectrum of watermarked image‘);
  39. FAO=ifft2(FB);
  40. figure,imshow(FAO); title(‘watermarked image‘);
  41. %imwrite(uint8(FAO),‘watermarked image.jpg‘);
  42. RI = FAO-double(im);
  43. figure,imshow(uint8(RI)); title(‘residual‘);
  44. %imwrite(uint8(RI),‘residual.jpg‘);
  45. xl = 1:imsize(2);
  46. yl = 1:imsize(1);
  47. [xx,yy] = meshgrid(xl,yl);
  48. figure, plot3(xx,yy,FA(:,:,1).^2+FA(:,:,2).^2+FA(:,:,3).^2),title(‘spectrum of original image‘);
  49. figure, plot3(xx,yy,FB(:,:,1).^2+FB(:,:,2).^2+FB(:,:,3).^2),title(‘spectrum of watermarked image‘);
  50. figure, plot3(xx,yy,FB(:,:,1).^2+FB(:,:,2).^2+FB(:,:,3).^2-FA(:,:,1).^2+FA(:,:,2).^2+FA(:,:,3).^2),title(‘spectrum of watermark‘);
  51. %% extract watermark
  52. FA2=fft2(FAO);
  53. G=(FA2-FA)/alpha;
  54. GG=G;
  55. for i=1:imsize(1)*0.5
  56. for j=1:imsize(2)
  57. GG(M(i),N(j),:)=G(i,j,:);
  58. end
  59. end
  60. for i=1:imsize(1)*0.5
  61. for j=1:imsize(2)
  62. GG(imsize(1)+1-i,imsize(2)+1-j,:)=GG(i,j,:);
  63. end
  64. end
  65. figure,imshow(GG);title(‘extracted watermark‘);
  66. %imwrite(uint8(GG),‘extracted watermark.jpg‘);
  67. %% MSE and PSNR
  68. C=double(im);
  69. RC=double(FAO);
  70. MSE=0; PSNR=0;
  71. for i=1:imsize(1)
  72. for j=1:imsize(2)
  73. MSE=MSE+(C(i,j)-RC(i,j)).^2;
  74. end
  75. end
  76. MSE=MSE/360.^2;
  77. PSNR=20*log10(255/sqrt(MSE));
  78. MSE
  79. PSNR
  80. %% attack test
  81. %% attack by smearing
  82. %A = double(imread(‘gl1.jpg‘));
  83. %B = double(imread(‘attacked image.jpg‘));
  84. attack = 1-double(imread(‘attack.jpg‘))/255;
  85. figure,imshow(attack);
  86. FAO_ = FAO;
  87. for i=1:imsize(1)
  88. for j=1:imsize(2)
  89. if attack(i,j,1)+attack(i,j,2)+attack(i,j,3)>0.5
  90. FAO_(i,j,:) = attack(i,j,:);
  91. end
  92. end
  93. end
  94. figure,imshow(FAO_);
  95. %extract watermark
  96. FA2=fft2(FAO_);
  97. G=(FA2-FA)*2;
  98. GG=G;
  99. for i=1:imsize(1)*0.5
  100. for j=1:imsize(2)
  101. GG(M(i),N(j),:)=G(i,j,:);
  102. end
  103. end
  104. for i=1:imsize(1)*0.5
  105. for j=1:imsize(2)
  106. GG(imsize(1)+1-i,imsize(2)+1-j,:)=GG(i,j,:);
  107. end
  108. end
  109. figure,imshow(GG);title(‘extracted watermark‘);
  110. %% attack by cutting
  111. s2 = 0.8;
  112. FAO_ = FAO;
  113. FAO_(:,s2*imsize(2)+1:imsize(2),:) = FAO_(:,1:int32((1-s2)*imsize(2)),:);
  114. figure,imshow(FAO_);
  115. %extract watermark
  116. FA2=fft2(FAO_);
  117. G=(FA2-FA)*2;
  118. GG=G;
  119. for i=1:imsize(1)*0.5
  120. for j=1:imsize(2)
  121. GG(M(i),N(j),:)=G(i,j,:);
  122. end
  123. end
  124. for i=1:imsize(1)*0.5
  125. for j=1:imsize(2)
  126. GG(imsize(1)+1-i,imsize(2)+1-j,:)=GG(i,j,:);
  127. end
  128. end
  129. figure,imshow(GG);title(‘extracted watermark‘);
  130. %%小波变换加水印,解水印大家按照加的思路逆过来就好
  131. clc;clear;close all;
  132. %% read data
  133. im = double(imread(‘gl1.jpg‘))/255;
  134. mark = double(imread(‘watermark.jpg‘))/255;
  135. figure, imshow(im),title(‘original image‘);
  136. figure, imshow(mark),title(‘watermark‘);
  137. %% RGB division
  138. im=double(im);
  139. mark=double(mark);
  140. imr=im(:,:,1);
  141. markr=mark(:,:,1);
  142. img=im(:,:,2);
  143. markg=mark(:,:,2);
  144. imb=im(:,:,3);
  145. markb=mark(:,:,3);
  146. %% parameter
  147. r=0.04;
  148. g = 0.04;
  149. b = 0.04;
  150. %% wavelet tranform and add watermark
  151. % for red
  152. [Cwr,Swr]=wavedec2(markr,1,‘haar‘);
  153. [Cr,Sr]=wavedec2(imr,2,‘haar‘);
  154. % add watermark
  155. Cr(1:size(Cwr,2)/16)=...
  156. Cr(1:size(Cwr,2)/16)+r*Cwr(1:size(Cwr,2)/16);
  157. k=0;
  158. while k<=size(Cr,2)/size(Cwr,2)-1
  159. Cr(1+size(Cr,2)/4+k*size(Cwr,2)/4:size(Cr,2)/4+...
  160. (k+1)*size(Cwr,2)/4)=Cr(1+size(Cr,2)/4+...
  161. k*size(Cwr,2)/4:size(Cr,2)/4+(k+1)*size(Cwr,2)/4)+...
  162. r*Cwr(1+size(Cwr,2)/4:size(Cwr,2)/2);
  163. Cr(1+size(Cr,2)/2+k*size(Cwr,2)/4:size(Cr,2)/2+...
  164. (k+1)*size(Cwr,2)/4)=Cr(1+size(Cr,2)/2+...
  165. k*size(Cwr,2)/4:size(Cr,2)/2+(k+1)*size(Cwr,2)/4)+...
  166. r*Cwr(1+size(Cwr,2)/2:3*size(Cwr,2)/4);
  167. Cr(1+3*size(Cwr,2)/4+k*size(Cwr,2)/4:3*size(Cwr,2)/4+...
  168. (k+1)*size(Cwr,2)/4)=Cr(1+3*size(Cr,2)/4+...
  169. k*size(Cwr,2)/4:3*size(Cr,2)/4+(k+1)*size(Cwr,2)/4)+...
  170. r*Cwr(1+3*size(Cwr,2)/4:size(Cwr,2));
  171. k=k+1;
  172. end;
  173. Cr(1:size(Cwr,2)/4)=Cr(1:size(Cwr,2)/4)+r*Cwr(1:size(Cwr,2)/4);
  174. % for green
  175. [Cwg,Swg]=WAVEDEC2(markg,1,‘haar‘);
  176. [Cg,Sg]=WAVEDEC2(img,2,‘haar‘);
  177. Cg(1:size(Cwg,2)/16)=...
  178. Cg(1:size(Cwg,2)/16)+g*Cwg(1:size(Cwg,2)/16);
  179. k=0;
  180. while k<=size(Cg,2)/size(Cwg,2)-1
  181. Cg(1+size(Cg,2)/4+k*size(Cwg,2)/4:size(Cg,2)/4+...
  182. (k+1)*size(Cwg,2)/4)=Cg(1+size(Cg,2)/4+...
  183. k*size(Cwg,2)/4:size(Cg,2)/4+(k+1)*size(Cwg,2)/4)+...
  184. g*Cwg(1+size(Cwg,2)/4:size(Cwg,2)/2);
  185. Cg(1+size(Cg,2)/2+k*size(Cwg,2)/4:size(Cg,2)/2+...
  186. (k+1)*size(Cwg,2)/4)=Cg(1+size(Cg,2)/2+...
  187. k*size(Cwg,2)/4:size(Cg,2)/2+(k+1)*size(Cwg,2)/4)+...
  188. g*Cwg(1+size(Cwg,2)/2:3*size(Cwg,2)/4);
  189. Cg(1+3*size(Cg,2)/4+k*size(Cwg,2)/4:3*size(Cg,2)/4+...
  190. (k+1)*size(Cwg,2)/4)=Cg(1+3*size(Cg,2)/4+...
  191. k*size(Cwg,2)/4:3*size(Cg,2)/4+(k+1)*size(Cwg,2)/4)+...
  192. g*Cwg(1+3*size(Cwg,2)/4:size(Cwg,2));
  193. k=k+1;
  194. end;
  195. Cg(1:size(Cwg,2)/4)=Cg(1:size(Cwg,2)/4)+g*Cwg(1:size(Cwg,2)/4);
  196. % for blue
  197. [Cwb,Swb]=WAVEDEC2(markb,1,‘haar‘);
  198. [Cb,Sb]=WAVEDEC2(imb,2,‘haar‘);
  199. Cb(1:size(Cwb,2)/16)+b*Cwb(1:size(Cwb,2)/16);
  200. k=0;
  201. while k<=size(Cb,2)/size(Cwb,2)-1
  202. Cb(1+size(Cb,2)/4+k*size(Cwb,2)/4:size(Cb,2)/4+...
  203. (k+1)*size(Cwb,2)/4)=Cb(1+size(Cb,2)/4+...
  204. k*size(Cwb,2)/4:size(Cb,2)/4+(k+1)*size(Cwb,2)/4)+...
  205. g*Cwb(1+size(Cwb,2)/4:size(Cwb,2)/2);
  206. Cb(1+size(Cb,2)/2+k*size(Cwb,2)/4:size(Cb,2)/2+...
  207. (k+1)*size(Cwb,2)/4)=Cb(1+size(Cb,2)/2+...
  208. k*size(Cwb,2)/4:size(Cb,2)/2+(k+1)*size(Cwb,2)/4)+...
  209. b*Cwb(1+size(Cwb,2)/2:3*size(Cwb,2)/4);
  210. Cb(1+3*size(Cb,2)/4+k*size(Cwb,2)/4:3*size(Cb,2)/4+...
  211. (k+1)*size(Cwb,2)/4)=Cb(1+3*size(Cb,2)/4+...
  212. k*size(Cwb,2)/4:3*size(Cb,2)/4+(k+1)*size(Cwb,2)/4)+...
  213. b*Cwb(1+3*size(Cwb,2)/4:size(Cwb,2));
  214. k=k+1;
  215. end;
  216. Cb(1:size(Cwb,2)/4)=Cb(1:size(Cwb,2)/4)+b*Cwb(1:size(Cwb,2)/4);
  217. %% image reconstruction
  218. imr=WAVEREC2(Cr,Sr,‘haar‘);
  219. img=WAVEREC2(Cg,Sg,‘haar‘);
  220. imb=WAVEREC2(Cb,Sb,‘haar‘);
  221. imsize=size(imr);
  222. FAO=zeros(imsize(1),imsize(2),3);
  223. for i=1:imsize(1);
  224. for j=1:imsize(2);
  225. FAO(i,j,1)=imr(i,j);
  226. FAO(i,j,2)=img(i,j);
  227. FAO(i,j,3)=imb(i,j);
  228. end
  229. end
  230. figure, imshow(FAO); title(‘watermarked image‘);
  • 其实如果防御做得好,想绕过还真的没那么容易。按照DLP,也就是数据防泄密的思路:

1.重要的图片或者文档内加水印,文件里面再加上全息数字水印(这个大家都说得很全面了)

然而这就足够了吗?或者说只有这些防护?乃义务!

2.所有终端监控敏感操作:另存、截屏、剪贴板、对敏感文档的操作等等,上述行为一律上传到审计服务器上备份待查。

3.禁止未授权(未安装终端防护程序)的终端接入内网和业务系统

4.有敏感操作或者跨终端登录的时候通过摄像头拍摄人脸(知道为什么扎克伯格要贴摄像头了吧)

5.定期对硬盘进行文件扫描,关键字、相似度、OCR等方法识别出可能是敏感或者涉密的文件,并提取特征,进行标定。

6.同样采用散列值、关键字、相似度匹配等方法检查所有网络出口:邮件、聊天、网站、网盘等,对传输内容全部解码进行审计并且记录。

7.检查或者关闭所有物理出口,USB、Wi-Fi、蓝牙、音频口(防止通过耳机口盗窃数据)。

8.所有文件落地加密(文件加密或者全盘加密),偷硬盘也没用。

9.所有电子设备进出办公区域全部审核检查。

10.核心机密文档不落地,存放于核心服务器,采用远程终端或者虚拟窗口方式查阅/编辑。

别笑,富士康和华为基本上就是这么干的。

 

转载请注明出处:https://stgod.com/1482




赞(1)

文章来源于网络,原文链接请点击 这里
文章版权归作者所有,如作者不同意请直接联系小编删除。
作者:阿里云云栖号