“Distribute” an under development app without enrolling iOS Developer Program

You are developing an iOS App.

Prior to Xcode 7, you have to enroll into Apple’s iOS Developer Program (IDP) to install an App to a device, either yours or your friend’s.

Now in Xcode 7, you can compile and deploy an under development App to your device.
The problem is: How do you “distribute” your App to your friend?

I quoted the “distribute” here, because I am talking about a casual situation that it is not a serious distribution but only within a small scope.

If your friend lives nearby, this is easy. You do the something you did for yourself. You connect his/her device to your Mac/Macbook and use Xcode to install the App.

If you need to make this happen remotely, we need some work. This solution only works if your friend has a Mac with Xcode 7 installed.

There are two options.

1. You send the whole project to your friend and ask him/her to compile it and deploy it to the device. This requires advanced knowledge if your project is somehow complex.

2. After you compiled your App, you can get the actually “AppName.app” file after compiling it for device from Xcode. You send this “AppName.app” to your friend. He/she can open Xcode and follow “Window->Device”, then drag-n-drop the “AppName.app” to his/her device.

However, it is very likely that the second option will show an error “a valid provisioning profile for this executable was not found” on your friend’ screen.

This is because without IDP, the provisioning file we get from Xcode contains the exact UDID (unique device ID) of the device connected to Xcode during compilation. Any other device would not accept the App unless its UDID is listed in the provisioning file. But without IDP, we can not explicitly add UDID to an provisioning file.

Here is the workaround.

1. Register a new Apple ID if you don’t want to share your Apple ID with your friend (for good reason).
2. Ask your friend to add this new Apple ID to your Xcode Account (Preference -> Account -> + button).
3. Your friend will need to create an iOS project (simply choose the single-view Application template), compile it and install it to the device. During this process, Xcode will prompt to ask to “fix issues”. Confirm that and make sure the right “Apple ID” is selected in the “Team” field.
4. Now the UDID of the remote device is associated with the Apple ID.
5. On your local machine, use the same Apple ID to compile the App for device and send out the “AppName.app” file. Now because the UDID of both your device and the remote device are all listed in the provisioning file, the “AppName.app” can be installed into the remote device by either iTunes or Xcode.

This solution is not perfect but it works well without paying $99 each year. Good luck!

Jonas过后

来美国第四个年头了。新泽西这个地方每年都有不小的雪。看雪的心情也从刚来时的兴奋变成了爱恨交织。一片白茫茫是不错的景致,但是想到白茫茫一片之下还有自己的车心情也就复杂起来了。

本来以为今年是一个暖冬。本该是雪花纷飞的圣诞节前后可以穿着单衣出门。所以当知道气象台预报有暴风雪要来的时候,我一开始是怀疑的。天气预报总是这样的小题大作。第一年来的时候,学校常常因为预报有飓风而停课。可是飓风常常失约,又或是还未到地方地就失去了活力。

只有Sandy那次,是准的。那时候住在学校附近。天气已经转凉,整整一周的停热水停电停暖气还真是难捱。所幸的是因为离学校不远。那时候每天早早的起床去实验室,再晚晚的回去。中午学校食堂还有免费的救济餐。

按照惯例,这次的暴风雪也有名字,叫Jonas。似乎是拉丁文,不知道有什么含义。如果不是如预报所说的猛烈,恐怕也没有记住的必要了。

气象台也算是是幸运的,这次他们又说对了。

周六早上起来,外边就一片白茫茫了。门口积的雪已经影响到开门了。

https://goo.gl/photos/k8fgeU24NKViZn5k8

https://goo.gl/photos/ByNS4hcQRPNJRcfYA

从家里往窗外望去,窗前小树上堆起的雪已经很高了。

https://goo.gl/photos/vc46b9nWn2E3xL8d7

可是雪还在一直下。这时我才感觉到天气预报这回又立功了。
果然,一夜之后,前门彻底打不开了。

https://goo.gl/photos/VHRwMV3GU2MdwRLNA

不得已,还得出门铲雪挖车。只好绕道从后门出去。计划要从后面挖出一条小道回到前门,以解前门之围。

