日期: 2021 年 4 月 28 日

iOS设备上回声消除的例子

工业上的声音处理中,回声消除是一个重要的话题,重要性不亚于噪声消除、人声放大、自动增益等,尤其是在VoIP功能上,回声消除是每一个做VoIP功能团队的必修课。QQ、Skype等等,回声消除的效果是一个重要的考查指标。

具体的回声消除算法比较复杂,我现在还没有研究的很明白。简单来说,就是在即将播放出来的声音中,将回声的那部分减去。其中一个关键,是如何估计回声大小,这需要用到自适应算法。研究不透,多说无益。有兴趣的同学可以一起学习。

Apple在Core Audio中提供了回声消除的接口,我写了一个测试APP,测试了其效果。链接:https://github.com/lixing123/iOSEchoCancellation
下面讲一下如何实现。

将声音输出route到speaker,这样声音比较大,回声明显:

AVAudioSession* session = [AVAudioSession sharedInstance];
[session overrideOutputAudioPort:AVAudioSessionPortOverrideSpeaker error:nil];
[session setActive:YES error:nil];

初始化一个AUGraph,创建一个AUNode,并将之添加到graph上。一般来说,沟通麦克风/扬声器的AUNode,其类型应该是RemoteIO,但是RemoteIO不带回声消除功能,VoiceProcessingIO类型的才带。

AudioComponentDescription inputcd = {0};
inputcd.componentType = kAudioUnitType_Output;
//inputcd.componentSubType = kAudioUnitSubType_RemoteIO;
//we can access the system’s echo cancellation by using kAudioUnitSubType_VoiceProcessingIO subtype
inputcd.componentSubType = kAudioUnitSubType_VoiceProcessingIO;
inputcd.componentManufacturer = kAudioUnitManufacturer_Apple;

配置AudioUnit的属性,打开与麦克风/扬声器的连接(这个比较难以理解,可以参考Apple文档:https://developer.apple.com/library/ios/documentation/MusicAudio/Conceptual/AudioUnitHostingGuide_iOS/UsingSpecificAudioUnits/UsingSpecificAudioUnits.html),并配置client data format(仅支持Linear PCM格式);配置回调函数。

//Open input of the bus 1(input mic)
UInt32 enableFlag = 1;
CheckError(AudioUnitSetProperty(myStruct->remoteIOUnit,
kAudioOutputUnitProperty_EnableIO,
kAudioUnitScope_Input,
1,
&enableFlag,
sizeof(enableFlag)),
“Open input of bus 1 failed”);

//Open output of bus 0(output speaker)
CheckError(AudioUnitSetProperty(myStruct->remoteIOUnit,
kAudioOutputUnitProperty_EnableIO,
kAudioUnitScope_Output,
0,
&enableFlag,
sizeof(enableFlag)),
“Open output of bus 0 failed”);

//Set up stream format for input and output
streamFormat.mFormatID = kAudioFormatLinearPCM;
streamFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
streamFormat.mSampleRate = 44100;
streamFormat.mFramesPerPacket = 1;
streamFormat.mBytesPerFrame = 2;
streamFormat.mBytesPerPacket = 2;
streamFormat.mBitsPerChannel = 16;
streamFormat.mChannelsPerFrame = 1;

CheckError(AudioUnitSetProperty(myStruct->remoteIOUnit,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Input,
0,
&streamFormat,
sizeof(streamFormat)),
“kAudioUnitProperty_StreamFormat of bus 0 failed”);

CheckError(AudioUnitSetProperty(myStruct->remoteIOUnit,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Output,
1,
&streamFormat,
sizeof(streamFormat)),
“kAudioUnitProperty_StreamFormat of bus 1 failed”);

//Set up input callback
AURenderCallbackStruct input;
input.inputProc = InputCallback;
input.inputProcRefCon = myStruct;
CheckError(AudioUnitSetProperty(myStruct->remoteIOUnit,
kAudioUnitProperty_SetRenderCallback,
kAudioUnitScope_Global,
0,//input mic
&input,
sizeof(input)),
“kAudioUnitProperty_SetRenderCallback failed”);

在回调函数inputCallback中,用AudioUnitRender() 函数获取麦克风的声音,存在一个bufferList中。这个bufferList是一个ring结构,存储*新的声音,然后播放旧声音。这样,声音的输入和输出之间,就有了0.5s(可调节)左右的延迟,形成了明显的回声。

给回声消除添加一个开关。VoiceProcessingIO有一个属性可用来打开/关闭回声消除功能:kAUVoiceIOProperty_BypassVoiceProcessing

UInt32 echoCancellation;
UInt32 size = sizeof(echoCancellation);
CheckError(AudioUnitGetProperty(myStruct.remoteIOUnit,
kAUVoiceIOProperty_BypassVoiceProcessing,
kAudioUnitScope_Global,
0,
&echoCancellation,
&size),
“kAUVoiceIOProperty_BypassVoiceProcessing failed”);

现在可以开始graph了:

CheckError(AUGraphInitialize(graph),
“AUGraphInitialize failed”);
CheckError(AUGraphStart(graph),
“AUGraphStart failed”);

在示例中,有一个简单的开关按钮,可以明显感觉到打开/关闭回声消除的区别。

在实测中,打开回声消除功能时,仍然能听到一点点的回声,不过很小,一般情况下足够使用了。

iPhone图片拉伸:resizableImageWithCapInsets

今天做了一个温度计的应用,需要一个图,能够根据输入的数据将温度计里面的红色图片拉伸。为了达到这个效果,使用了iOS5的函数:resizableImageCapInsets:(UIEdgeInsets)Insets。

其中Insets这个参数的格式是(top,left,bottom,right),从上、左、下、右分别在图片上画了一道线,这样就给一个图片加了一个框。只有在框里面的部分才会被拉伸,而框外面的部分则不会改变。比如(20,5,10,5),意思是下图矩形里面的部分可以被拉伸,而其余部分不变。

%title插图%num
据说stretchableImageWithLeftCapWidth:topCapHeight这个函数也能够实现,但是在iOS5里面建议不要使用这个函数。效果如下图:

%title插图%num

当修改了数据之后,变成这样:

%title插图%num

下面来看如何实现。

温度计共由三张图组成:

背景图ThermometerBackground.png:

%title插图%num

刻度图ThermometerCalibration:

%title插图%num
里面的溶液Calibration:

%title插图%num
首先将背景图加入superview中,再将刻度图和溶液图加入背景图中:(为简化起见,一些不必要的代码已经省略)

//将背景图加入superview
UIImageView *thermometerBackground = [[UIImageView alloc] initWithFrame:THERMOMETER_FRAME];
[thermometerBackground setImage:[UIImage imageNamed:@”ThermometerBackground.png”]];
[self.view addSubview:self.thermometerBackground];
//将溶液图加入背景图
UIImageView *thermometer = [[UIImageView alloc]init];
[self.thermometerBackground addSubview:self.thermometer];
//将刻度图加入背景图
UIImageView *thermometerCalibration = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@”ThermometerCalibration.png”]];
[self.thermometerCalibration setFrame:CGRectMake(0, 10, thermometerBackground.frame.size.width, thermometerCalibration.image.size.height*thermometerBackground.frame.size.width/thermometerCalibration.frame.size.width)];
[self.thermometerBackground addSubview:thermometerCalibration];
然后,根据度数生成对应高度的image;

