CORDEA blog

Android application engineer

Android で Path を animation させるには

android で線を引くようなアニメーションを行う方法について


リポジトリはこちらですgithub.com


とりあえず今回は四角形を描きます

public class PathAnimationView extends View {

    private Path mPath;
    private PathMeasure mMeasure;

    public PathAnimationView(Context context) {
        super(context);
        init();
    }

    public PathAnimationView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public PathAnimationView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        Path path = new Path();
        path.moveTo(50, 50);
        path.lineTo(50, 100);
        path.lineTo(100, 100);
        path.lineTo(100, 50);
        path.lineTo(50, 50);

        mPath = path;
    }
}

 

あとで path の長さを取得して animation させるので、ここで pathMeasure に path をセットしておきます
また、 Lollipop より低い version の場合、正常に描画されない場合があるので、Hardware Acceleration を切ります


    private void init() {
        Path path = new Path();
        path.moveTo(50, 50);
        path.lineTo(50, 100);
        path.lineTo(100, 100);
        path.lineTo(100, 50);
        path.lineTo(50, 50);

        PathMeasure measure = new PathMeasure();
        measure.setPath(path, false);

        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
            setLayerType(View.LAYER_TYPE_SOFTWARE, null);
        }

        mPath = path;
        mMeasure = measure;
    }


 

onDraw の中身は普通に描画する場合と特に変わりません
objectAnimator を使って、0.0-1.0 までの各地点で path を切り出してそれを描画します

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        Paint paint = new Paint();
        paint.setAntiAlias(true);
        paint.setColor(getResources().getColor(android.R.color.black));
        paint.setStrokeWidth(5);
        paint.setStyle(Paint.Style.STROKE);

        canvas.drawPath(mPath, paint);
    }

 

objectAnimator の部分

    private void setProgress(float progress) {
        mPath.reset();
        mMeasure.getSegment(0.0f, mMeasure.getLength() * progress, mPath, true);
        invalidate();
    }

    public void startAnimation() {
        ObjectAnimator animator = ObjectAnimator.ofFloat(this, "progress", 0.0f, 1.0f);
        animator.setDuration(5000);
        animator.start();
    }

 
あとはこの view を追加して startAnimation() を呼び出す

Jenkins を Docker で運用する

自宅のサーバーで運用している jenkins を docker 上で運用したら楽そうな気がしたので docker のインストールから確認まで行ったメモ。

といっても特に移行作業などはせず、もともと動いていた jenkins を停止して docker hub に公開されている jenkins を pull します。

環境

手順

Install docker

docker 入ってなかった

% sudo yum install -y docker

configure

% vim ~/.zshrc
..

export DOCKER_HOST=tcp://0.0.0.0:2376

...
% source ~/.zshrc


 

docker 起動時の設定を修正する。

% sudo vim /etc/sysconfig/docker
...

OPTIONS='--selinux-enabled -H tcp://0.0.0.0:2376 -H unix:///var/run/docker.sock -G docker'

...

INSECURE_REGISTRY='--insecure-registry 0.0.0.0:2376'

...

ユーザーを docker グループに追加する

% sudo groupadd docker
% sudo usermod -aG docker $USER


 
 
firewalld を切って iptables を使用する

% sudo systemctl stop firewalld.service
% sudo systemctl disable firewalld.service
% sudo systemctl start iptables.service
% sudo systemctl enable iptables.service

 

Pull

% docker pull jenkins
% docker run --name myjenkins -p 8080:8080 jenkins

 

ここまでやって localhost:8080 にアクセスすると jenkins が立ち上がっていることが確認できます。
はじめは tlsverify をするつもりだったのでかなり苦戦しましたが、結局諦めました...やり方が分かったら追記します
 

 

【Python】画像の寒色・暖色を判定するプログラム

画像の寒色・暖色を判断するプログラムというのはあまり無いので書いてみた。

stackoverflowの投稿をもとに、rgb -> hsv に変換し、hの範囲で判断する。
結局のところ、どこまでの寒色・暖色とするかは用途や人によって違うと思うので、とりあえずパーセンテージで出力。
いくつか試してみたけど予想以上に上手く行っているので驚いた。

#!/usr/bin/env python
# encoding:utf-8
#
# Copyright [2015] [Yoshihiro Tanaka]
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

__Author__ =  "Yoshihiro Tanaka <contact@cordea.jp>"
__date__   =  "2015-05-16"

from PIL import Image
import sys, colorsys

