Alicia's Blog

[LEAF Photo]作者


  • Home

  • Tags

  • Archives

Using OpenCV

Posted on 2017-12-14

Using OpenCV

背景

最近这几年人工智能大火,公司也想向现有产品(移动销售自动化管理软件)中加入些沾边的功能,于是想到现在销售填报数据时将现有的人工采集数据(超市货架中货品种类和数量统计)方式改用机器来做。让机器识别出货物首先要给机器大量的图片让它学习,然后通过图像识别技术来辨识超市货架的货物,并计算出数量。

本来按着这个思路下去应该是先进行 CoreML 等方式的调研,然后线下人员采集大量产品图片,结果公司领导不知道是基于什么原因,要求移动端开发先做个图像分割的应用,将一张超市货架的图片拍照后,再手动将每层货架标识出来,然后手动分割每层货架的产品,显然这种方式太没有技术含量了,所以用业余时间研究了一下 OpenCV ,看看有什么方式能实现自动检测出货架,并分割出每个产品。

经研究,通过直线检测方式能检测出货架位置,但是图像分割的效果由于光线以及产品摆放方式等原因会效果较差,趁着印象深刻的时候,把用到的知识点以及遇到的问题和解决方案总结一下。

LTImageAnalysis - Demo地址

img

书籍推荐

如果想用好 OpenCV,就要对 OpenCV 能做什么有非常清楚的了解,所以 《Learning OpenCV 3》 是个人感觉最有用的书,第三版好像还没有中文版,所以看了英文版,对比了下中文版的第一版,第三版内容更丰富目录结构更合理。另外推荐 《Mastering OpenCV with Practical Computer Vision Projects》,在没有思路的时候可以借鉴一下。

OpenCV 安装和使用

OpenCV 是 Open source computer vision 的缩写,它的目的是提供一种更简单的方式来快速处理复杂的视觉应用。

Read more »

An Organic Problem Solving Approach

Posted on 2017-08-07

《成为技术领导者:掌握全面解决问题的方法》中文版书名的副标题才是原版书名,即这是一本讲解决问题方法的书,同时介绍了如何获得领导力。作为领导者,不应该把自己放的高高在上的位置而不去为他人着想;普通员工要替领导者思考,毕竟不想做将军的士兵不是好厨子嘛,所以这不只是一本给领导者看的书。

领导力 和 领导模型

所谓领导力,就是创造这样一个环境,每个人都能在其中发挥出更多的能力。

西方的管理学主要多会创建一些模型,本书作者提出的领导力模型为 MOI,即 激励(Motivation),组织(Organization),创意(ideas or innovation)。

激励:领导者要做的事情是激励他人更好的完成工作任务。

激励的方式有很多种,中国父母最爱用的激励方式就是夸别人家的孩子怎么优秀,要不就是怎么都看不上自己家的孩子,觉得他们只要学习不好就一无是处。领导管理下属的方式也是一样,差劲的领导经常是在夸别的部门员工怎么好,自己手下的员工多么差劲,对员工的优点视而不见,小小的缺点都无法忍受。

惩罚属于激励的一种方式,但是用打击的方式去激励他人,只适合那些心里强大并且很有上进心的下属,对于大部分人来说这种方法很不受用,尤其是在你并非是下属父母的情况下,下属很可能被你这么“激励”几次就会辞职不干了。如果制度中没有说明某些行为是需要被惩罚的,我建议都不要使用惩罚方式去激励,私下用平和语气一对一沟通是一种更好的解决方式,同时想办法避免同类事情再次发生。

组织:领导者要做的事情是创造一个环境,让每个人都能发挥更多的能力,并将想法化为实践。

创意:应当具备创意并且能够接受他人想法。

要保证领导力的效果,就必须在激励、组织和创新之间求平衡,太偏向一边就不是好的领导者。

解决问题的方式

本书是介绍解决问题的方式的,作者认为遇到问题应当从以下几个方面着手

Read more »

Optimize App Performance

Posted on 2017-07-31

之前写过一篇关于性能的文章,最近又需要优化性能,所以在此基础上写一篇最近的优化总结

性能优化的几个方面:内存问题、电量消耗、启动时间、执行与响应速度、网络条件等等,下面就从这几个方面讨论下如何优化

内存问题

可借助工具:Instruments -> Leaks / Allocations / Zombies

内存问题,主要包括避免内存泄漏(使用 ARC,Block 中使用变量不要循环引用,可以借鉴以前的文章)、及时释放可以释放的无用内存(例如在一个循环中处理图片,可以使用自动释放池)

电量消耗

可借助工具:Instruments -> Energy Log