UIImage* image = [UIImage imageNamed:@”Thermometer.png”];
UIEdgeInsets insets = UIEdgeInsetsMake(20, 0, 25, 0);
image = [image resizableImageWithCapInsets:insets];
int top = 10.00+(38.00-temperature)*20.00;
[self.thermometer setFrame:CGRectMake(0, top, self.thermometerBackground.frame.size.width, self.thermometerBackground.frame.size.height-top)];
[self.thermometer setImage:image];
在这里,top这个变量就代表了根据度数计算出的溶液的高度。
这样,当改变温度temperature的大小时,只要在viewWillAppear里调用这段代码,就能够动态生成温度计图片了。

iOS RunLoop总结

为什么要有RunLoop
我们知道,一个线程,在整个生命周期中,很可能大部分时间都是没有事情可做的,有事情需要处理的时间总是比较短的。在没有事情处理的时候,线程应该怎么办呢?我们会希望它处于“休眠”状态,就是不要占用CPU资源,而在用到它的时候,再被“唤醒”。这种机制,叫作”Event Loop”,即事件驱动型的。

扯一点远的,在生活当中,我们也会喜欢这样的处理方式。比如,前段时间我不小心开车闯了一次红灯,后悔之余,每天都要刷新一下APP查一下有没有被拍到扣分。不过,市交通局其实已经提供了一个服务,当我名下的车子违反了交规,我会收到一条短信,通知我去处理。这样,其实我就不需要一遍一遍“轮循”,而只需要接收“通知”,大大减少了我的精力消耗。

Run Loop,就是这样一种基于事件通知的模式,它能够减少线程的资源占用。线程和runloop是一一对应的,每一个线程都有一个runloop。runloop的初始化是lazy load模式的,即在*次请求时再创建。

几个概念
是时候放出这张介绍Run Loop的经典图片(1)了:

这里面有几个概念:

Mode:一个runloop可能有几个mode。一个mode其实是sources/observers/timers的集合。一个runloop在同一时刻只会运行在一个mode下,此时这个mode里面的内容是active的,而其它modes里面的内容都不会生效。这是为了保证专注于某一类事件。比如,UIScrollView的滚动事件,对于线程是一个高要求事件,所以被放在一个专门的mode下,此时其它mode下的事件,比如timer等,都不会被触发,以保证滚动刷新的流畅。