def main(filename):
    image = Image.open(filename)

    width, height = image.size
    pixel = image.load()

    data = []
    for w in range(width):
        for h in range(height):
            r, g, b = [r/255.0 for r in pixel[w, h]]
            data.append((colorsys.rgb_to_hsv(r, g, b)[0])*255.0)
    
    warmcool = [0, 0]
    for h in data:
        if 0 <= h <= 80 or 330 <= h <= 360:
            warmcool[0] += 1
        else:
            warmcool[1] += 1

    per = (warmcool[0] / float(sum(warmcool))) * 100
    print("warm: %f %%" % per)

if __name__=='__main__':
    main(sys.argv[1])

AFNetworking+OnoでXMLを取ってきてパースする

調べたらいっぱい出てくるんですけど、若干やり方変わったようなのでメモ。

何も考えずAFXMLParserとか使うとNSXMLParserが返ってくるので若干その後の処理が面倒になりそうな様子。

#import "XMLParser.h"
#import <AFNetworking/AFNetworking.h>
#import <AFOnoResponseSerializer/AFOnoResponseSerializer.h>
#import <Ono/Ono.h>

@implementation XMLParser

// method: 1
- (void) parseXMLUsingAFNetworkingAndOnoFirst: (NSString *)url {
    AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
    manager.responseSerializer = [AFOnoResponseSerializer XMLResponseSerializer];
    
    [manager
     GET:url
     parameters:nil
     success:^(AFHTTPRequestOperation *operation, ONOXMLDocument *responseDocument) {
         // ONOXMLDocument
         NSLog(@"responseDocument: %@", [responseDocument class]);
         // ref. https://github.com/AFNetworking/AFOnoResponseSerializer
     } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
         NSLog(@"failure: %@", error);
     }];
}

// method: 2
- (void) parseXMLUsingAFNetworkingAndOnoSecond: (NSString *)url {
    AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
    manager.responseSerializer = [AFHTTPResponseSerializer serializer];
    
    [manager
     GET:url
     parameters:nil
     success:^(AFHTTPRequestOperation *operation, id responseObject) {
         // _NSInlineData
         NSLog(@"responseObject: %@", [operation.responseData class]);
         // HTMLDocumentWithDataとか適当に
     } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
         NSLog(@"failure: %@", error);
     }];
}

// NSXMLParser使う場合
- (void) parseXMLUsingAFNetworking: (NSString *)url {
    AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
    manager.responseSerializer = [AFXMLParserResponseSerializer serializer];
    
    [manager
     GET:url
     parameters:nil
     success:^(AFHTTPRequestOperation *operation, id responseObject) {
         // NSXMLParser
         NSLog(@"responseObject: %@", [responseObject class]);
     } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
         NSLog(@"failure: %@", error);
     }];
}

@end

どうでも良いがobj-cのシンタックスハイライトが微妙すぎて笑える。
久々にブログ書いて疲れたので大した説明もなしで終わり。

【pylearn2】自分のデータセットを使ってカンタンにGRBMしよう

はじめに

pylearn2というdeep learning libraryは、installしていくつかのサンプルを動かすだけなら割と簡単です。

ただ、いざ自分の用意したデータセットを使用してdeep learningさせようと思うと意外に大変。

というわけで可能な限り簡単に自分のデータセットを使ってGRBM(Gaussian restricted Boltzmann machine)を行うためのパイプラインを作成しました。
なんか間違ってたら適当に修正して下さい。

 

hoge_dataset.pyとgrbm.yamlこちらのプログラムにいくつか私が変更を加えたものです。
私が作成したものではないパラメータ等ありますので、元のリポジトリもご参照下さい。


github.com

 

方法

 

pylearn2のinstallはいろんなところで書かれていますので割愛します。
 

自分のデータセットを作成

識別したい画像を用意してこんな感じで配置
配置する場所はPYLEARN2_DATA_PATH内にディレクトリ作ってその中に
今回は ${PYLEARN2_DATA_PATH}/train_test 内に in ディレクトリを作成したものとして書いています
 

in ディレクトリの名前が紛らわしいと感じたならconvert_image.pyの_DIRを修正して下さい。
 

└── in
    ├── class_1
    │   ├── 1.jpg
    │   └── 2.jpg
    ├── class_2
    │   ├── 1.jpg
    │   └── 2.jpg
    └── class_3
        ├── 1.jpg
        └── 2.jpg
% mv in ${PYLEARN2_DATA_PATH}/train_test/

 

下準備

% PYLEARN2_INSTALL_DIR=$HOME # installした場所
% cd $PYLEARN2_INSTALL_DIR/pylearn2/pylearn2/scripts/tutorials/ # 別にどこでもいいです
% git clone https://github.com/CORDEA/use_images_in_pylearn2.git
% cd use_images_in_pylearn2
% mv *.py $PYLEARN2_INSTALL_DIR/pylearn2/pylearn2/datasets/