后院的情况也不太乐观,之前院子里还有房东家小朋友的玩具小车和一些杂物。看起来它们要重见天日还需要耐心等待了。

https://goo.gl/photos/5rnPpbMwkU6pcGtt8

大多数地方的雪都没过膝盖了。吭哧吭哧地劳作了一段时间,总算是从后院挪动到了停车道上。这才看见了车被埋成了什么样。

https://goo.gl/photos/z1ZSkvNhRJ5hR61b7

要把车给挖出来,这个基本上很难。

https://goo.gl/photos/67zUQVsfGUP6es4R7

挖啊挖,终于挖到前门了。抬头一看,门打不开也是讲道理的。

https://goo.gl/photos/HMGezgjix2zfwtCZ9

https://goo.gl/photos/N1DfHZ9zBJJhSgvn7

之前是台阶的地方已经无迹可寻。没有办法,只有继续挖。
成功的挖开门之后,是这个样子的。

https://goo.gl/photos/2XJCaJ6BKogUuzBk6

从上往下看

https://goo.gl/photos/FDiowu3GnXDsPFkv7

下午和小伙伴们一起在停车道上劳作了两三个小时。
Sandy之后,这下又记住Jonas的大名了。

希望这个冬天快点过去吧。

iOS上mxnet的一个演示App

mxnet是最近火的不行的一个深度学习的框架,支持好多好多语言,有好多好多大牛在写。

之前也有想过把同样很牛很牛的caffe跑到iOS上看看速度怎么样,但是caffe有一大堆文件,感觉做起来很麻烦。

最近看到mxnet居然有一个单文件的版本
就做了一个简单的图像识别的演示App。跑在6上速度还可以,大概4秒一张图。

代码在这里:

WhatsThis-iOS on Github

Cardboard VR

上次开会的时候排队尝试了Google的Cardboard和Oculus,虚拟现实(VR)的体验很真实。于是也不难理解现在VR/AR的火热程度了。Facebook有Oculus,Google有Cardboard,微软有HoloLens,还有Magic Leap的神秘兮兮又牛叉哄哄的演示,也是醉了。大家都看好这个市场,虚拟现实(VR)和增强现实(AR)的市场规模可能会达到1,500亿美元…

为了紧跟社会潮流,果断去大Amazon淘了一个Cardboard来玩,就长这样。
http://www.amazon.com/Pro-Compatible-Instructions-Construction-Experience/dp/B00Q1FITMO

Amazon上有各种Cardboard,大都支持Google Cardboard的Apps。Cardboard主体就一张纸板,还有两个镜片,折了几折就成了前面图上的样子。把你的手机放上去做屏幕就可以体验VR了!

这基本上应该是最经济方便的体验VR的方式了。Cardboard支持很多大屏幕手机,我用的iPhone 6没有问题。用的时候需要凑近镜片去看屏幕。因为近视的关系,我起初比较担心戴着眼镜看不是很方便,实际上把眼镜摘了也看得很清楚。因为其实看到的不是真的3D…屏幕就在眼前不远,不是上千度的近视的话,当然应该看得清楚。

目前各种VR设备面临的一个重要问题是晕动病 (VR motion sickness)。wiki上的对晕动病的解释是:

晕动病或运动病,生活中通常被称为晕车、暈機和晕船,是一种平衡失调的疾病。当人眼所见到的运动与前庭系統感觉到的运动不相符时,就会有昏厥、恶心、食欲减退等症状出现。严重者会呕吐。

这个和有些同学打CS会头晕或者开极品飞车就也能开吐了是相同的原理。可能的一个原因是显示屏的刷新率不够高,我自己用的时候也能不时地感觉到屏幕的刷新率跟不上头的移动。这个时候就会有点“跳戏”的感觉 🙂 据说只有一小部分人是很幸运的天生没有晕动症这个问题的。所以,如何解决这个问题也是VR厂商们面前的一个难题。当然大家也在积极的寻找对策。简单的解决方法据说是喝点酒… 也有研究科学家表示,在画面中增加一个虚拟的鼻子也可以缓解晕动症 ._.