当 CPU 占用率较高,使用网络 / GPS 等情况下,电量会消耗较快。

降低 CPU 使用率的方式是优化代码中的算法,能使用系统 API 的尽量使用系统 API,这要求我们对不常用的 API 要有所了解,另外多看别人的源代码,对于不了解的 API 要查询下用法,算法方面,除了好脑子就要靠平时多看算法类的书籍锻炼了。

网络问题见下详述

GPS检查,设置合适的处理精度和距离,使用合适的 API 来更新位置。

例如在非实时(追踪走路等)定位的场景下,调用如下方法延时获取数据

[locationManager allowDeferredLocationUpdatesUntilTraveled:timeout:]

或者位置有重大变化(天气应用)时才需要获取数据,调用如下方法

[locationManager startMonitoringSignificantLocationChanges]

再或者使用区域检测

[locationManager startMonitoringForRegion:]

启动时间

见另一篇文章

执行与响应速度

可借助工具:Instruments -> Time Profiler

通过 Time Profiler 可以找到调用时间较长的 API,对消耗时间较长的代码进行优化,找到可优化代码只是第一步,比较困难的可能是如何优化,下面就几个方面讨论下优化途径

缓存

Read more »

iOS App Thinning

Posted on 2017-04-07

图片资源删减

使用工具查找未引用资源

LSUnusedResources 比之前的 Unused 好用,对于大型工程来说 Unused 效率太低

压缩 PNG

按照文件大小排列,看看是否有上百 K 的 PNG 图片,使用工具进行压缩,可以使用 JPG 的不要用 PNG

大图片不要使用 PNG,用 JPG 替换

删除掉 1x 图片

代码精简

查找无用的 OC 类

维护时间较长的代码,可能会出现废弃的类出现在代码中,这种无用的文件比较难找,可以通过 linkMap 文件来分析。

设置 Project -> Build Settings -> Write Link Map File 为 YES,并设置 Path to Link Map File,build 完后找到 linkMap 文件,来分析该文件,该文件默认位于

~/Library/Developer/Xcode/DerivedData/XXX-eumsvrzbvgfofvbfsoqokmjprvuh/Build/Intermediates/XXX.build/Debug-iphoneos/XXX.build/

该文件的介绍,可以参考下 这里

在 bang 同学的脚本基础上作了改进,原脚本支持第三方库大小统计,在该脚本的基础上,添加了分析 objc-class-ref 段,查找未引用的类的方法,代码点击这里

查找无用的函数

无用函数,可能是暂时无用,或者不确定是否以后会用到的,可以通过工具来查找无用函数,推荐工具点这里

或者按照查找无用 OC 类的方式写脚本分析 selrefs 段

编译选项优化

Strip Link Product 是否为 YES
Make Strings Read-Only 是否 为YES
去掉异常支持,Enable C++ Exceptions 和 Enable Objective-C Exceptions 设为 NO,并且Other C Flags 添加 -fno-exceptions

iOS 9 以上的 App Thnning

Slicing 仅向设备传送与之相关的资源

On-Demand Resources(ODR) 不重要的资源不下载,使用的时候下载

Bitcode 更新应用时,仅下载更新的内容。

Source Code Learning - NullSafe

Posted on 2017-03-27

起源

代码中有时会处理跟 NSNull 相关的逻辑,有时候我们并不想要 NSNull,我们希望的是 nil,例如后台下发 json 出现如下数据

{
    "nullValue": null
}

这个时候用一般的库转换 JSON 为对象的时候,就会变为

{
    "nullValue": "<null>"
}

如果后台本来应该下发数组,而写代码的时候没有判断数据类型,例如直接获取 [array length],肯定会崩溃,出错原因是 [NSNull length] 没有对应的响应方法。

如何不手动判断类型,又能避免崩溃?NullSafe 就是为了解决这个问题而诞生的。

实现

NullSafe 只有短短的一百行代码。实现的方式是,创建 NSNull 的类别,在该类别中首先查找 NSNull 是否能响应某方法,如果不可以响应的话,就查找系统中是否有某个类可以处理调用的方法,如果可以的话,该方法转发给 nil,当作 nil 处理这个方法,例如 nil 调用 [nil length] 是不会抛出异常的。代码如下:

Read more »

Optimize App Startup Time

Posted on 2017-02-22

前言

启动时间包括 main 执行之前的时间,以及 main 执行之后的时间。

main 执行之后的时间通过 Time Profiler 查看即可,之前写过文章,详情点击这里。

这篇文章主要讨论 main 执行之前的时间。

main 之前 的加载过程

Load dylibs => Rebase => Binding => ObjC => Initializers