実行

% train.py grbm.yaml

重みの可視化

% show_weight.py grbm.pkl

 

設定値など

ディレクトリをtrain_testとして書いてありますので、適宜読み替えて下さい。

各種パラメータについて

grbm.yamlにおけるパラメータで大体設定できるようにしてあります。

  • which_set
    • csvの名前になります
  • base_path
    • 自分のデータセットを置いたディレクトリへのPATHです
  • image_to_csv
    • Trueにすると in ディレクトリにあるimageをcsvにしてから学習に移ります
  • image_size
    • imageの大きさです。defaultで128ですがコンピュータの処理性能等や目的に応じて。
  • color
    • defaultでFalseです。Trueにすると色情報を持ったcsvになりますが、次元数が3倍に。
  • save
    • defaultでFalseです。TrueにするとnpyファイルをPYLEARN2_DATA_PATH/train_test/に保存します。既にnpyファイルが存在する場合はcsvファイルではなくnpyファイルを読み込みます。

 

作成されるファイルについて

  • ${PYLEARN2_DATA_PATH}/train_test/train.csv
    • imageから作成したcsvファイル
  • ${PYLEARN2_DATA_PATH}/train_test/comparative_table.name
    • labelとディレクトリ, 画像名の対応表。いらないような気がします
  • ${PYLEARN2_DATA_PATH}/train_test/*.npy
    • numpyのファイル, 詳しくはhoge_dataset.pyを参照して下さい。saveがTrueである場合のみ作成及び読み込みを行います。

Caffe, Pylearn2をそれぞれinstallしたDockerコンテナをDocker Hubに公開した

QiitaにてCaffe, Pylearn2のinstallに関する記事を投稿したところTwitterで次のような反応を頂きました。


これは私も感じていたことで、installが一番の関門ではないにしろ、「ちょっと使ってみたい」というユーザーを阻むには十分すぎる障壁だろうと思います。

 

もちろん、Pylearn2はVagrantに慣れていればVMが公開されているのでそちらを使用する手もあります。

一応Dockerfileも書いてはいる(動作確認はしていない)のですが、そもそもDockerfileを使用するにも時間が掛かるので、Docker Hubにコンテナを公開することにしました。

他の方も同じようなコンテナは公表しておられますので、そこらへんは好みで...

 

使い方とか

Caffe

% docker pull cordea/pycaffe

Caffeのmake, python wrapperに必要なライブラリのinstall, pathを通すところまで終了している状態のコンテナです。
Qiitaの記事で言うと"make"まで終了しています。


Pylearn2

% docker pull cordea/pylearn2

pylearn2のinstallとpathを通すところまで終了している状態のコンテナです。

docker上のUbuntu 14.04にcaffeをinstall

Caffe

Caffeはディープラーニングのフレームワークです。


BVLC/caffe · GitHub


はじめに

今回はDocker上のUbuntuにCaffeをinstallします。
GPUが絡むと面倒なので、今回はCPUモードで使用します。
また、Pythonで使用するための設定やインストールは行いません。
そちらは本家のInstallationを参考にして下さい。

  • 2015/01/26 追記

 CaffeのPython wrapperを使用するための手順を追記したものをQiitaに投稿しました。
 Pythonで使用される方はそちらをご覧ください。

Version

  • Docker version 1.3.2, build 39fa2fa/1.3.2

手順

ユーザーの作成

行わなくても問題ありません

% docker run -it --name="caffe" ubuntu /bin/bash
root@4536d063fc8a:/# adduser --disabled-password --gecos '' cordea
root@4536d063fc8a:/# adduser cordea sudo
root@4536d063fc8a:/# echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers


 

installとか

root@4536d063fc8a:/# su cordea
cordea@4536d063fc8a:/$ cd home/cordea/
cordea@4536d063fc8a:~$ sudo apt-get update
cordea@4536d063fc8a:~$ sudo apt-get install git vim wget make bc libprotobuf-dev libleveldb-dev libsnappy-dev libopencv-dev libboost-all-dev libhdf5-serial-dev libblas-dev libatlas-base-dev libgflags-dev libgoogle-glog-dev liblmdb-dev protobuf-compiler
cordea@4536d063fc8a:~$ mkdir caffe
cordea@4536d063fc8a:~$ cd caffe/


 

CUDA

CPUモードではGraphics Driverは必要ありませんが、CUDA Toolkitは必要なようなのでToolkitだけinstallします。

cordea@4536d063fc8a:~/caffe$ wget http://developer.download.nvidia.com/compute/cuda/6_5/rel/installers/cuda_6.5.14_linux_64.run
cordea@4536d063fc8a:~/caffe$ chmod u+x cuda_6.5.14_linux_64.run 
cordea@4536d063fc8a:~/caffe$ ./cuda_6.5.14_linux_64.run 
Do you accept the previously read EULA? (accept/decline/quit): accept
Install NVIDIA Accelerated Graphics Driver for Linux-x86_64 340.29? ((y)es/(n)o/(q)uit): n
Install the CUDA 6.5 Toolkit? ((y)es/(n)o/(q)uit): y
Enter Toolkit Location [ default is /usr/local/cuda-6.5 ]: 
/usr/local/cuda-6.5 is not writable.
Do you wish to run the installation with 'sudo'? ((y)es/(n)o): y
Do you want to install a symbolic link at /usr/local/cuda? ((y)es/(n)o/(q)uit): y
Install the CUDA 6.5 Samples? ((y)es/(n)o/(q)uit): n
Installing the CUDA Toolkit in /usr/local/cuda-6.5 ...

===========
= Summary =
===========

Driver:   Not Selected
Toolkit:  Installed in /usr/local/cuda-6.5
Samples:  Not Selected

cordea@4536d063fc8a:~/caffe$ sudo ldconfig /usr/local/cuda-6.5/lib64/


 

makeとか

runtestでerrorが出るのはGPUが無いからだ...と思います

cordea@4536d063fc8a:~/caffe$ git clone https://github.com/BVLC/caffe
cordea@4536d063fc8a:~/caffe$ cd caffe/
cordea@4536d063fc8a:~/caffe/caffe$ cp Makefile.config.example Makefile.config         
cordea@4536d063fc8a:~/caffe/caffe$ make all
cordea@4536d063fc8a:~/caffe/caffe$ make test
cordea@4536d063fc8a:~/caffe/caffe$ make runtest
.build_release/test/test_all.testbin 0 --gtest_shuffle
libdc1394 error: Failed to initialize libdc1394
Cuda number of devices: 0
Setting to use device 0
Current device id: 0
Note: Randomizing tests' orders with a seed of 65626 .
[==========] Running 838 tests from 169 test cases.
[----------] Global test environment set-up.
[----------] 7 tests from SyncedMemoryTest
[ RUN      ] SyncedMemoryTest.TestInitialization
[       OK ] SyncedMemoryTest.TestInitialization (0 ms)
[ RUN      ] SyncedMemoryTest.TestAllocationCPU
[       OK ] SyncedMemoryTest.TestAllocationCPU (0 ms)
[ RUN      ] SyncedMemoryTest.TestCPUWrite
[       OK ] SyncedMemoryTest.TestCPUWrite (0 ms)
[ RUN      ] SyncedMemoryTest.TestGPUWrite
F0120 07:23:59.559131 31252 syncedmem.cpp:51] Check failed: error == cudaSuccess (35 vs. 0)  CUDA driver version is insufficient for CUDA runtime version
*** Check failure stack trace: ***
    @     0x2b0c0e68ddaa  (unknown)
    @     0x2b0c0e68dce4  (unknown)
    @     0x2b0c0e68d6e6  (unknown)
    @     0x2b0c0e690687  (unknown)
    @           0x70090b  caffe::SyncedMemory::mutable_gpu_data()
    @           0x5bf8ad  caffe::SyncedMemoryTest_TestGPUWrite_Test::TestBody()
    @           0x65a883  testing::internal::HandleExceptionsInMethodIfSupported<>()
    @           0x651327  testing::Test::Run()
    @           0x6513ce  testing::TestInfo::Run()
    @           0x6514d5  testing::TestCase::Run()
    @           0x654818  testing::internal::UnitTestImpl::RunAllTests()
    @           0x654aa7  testing::UnitTest::Run()
    @           0x41d480  main
    @     0x2b0c114b4ec5  (unknown)
    @           0x4244b7  (unknown)
    @              (nil)  (unknown)
make: *** [runtest] Aborted (core dumped)


 

試す

Tutorialにしたがって動作を確認します。

prototxtを編集しないとエラーが出ますので、"lenet_solver.prototxt"の一番下の行のGPUをCPUに変更して下さい。

cordea@4536d063fc8a:~/caffe/caffe$ vim examples/mnist/lenet_solver.prototxt
cordea@4536d063fc8a:~/caffe/caffe$ ./data/mnist/get_mnist.sh 
cordea@4536d063fc8a:~/caffe/caffe$ ./examples/mnist/create_mnist.sh
cordea@4536d063fc8a:~/caffe/caffe$ ./examples/mnist/train_lenet.sh