我自己用Cardboard的时候也没有感觉到这个问题,可能是因为看的时间不是很久。毕竟Cardboard只是用来体验VR的,需要用手托住Cardboard来看,不适合长时间的看。不知道是不是iPhone 6屏幕的问题,看的时候感觉画面不是特别的锐利,有一种显示的分辨率不够高的感觉。但是整体的体验还是很赞的。iOS上的VR Apps不如Andriod上的多。在这里推荐几个值得试试的应用。

Google Carboard
这个是Google官方的应用,可以先通过这个应用体验一下基本的功能。其中有一个街景的功能,可以体验站在各个著名景点现场环视四周的感觉。

InMind VR
这是一个VR的游戏,画面不错,挺有代入感。用头部的动作来完成射击任务,时间不长,值得一试。

VRSE
这个App里提供了不少很有意思的VR电影,影片时间长短合适,非常推荐。有些是记录片,有些是软广,但是通过VR来看,都挺有代入感。
类似的App还有:RYOT

暂时就发现这么几个,试试看吧 🙂

补充:

GermBuster
一个非常有趣的游戏,用泡泡攻击细菌。最有趣的是细菌也会吐泡泡攻击你,快被打到的时候3D感特别明显,有种被直接打到脸上的感觉…

Build a Robot From A Power Wheelchair (1/2)

I have been working on a robotic project for a while. In this project, we build a robotic wheelchair controlled by head motions.

IMG_2245

It starts from a commercial powered wheelchair (Titan Front Wheel Drive Power Chair).

We took over the control signals, added a number of sensors and wrote some computer vision softwares. It is a lot of fun. At this time point, we can drive it with head motions, a little slow but very easy to control. A short video is posted.

Robotic Wheelchair
[KGVID width=”640″ height=”360″]http://personal.stevens.edu/~hli18/video/robot.mp4[/KGVID]

The most challenging part so far, to our surprise, is how to take over the driving signals. In fact, once the powered wheelchair can be controlled with digital signals, it is somehow a robot.