在mode这个概念里,还有一个小概念,即common modes。我们可以将某一个事件放入common mode items,这样这个事件就可以在所有被标记为”common”的modes里都运行了。比如,我们将某个timer加入主线程runloop的common mode items里,这样在UIScrollView滚动的时候也可以被fire了。

对于主线程,主要用到的有2个modes:

NSDefaultRunLoopMode:默认的mode,正常情况下都是在这个mode。
UITrackingRunLoopMode:当滚动UIScrollView的时候,就处于这个mode。
Source:即可以唤醒runloop的一些事件。比如用户点击了屏幕,就会创建一个input source。

Timer:嗯,我们经常用的NSTimer就属于这一类。

Observer:某个observer可以监听runloop的状态变化,并作出一定反应。runloop的状态有很多,下面会讲到。

一般如何使用呢?

将source标记为待处理;或者注册timer,到了时间后。
唤醒runloop,让其处理input source/timer。
RunLoop运行流程
再放一张经典大图:

上面的图还有点复杂,其实就是一句话:没有事情的时候,runloop处于休眠状态。当外部source将其唤醒后,它会依次处理接收到的timer/source,然后再次进入休眠。

那么,runloop是内部是怎么实现休眠/唤醒机制的呢?这就用到了操作系统内核里的mach port技术,来实现休眠/唤醒/处理事件的操作。

RunLoop在iOS的使用
刚才讲了,一个APP启动的时候,会新建一个主线程+对应的run loop。而run loop会自动生成(至少)2个mdoes,用于处理UI事件。其它的包括系统事件响应、手势识别、定时器等等,都用到了run loop的机制。

我的使用例子
我曾经做过一个音频播放的项目,没做完,链接在这里:LXAudioPlayer。

在播放音频的时候,音频在一个后台线程中播放,这是一个持续不断的操作。我将一个NSInputStream放入runloop中运行,这样就避免了在主线程中运行,可能导致主线程阻塞的问题。

几个小问题
本来想在这里回答一下几个问题,回头看一下,这几个问题在上面的文章里,其实已经都讲到了,就当个思考题吧。

runloop和线程是什么关系?
runloop的mode作用是什么?
以+scheduledTimerWithTimeInterval:的方式触发的timer,在滑动页面上的列表时,timer会暂停回调,为什么?如何解决?
runloop的内容是如何实现的?
over!

修改iOS系统的音量

###请注意:

##修改系统音量无法在模拟器上看到效果,必须使用真机调试才能看到效果!

使用前请导入库 #import <MediaPlayer/MediaPlayer.h>

1. 获取系统音量控制视图

先声明_volumeViewSlider属性

  1. -(void)getVolumeVolue
  2. {
  3. MPVolumeView *volumeView = [[MPVolumeView alloc] init];
  4. _volumeViewSlider = nil;
  5. for (UIView *view in [volumeView subviews]){
  6. if ([view.class.description isEqualToString:@”MPVolumeSlider”]){
  7. _volumeViewSlider = (UISlider *)view;
  8. break;
  9. }
  10. }
  11. }
  12. 复制代码

2. 修改系统音量的值

  1. – (void)verticalMoved:(CGFloat)value
  2. {
  3. // 更改系统的音量
  4. self.volumeViewSlider.value = value ;// 越小幅度越小0-1之间的数值
  5. }
  6. 复制代码

其他的需求:

通过上面的方法获取到控制音量的滑块之后,当我们改变滑块的value之后,系统的音量提示框会展示出来,也许有的APP中要自己定义音量改变的提示框,于是便要隐藏系统的音量提示框

####实现: 上面的 获取 系统音量滑块 的时候,并没有将滑块假如到我们的视图中,如果将其假如到我们的视图之中后,就会发现系统的音量提示框便不会展示,可以知道:音量滑块 (volumeViewSlider)在视图层级中,系统的音量提示框便不会展示,音量滑块 (volumeViewSlider)不在视图层级中,系统的音量提示框便会展示,这样就好办了,将音量滑块 (volumeViewSlider)的坐标调整到*低层级,或者将其坐标设置为负值如(-1000,-1000,100,4) 但是有一点要注意,不能将其 hidden 设置为YES ,如果设置为YES ,就会检测到 音量滑块 (volumeViewSlider)并没有在视图层级中,系统的音量提示框还会展示

iOS代码修改音量

*近在做一个项目,需要用户在打开APP后,自动将音量调节到某个值,于是研究了一下。
之前做过iOS上声音的研究,苹果对iPhone设备的输入/输出的控制很严格,因为苹果要控制用户体验的一致性。比如:用户将耳机拔下来的时候,苹果认为,用户这时候不希望其他人知道自己在听什么,于是这时候声音会被自动暂停。在音量调整上,苹果也采取了类似的策略。苹果认为,用户不需要APP来为他指定音量,因为这样有时候用户会感到不舒服。苹果的开发文档是这么说的:

You cannot change device volume programatically,however MPVolumeView (volume slider) is there to change device volume but only through user interaction.

苹果提供了一个让用户手动修改音量的方法:MPVolumeView。用户通过拖动slider bar修改音量,就是下面这玩意儿:

%title插图%num

虽然苹果将几乎所有的代码实现控制音量的方法都堵死了,但通过一些私有的方法还是可以修改的。比如,我们遍历一下MPVolumeView的subViews,从中得到UISlider,然后修改slider的value。这种方法虽然可以修改,但访问了私有的类,有被App Store拒*的风险。而且不知道什么时候苹果修改MPVolumeView的结构,这样的方法就不行了。

下面介绍一个可以修改音量的小trick,一个苹果想干掉而没法干掉的方法:

MPMusicPlayerController* musicController = [MPMusicPlayerController applicationMusicPlayer];
musicController.volume = 0.2;
使用之前需要添加MediaPlayer.framework。

为什么说苹果想干掉而没法干掉呢?这个方法是在iOS3.0里添加的,当时估计还没有”不允许使用代码修改音量“这样的规范;后来在7.0的时候,这个方法被depress掉了,说明苹果是想干掉的。但是对于一个持续改进的系统来说,一般都要做向前兼容,否则就会出现像WP6-WP7-WP8这样的悲剧。所以苹果对于去掉一个方法是非常谨慎的,终于还是把这个方法留着了,在它强大的围墙里给开发都留下了一扇窗户。

OpenStack云计算快速入门教程

*部分 OpenStack及其构成简介

一、云计算

云计算是一种计算模型,它将诸如运算能力、存储、网络和软件等资源抽象成为服务,以便让用户通过互联网远程享用,付费的形式也如同传统公共服务设施一样。因需而定、提供方便、动态改变和无限的虚拟化扩展能力是云计算的几个重要特征。

不同的“云”对应着不同的基础设施。下面是三种广义的“云”:

l 基础设施即服务(IaaS)

l 平台即服务(PaaS)

l 软件即服务(SaaS)

译者注:Open为开放之意,Stack则是堆砌,OpenStack合起来如其名,就是许多Open的Softwares堆积的集合,但1 + 1 > 2,系统的功能更为强大。

相关阅读:

Ubuntu 12.10 上安装部署Openstack  http://www.linuxidc.com/Linux/2013-08/88184.htm

Ubuntu 12.04 OpenStack Swift单节点部署手册 http://www.linuxidc.com/Linux/2013-08/88182.htm

在Ubuntu上安装OpenStack的Swift组件-installing openstack object storage  http://www.linuxidc.com/Linux/2013-08/88180.htm

OpenStack Hands on lab系列  http://www.linuxidc.com/Linux/2013-08/88170.htm

二、OpenStack

(一)OpenStack概要

OpenStack是一整套开源软件项目的综合,它允许企业或服务提供者建立、运行自己的云计算和存储设施。Rackspace与NASA是*初重要的两个贡献者,前者提供了“云文件”平台代码,该平台增强了OpenStack对象存储部分的功能,而后者带来了“Nebula”平台形成了OpenStack其余的部分。而今,OpenStack基金会已经有150多个会员,包括很多知名公司如“Canonical、DELL、Citrix”等。

以下是5个OpenStack的重要构成部分:

l Nova – 计算服务

l Swift – 存储服务

l Glance – 镜像服务

l Keystone – 认证服务

l Horizon – UI服务

%title插图%num

图1 OpenStack基本构架

下图展示了Keystone、Dashboard二者与其它OpenStack部分的交互。

%title插图%num

(二)OpenStack计算设施—-Nova

Nova是OpenStack计算的弹性控制器。OpenStack云实例生命期所需的各种动作都将由Nova进行处理和支撑,这就意味着Nova以管理平台的身份登场,负责管理整个云的计算资源、网络、授权及测度。虽然Nova本身并不提供任何虚拟能力,但是它将使用libvirt API与虚拟机的宿主机进行交互。Nova通过Web服务API来对外提供处理接口,而且这些接口与Amazon的Web服务接口是兼容的。

功能及特点

l 实例生命周期管理

l 计算资源管理

l 网络与授权管理

l 基于REST的API

l 异步连续通信

l 支持各种宿主:Xen、XenServer/XCP、KVM、UML、VMware vSphere及Hyper-V

OpenStack计算部件

l Nova弹性云包含以下主要部分:

l API Server(nova-api)

l 消息队列(rabbit-mq server)

l 运算工作站(nova-compute)

l 网络控制器(nova-network)

l 卷管理(nova-volume)

l 调度器(nova-scheduler)

 

API服务器(nova-api)