在 Xcode 中 Edit scheme -> Run -> Auguments 中设置 DYLD_PRINT_STATICS 环境变量可以输出 main 之前执行的时间

Load dylibs

要了解第一个阶段的 dylibs,先要介绍下 OS X 的可执行文件 Mach-O

Mach-O 二进制格式

系统判断一个文件是否可以执行,是通过将文件读入内存,然后寻找一个头签名,头签名通常被称为 魔数 magic,通过 magic 可以判断文件的二进制格式,如果是被支持的二进制格式,那么就可以执行该文件。

在很多种可执行文件格式中, OS X 目前只支持:解释器脚本格式、通用二进制格式以及 Mach-O 格式。Mach-Object,简称 Mach-O,是苹果在 OS X 中维护的一种独有的二进制格式。

Mach-O 的文件头 mach_header 中包含magic、CPU 类型和子类型等。mach_header 其后包含了很多指令,这些指令被调用时清晰地指导了如何设置并加载二进制数据,这些指令被称为“加载指令”。加载指令包括将文件中的段映射到进程地址空间、调用 dyld、开启线程、代码签名等。

OS X 上几乎所有的程序都是动态链接的,仅有非常少量的进程只需要内核加载起就可以完成加载。通常情况下,使用 dyld 作为动态连接器。

Loading Dylibs 的加载过程又分为

Parse list of dependent dylibs => Find requested mach-o file => Open and read start of file => Validate mach-o => Register code signature => Call mmap() for each segment

上面说过 mach_header 中包含很多指令,其中包含了 LC_CODE_SIGNATURE 用于数字签名,iOS 强制要求代码签名,且代码签名和沙盒机制是绑定在一起的,也就是说必须放到沙盒中经过签名才能运行,非越狱的机器无法自行下载一个动态库并执行。

mmap的作用是将一个文件或者其他对象映射进内存,普通文件被映射到进程地址空间后,进程可以像访问普通内存一样对文件进行访问。

通常一个 App 需要加载 100 - 400 个 dylibs,但是其中的系统库加载会被优化,能在很快的时间内加载完成

优化 Load dylibs 过程

Read more »

Source Code Learning - IQKeyboardManager

Posted on 2017-01-27

OC 中如何做到不加一行代码就实现功能的

IQKeyboardManager

+(void)load
{
    //Enabling IQKeyboardManager. Loading asynchronous on main thread
    [self performSelectorOnMainThread:@selector(sharedManager) withObject:nil waitUntilDone:NO];
}

利用 +load 方法来实现不调用就执行的功能

另: +load 方法
每个类在 OC runtime 中会自动调用两个方法,+load 方法是类初始化的时候调用, +initialize 是类或者实例的方法第一次被调用的时候调用。但是,在 Swift 桥接到 C 的代码中自定义的 +load 方法不会自动被调用,所以 Swift 需要写一行代码来实现,OC 不用。

父类先执行 +load,子类后执行。类的+load 先执行,Category 的该方法后执行。

+load 和 +initialize 是线程安全的,但是 IQKeyboardManager 中有 UI 操作说一要保证其在主线程中执行。

初始化中会调用注册方法,注册监听键盘和展开和收起事件,并为 UITextField 和 UITextView 分别注册开始编辑和结束编辑事件。事件中处理 adjustFrame 方法调整 Frame。

手动开关设置的处理都在初始化中进行,可以设置的功能见文档,自定义设置方法

// … 待完成

参考文章

+load 方法

2016 book list

Posted on 2016-12-31

这一年,看过的工作类图书如下:

乔布斯的魔力演讲

即使看过乔布斯演讲的人看看这书也能有所收获。

不懂带人你就自己干到死

看完后写过一篇文章,感兴趣点这里

软技能代码之外的生存之道

书中很多东西可能对于一个老程序员来说,早已领悟,看看无妨。对番茄工作法用来估测自己工作时间的方式感觉很有用处,即当你被分配一个任务时,需要预估做完这个工作需要多少时间,可以先预估大致需要几个番茄时间,之后用一个番茄时间 20 分钟去完成,看看进度是多少,然后重新预估的时间一半比较准确。例如预估 8 个 番茄时间能完成的工作,实际工作 1 个番茄时间后发现工作只完成了 1/16,那么预估时间大约就是 16 个番茄时间,这个时间更准确些。

Learning React Native

一边看官方文档,一般看这本书写个 Demo,能对 RN 所有类的用法有个基本掌握。

Design Code

Design 方面讲的还是不错,还介绍了 Sketch 的用法,但是 Code 方面应该只是对刚入门的程序员来说可能又用,所以没有仔细看。

Git 版本控制管理