We can find quite a few posts discussing how to hack the joysticks with Arduino. If you have a VR2 joystick, it would be much easier. This post (http://myrobotnstuff.blogspot.com.au/2012/07/circuit-for-wheelchair-robot.html) explains the process well. Basically, you can reproduce the digital signals triggered by the joystick with the Arduino.

But unfortunately, the joystick with the Titan power chair is with a different design and it is much more difficult to hack.
It is Dynamic Shark controller. If your remote (joystick) looks like this one , you probably have this kind of joystick.

The difficulty in reproducing the control signals generated by this kind of joystick is that it directly outputs 25V differential signals from the remote to the power module, which is a big black box under the seat. The signals are encoded and there is probably no way to get the encoding protocol.

We did quite a few rounds of trial and error and finally figured out a plan after burning out a joystick…

IMG_1587

This kind of joystick works in a special way. At the end of the handle of joystick, there is with a small coil. 4 small coils are on the board under it. Because of the electromagnetic induction, the coil on the handle of the joystick produces different signals at different positions in the 4 small coils under it.

Roughly speaking, the (analog) signals produced by the 4 small coils are then processed by an on-board micro-controller to produce the driving signal. Because the signals produced by the micro-controller are encoded in an unknown protocol, we choose to get in by reproducing the outputs from the 4 small coils.

If you take away all 4 small coils (DO NOT do that…), the board looks like this

A

After some processing circuits, finally the outputs of the 4 coils can be found as two signals passed the two resistances in the red circuits. If you use an oscilloscope to check the signals, you will find that they are sine waves!

With this observation, the plan is clear. Soldering two wires at the right end of these two resistances (be careful!), we need to use an Arduino to reproduce these two sine waves to drive the wheelchair.

One of the two sine waves is for the X-direction and the other one is controlling the driving in the Y-direction.
The phase the sine wave indicates the sign (forward in X-direction or backward in X-direction) and the amplitude indicates the speed. The two sine waves should be sort-of aligned, which means the phase difference should be either 0 or 180.

With an Arduino, we will produce these sine waves signals to the two wires.

[Note] Saliency Detection: A Boolean Map Approach

Saliency应该是翻译为显著性。个人理解显著性检测是得到一张图片上每一个像素点的显著程度的过程。对于这个显著程度,直观的理解就是它在这张图上的重要程度。比如,这些照片里

Bird Diversity 2013

组成鸟的像素应该是比背景的像素更加重要,也就是应该有更高的显著性值。知道了各个像素点的显著性之后,可以用来帮助一系列的更加具体的任务,比如这篇文章里的Eye Fixation的预测,也就是预测在这张图片上人会看哪里。还有显著物体的检测,可以更进一步的做物体检测和识别。

直接描述这篇文章的方法吧。输入是一张图片,输出是一张Saliency Map,表示每一个像素点上的显著性。根据Saliency Map可以进一步的做更佳具体的任务。得到Saliency Map的过程是先得到一组Boolean Maps,然后每一张Boolean Map得到一张Attention Map,对所有的Attention Maps求均值之后做Dilation就得到了Saliency Map。过程很简洁。

假设输入图片有三个颜色通道,随机的选一个颜色取一个阈值。然后据此把图片转成一张0/1的图片,颜色值大于阈值的为1,否则为0。这张0/1的图就是一张Boolean Map。重复这个过程就得到了一组Boolean Maps。Boolean Map如果一块区域和很好的封闭的边缘,那么就有可能是一个显著的物体。所以连着图片边框的区域显著性就会比较低。基于这个假设,把连着图片边框的区域都去掉,然后对全图做归一化,就得到了Attention Map。

没有做过Saliency Detection,欢迎指出各种错误。看到一篇文章引用了这个叫BMS的方法就找来看看。然后就发现作者是一起实习的小伙伴。。

[Note] Learning to See by Moving

这是一篇用CNN做特征学习的文章,题目比较格调。目标是训练得到可以用来做场景识别、物体识别等等任务的特征。
和之前的工作相比,训练时需要的监督信息不是图片所属的类别,而是两张图片之间的位置变换。准确地说,是拍摄两张相关图片的相机的相对位置变换。

Screen Shot 2015-05-25 at 12.29.27 PM

具体的网络结构如上图。输入两张图片,训练这个网络来判断两张图片之间的变换(Transformation)。每两个BaseCNN取得的特征(Lk)连接起来作为TopCNN的输入,TopCNN输出变换向量。训练结束之后TopCNN就不用了,直接用BaseCNN对输入图片取特征。

在使用相同数量的有标记数据的情况下,用这种相对更容易得到的监督信息训练出来的网络来做分类网络的初始化,比随机初始化分类效果更好。

虽然这个方法并不是完全的无监督学习,但是在移动机器人这种平台上,两张照片的相对位置变换确实是很容易得到的信息。按照这种方法确实可以很方便的给机器人增加场景识别功能。理想情况下,只需要在所在环境下移动的时间采集一些图片来学习特征,简单的通过人机交互标定几个场景,这种用CNN得到的特征应该会有很不错的表现吧。

Reference:

Pulkit Agrawal, Joao Carreira, Jitendra Malik, Learning to See by Moving

[Note] Discovering Hidden Factors of Variation in Deep Networks

一篇很有意思的文章。在一个半监督学习的框架下把需要预测的部分和其他隐含的变化因素(Hidden variations)分开。

比如我们现在的问题是表情分类,给定七种不同的表情,喜怒忧思悲恐惊(老中医..),我们可以训练出一个来判断任一输入图片中人的表情,记为\(y\)。
于此同时,我们还从输入图片中得到了代表其他和任务无关部分的信息,记为\(z\)。具体来说,两个不同的人的照片可以是同样的表情。但是除了表情相同之外,两张照片因为来自不同的人当然有很多其它的不同。除了表情之外其它的隐含信息就是\(z\)。

具体的实现上是基于auto encoder的,在encoding的时候设置两部分输出\(y\)和\(z\)。其中\(y\)的部分就同有监督学习一样。
Screen Shot 2015-05-12 at 10.36.18 AM

目标函数:

\[ \hat{\theta}, \hat{\phi} = \arg \underset{\theta,\phi} \min \sum_{\{x,y\}\in \cal{D}} \alpha U(x,\hat{x}) + \beta S(y,\hat{y}) + \gamma C(\hat{y},z) \]

其中\(\hat{\theta}, \hat{\phi}\)是encoder和decoder的参数,\(\alpha,\beta,\gamma\)是个部分的权值。第一部分就是auto encoder的无监督学习,第二部分是针对需要预测的量的有监督学习,第三部分是作者提出的 cross-covariance penalty (XCov)。目标函数的第三部分XCov意在最小化\(y\)和\(z\)的相关程度,让两者分开。

实验部分也很有意思,给定一个输入图片得到\(y\)和\(z\)之后。可以固定\(z\)然后改变\(y\),从而使得decoder部分可以重建出同样一个人的不同表情。

Screen Shot 2015-05-12 at 10.36.34 AM

Reference:
Brian Cheung and Jesse A. Livezey and Arjun K. Bansal and Bruno A. Olshausen, Discovering Hidden Factors of Variation in Deep Networks, CoRR 2014

[推荐] 王天珍老师的文章

来自科学网博客,王天珍老师的博文:
视觉研究的前世今生(上)
视觉研究的前世今生(中)
视觉研究的前世今生(下)

虽然很多概念不是很明白,但是感觉非常值得一读。这不是关于Computer Vision的研究,主要讨论是对人类视觉的研究。一开始读起来感觉像是在回顾很久远的时代里人们对人类视觉研究的初步探索,读到最后才惊觉原来人们至今对人类视觉的原理仍然知之甚少。我不觉得CV一定要去模拟生物特性来才能得到好的效果。但是人类视觉毕竟是一个强大复杂的系统,非常的有意思。

看到这些文章就想起来上次CVPR上的关于Professor Tsao的邀请报告,讲到她们对猴脑是如何响应视觉刺激而对猴脑的不同部位的不同刺激又是如何影响到视觉感知的研究。虽然我们的CV算法已经可以在很多视觉任务上面得到很好的结果,但是我们对于人类的视觉系统似乎还是不甚了解啊。

Convert the saved checkpoint of cuda-convenet to the proto of Caffe

*Credits of the scripts go to jamt9000 on github, thanks for the helpful work!

You are a deep learning consumer, you have a saved check point you trained with the cuda-convenet. You want to use Caffe to evaluate the trained neural networks on new data possiblely due to the absent of GPU. Hence you need to convert the saved checkpoint to the format compatible to Caffe.

1. check out this version of caffe: jamt9000/caffe:convert-cuda-convnet or my copy.

$git clone https://github.com/jamt9000/caffe/tree/convert-cuda-convnet convert-cuda-convnet

2. compile it following the Caffe installation instruction

## Misc. Setup 
$make all
$make pycaffe

3. convert the check-point with the following codesnippet

import sys
sys.path.append('./python/')
sys.path.append('./tools/extra/')

from convert_net import *

if (len(sys.argv) < 2):
    print "Usage:- path-to-saved-convnet"
    sys.exit(-1)

arg_convnet = sys.argv[1]
output_prototxt = arg_convnet + "-prototxt"
output_proto = arg_convnet + "-proto"

netpt = cudaconv_to_prototxt(arg_convnet)
fh=open(output_prototxt, 'w')
fh.write(netpt)
fh.close()
print "Wrote {0}".format(output_prototxt)

netpb = cudaconv_to_proto(arg_convnet)
fh=open(output_proto, 'wb')
fh.write(netpb.SerializeToString())
fh.close()
print "Wrote {0}".format(output_proto)
$python convert-convnet2caffe.py saved-convnet-checkpoint

4. Now you should find two files: saved-convnet-checkpoint-proto and saved-convnet-checkpoint-prototxt, they are in an older format, you need some tools provided by Caffe to upgrade them.

5. checkout and compile the up-to-date (or any more recent stable) version of Caffe

6. Under build/tools/ you will find tools named upgrade_net_proto_text.bin and upgrade_net_proto_binary.bin, use them to upgrade the saved-convnet-checkpoint-proto and saved-convnet-checkpoint-prototxt accordingly.

7. Almost done, you may need to manually fix the prototext file a little bit for example, add the input layer following any example proto text files provided by the Caffe.

Good luck!