API服务器提供了云设施与外界交互的接口,它是外界用户对云实施管理的唯一通道。通过使用web服务来调用各种EC2的API,接着API服务器便通过消息队列把请求送达至云内目标设施进行处理。作为对EC2-api的替代,用户也可以使用OpenStack的原生API,我们把它叫做“OpenStack API”。

消息队列(Rabbit MQ Server)

OpenStack内部在遵循AMQP(高级消息队列协议)的基础上采用消息队列进行通信。Nova对请求应答进行异步调用,当请求接收后便则立即触发一个回调。由于使用了异步通信,不会有用户的动作被长置于等待状态。例如,启动一个实例或上传一份镜像的过程较为耗时,API调用就将等待返回结果而不影响其它操作,在此异步通信起到了很大作用,使整个系统变得更加高效。

运算工作站(nova-compute)

运算工作站的主要任务是管理实例的整个生命周期。他们通过消息队列接收请求并执行,从而对实例进行各种操作。在典型实际生产环境下,会架设许多运算工作站,根据调度算法,一个实例可以在可用的任意一台运算工作站上部署。

网络控制器(nova-network)

网络控制器处理主机的网络配置,例如IP地址分配,配置项目VLAN,设定安全群组以及为计算节点配置网络。

卷工作站(nova-volume)

卷工作站管理基于LVM的实例卷,它能够为一个实例创建、删除、附加卷,也可以从一个实例中分离卷。卷管理为何如此重要?因为它提供了一种保持实例持续存储的手段,比如当结束一个实例后,根分区如果是非持续化的,那么对其的任何改变都将丢失。可是,如果从一个实例中将卷分离出来,或者为这个实例附加上卷的话,即使实例被关闭,数据仍然保存其中。这些数据可以通过将卷附加到原实例或其他实例的方式而重新访问。

因此,为了日后访问,重要数据务必要写入卷中。这种应用对于数据服务器实例的存储而言,尤为重要。

调度器(nova-scheduler)

调度器负责把nova-API调用送达给目标。调度器以名为“nova-schedule”的守护进程方式运行,并根据调度算法从可用资源池中恰当地选择运算服务器。有很多因素都可以影响调度结果,比如负载、内存、子节点的远近、CPU架构等等。强大的是nova调度器采用的是可插入式架构。

目前nova调度器使用了几种基本的调度算法:

随机化:主机随机选择可用节点;

可用化:与随机相似,只是随机选择的范围被指定;

简单化:应用这种方式,主机选择负载*小者来运行实例。负载数据可以从别处获得,如负载均衡服务器。

(三)OpenStack镜像服务器—-Glance

OpenStack镜像服务器是一套虚拟机镜像发现、注册、检索系统,我们可以将镜像存储到以下任意一种存储中:

本地文件系统(默认)

l OpenStack对象存储

l S3直接存储

l S3对象存储(作为S3访问的中间渠道)

l HTTP(只读)

功能及特点

提供镜像相关服务

Glance构件

l Glance控制器

l Glance注册器

 

(四)OpenStack存储设施—-Swift

Swift为OpenStack提供一种分布式、持续虚拟对象存储,它类似于Amazon Web Service的S3简单存储服务。Swift具有跨节点百级对象的存储能力。Swift内建冗余和失效备援管理,也能够处理归档和媒体流,特别是对大数据(千兆字节)和大容量(多对象数量)的测度非常高效。

功能及特点

l 海量对象存储

l 大文件(对象)存储

l 数据冗余管理

l 归档能力—–处理大数据集

l 为虚拟机和云应用提供数据容器

l 处理流媒体

l 对象安全存储

l 备份与归档

l 良好的可伸缩性

Swift组件

l Swift账户

l Swift容器

l Swift对象

l Swift代理

l Swift RING

Swift代理服务器

用户都是通过Swift-API与代理服务器进行交互,代理服务器正是接收外界请求的门卫,它检测合法的实体位置并路由它们的请求。

此外,代理服务器也同时处理实体失效而转移时,故障切换的实体重复路由请求。

Swift对象服务器

对象服务器是一种二进制存储,它负责处理本地存储中的对象数据的存储、检索和删除。对象都是文件系统中存放的典型的二进制文件,具有扩展文件属性的元数据(xattr)。

注意:xattr格式被Linux中的ext3/4,XFS,Btrfs,JFS和ReiserFS所支持,但是并没有有效测试证明在XFS,JFS,ReiserFS,Reiser4和ZFS下也同样能运行良好。不过,XFS被认为是当前*好的选择。

Swift容器服务器

容器服务器将列出一个容器中的所有对象,默认对象列表将存储为SQLite文件(译者注:也可以修改为MySQL,安装中就是以MySQL为例)。容器服务器也会统计容器中包含的对象数量及容器的存储空间耗费。

Swift账户服务器

账户服务器与容器服务器类似,将列出容器中的对象。

Ring(索引环)