不只是 Git 的一本不错的工具书,还介绍了一点原理

iOS 测试指南

稍微有些过时,对于平时感觉没有那么有用,有空会再看看

写给大忙人看的 Swift

太简约了,感觉如果真的忙的没有时间,那看官方的手册前几页就可以了,没有必要看这本书。

Mac OS X and iOS Internals

对系统底层非常详细的介绍,但是稍微有些太理论,所以有些枯燥,没有那么容易一气呵成的读完,仍然值得一看。

About Message send to dealloc instance

Posted on 2016-11-17

前言

最近,遇到一个崩溃问题,崩溃前控制台打印出 “message send to dealloc instance”,在解决问题的过程中发现一个调试工具。

话说,这一次的问题主要是发生在 MRC 环境下,除了发现调试工具,还回忆了一下 MRC。感兴趣的话,可以当作面试题来看看下面代码有什么问题。

上一次用到 MRC 恐怕还是 2011 年,这次是因为公司有个老代码使用的是很早以前别人写的库,一直没有升级所以还是在 MRC 下。先来描述下问题。

崩溃代码

重要的事情说三遍,MRC 下,MRC 下,MRC 下

//.h 头文件中定义了一个变量
NSString *_title;
//.m 实现文件中
- (id)initWithTitle:(NSString *)title {
    _title = [title copy];
    // … 
}
- (void)dealloc  {
    [_title release];
    [super dealloc];
}
// 另一个调用文件中是这样子的
[[xxClass alloc] initWithTitle:nil];

最近的一次修改导致崩溃是被改成了下面的样子,当 title 为 nil 时把它定义为默认字符串,于是上面的 initWithTitle 改为

- (id)initWithTitle:(NSString *)title {
    if (title) {
        _title = [title copy];
    } else {
        _title = NSLocalizedString(@"Alert", nil);
    }
}

接下来的事情是这样的,某个页面在多次调用 initWithTitle 的时候会发生崩溃,错误信息是这样子的:

UncaughtExceptionHandlerAddressesKey = (
4   CoreFoundation                      0x1b9ca81c <redacted> + 2124,
5   CoreFoundation                      0x1b9c9f8f CFDictionaryGetValue + 126,
6   CoreFoundation                      0x1bb1446b <redacted> + 142,
7   CoreFoundation                      0x1bb14111 CFBundleCopyLocalizedStringForLocalization + 94,
8   CoreFoundation                      0x1ba0f6bb CFBundleCopyLocalizedString + 18,

调试的话,崩溃的位置就在 _title = NSLocalizedString(@”提示”, nil); 这一行。

不知道各位看官是否一眼发现了问题,控制台还有这样的输出

message sent to deallocated instance 0x6d564f0

一时没想到 NSLocalizedString 会有什么问题,因为好久不用 MRC,武功已经全废,所以关注上了这个 message sent to deallocated instance,想通过这条信息查找到问题。

Read more »

Source Code Learning - JDStatusBarNotification

Posted on 2016-10-11

RunLoop 和 NSTimer

每次显示时先要将之前设置过的 timer 取消

// cancel previous dismissing & remove animations
[[NSRunLoop currentRunLoop] cancelPerformSelector:@selector(dismiss) target:self argument:nil];

timer 的设置代码如下:

- (void)setDismissTimerWithInterval:(NSTimeInterval)interval; {
    [self.dismissTimer invalidate];             // 重新赋值时先要使其无效
    self.dismissTimer = [[NSTimer alloc] initWithFireDate:[NSDate dateWithTimeIntervalSinceNow:interval]
                                             interval:0 target:self selector:@selector(dismiss:) userInfo:nil repeats:NO];
    [[NSRunLoop currentRunLoop] addTimer:self.dismissTimer forMode:NSRunLoopCommonModes];
}

为了能在用户拖拽页面的时候 timer 正确计时,将 timer 添加到 NSRunLoopCommonModes 模式下

UIWindowLevel

每个应用都有一个主 window,通常在 AppDelegate 中设置

self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.window.backgroundColor = [UIColor whiteColor];
self.window.rootViewController = [[UINavigationController alloc] initWithRootViewController:
                                  [[SBExampleViewController alloc] initWithStyle:UITableViewStyleGrouped]];

[self.window makeKeyAndVisible];

makeKeyAndVisible 方法是将某个 window 设置为主窗口并设置为可见,这个窗口的级别使用默认值 UIWindowLevelNormal,UIWindowLevel 的级别如下

Read more »
123…5
Alicia

Alicia

45 posts
23 tags
GitHub E-Mail Twitter weibo
© 2020 Alicia
Powered by Hexo
|
Theme — NexT.Mist v5.1.4