Ring容器记录着Swift中物理存储对象的位置信息,它是真实物理存储位置的实体名的虚拟映射,类似于查找及定位不同集群的实体真实物理位置的索引服务。这里所谓的实体指账户、容器、对象,它们都拥有属于自己的不同的Rings。

(五)OpenStack认证服务(Keystone)

Keystone为所有的OpenStack组件提供认证和访问策略服务,它依赖自身REST(基于Identity API)系统进行工作,主要对(但不限于)Swift、Glance、Nova等进行认证与授权。事实上,授权通过对动作消息来源者请求的合法性进行鉴定。如下图所示:

%title插图%num

Keystone采用两种授权方式,一种基于用户名/密码,另一种基于令牌(Token)。除此之外,Keystone提供以下三种服务:

l 令牌服务:含有授权用户的授权信息

l 目录服务:含有用户合法操作的可用服务列表

l 策略服务:利用Keystone具体指定用户或群组某些访问权限

认证服务组件

服务入口:如Nova、Swift和Glance一样每个OpenStack服务都拥有一个指定的端口和专属的URL,我们称其为入口(endpoints)。

l 区位:在某个数据中心,一个区位具体指定了一处物理位置。在典型的云架构中,如果不是所有的服务都访问分布式数据中心或服务器的话,则也称其为区位。

l 用户:Keystone授权使用者

译者注:代表一个个体,OpenStack以用户的形式来授权服务给它们。用户拥有证书(credentials),且可能分配给一个或多个租户。经过验证后,会为每个单独的租户提供一个特定的令牌。[来源:http://blog.sina.com.cn/s/blog_70064f190100undy.html]

l 服务:总体而言,任何通过Keystone进行连接或管理的组件都被称为服务。举个例子,我们可以称Glance为Keystone的服务。

l 角色:为了维护安全限定,就云内特定用户可执行的操作而言,该用户关联的角色是非常重要的。

译者注:一个角色是应用于某个租户的使用权限集合,以允许某个指定用户访问或使用特定操作。角色是使用权限的逻辑分组,它使得通用的权限可以简单地分组并绑定到与某个指定租户相关的用户。

l 租间:租间指的是具有全部服务入口并配有特定成员角色的一个项目。

译者注:一个租间映射到一个Nova的“project-id”,在对象存储中,一个租间可以有多个容器。根据不同的安装方式,一个租间可以代表一个客户、帐号、组织或项目。

(六)OpenStack管理的Web接口—-Horizon

Horizon是一个用以管理、控制OpenStack服务的Web控制面板,它可以管理实例、镜像、创建密匙对,对实例添加卷、操作Swift容器等。除此之外,用户还可以在控制面板中使用终端(console)或VNC直接访问实例。总之,Horizon具有如下一些特点:

l 实例管理:创建、终止实例,查看终端日志,VNC连接,添加卷等

l 访问与安全管理:创建安全群组,管理密匙对,设置浮动IP等

l 偏好设定:对虚拟硬件模板可以进行不同偏好设定

l 镜像管理:编辑或删除镜像

l 查看服务目录

l 管理用户、配额及项目用途

l 用户管理:创建用户等

l 卷管理:创建卷和快照

l 对象存储处理:创建、删除容器和对象

l 为项目下载环境变量

pyecharts图在flask中的使用

pyecharts图在flask中的使用

我们常用的的echarts画图,使用{{  }} 进行传递参数,,如果参数太多呢?就太多的变量了。这里我们可以直接用pyecahrts直接将图做好,然后直接传到前端去,,说来就来:
这里面*麻烦的是画词云图,我将所有的代码已经打包好,上传到GitHub了 https://github.com/jevy146/pyecharts-flask 。
pyecharts的图直接将示例中的代码封装到函数中即可 ,pyecahrts 用的1.0版本以上,(1.7.1) 链接:https://gallery.pyecharts.org/#/README ,

from random import randrange

from flask import Flask, render_template

from pyecharts import options as opts
from pyecharts.charts import Bar
from jinja2 import Markup, Environment, FileSystemLoader
from pyecharts.globals import CurrentConfig

CurrentConfig.GLOBAL_ENV = Environment(loader=FileSystemLoader(“./templates”))

app = Flask(__name__, )

# pyecharts 的图 上传到html中
def bar_base() -> Bar:
c = (
Bar()
.add_xaxis([“衬衫”, “羊毛衫”, “雪纺衫”, “裤子”, “高跟鞋”, “袜子”])
.add_yaxis(“商家A”, [randrange(0, 100) for _ in range(6)])
.add_yaxis(“商家B”, [randrange(0, 100) for _ in range(6)])
.set_global_opts(title_opts=opts.TitleOpts(title=”Bar-基本示例”, subtitle=”我是副标题”))
)
return c

from pyecharts.charts import WordCloud

def WordCloudPic():
data = [(‘ネイルマシン’, ’41’),
(‘ネイルマシーン’, ’40’),
(‘ネイル マシン’, ’35’),
(‘ネイルケア 電動’, ’33’),
(‘電動ネイルケア’, ’29’),
(‘ネイル 電動’, ’28’),
(‘ネイル マシーン’, ’27’),
(‘ネイルマシーン 電動ネイルマシン’, ’20’),
(‘ネイルドリル’, ’20’),
(‘爪やすり 電動’, ’20’),
(‘ネイルケア’, ’19’),
(‘つめやすり 電動’, ’15’),
(‘ネイルオフマシーン’, ’15’),
(‘stargreen’, ’13’),
(‘ネイルケアセット’, ’10’),
(‘爪 やすり 電動’, ‘9’),
(‘電動つめやすり’, ‘8’),
(‘ネイルケア セット’, ‘7’),
(‘ネイルオフ’, ‘7’),
(‘ジェルネイル オフ 電動’, ‘7’),
(‘ネイル ケア’, ‘6’),
(‘爪 電動’, ‘6’),
(‘電動爪やすり’, ‘6’),
(‘ネイル オフマシーン’, ‘6’),
(‘爪 やすり おすすめ 電動’, ‘5’),
(‘つめみがき 電動’, ‘5’),
(‘甘皮処理 電動’, ‘5’),
(‘電動 ネイル’, ‘4’),
(‘ネイルケアキット’, ‘4’),
(‘電動ネイルマシン’, ‘4’),
(‘電動 爪 ヤスリ’, ‘3’),
(‘ネイルマシン 電動ネイルケア’, ‘3’),
(‘電動 爪 やすり’, ‘3’),
(‘電動ネイル’, ‘3’),
(‘ネイルケアマシン’, ‘3’),
(‘ネイル やすり 電動’, ‘3’),
(‘爪けずり 電動’, ‘2’),
(‘ネイルケアセット 電動’, ‘2’),
(‘ネイルオフマシン’, ‘2’),
(‘爪ヤスリ 電動’, ‘2’),
(‘電動式ネイルケア’, ‘2’),
(‘ネイルけあセット’, ‘2’),
(‘電動ネイルケアセット’, ‘2’),
(‘ネイル オフ マシーン’, ‘1’),
(‘ネイルましーん’, ‘1’),
(‘プチトル ネイルマシン’, ‘1’),
(‘プチトル’, ‘1’),
(‘nail care set’, ‘1’),
(‘ネイルオフ マシン’, ‘1’),
(‘美甲’, ‘1’),
(‘ネイルマシン プロ用’, ‘1’),
(‘電動爪 やすり’, ‘1’),
(‘ネイルケア 甘皮’, ‘1’),
(‘爪ケアセット’, ‘1’),
(‘ネイル オフ’, ‘1’),
(‘ネイルケア 電動 ランキング’, ‘1’),
(‘nail’, ‘1’),
(‘ネイル ケア セット’, ‘1’),
(‘ネイルケア マシン’, ‘1’)]
c = (
WordCloud()
.add(series_name=”关键词分析”, data_pair=data, word_size_range=[6, 66])
.set_global_opts(
title_opts=opts.TitleOpts(
title=”关键词-热点分布”, title_textstyle_opts=opts.TextStyleOpts(font_size=23)
),
tooltip_opts=opts.TooltipOpts(is_show=True),
)
)
return c

@app.route(“/barChart”)
def get_bar_chart():
c = bar_base()
return c.dump_options_with_quotes()

@app.route(“/”)
def index():

c2 = bar_base() # pyecharts 画图
c = WordCloudPic() # pyecharts 画图

return render_template(“index.html”,
Bar2_options=c2.dump_options_with_quotes(), # 柱状图
Bar3_options=c2.dump_options(), #
Cloud_options=c.dump_options(), # 词云图

)

if __name__ == “__main__”:
app.run(debug=True)

*后的效果如下:

%title插图%num%title插图%num

iOS开发中使用OC和swift的对比

背景:

为了更好地学习,本人决定将学习的swift和OC进行下对比。

对比:

1.import的类

OC:某个只要要使用某个类就要将该类import。

swift:如果是用户自己创建类,其他类无需import可以直接使用。pod的一些三方类和系统的一些类,在使用的时候需要import

2.遵守协议实现协议中的代理方法

OC:

%title插图%num
OC中的遵守协议
swift:

%title插图%num
swift中的遵守协议

python tips:warning消除

python tips:warning消除

两种方法:

1.在代码中

import warnings
warnings.filterwarnings(“ignore”)
2.运行时

python -W ignore script.py
ELSE:

以上两种方法对于库源码中的报错没有作用,比如对于torchtext中的warning.warn,目前是直接注释了源码中的warning.

/home/***/anaconda3/envs/py36/lib/python3.6/site-packages/torchtext/data/field.py:68: UserWarning: Field class will be retired soon and moved to torchtext.legacy. Please see the most recent release notes for further information.
warnings.warn(‘{} class will be retired soon and moved to torchtext.legacy. Please see the most recent release notes for further information.’.format(self.__class__.__name__), UserWarning)
def fromJSON(cls, data, fields):
#warnings.warn(‘Example class will be retired soon and moved to torchtext.legacy. Please see the most recent release notes for further information.’, UserWarning)
“`

python画P-R曲线,并计算AUPR值-实战代码

python画P-R曲线,并计算AUPR值-实战代码

def draw_PR(dictNameYtruePred,title=None,savePath = ‘./picture/’,dpi = 600):
”’
:param dictNameYtruePred:
:param title:
:param savePath:
:param dpi:
#输入实例
# label = [1, 1, 0, 0,0,0,0, ] # y 是 a的值,x是各个元素的索引
# probability = [0.8, 0.3, 0.1, 0.2,0.3,0.4,0.6,]
# draw_PR({‘name’: [label, probability]})
”’
colors = cycle([‘sienna’,’seagreen’,’blue’, ‘red’, ‘darkorange’, ‘gold’, ‘orchid’, ‘gray’])
plt.figure() # 指定大小分辨率等,相当于画纸
for toolsName,y_trueANDpred_proba ,color in zip(dictNameYtruePred.keys(),dictNameYtruePred.values(),colors):
precision, recall, thresholds = precision_recall_curve(y_trueANDpred_proba[0], y_trueANDpred_proba[1], pos_label=1)
aupr = auc( recall,precision)#计算面积的
plt.plot(precision, recall, color=color, label=str(toolsName)+'(AUPR = %0.3f)’ % aupr, linestyle=’–‘, LineWidth=3)#横纵坐标的取值,颜色样式等

plt.xlim([-0.05, 1.05])#x坐标轴
plt.ylim([-0.05, 1.05])#y坐标轴
plt.xlabel(‘Recall’, size=25)#x标签
plt.ylabel(‘Precision’, size=25)#y标签
plt.legend(loc=”lower right”, ncol=1, fontsize=22)#加上图例
plt.title(title, size=25)
if not os.path.exists(savePath):
os.makedirs(savePath)
plt.savefig(savePath+str(1), dpi=dpi)
plt.show()
if __name__ == ‘__main__’:
label1 = [1,1, 1, 1, 1,1,1 ,1,1,0, 0, 0, 0, 0, ]
probability1 = [0.1,0.8, 0.3, 0.1, 0.6,0.5,0.8,0.9,0.4 ,0.2,0.3,0.4,0.6,0.1]
label2 = [1, 1, 1, 1,1,1 ,1,1,0, 0, 0, 0, 0, 0,0,]
probability2 = [0.9, 0.3, 0.8, 0.6,0.5,0.8,0.9,0.4 ,0.2,0.3,0.4,0.6,0.1,0.3,0.9]
draw_PR({‘name1’: [label1, probability1],
‘name2’: [label2, probability2]

})
结果:因为数据量较少,所以显示的粗糙

%title插图%num

友情链接: SITEMAP | 旋风加速器官网 | 旋风软件中心 | textarea | 黑洞加速器 | jiaohess | 老王加速器 | 烧饼哥加速器 | 小蓝鸟 | tiktok加速器 | 旋风加速度器 | 旋风加速 | quickq加速器 | 飞驰加速器 | 飞鸟加速器 | 狗急加速器 | hammer加速器 | trafficace | 原子加速器 | 葫芦加速器 | 麦旋风 | 油管加速器 | anycastly | INS加速器 | INS加速器免费版 | 免费vqn加速外网 | 旋风加速器 | 快橙加速器 | 啊哈加速器 | 迷雾通 | 优途加速器 | 海外播 | 坚果加速器 | 海外vqn加速 | 蘑菇加速器 | 毛豆加速器 | 接码平台 | 接码S | 西柚加速器 | 快柠檬加速器 | 黑洞加速 | falemon | 快橙加速器 | anycast加速器 | ibaidu | moneytreeblog | 坚果加速器 | 派币加速器 | 飞鸟加速器 | 毛豆APP | PIKPAK | 安卓vqn免费 | 一元机场加速器 | 一元机场 | 老王加速器 | 黑洞加速器 | 白石山 | 小牛加速器 | 黑洞加速 | 迷雾通官网 | 迷雾通 | 迷雾通加速器 | 十大免费加速神器 | 猎豹加速器 | 蚂蚁加速器 | 坚果加速器 | 黑洞加速 | 银河加速器 | 猎豹加速器 | 海鸥加速器 | 芒果加速器 | 小牛加速器 | 极光加速器 | 黑洞加速 | movabletype中文网 | 猎豹加速器官网 | 烧饼哥加速器官网 | 旋风加速器度器 | 哔咔漫画 | PicACG | 雷霆加速